/** * SIEM connector registry. * * Every connector implements the same `SiemConnector` interface so the * poc-from-siem tool can iterate them for credential discovery and pick * one by id for event pulls. * * Adding a new SIEM: * 1. Implement a `SiemConnector` in its own file under src/lib/siem/ * 2. Export it here in `ALL_CONNECTORS` * 3. Add its id to `SiemId` in pricing.ts * 4. Add defaults to `DEFAULT_ANALYZER_COST_PER_GB` */ import type { SiemId } from './pricing.js'; import { SIEM_DISPLAY_NAMES } from './pricing.js'; export type CredentialSource = 'env' | 'cli_config' | 'ambient' | 'none'; export interface CredentialDiscovery { available: boolean; source: CredentialSource; details?: Record; } export interface SiemSchemaOverride { timestampColumn?: string; messageColumn?: string; serviceColumn?: string; severityColumn?: string; table?: string; } export interface PullEventsOptions { window: string; scope?: string; query?: string; targetEventCount: number; maxPullMinutes: number; onProgress: (p: { step: string; pct: number; eventsFetched: number; }) => void; schemaOverride?: SiemSchemaOverride; /** Number of stratified time-buckets to scatter the sample across. * Default (when undefined) is the connector's representative-sampling * count (CloudWatch: 24). A low value (1) collapses to a fast * recent-window pull — appropriate when the caller wants a quick * sample (e.g. log10x_top_patterns descriptors + field-variation) * rather than time-representative coverage. Trades temporal spread * for speed: 24 parallel-hash buckets blow past the per-hash timeout; * 1 bucket returns ~250 events in a single ~3s call. */ buckets?: number; } /** * Why a pull stopped. * * `source_exhausted` means "every slice we asked for came back empty", which * for a stratified sampler (CloudWatch draws 24 scattered sub-windows) says * only that the sample was drawn — not that the source held nothing more. * Every connector initialises its reason to this value and overwrites it on * the other outcomes, so it is a fall-through, never a positive finding. It * must not be read as evidence about pattern discovery; see * `saturation_reached` in poc-envelope-v2, which is measured separately. */ export type PullStopReason = 'target_reached' | 'time_exhausted' | 'source_exhausted' | 'error'; export interface PullEventsResult { events: unknown[]; metadata: { actualCount: number; truncated: boolean; queryUsed: string; reasonStopped: PullStopReason; notes?: string[]; }; } export interface VolumeDetectionOptions { /** Scope from the POC submit (log group, index, workspace, etc.). */ scope?: string; /** * How many days of history to average. Implementations default to 7 * when possible, fall back to whatever window the vendor API gives. */ lookbackDays?: number; /** ClickHouse-specific — the table to measure. */ schemaOverride?: SiemSchemaOverride; } export interface VolumeDetectionResult { /** * Detected daily volume in GB/day. Undefined when detection fails or * isn't supported on this SIEM / install. */ dailyGb?: number; /** * Human-readable description of the source, e.g., "CloudWatch * describeLogGroups / 30d retention" — shown in the report banner. */ source?: string; /** * Short reason when detection failed or was skipped (e.g., insufficient * scope, API 403, self-hosted install without usage API). Surfaced in * the report so users know what to fix. */ errorNote?: string; /** * Cost-figure uncertainty bracket. Undefined when `dailyGb` was read * from a byte-precise source (Datadog usage/logs byte endpoint, ES * `_stats`, CloudWatch `storedBytes` with explicit retention). Set * when a fallback estimator was used (Datadog `logs_by_index` × * 500 B/event, CloudWatch NEVER_EXPIRE retention) so the renderer * can emit a range instead of a single misleading headline number. * * Multipliers apply to the headline cost: e.g., `{ low: 0.4, high: 4 }` * means the true cost likely sits between 0.4× and 4× the central * estimate. The wide bracket is intentional — Datadog log line sizes * range from 200 B (small structured) to 2 KB (verbose JSON), so a * 500 B/event guess can be wrong in either direction by 10×. */ rangeMultiplier?: { low: number; high: number; }; } export interface SiemConnector { id: SiemId; displayName: string; discoverCredentials(): Promise; pullEvents(opts: PullEventsOptions): Promise; /** * Optional — best-effort auto-detection of the customer's total daily * log volume. Used to project sample-observed pattern cost to annual * savings. Implementations should fail-soft and return an errorNote * rather than throwing. */ detectDailyVolumeGb?(opts: VolumeDetectionOptions): Promise; } export declare const ALL_CONNECTORS: SiemConnector[]; export declare function getConnector(id: string): SiemConnector; export interface DiscoveredConnector { id: SiemId; displayName: string; detection: CredentialDiscovery; } /** Run credential discovery on every registered connector in parallel. */ export declare function discoverAvailable(): Promise; /** * Parse a window expression like `1h`, `24h`, `7d`, `30d` into milliseconds. * Accepts minute/hour/day suffixes. Throws on invalid input. */ export declare function parseWindowMs(expr: string): number; export { SIEM_DISPLAY_NAMES }; export type { SiemId } from './pricing.js';