UNPKG

@vigilbase/cli

Version:

Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.

111 lines (110 loc) • 7.44 kB
import { z } from 'zod'; const record = z.record(z.string(), z.unknown()); const rows = z.array(record); const passthrough = (shape) => z.object(shape).passthrough(); /** Wire envelopes match One's flarehawk-ui normalizers; JSON retains evidence fields. */ export const securityResponses = { analytics: passthrough({ data: record }), analyticsRows: passthrough({ data: rows }), dnsSecurity: passthrough({ data: passthrough({ series: rows, top_domains: rows }) }), providerEvents: passthrough({ data: rows, hasData: z.boolean(), count: z.number(), provider: z.string(), dataset: z.string(), aggregates: record.nullable() }), deviceHealth: passthrough({ data: passthrough({ timeseries: rows, devices: rows }) }), appTests: passthrough({ data: passthrough({ timeseries: rows, tests: rows }) }), gateway: passthrough({ data: passthrough({ surface: z.enum(['dns', 'http', 'network']), timeseries: rows, top: rows, secondary: rows }) }), access: passthrough({ data: passthrough({ timeseries: rows, apps: rows, users: rows, idps: rows, geo: rows }) }), sessions: passthrough({ data: passthrough({ timeseries: rows, users: rows }) }), devicePosture: passthrough({ data: passthrough({ checks: rows }) }), accountInventory: passthrough({ data: passthrough({ connections: rows, assetDatasets: rows, logpushJobs: rows }) }), accountAudit: passthrough({ data: passthrough({ summary: record, over_time: rows, top_actions: rows, top_resource_products: rows, outcomes: rows, recent_changes: rows }) }), accountIngestion: passthrough({ data: passthrough({ volume: rows, by_asset: rows }) }), accountPosture: passthrough({ data: passthrough({ posture: rows, heatmap: rows }) }), providers: passthrough({ providers: rows }), notifications: passthrough({ notifications: rows, unreadCount: z.number().int().nonnegative() }), notificationSettings: passthrough({ channels: rows, preferences: record.nullish() }), preferences: passthrough({ preferences: record }), slackChannels: passthrough({ channels: rows }), ipList: passthrough({ entries: rows }), assetRemediation: passthrough({ effective: record }), autonomy: passthrough({ settings: record }), datasets: passthrough({ datasets: z.array(z.union([z.string(), record])) }), defaultAsset: passthrough({ asset_id: z.string().uuid().nullable() }), graph: passthrough({ asset_id: z.string(), domain_id: z.string(), dataset: z.string(), nodes: rows, edges: rows }), availableAssets: passthrough({ assets: rows }), connectionRemediation: passthrough({ cascading_default: record }), logpushStatus: passthrough({ stored: record, asset: record, receipt: record, canRecreate: z.boolean(), warnings: z.array(z.string()), updatedAt: z.string() }), workerStats: passthrough({ period: record, requests: record, errors: record, cpuTime: record, queue: record.nullable(), links: record, queueMetricsError: z.string().nullable(), updatedAt: z.string() }), reportSettings: passthrough({ enabled: z.boolean(), delivery_day: z.string(), delivery_time_utc: z.string(), email_recipients: z.array(z.string()), include_traffic: z.boolean(), include_incidents: z.boolean(), include_top_threats: z.boolean() }), alerts: passthrough({ alerts: rows }), alert: passthrough({ alert: record }), shareLinks: passthrough({ share_links: rows }), lifecycleEmails: passthrough({ enabled: z.boolean() }), broadcastEmails: passthrough({ marketingEmailEnabled: z.boolean(), releaseEmailEnabled: z.boolean(), releaseInAppEnabled: z.boolean() }), applications: passthrough({ grants: rows }), overview: passthrough({ overview: passthrough({ stats: record }) }), incidents: passthrough({ incidents: rows, total: z.number() }), incident: passthrough({ incident: record }), timeline: passthrough({ events: rows, next_cursor: z.string().nullable(), degraded: z.boolean() }), logs: passthrough({ logs: rows }), assets: passthrough({ domains: rows }), detections: passthrough({ rules: rows.optional(), detections: rows.optional() }) .refine((value) => value.rules !== undefined || value.detections !== undefined), connections: passthrough({ connections: rows, total: z.number() }), connection: passthrough({ connection: record }), reports: passthrough({ reports: rows, total: z.number() }), report: passthrough({ report: record }), audit: passthrough({ events: rows, next_cursor: z.string().nullable() }), intel: passthrough({ query: z.string(), query_type: z.enum(['ip', 'asn', 'cidr', 'ja3', 'ja4']), quota: record }), quota: z.union([passthrough({ quota: record }), passthrough({ used: z.number(), remaining: z.number().nullable() })]), update: z.union([ passthrough({ ok: z.literal(true), status: z.string() }), passthrough({ success: z.literal(true), incident_id: z.string(), status: z.string() }), ]), }; export class SecurityClient { one; constructor(one) { this.one = one; } async request(input) { // Paths are generated by the command grammar. Never accept upstream URLs or tenant claims. if (!/^\/[a-z0-9/-]+$/i.test(input.path) || input.path.includes('..')) { throw new Error('Invalid security API path.'); } const params = new URLSearchParams(); for (const [key, value] of Object.entries(input.query)) { if (/^(customerId|customer_id|organizationId|organization_id|org_id)$/.test(key)) { throw new Error('Tenant identity must use the validated customer scope.'); } if (value !== undefined) params.set(key, String(value)); } if (input.customerId) params.set('customerId', z.string().uuid().parse(input.customerId)); const query = params.size ? `?${params}` : ''; const payload = await this.one.requestJson(`/api/flarehawk${input.path}${query}`, input.body ? { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(input.body), } : undefined); if (payload.success === false || payload.ok === false) { throw new Error('Security request was unsuccessful.'); } const parsed = securityResponses[input.view].safeParse(payload); if (!parsed.success) throw new Error(`Invalid security ${input.view} response from One.`); if (input.body && (payload.status !== input.body.status || (payload.incident_id !== undefined && payload.incident_id !== input.path.split('/').at(-1)))) { throw new Error('Incident update response did not match the requested incident and status.'); } if (input.view === 'intel' && (payload.query !== input.query.q || payload.query_type !== input.query.type)) { throw new Error('Intel response did not match the requested lookup.'); } if (input.view === 'providerEvents' && (payload.provider !== input.query.provider_id || payload.dataset !== input.query.dataset_id)) { throw new Error('Provider events response did not match the requested provider and dataset.'); } if (input.view === 'gateway' && payload.data.surface !== input.query.surface) { throw new Error('Gateway response did not match the requested surface.'); } return payload; } }