All files / src/entities/vulnerabilities schema-readonly.ts

100% Statements 13/13
100% Branches 4/4
100% Functions 1/1
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 10017x 17x                       17x           17x       17x       17x                               17x                         17x             17x     17x                                 17x           17x       9x            
import { z } from 'zod';
import { requiredId } from '../utils';
 
// ============================================================================
// browse_vulnerabilities - CQRS Query Tool (discriminated union schema)
// Actions: list, get
//
// Vulnerability Management is an Ultimate-tier capability. GraphQL exposes a much
// richer surface than REST (nested scanner/location/state metadata), so the entity
// is GraphQL-first. list scopes by project_id / group_id, or neither for an
// instance-wide view. Gated behind USE_VULNERABILITIES.
// ============================================================================
 
export const vulnerabilityIdField = z.coerce
  .number()
  .int()
  .positive()
  .describe('Numeric vulnerability ID (from a list action); expanded to a global ID internally.');
 
const stateFilter = z
  .array(z.enum(['DETECTED', 'CONFIRMED', 'RESOLVED', 'DISMISSED']))
  .optional()
  .describe('Filter by vulnerability state(s).');
const severityFilter = z
  .array(z.enum(['INFO', 'UNKNOWN', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL']))
  .optional()
  .describe('Filter by severity level(s).');
const reportTypeFilter = z
  .array(
    z.enum([
      'SAST',
      'DAST',
      'DEPENDENCY_SCANNING',
      'CONTAINER_SCANNING',
      'SECRET_DETECTION',
      'COVERAGE_FUZZING',
      'API_FUZZING',
      'CLUSTER_IMAGE_SCANNING',
      'GENERIC',
    ]),
  )
  .optional()
  .describe('Filter by scanner report type(s).');
const sortField = z
  .enum([
    'severity_desc',
    'severity_asc',
    'detected_desc',
    'detected_asc',
    'state_desc',
    'state_asc',
    'title_desc',
    'title_asc',
  ])
  .optional()
  .describe('Sort order (default: severity_desc).');
const firstField = z.coerce
  .number()
  .int()
  .positive()
  .max(100)
  .optional()
  .describe('Max items to return (cursor pagination, default 20, max 100).');
const afterField = z.string().optional().describe('Cursor for the next page (endCursor).');
 
// --- Action: list (project / group / instance) ---
const ListVulnerabilitiesSchema = z.object({
  action: z
    .literal('list')
    .describe(
      'List vulnerabilities. Pass project_id for a project, group_id for a group, or neither for an instance-wide view (admin).',
    ),
  project_id: requiredId.optional().describe('Project full path or ID to scope the list.'),
  group_id: requiredId.optional().describe('Group full path or ID to scope the list.'),
  state: stateFilter,
  severity: severityFilter,
  report_type: reportTypeFilter,
  sort: sortField,
  first: firstField,
  after: afterField,
});
 
// --- Action: get ---
const GetVulnerabilitySchema = z.object({
  action: z.literal('get').describe('Get a single vulnerability by its numeric ID.'),
  vulnerability_id: vulnerabilityIdField,
});
 
// --- Discriminated union combining all actions ---
export const BrowseVulnerabilitiesSchema = z
  .discriminatedUnion('action', [ListVulnerabilitiesSchema, GetVulnerabilitySchema])
  // A vulnerability list is scoped to a single namespace; project_id and group_id
  // are mutually exclusive.
  .refine((data) => data.action !== 'list' || !(data.project_id && data.group_id), {
    message: 'Pass at most one of project_id or group_id (a list targets a single scope)',
    path: ['project_id'],
  });
 
export type BrowseVulnerabilitiesInput = z.infer<typeof BrowseVulnerabilitiesSchema>;