@securitychecks/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/cloud-config.ts","../src/lib/license.ts","../src/lib/errors.ts","../src/lib/ci-detect.ts","../src/lib/cloud-eval.ts","../src/lib/project-slug.ts","../src/audit.ts","../src/lib/schema.ts","../src/findings/finding-id.ts","../src/baseline/schema.ts","../src/baseline/storage.ts","../src/baseline/matcher.ts","../src/lib/correlation.ts","../src/lib/correlation-telemetry.ts","../src/lib/telemetry.ts","../src/lib/calibration.ts","../src/lib/staff.ts","../src/lib/score.ts"],"names":["findingId","join","existsSync","readFile","mkdir","writeFile","DEFAULT_ENDPOINT","randomUUID"],"mappings":"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","file":"lib.js","sourcesContent":["/**\n * Cloud Configuration Management\n *\n * Manages CLI configuration for cloud integration with SecurityChecks.ai\n * Configuration is stored in ~/.securitychecks/config.json\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/** Configuration directory path */\nconst CONFIG_DIR = join(homedir(), '.securitychecks');\n\n/** Configuration file path */\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\n\n/** Cloud API base URL */\nconst DEFAULT_API_URL = 'https://api.securitychecks.ai';\n\nexport function normalizeApiBaseUrl(input: string): string {\n const value = input.trim();\n if (!value) {\n throw new Error('API URL is empty');\n }\n\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`Invalid API URL: ${input}`);\n }\n\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw new Error('API URL must start with http:// or https://');\n }\n\n if (url.username || url.password) {\n throw new Error('API URL must not include credentials');\n }\n\n url.hash = '';\n url.search = '';\n\n // Accept both base URLs and v1-style aliases, normalize to a base.\n // Examples:\n // - https://api.securitychecks.ai/v1 -> https://api.securitychecks.ai\n // - https://example.com/api/v1 -> https://example.com\n const pathname = url.pathname.replace(/\\/+$/, '');\n const stripped = pathname\n .replace(/\\/api\\/v1$/i, '')\n .replace(/\\/v1$/i, '');\n url.pathname = stripped.length === 0 ? '/' : `${stripped}/`;\n\n // Remove trailing slash (keep origin+path stable).\n return url.toString().replace(/\\/$/, '');\n}\n\n/**\n * Cloud configuration structure\n */\nexport interface CloudConfig {\n /** API key for authentication */\n apiKey?: string;\n\n /** Default project slug */\n project?: string;\n\n /** API base URL (for self-hosted instances) */\n apiUrl?: string;\n\n /** Enable cloud mode by default */\n cloudEnabled?: boolean;\n\n /** User email (for display purposes) */\n email?: string;\n\n /** Organization name (for display purposes) */\n organization?: string;\n\n /** Last sync timestamp */\n lastSync?: string;\n\n /** Suppress periodic usage awareness banner */\n usageBannerDisabled?: boolean;\n}\n\n/**\n * Ensure configuration directory exists\n */\nasync function ensureConfigDir(): Promise<void> {\n if (!existsSync(CONFIG_DIR)) {\n await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });\n }\n}\n\n/**\n * Load cloud configuration from disk\n */\nexport async function loadCloudConfig(): Promise<CloudConfig> {\n try {\n if (!existsSync(CONFIG_FILE)) {\n return {};\n }\n const content = await readFile(CONFIG_FILE, 'utf-8');\n return JSON.parse(content) as CloudConfig;\n } catch {\n return {};\n }\n}\n\n/**\n * Save cloud configuration to disk\n */\nexport async function saveCloudConfig(config: CloudConfig): Promise<void> {\n await ensureConfigDir();\n await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 });\n}\n\n/**\n * Update specific configuration values\n */\nexport async function updateCloudConfig(\n updates: Partial<CloudConfig>\n): Promise<CloudConfig> {\n const config = await loadCloudConfig();\n const updated = { ...config, ...updates };\n await saveCloudConfig(updated);\n return updated;\n}\n\n/**\n * Clear cloud configuration\n */\nexport async function clearCloudConfig(): Promise<void> {\n await saveCloudConfig({});\n}\n\n/**\n * Get the effective API key (from config, env, or CLI option)\n */\nexport function getApiKey(cliOption?: string): string | undefined {\n // CLI option takes precedence\n if (cliOption) return cliOption;\n\n // Then environment variable\n const envKey = process.env['SECURITYCHECKS_API_KEY'];\n if (envKey) return envKey;\n\n // Config is loaded async, so this needs to be called after loading config\n return undefined;\n}\n\n/**\n * Get the effective project slug (from config, env, or CLI option)\n */\nexport function getProject(cliOption?: string): string | undefined {\n if (cliOption) return cliOption;\n return process.env['SECURITYCHECKS_PROJECT'];\n}\n\n/**\n * Get the API base URL\n */\nexport function getApiUrl(config: CloudConfig): string {\n const raw = config.apiUrl || process.env['SECURITYCHECKS_API_URL'] || DEFAULT_API_URL;\n return normalizeApiBaseUrl(raw);\n}\n\n/**\n * Check if cloud mode is enabled\n */\nexport function isCloudEnabled(\n config: CloudConfig,\n cliOption?: boolean\n): boolean {\n if (cliOption !== undefined) return cliOption;\n if (process.env['SECURITYCHECKS_CLOUD'] === 'true') return true;\n return config.cloudEnabled ?? false;\n}\n\n/**\n * Format configuration for display\n */\nexport function formatConfig(config: CloudConfig): string {\n const lines: string[] = [];\n\n lines.push('Cloud Configuration:');\n lines.push('');\n\n if (config.apiKey) {\n const masked = config.apiKey.substring(0, 10) + '...' + config.apiKey.slice(-4);\n lines.push(` API Key: ${masked}`);\n } else {\n lines.push(' API Key: (not set)');\n }\n\n lines.push(` Project: ${config.project || '(not set)'}`);\n lines.push(` API URL: ${config.apiUrl || DEFAULT_API_URL}`);\n lines.push(` Cloud Mode: ${config.cloudEnabled ? 'enabled' : 'disabled'}`);\n\n if (config.email) {\n lines.push(` Email: ${config.email}`);\n }\n\n if (config.organization) {\n lines.push(` Organization: ${config.organization}`);\n }\n\n if (config.lastSync) {\n lines.push(` Last Sync: ${config.lastSync}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Validate API key format\n */\nexport function isValidApiKey(key: string): boolean {\n // API keys should start with sc_live_ or sc_test_\n return /^sc_(live|test)_[a-zA-Z0-9]{20,}$/.test(key);\n}\n\nexport { CONFIG_DIR, CONFIG_FILE, DEFAULT_API_URL };\n","/**\n * Cloud Access (Thinware)\n *\n * Local scans always run. Cloud features require an API key.\n */\n\nimport { normalizeApiBaseUrl } from './cloud-config.js';\n\nconst CLOUD_API_KEY_ENV_VARS = [\n 'SECURITYCHECKS_API_KEY',\n 'SECURITYCHECKS_LICENSE_KEY',\n];\n\nconst DEFAULT_CLOUD_BASE_URL = 'https://api.securitychecks.ai';\n\nexport function getCloudApiKey(): string | undefined {\n for (const envVar of CLOUD_API_KEY_ENV_VARS) {\n const value = process.env[envVar];\n if (value) {\n return value;\n }\n }\n return undefined;\n}\n\nexport function formatCloudStatus(apiKey?: string): string {\n if (apiKey) {\n return 'local + cloud (API key detected)';\n }\n return 'local-only (cloud features require SECURITYCHECKS_API_KEY)';\n}\n\nexport function getCloudApiBaseUrl(): string {\n const raw = process.env['SECURITYCHECKS_API_URL'] ?? DEFAULT_CLOUD_BASE_URL;\n return normalizeApiBaseUrl(raw);\n}\n\nexport function getCloudEndpoints(baseUrl?: string): {\n patterns: string;\n calibrate: string;\n telemetry: string;\n correlations: string;\n aggregateCalibration: string;\n} {\n const base = baseUrl ?? getCloudApiBaseUrl();\n return {\n patterns: `${base}/v1/patterns`,\n calibrate: `${base}/v1/calibrate`,\n telemetry: `${base}/v1/telemetry`,\n correlations: `${base}/v1/correlations`,\n aggregateCalibration: `${base}/v1/calibration`,\n };\n}\n","/**\n * Deterministic Error Codes for SecurityChecks CLI\n *\n * Format: SC_<CATEGORY>_<NUMBER>\n *\n * Categories:\n * - CONFIG: Configuration errors\n * - PARSE: Parsing/syntax errors\n * - CHECK: Checker execution errors\n * - IO: File system / network errors\n * - CLI: Command line argument errors\n */\n\nexport const ErrorCodes = {\n // CONFIG errors (001-099)\n CONFIG_NOT_FOUND: 'SC_CONFIG_001',\n CONFIG_INVALID: 'SC_CONFIG_002',\n CONFIG_SCHEMA_ERROR: 'SC_CONFIG_003',\n\n // PARSE errors (100-199)\n PARSE_TYPESCRIPT_ERROR: 'SC_PARSE_101',\n PARSE_FILE_NOT_FOUND: 'SC_PARSE_102',\n PARSE_UNSUPPORTED_SYNTAX: 'SC_PARSE_103',\n\n // CHECK errors (200-299)\n CHECK_EXECUTION_ERROR: 'SC_CHECK_201',\n CHECK_TIMEOUT: 'SC_CHECK_202',\n CHECK_INVARIANT_NOT_FOUND: 'SC_CHECK_203',\n\n // IO errors (300-399)\n IO_READ_ERROR: 'SC_IO_301',\n IO_WRITE_ERROR: 'SC_IO_302',\n IO_PERMISSION_DENIED: 'SC_IO_303',\n IO_PATH_NOT_FOUND: 'SC_IO_304',\n\n // CLI errors (400-499)\n CLI_INVALID_ARGUMENT: 'SC_CLI_401',\n CLI_MISSING_ARGUMENT: 'SC_CLI_402',\n CLI_UNKNOWN_COMMAND: 'SC_CLI_403',\n\n // ARTIFACT errors (500-599)\n ARTIFACT_NOT_FOUND: 'SC_ARTIFACT_501',\n ARTIFACT_INVALID: 'SC_ARTIFACT_502',\n ARTIFACT_VERSION_MISMATCH: 'SC_ARTIFACT_503',\n\n // CLOUD errors (600-699)\n CLOUD_AUTH_FAILED: 'SC_CLOUD_601',\n CLOUD_PERMISSION_DENIED: 'SC_CLOUD_602',\n CLOUD_NOT_FOUND: 'SC_CLOUD_603',\n CLOUD_RATE_LIMITED: 'SC_CLOUD_604',\n CLOUD_API_ERROR: 'SC_CLOUD_605',\n CLOUD_NETWORK_ERROR: 'SC_CLOUD_606',\n CLOUD_INVALID_API_KEY: 'SC_CLOUD_607',\n AUTH_REQUIRED: 'SC_CLOUD_608',\n OFFLINE_NOT_SUPPORTED: 'SC_CLOUD_609',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\n/**\n * User-friendly error messages for each error code\n */\nexport const ErrorMessages: Record<ErrorCode, string> = {\n [ErrorCodes.CONFIG_NOT_FOUND]: 'Configuration file not found',\n [ErrorCodes.CONFIG_INVALID]: 'Configuration file is invalid',\n [ErrorCodes.CONFIG_SCHEMA_ERROR]: 'Configuration does not match expected schema',\n\n [ErrorCodes.PARSE_TYPESCRIPT_ERROR]: 'Failed to parse TypeScript file',\n [ErrorCodes.PARSE_FILE_NOT_FOUND]: 'Source file not found',\n [ErrorCodes.PARSE_UNSUPPORTED_SYNTAX]: 'Unsupported syntax encountered',\n\n [ErrorCodes.CHECK_EXECUTION_ERROR]: 'Error executing invariant check',\n [ErrorCodes.CHECK_TIMEOUT]: 'Invariant check timed out',\n [ErrorCodes.CHECK_INVARIANT_NOT_FOUND]: 'Invariant not found',\n\n [ErrorCodes.IO_READ_ERROR]: 'Failed to read file',\n [ErrorCodes.IO_WRITE_ERROR]: 'Failed to write file',\n [ErrorCodes.IO_PERMISSION_DENIED]: 'Permission denied',\n [ErrorCodes.IO_PATH_NOT_FOUND]: 'Path not found',\n\n [ErrorCodes.CLI_INVALID_ARGUMENT]: 'Invalid argument provided',\n [ErrorCodes.CLI_MISSING_ARGUMENT]: 'Required argument missing',\n [ErrorCodes.CLI_UNKNOWN_COMMAND]: 'Unknown command',\n\n [ErrorCodes.ARTIFACT_NOT_FOUND]: 'Artifact file not found',\n [ErrorCodes.ARTIFACT_INVALID]: 'Invalid artifact format',\n [ErrorCodes.ARTIFACT_VERSION_MISMATCH]: 'Artifact version not supported',\n\n [ErrorCodes.CLOUD_AUTH_FAILED]: 'Authentication failed',\n [ErrorCodes.CLOUD_PERMISSION_DENIED]: 'Permission denied',\n [ErrorCodes.CLOUD_NOT_FOUND]: 'Resource not found',\n [ErrorCodes.CLOUD_RATE_LIMITED]: 'Rate limit exceeded',\n [ErrorCodes.CLOUD_API_ERROR]: 'Cloud API error',\n [ErrorCodes.CLOUD_NETWORK_ERROR]: 'Network error',\n [ErrorCodes.CLOUD_INVALID_API_KEY]: 'Invalid API key format',\n [ErrorCodes.AUTH_REQUIRED]: 'API key required for evaluation',\n [ErrorCodes.OFFLINE_NOT_SUPPORTED]: 'Offline mode is not supported',\n};\n\n/**\n * Remediation guidance for each error code\n * Helps users understand what to do when they encounter an error.\n */\nexport const ErrorRemediation: Record<ErrorCode, string> = {\n // CONFIG errors\n [ErrorCodes.CONFIG_NOT_FOUND]: `\nCreate a configuration file in your project root:\n\n scheck init\n\nOr create securitychecks.config.ts manually:\n\n export default {\n include: ['src/**/*.ts'],\n exclude: ['node_modules/**'],\n };\n`.trim(),\n\n [ErrorCodes.CONFIG_INVALID]: `\nCheck your securitychecks.config.ts for syntax errors.\n\nCommon issues:\n- Missing export default\n- Invalid JSON in securitychecks.json\n- Typo in configuration keys\n\nRun with --verbose for more details.\n`.trim(),\n\n [ErrorCodes.CONFIG_SCHEMA_ERROR]: `\nYour configuration has invalid options. Check these common issues:\n\n- 'include' and 'exclude' must be arrays of glob patterns\n- 'testPatterns' must be an array of test file patterns\n- 'servicePatterns' must be an array of service file patterns\n\nSee: https://securitychecks.ai/docs/configuration\n`.trim(),\n\n // PARSE errors\n [ErrorCodes.PARSE_TYPESCRIPT_ERROR]: `\nA TypeScript file failed to parse. This usually means:\n\n1. The file has syntax errors - run tsc to check\n2. The file uses unsupported TypeScript features\n3. There are missing dependencies\n\nTry:\n npx tsc --noEmit\n\nIf the error persists, exclude the problematic file:\n exclude: ['path/to/problematic-file.ts']\n`.trim(),\n\n [ErrorCodes.PARSE_FILE_NOT_FOUND]: `\nThe specified source file doesn't exist. Check:\n\n1. The file path is correct\n2. The file hasn't been moved or deleted\n3. Your include/exclude patterns are correct\n\nRun: ls <path> to verify the file exists.\n`.trim(),\n\n [ErrorCodes.PARSE_UNSUPPORTED_SYNTAX]: `\nThe file contains syntax that can't be parsed. This may happen with:\n\n- Very new TypeScript/JavaScript features\n- Non-standard syntax extensions\n- Malformed source code\n\nTry excluding the file or updating the parser.\n`.trim(),\n\n // CHECK errors\n [ErrorCodes.CHECK_EXECUTION_ERROR]: `\nAn invariant check failed to run. This is usually a bug in scheck.\n\nPlease report this issue with:\n1. The full error message (--verbose)\n2. A minimal reproduction\n3. Your Node.js and @securitychecks/cli versions\n\nReport at: https://github.com/securitychecks/securitychecks.ai/issues\n`.trim(),\n\n [ErrorCodes.CHECK_TIMEOUT]: `\nAn invariant check took too long. This can happen with:\n\n1. Very large codebases\n2. Complex file structures\n3. Slow file system access\n\nTry:\n- Narrowing include patterns to scan fewer files\n- Excluding large generated files\n- Running with --only to check specific invariants\n`.trim(),\n\n [ErrorCodes.CHECK_INVARIANT_NOT_FOUND]: `\nThe specified invariant ID doesn't exist.\n\nList available invariants:\n scheck explain --list\n\nCommon invariant IDs:\n- AUTHZ.SERVICE_LAYER.ENFORCED\n- WEBHOOK.IDEMPOTENT\n- TRANSACTION.POST_COMMIT.SIDE_EFFECTS\n`.trim(),\n\n // IO errors\n [ErrorCodes.IO_READ_ERROR]: `\nFailed to read a file. Check:\n\n1. The file exists and is readable\n2. You have permission to read the file\n3. The file is not locked by another process\n\nTry: cat <file> to verify readability.\n`.trim(),\n\n [ErrorCodes.IO_WRITE_ERROR]: `\nFailed to write a file. Check:\n\n1. The directory exists\n2. You have write permission\n3. There's enough disk space\n4. The file is not locked\n\nTry: touch <file> to verify writability.\n`.trim(),\n\n [ErrorCodes.IO_PERMISSION_DENIED]: `\nPermission denied accessing a file or directory.\n\nOn Unix/Mac:\n chmod +r <file> # Make readable\n chmod +w <file> # Make writable\n\nOn Windows: Check file properties > Security tab.\n`.trim(),\n\n [ErrorCodes.IO_PATH_NOT_FOUND]: `\nThe specified path doesn't exist.\n\nCheck:\n1. You're in the correct directory\n2. The path is spelled correctly\n3. The directory structure is correct\n\nRun: pwd && ls to verify your location.\n`.trim(),\n\n // CLI errors\n [ErrorCodes.CLI_INVALID_ARGUMENT]: `\nInvalid command-line argument.\n\nRun: scheck --help\n\nCommon commands:\n scheck run # Run all checks\n scheck run --ci # CI mode (fails on P0/P1)\n scheck explain <id> # Explain an invariant\n scheck init # Initialize configuration\n`.trim(),\n\n [ErrorCodes.CLI_MISSING_ARGUMENT]: `\nA required argument is missing.\n\nCheck the command syntax:\n scheck --help\n scheck <command> --help\n`.trim(),\n\n [ErrorCodes.CLI_UNKNOWN_COMMAND]: `\nUnknown command. Available commands:\n\n run Run invariant checks\n init Initialize configuration\n explain Explain an invariant\n baseline Manage baseline\n waive Waive a finding\n\nRun: scheck --help\n`.trim(),\n\n // ARTIFACT errors\n [ErrorCodes.ARTIFACT_NOT_FOUND]: `\nArtifact file not found.\n\nThe artifact file stores collected code facts. Options:\n\n1. Let scheck collect automatically (default):\n scheck run\n\n2. Collect manually first:\n npx scc collect -o .securitychecks/artifacts.json\n scheck run --artifact .securitychecks/artifacts.json\n\n3. Check if file was deleted:\n ls .securitychecks/\n`.trim(),\n\n [ErrorCodes.ARTIFACT_INVALID]: `\nThe artifact file is malformed or corrupt.\n\nCommon issues:\n- Incomplete JSON (process was killed during write)\n- Modified manually with syntax errors\n- Wrong file format\n\nFix:\n1. Delete the corrupt artifact:\n rm .securitychecks/artifacts.json\n\n2. Re-collect:\n scheck run\n (or: npx scc collect -o .securitychecks/artifacts.json)\n`.trim(),\n\n [ErrorCodes.ARTIFACT_VERSION_MISMATCH]: `\nThe artifact was created by an incompatible version.\n\nThis happens when:\n- Artifact was created by an older/newer scheck version\n- Artifact schema has changed\n\nFix:\n1. Delete the old artifact:\n rm .securitychecks/artifacts.json\n\n2. Re-collect with current version:\n scheck run\n\nYour current version: scheck --version\n`.trim(),\n\n // CLOUD errors\n [ErrorCodes.CLOUD_AUTH_FAILED]: `\nAuthentication failed. Your API key may be invalid or expired.\n\nFix:\n1. Generate a new API key at https://securitychecks.ai/dashboard/settings/api-keys\n2. Log in again:\n scheck login\n\nEnvironment variable:\n export SECURITYCHECKS_API_KEY=sc_live_...\n`.trim(),\n\n [ErrorCodes.CLOUD_PERMISSION_DENIED]: `\nYou don't have permission for this action.\n\nCheck:\n1. You have access to the project/organization\n2. Your API key has the required scopes\n3. Your subscription is active\n\nManage at: https://securitychecks.ai/dashboard\n`.trim(),\n\n [ErrorCodes.CLOUD_NOT_FOUND]: `\nThe requested resource was not found.\n\nCheck:\n1. The project slug is correct\n2. The project exists and you have access\n3. The resource ID is valid\n\nList your projects:\n scheck config --show\n`.trim(),\n\n [ErrorCodes.CLOUD_RATE_LIMITED]: `\nYou've hit the rate limit. Please try again later.\n\nOptions:\n1. Wait a few minutes and retry\n2. Upgrade your plan for higher limits\n\nPlan limits: https://securitychecks.ai/pricing\n`.trim(),\n\n [ErrorCodes.CLOUD_API_ERROR]: `\nThe SecurityChecks API returned an error.\n\nThis could be:\n1. A temporary service issue - try again shortly\n2. An invalid request - check your parameters\n\nStatus: https://status.securitychecks.ai\nHelp: https://securitychecks.ai/docs/troubleshooting\n`.trim(),\n\n [ErrorCodes.CLOUD_NETWORK_ERROR]: `\nCould not connect to SecurityChecks API.\n\nCheck:\n1. Your internet connection\n2. Firewall/proxy settings\n3. API endpoint accessibility\n\nDefault API: https://api.securitychecks.ai\n`.trim(),\n\n [ErrorCodes.CLOUD_INVALID_API_KEY]: `\nThe API key format is invalid.\n\nAPI keys should start with:\n- sc_live_ for production\n- sc_test_ for testing\n\nGet a key at: https://securitychecks.ai/dashboard/settings/api-keys\n`.trim(),\n\n [ErrorCodes.AUTH_REQUIRED]: `\nAn API key is required to run security checks.\n\nSecurityChecks uses cloud evaluation to protect proprietary patterns.\nYour source code never leaves your machine - only structural facts are sent.\n\nSetup:\n1. Get your API key at https://securitychecks.ai/dashboard/settings/api-keys\n2. Set environment variable:\n export SECURITYCHECKS_API_KEY=sc_live_...\n\nOr add to securitychecks.config.yaml:\n calibration:\n apiKey: sc_live_...\n`.trim(),\n\n [ErrorCodes.OFFLINE_NOT_SUPPORTED]: `\nOffline mode is not supported.\n\nSecurityChecks requires cloud evaluation to protect proprietary patterns.\nYour source code never leaves your machine - only structural facts are sent.\n\nOptions:\n1. Remove --offline flag and ensure network connectivity\n2. For air-gapped environments, contact sales for an enterprise on-premise license:\n https://securitychecks.ai/enterprise\n`.trim(),\n};\n\n/**\n * Structured CLI Error with deterministic error code\n */\nexport class CLIError extends Error {\n public readonly code: ErrorCode;\n public readonly details?: unknown;\n public override readonly cause?: Error;\n\n constructor(code: ErrorCode, message?: string, options?: { details?: unknown; cause?: Error }) {\n const baseMessage = message ?? ErrorMessages[code];\n super(baseMessage, { cause: options?.cause });\n\n this.name = 'CLIError';\n this.code = code;\n this.details = options?.details;\n this.cause = options?.cause;\n\n // Maintains proper stack trace for where error was thrown\n Error.captureStackTrace?.(this, CLIError);\n }\n\n /**\n * Get remediation guidance for this error\n */\n getRemediation(): string {\n return ErrorRemediation[this.code];\n }\n\n /**\n * Format error for user display\n */\n toUserString(verbose = false): string {\n const parts: string[] = [`[${this.code}] ${this.message}`];\n\n if (verbose && this.details) {\n parts.push(`\\nDetails: ${JSON.stringify(this.details, null, 2)}`);\n }\n\n if (verbose && this.cause) {\n parts.push(`\\nCaused by: ${this.cause.message}`);\n if (this.cause.stack) {\n parts.push(`\\n${this.cause.stack}`);\n }\n }\n\n return parts.join('');\n }\n\n /**\n * Format error with remediation for user display\n */\n toUserStringWithRemediation(): string {\n const parts: string[] = [this.toUserString()];\n const remediation = this.getRemediation();\n\n if (remediation) {\n parts.push('\\n\\nHow to fix:\\n');\n // Indent each line of remediation\n const indented = remediation\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n parts.push(indented);\n }\n\n return parts.join('');\n }\n\n /**\n * Format error for JSON output\n */\n toJSON(): Record<string, unknown> {\n return {\n code: this.code,\n message: this.message,\n remediation: this.getRemediation(),\n details: this.details,\n cause: this.cause\n ? {\n message: this.cause.message,\n stack: this.cause.stack,\n }\n : undefined,\n };\n }\n}\n\n/**\n * Check if an error is a CLIError\n */\nexport function isCLIError(error: unknown): error is CLIError {\n return error instanceof CLIError;\n}\n\n/**\n * Wrap an unknown error in a CLIError\n */\nexport function wrapError(error: unknown, code: ErrorCode, message?: string): CLIError {\n if (error instanceof CLIError) {\n return error;\n }\n\n const cause = error instanceof Error ? error : new Error(String(error));\n return new CLIError(code, message, { cause });\n}\n","/**\n * CI Environment Detection\n *\n * Detects CI/CD environment and extracts relevant context\n * (branch, commit SHA, PR number) for proper scan association.\n */\n\nimport { readFileSync } from 'node:fs';\n\nexport interface CIContext {\n /** CI provider name */\n provider: 'github-actions' | 'gitlab-ci' | 'circleci' | 'jenkins' | 'unknown';\n /** Git branch name */\n branch?: string;\n /** Git commit SHA */\n commitSha?: string;\n /** Pull/Merge request number */\n prNumber?: number;\n /** Repository name (owner/repo) */\n repository?: string;\n /** Whether this is a PR/MR event */\n isPullRequest: boolean;\n}\n\n/**\n * Detect CI environment and extract context\n */\nexport function detectCIContext(): CIContext | null {\n // GitHub Actions\n if (process.env['GITHUB_ACTIONS'] === 'true') {\n return detectGitHubActions();\n }\n\n // GitLab CI\n if (process.env['GITLAB_CI'] === 'true') {\n return detectGitLabCI();\n }\n\n // CircleCI\n if (process.env['CIRCLECI'] === 'true') {\n return detectCircleCI();\n }\n\n // Jenkins\n if (process.env['JENKINS_URL']) {\n return detectJenkins();\n }\n\n // Not in CI\n return null;\n}\n\n/**\n * Detect GitHub Actions context\n */\nfunction detectGitHubActions(): CIContext {\n const eventName = process.env['GITHUB_EVENT_NAME'];\n const isPullRequest = eventName === 'pull_request' || eventName === 'pull_request_target';\n const eventPayload = readGitHubEventPayload();\n\n // For PRs, use the head branch; for pushes, parse from GITHUB_REF\n let branch: string | undefined;\n if (isPullRequest) {\n branch = eventPayload?.pull_request?.head?.ref || process.env['GITHUB_HEAD_REF'];\n } else {\n const ref = process.env['GITHUB_REF'] || '';\n // refs/heads/main -> main\n branch = ref.replace(/^refs\\/heads\\//, '');\n }\n\n // In GitHub pull_request workflows, GITHUB_SHA is often the synthetic merge commit.\n // Prefer payload head SHA so we can associate scans to webhook-created PR scans/check-runs.\n const commitSha = isPullRequest\n ? eventPayload?.pull_request?.head?.sha || process.env['GITHUB_SHA']\n : process.env['GITHUB_SHA'];\n\n // Prefer payload PR number, then fallback to refs/pull/<n>/merge parsing.\n let prNumber: number | undefined;\n if (isPullRequest) {\n prNumber = eventPayload?.number;\n if (!prNumber) {\n const prRef = process.env['GITHUB_REF'] || '';\n const match = prRef.match(/refs\\/pull\\/(\\d+)/);\n if (match && match[1]) {\n prNumber = parseInt(match[1], 10);\n }\n }\n }\n\n return {\n provider: 'github-actions',\n branch,\n commitSha,\n prNumber,\n repository: process.env['GITHUB_REPOSITORY'],\n isPullRequest,\n };\n}\n\ninterface GitHubPullRequestPayload {\n number?: number;\n pull_request?: {\n head?: {\n sha?: string;\n ref?: string;\n };\n };\n}\n\nfunction readGitHubEventPayload(): GitHubPullRequestPayload | null {\n const eventPath = process.env['GITHUB_EVENT_PATH'];\n if (!eventPath) {\n return null;\n }\n\n try {\n const raw = readFileSync(eventPath, 'utf8');\n return JSON.parse(raw) as GitHubPullRequestPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Detect GitLab CI context\n */\nfunction detectGitLabCI(): CIContext {\n const mrIid = process.env['CI_MERGE_REQUEST_IID'];\n const isPullRequest = !!mrIid;\n\n let prNumber: number | undefined;\n if (mrIid) {\n prNumber = parseInt(mrIid, 10);\n }\n\n return {\n provider: 'gitlab-ci',\n branch: process.env['CI_COMMIT_REF_NAME'],\n commitSha: process.env['CI_COMMIT_SHA'],\n prNumber,\n repository: process.env['CI_PROJECT_PATH'],\n isPullRequest,\n };\n}\n\n/**\n * Detect CircleCI context\n */\nfunction detectCircleCI(): CIContext {\n let prNumber: number | undefined;\n const prUrl = process.env['CIRCLE_PULL_REQUEST'];\n if (prUrl) {\n const match = prUrl.match(/\\/pull\\/(\\d+)/);\n if (match && match[1]) {\n prNumber = parseInt(match[1], 10);\n }\n }\n\n return {\n provider: 'circleci',\n branch: process.env['CIRCLE_BRANCH'],\n commitSha: process.env['CIRCLE_SHA1'],\n prNumber,\n repository: `${process.env['CIRCLE_PROJECT_USERNAME']}/${process.env['CIRCLE_PROJECT_REPONAME']}`,\n isPullRequest: !!prUrl,\n };\n}\n\n/**\n * Detect Jenkins context\n */\nfunction detectJenkins(): CIContext {\n const changeId = process.env['CHANGE_ID'];\n const isPullRequest = !!changeId;\n\n let prNumber: number | undefined;\n if (changeId) {\n prNumber = parseInt(changeId, 10);\n }\n\n return {\n provider: 'jenkins',\n branch: process.env['BRANCH_NAME'] || process.env['GIT_BRANCH'],\n commitSha: process.env['GIT_COMMIT'],\n prNumber,\n isPullRequest,\n };\n}\n","/**\n * Cloud Evaluation Client\n *\n * Sends artifacts to the cloud API for async server-side evaluation.\n * Artifacts are stored in R2 and processed by Fly.io workers.\n *\n * Architecture:\n * 1. CLI collects artifact locally (code never leaves)\n * 2. Artifact sent to /api/v1/evaluate, stored in R2\n * 3. Server queues QStash job for Fly.io worker\n * 4. CLI polls /api/v1/scans/{id} until complete\n * 5. Findings returned to CLI for display\n */\n\nimport type { CollectorArtifact, Finding } from '@securitychecks/collector';\nimport { CLIError, ErrorCodes } from './errors.js';\nimport { detectCIContext, type CIContext } from './ci-detect.js';\nimport { gzipSync } from 'node:zlib';\n\n// Re-export for convenience\nexport { detectCIContext, type CIContext } from './ci-detect.js';\n\n/**\n * Build request headers with optional Vercel deployment protection bypass.\n * Set VERCEL_AUTOMATION_BYPASS_SECRET env var to bypass Vercel deployment protection\n * on preview deployments.\n */\nfunction buildHeaders(extra: Record<string, string> = {}): Record<string, string> {\n const headers: Record<string, string> = { ...extra };\n const bypassSecret = process.env['VERCEL_AUTOMATION_BYPASS_SECRET'];\n if (bypassSecret) {\n headers['x-vercel-protection-bypass'] = bypassSecret;\n }\n return headers;\n}\n\nfunction isTruthy(value: string | undefined): boolean {\n if (!value) return false;\n return value === '1' || value.toLowerCase() === 'true' || value.toLowerCase() === 'yes';\n}\n\nexport interface CloudEvaluateOptions {\n /** API key for authentication */\n apiKey: string;\n /** Cloud API base URL */\n baseUrl: string;\n /** Specific invariants to run (default: all) */\n invariants?: string[];\n /** Invariants to skip */\n skip?: string[];\n /** Minimum severity to return */\n severity?: 'P0' | 'P1' | 'P2';\n /** Project slug for scan association */\n projectSlug?: string;\n /** Timeout in ms (default: 300000 = 5 min) */\n timeout?: number;\n /** Poll interval in ms (default: 2000 = 2s) */\n pollInterval?: number;\n /** Progress callback */\n onProgress?: EvaluationProgressCallback;\n /** CI context (auto-detected if not provided) */\n ciContext?: CIContext | null;\n}\n\nexport interface CloudEvaluateResult {\n findings: Finding[];\n stats: {\n invariantsRun: number;\n patternsRun: number;\n findingsCount: number;\n executionMs: number;\n };\n usage: {\n scansUsed: number;\n scansRemaining: number;\n };\n}\n\nexport interface CloudEvaluateError {\n error: string;\n details?: unknown;\n usage?: {\n scansUsed: number;\n scansRemaining: number;\n };\n}\n\n/** Scan status from API */\nexport type ScanStatus = 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED';\n\n/** Progress callback for evaluation */\nexport type EvaluationProgressCallback = (info: {\n status: ScanStatus;\n message?: string;\n}) => void;\n\n/** Response from submit endpoint */\ninterface SubmitResult {\n scanId: string;\n status: ScanStatus;\n pollUrl: string;\n usage?: {\n scansUsed: number;\n scansRemaining: number;\n };\n}\n\n/** Response from scan status endpoint */\ninterface ScanStatusResult {\n id: string;\n status: ScanStatus;\n findings?: Finding[];\n stats?: {\n invariantsRun: number;\n patternsRun: number;\n findingsCount: number;\n executionMs: number;\n };\n usage?: {\n scansUsed: number;\n scansRemaining: number;\n };\n errorMessage?: string;\n}\n\n/**\n * Check if cloud evaluation is available\n */\nexport function isCloudEvalAvailable(apiKey?: string): boolean {\n return !!apiKey;\n}\n\n/**\n * Build the artifact payload for cloud evaluation\n */\nfunction buildEvaluatePayload(artifact: CollectorArtifact, options: CloudEvaluateOptions) {\n // Auto-detect CI context if not provided\n const ciContext = options.ciContext !== undefined ? options.ciContext : detectCIContext();\n\n return {\n artifact: {\n version: artifact.version,\n schemaVersion: artifact.schemaVersion,\n profile: artifact.profile,\n extractedAt: artifact.extractedAt,\n targetPath: artifact.codebase?.root,\n codebase: {\n file_count: artifact.codebase?.filesScanned ?? 0,\n languages: artifact.codebase?.languages ?? [],\n },\n services: artifact.services,\n authzCalls: artifact.authzCalls ?? [],\n cacheOperations: artifact.cacheOperations ?? [],\n transactionScopes: artifact.transactionScopes ?? [],\n webhookHandlers: artifact.webhookHandlers ?? [],\n jobHandlers: artifact.jobHandlers ?? [],\n membershipMutations: artifact.membershipMutations ?? [],\n tests: artifact.tests ?? [],\n routes: artifact.routes ?? [],\n callGraph: artifact.callGraph,\n dataFlow: artifact.dataFlows?.flows ?? [],\n rlsPolicies: artifact.rlsArtifact?.rlsPolicies ?? [],\n },\n options: {\n invariants: options.invariants,\n skip: options.skip,\n severity: options.severity,\n projectSlug: options.projectSlug,\n // CI context for scan association (enables PR comments)\n branch: ciContext?.branch,\n commitSha: ciContext?.commitSha,\n prNumber: ciContext?.prNumber,\n // Opt-in guard for GitHub PR CI mode to enforce webhook + evaluate env alignment.\n // This is intentionally gated to avoid breaking standalone CLI workflows that do not use GitHub App webhooks.\n requireExistingCiScan:\n ciContext?.provider === 'github-actions' &&\n ciContext?.isPullRequest &&\n isTruthy(process.env['SECURITYCHECKS_REQUIRE_EXISTING_CI_SCAN'])\n ? true\n : undefined,\n },\n };\n}\n\n/**\n * Submit artifact for async evaluation\n * Returns scan ID for polling\n */\nasync function submitForEvaluation(\n artifact: CollectorArtifact,\n options: CloudEvaluateOptions\n): Promise<SubmitResult> {\n const endpoint = `${options.baseUrl}/api/v1/evaluate`;\n const payload = buildEvaluatePayload(artifact, options);\n const json = JSON.stringify(payload);\n const gz = gzipSync(Buffer.from(json, 'utf8'));\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: buildHeaders({\n 'Content-Type': 'application/json',\n 'Content-Encoding': 'gzip',\n Authorization: `Bearer ${options.apiKey}`,\n }),\n body: gz,\n });\n\n if (!response.ok) {\n const errorBody = (await response.json().catch(() => ({}))) as CloudEvaluateError;\n const serverMessage = (errorBody as any)?.message as string | undefined;\n const errorText = serverMessage\n ? `${errorBody.error || 'Cloud API error'}: ${serverMessage}`\n : errorBody.error;\n\n if (response.status === 401) {\n throw new CLIError(ErrorCodes.CLOUD_AUTH_FAILED, 'Invalid API key. Check your SECURITYCHECKS_API_KEY.');\n }\n\n if (response.status === 413) {\n throw new CLIError(\n ErrorCodes.CLOUD_API_ERROR,\n `Artifact too large. ${errorBody.details || 'Contact support if this persists.'}`,\n { details: errorBody.details }\n );\n }\n\n if (response.status === 429) {\n const remaining = errorBody.usage?.scansRemaining ?? 0;\n throw new CLIError(\n ErrorCodes.CLOUD_RATE_LIMITED,\n `Monthly scan limit reached (${remaining} remaining). Upgrade at https://securitychecks.ai/pricing`,\n { details: { scansRemaining: remaining } }\n );\n }\n\n if (response.status === 503) {\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, 'Cloud evaluation temporarily unavailable. Try again later.');\n }\n\n throw new CLIError(\n ErrorCodes.CLOUD_API_ERROR,\n errorText || `Cloud API error: ${response.status}`,\n { details: errorBody }\n );\n }\n\n return (await response.json()) as SubmitResult;\n}\n\n/**\n * Poll for evaluation results\n * Blocks until scan completes, fails, or times out\n */\nasync function pollForResults(\n scanId: string,\n options: CloudEvaluateOptions\n): Promise<CloudEvaluateResult> {\n const timeout = options.timeout ?? 300000; // 5 min default\n const pollInterval = options.pollInterval ?? 2000; // 2s default\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const response = await fetch(`${options.baseUrl}/api/v1/scans/${scanId}`, {\n method: 'GET',\n headers: buildHeaders({\n Authorization: `Bearer ${options.apiKey}`,\n }),\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new CLIError(ErrorCodes.CLOUD_NOT_FOUND, `Scan ${scanId} not found`);\n }\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, `Failed to get scan status: ${response.status}`);\n }\n\n const scan = (await response.json()) as ScanStatusResult;\n\n // Report progress\n options.onProgress?.({\n status: scan.status,\n message: scan.status === 'RUNNING' ? 'Evaluating...' : undefined,\n });\n\n if (scan.status === 'COMPLETED') {\n return {\n findings: scan.findings ?? [],\n stats: scan.stats ?? {\n invariantsRun: 0,\n patternsRun: 0,\n findingsCount: scan.findings?.length ?? 0,\n executionMs: Date.now() - startTime,\n },\n usage: scan.usage ?? { scansUsed: 0, scansRemaining: 0 },\n };\n }\n\n if (scan.status === 'FAILED') {\n throw new CLIError(\n ErrorCodes.CLOUD_API_ERROR,\n `Scan failed: ${scan.errorMessage ?? 'Unknown error'}`,\n { details: { scanId, errorMessage: scan.errorMessage } }\n );\n }\n\n if (scan.status === 'CANCELLED') {\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, 'Scan was cancelled', { details: { scanId } });\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new CLIError(\n ErrorCodes.CHECK_TIMEOUT,\n `Scan timed out after ${timeout / 1000}s. Check dashboard for results.`,\n { details: { timeoutMs: timeout, scanId } }\n );\n}\n\n/**\n * Evaluate artifact via cloud API (async with polling)\n *\n * @param artifact The artifact to evaluate\n * @param options Evaluation options\n * @throws Error if evaluation fails or times out\n */\nexport async function evaluateCloud(\n artifact: CollectorArtifact,\n options: CloudEvaluateOptions\n): Promise<CloudEvaluateResult> {\n // Submit artifact for evaluation\n const { scanId } = await submitForEvaluation(artifact, options);\n\n // Report initial status\n options.onProgress?.({\n status: 'PENDING',\n message: 'Submitted for evaluation...',\n });\n\n // Poll for results\n return pollForResults(scanId, options);\n}\n\n/**\n * Check cloud API health\n */\nexport async function checkCloudHealth(baseUrl: string): Promise<boolean> {\n try {\n const response = await fetch(`${baseUrl}/api/health`, {\n method: 'GET',\n headers: buildHeaders(),\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n\n/**\n * Get available invariants from cloud API\n */\nexport async function getCloudInvariants(\n baseUrl: string,\n apiKey: string\n): Promise<Array<{ id: string; name: string; description: string; severity: string }>> {\n const response = await fetch(`${baseUrl}/api/v1/evaluate`, {\n method: 'GET',\n headers: buildHeaders({\n Authorization: `Bearer ${apiKey}`,\n }),\n });\n\n if (!response.ok) {\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, `Failed to fetch invariants: ${response.status}`);\n }\n\n const data = (await response.json()) as {\n invariants: Array<{ id: string; name: string; description: string; severity: string }>;\n };\n return data.invariants;\n}\n","type Env = Record<string, string | undefined>;\n\nexport function getProjectSlug(env: Env = process.env): string | undefined {\n const raw = env['SECURITYCHECKS_PROJECT'];\n const trimmed = raw?.trim();\n return trimmed ? trimmed : undefined;\n}\n","/**\n * Audit API - Programmatic interface for running the staff check\n *\n * This module provides the core audit functionality that can be used by:\n * - CLI commands\n * - MCP server\n * - Programmatic integration\n *\n * SECURITY NOTE: All audit functions require cloud API authentication.\n * Detection logic runs server-side to protect IP.\n * See: docs/POST_MORTEM_001_ENGINE_EXPOSURE.md\n */\n\nimport {\n collect,\n resolveTargetPath,\n type AuditResult,\n type CollectorArtifact,\n type Artifact,\n} from '@securitychecks/collector';\nimport { getCloudApiKey, getCloudApiBaseUrl } from './lib/license.js';\nimport { evaluateCloud } from './lib/cloud-eval.js';\nimport { CLIError, ErrorCodes } from './lib/errors.js';\nimport { getProjectSlug } from './lib/project-slug.js';\n\n// NOTE: Engine import removed - detection runs server-side only\n// import { runAllCheckers } from '@securitychecks/engine';\n\nexport interface AuditOptions {\n /** Target path to audit (default: current directory) */\n targetPath?: string;\n /** Only run specific invariant checks by ID */\n only?: string[];\n /** Skip specific invariant checks by ID */\n skip?: string[];\n}\n\n/**\n * Convert CollectorArtifact to Artifact for checker compatibility\n */\nfunction toArtifact(collectorArtifact: CollectorArtifact): Artifact {\n return {\n version: '1.0',\n extractedAt: collectorArtifact.extractedAt,\n targetPath: collectorArtifact.codebase.root,\n services: collectorArtifact.services,\n authzCalls: collectorArtifact.authzCalls ?? [],\n cacheOperations: collectorArtifact.cacheOperations ?? [],\n transactionScopes: collectorArtifact.transactionScopes ?? [],\n webhookHandlers: collectorArtifact.webhookHandlers ?? [],\n jobHandlers: collectorArtifact.jobHandlers ?? [],\n membershipMutations: collectorArtifact.membershipMutations ?? [],\n tests: collectorArtifact.tests ?? [],\n routes: collectorArtifact.routes ?? [],\n dataFlows: collectorArtifact.dataFlows,\n callGraph: collectorArtifact.callGraph,\n };\n}\n\n/**\n * Run the full staff check audit\n *\n * This is the main programmatic API for running the staff check.\n * It performs two steps:\n * 1. Collect artifacts from the target codebase (facts)\n * 2. Send to cloud API for evaluation (findings)\n *\n * SECURITY: Detection logic runs server-side to protect IP.\n * An API key is required. Get one at https://securitychecks.ai/dashboard/settings/api-keys\n *\n * @example\n * ```ts\n * import { audit } from '@securitychecks/cli';\n *\n * // Requires SECURITYCHECKS_API_KEY environment variable\n * const result = await audit({\n * targetPath: '/path/to/codebase',\n * only: ['WEBHOOK.IDEMPOTENT'],\n * });\n *\n * console.log(result.summary);\n * ```\n */\nexport async function audit(options: AuditOptions = {}): Promise<AuditResult> {\n const startTime = Date.now();\n\n // SECURITY: Require API key - detection runs server-side to protect IP\n const apiKey = getCloudApiKey();\n if (!apiKey) {\n throw new CLIError(\n ErrorCodes.AUTH_REQUIRED,\n 'API key required for scanning',\n {\n details: {\n remediation: `Set SECURITYCHECKS_API_KEY environment variable.\nGet your API key at https://securitychecks.ai/dashboard/settings/api-keys\n\nFor air-gapped environments, contact sales@securitychecks.ai for enterprise options.`,\n },\n }\n );\n }\n\n const targetPath = resolveTargetPath(options.targetPath);\n\n // Step 1: Collect artifacts (facts) - runs locally\n const collectorArtifact = await collect({\n targetPath,\n profile: 'securitychecks',\n });\n\n // Step 2: Send to cloud for evaluation (findings) - runs server-side\n const cloudResult = await evaluateCloud(collectorArtifact, {\n apiKey,\n baseUrl: getCloudApiBaseUrl(),\n invariants: options.only,\n skip: options.skip,\n projectSlug: getProjectSlug(),\n });\n\n // Step 3: Convert to checker-compatible format for result\n const artifact = toArtifact(collectorArtifact);\n\n // Compute summary from cloud results\n const findings = cloudResult.findings;\n const byPriority = {\n P0: findings.filter((f) => f.severity === 'P0').length,\n P1: findings.filter((f) => f.severity === 'P1').length,\n P2: findings.filter((f) => f.severity === 'P2').length,\n };\n\n // Synthesize results format from cloud response\n const invariantIds = [...new Set(findings.map(f => f.invariantId))];\n const results = invariantIds.map(id => ({\n invariantId: id,\n passed: !findings.some(f => f.invariantId === id),\n findings: findings.filter(f => f.invariantId === id),\n checkedAt: new Date().toISOString(),\n duration: 0,\n }));\n\n const passed = results.filter((r) => r.passed).length;\n const failed = results.filter((r) => !r.passed).length;\n const waived = findings.filter((f) => f.waived).length;\n\n return {\n version: '1.0',\n targetPath,\n runAt: new Date().toISOString(),\n duration: Date.now() - startTime,\n summary: {\n total: cloudResult.stats.invariantsRun,\n passed,\n failed,\n waived,\n byPriority\n },\n results,\n artifact,\n };\n}\n","/**\n * Schema Version Compatibility\n *\n * Ensures CLI can consume artifacts from compatible collector versions.\n *\n * The schema version follows semver:\n * - MAJOR: Breaking changes (fields removed, types changed)\n * - MINOR: Additive changes (new optional fields)\n * - PATCH: Bug fixes, clarifications\n *\n * CLI declares a supported range, collector emits current version.\n */\n\nimport { ARTIFACT_SCHEMA_VERSION } from '@securitychecks/collector';\n\n/**\n * The schema version range this CLI version supports.\n *\n * Format: \"^MAJOR.MINOR.x\" - compatible with any version that has:\n * - Same MAJOR version (no breaking changes)\n * - Same or higher MINOR version (may have new optional fields)\n *\n * When updating:\n * - Bump MINOR when CLI starts using new optional fields\n * - Bump MAJOR when CLI requires breaking schema changes\n */\nexport const SUPPORTED_SCHEMA_RANGE = {\n // Minimum version we can consume\n minMajor: 1,\n minMinor: 0,\n // Maximum major version we understand (breaking changes)\n maxMajor: 1,\n};\n\nexport interface SchemaValidationResult {\n valid: boolean;\n artifactVersion: string;\n currentVersion: string;\n error?: string;\n remediation?: string;\n}\n\n/**\n * Parse a semver string into components\n */\nfunction parseSemver(version: string): { major: number; minor: number; patch: number } | null {\n const match = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!match || !match[1] || !match[2] || !match[3]) return null;\n\n return {\n major: parseInt(match[1], 10),\n minor: parseInt(match[2], 10),\n patch: parseInt(match[3], 10),\n };\n}\n\n/**\n * Validate that an artifact's schema version is compatible with this CLI.\n *\n * Compatibility rules:\n * - Artifact MAJOR must equal CLI's supported MAJOR (breaking changes)\n * - Artifact MINOR must be >= CLI's minMinor (additive features)\n * - Pre-1.0.0 artifacts (missing schemaVersion) are assumed \"1.0.0\"\n */\nexport function validateSchemaVersion(artifactSchemaVersion?: string): SchemaValidationResult {\n const currentVersion = ARTIFACT_SCHEMA_VERSION;\n\n // Handle missing schemaVersion (pre-versioning artifacts)\n const effectiveVersion = artifactSchemaVersion ?? '1.0.0';\n\n const parsed = parseSemver(effectiveVersion);\n if (!parsed) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Invalid schema version format: \"${effectiveVersion}\" (expected semver like \"1.0.0\")`,\n remediation: 'Re-collect artifacts with: npx scc collect -o .securitychecks/artifacts.json',\n };\n }\n\n const { major, minor } = parsed;\n\n // Check MAJOR version (breaking changes)\n if (major > SUPPORTED_SCHEMA_RANGE.maxMajor) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Artifact schema version ${effectiveVersion} is too new (CLI supports up to ${SUPPORTED_SCHEMA_RANGE.maxMajor}.x.x)`,\n remediation: `Upgrade scheck: npm install -g @securitychecks/cli@latest`,\n };\n }\n\n if (major < SUPPORTED_SCHEMA_RANGE.minMajor) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Artifact schema version ${effectiveVersion} is too old (CLI requires ${SUPPORTED_SCHEMA_RANGE.minMajor}.x.x+)`,\n remediation: 'Re-collect artifacts: npx scc collect -o .securitychecks/artifacts.json',\n };\n }\n\n // Check MINOR version (additive features - older artifacts may lack fields we use)\n if (minor < SUPPORTED_SCHEMA_RANGE.minMinor) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Artifact schema version ${effectiveVersion} is missing required fields (CLI requires ${SUPPORTED_SCHEMA_RANGE.minMajor}.${SUPPORTED_SCHEMA_RANGE.minMinor}.x+)`,\n remediation: 'Re-collect artifacts: npx scc collect -o .securitychecks/artifacts.json',\n };\n }\n\n return {\n valid: true,\n artifactVersion: effectiveVersion,\n currentVersion,\n };\n}\n\n/**\n * Get the current collector schema version\n */\nexport function getCurrentSchemaVersion(): string {\n return ARTIFACT_SCHEMA_VERSION;\n}\n","/**\n * Stable Finding ID Generation\n *\n * Generates deterministic, stable IDs for findings that survive:\n * - Re-runs\n * - Ordering changes\n * - Remediation/message tweaks\n * - Minor code refactors\n *\n * IDs are NOT stable across:\n * - Moving code to different files\n * - Renaming functions (these are legitimately different anchors)\n *\n * Format: `${invariantId}:${hash}` (e.g., WEBHOOK.IDEMPOTENT:9c31f0a2b4d1)\n */\n\nimport { createHash } from 'crypto';\nimport type { Finding } from '@securitychecks/collector';\n\n// ============================================================================\n// Identity Payload Extraction\n// ============================================================================\n\n/**\n * Invariant-specific anchor extractors.\n * Each returns additional identity fields beyond the base (invariantId + file + symbol).\n */\ntype AnchorExtractor = (finding: Finding) => Record<string, string>;\n\nconst ANCHOR_EXTRACTORS: Record<string, AnchorExtractor> = {\n // Webhook: include provider from context if available\n 'WEBHOOK.IDEMPOTENT': (finding) => {\n const context = finding.evidence[0]?.context ?? '';\n // Extract provider from context like \"stripe: handleStripeWebhook\"\n const providerMatch = context.match(/^(stripe|github|slack|svix|generic):/i);\n return {\n provider: providerMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n\n // Transaction: include side effect type from message\n 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS': (finding) => {\n // Extract side effect type from message like \"contains email side effect\"\n const typeMatch = finding.message.match(/contains (\\w+) side effect/i);\n return {\n sideEffectType: typeMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n\n // Membership revocation: include mutation type\n 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE': (finding) => {\n const context = finding.evidence[0]?.context ?? '';\n // Extract mutation type from context\n const mutationMatch = context.match(/mutationType[:\\s]+(\\w+)/i);\n return {\n mutationType: mutationMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n\n // Keys revocation: include entity type\n 'AUTHZ.KEYS.REVOCATION.IMMEDIATE': (finding) => {\n const context = finding.evidence[0]?.context ?? '';\n const entityMatch = context.match(/entity[:\\s]+(\\w+)/i);\n return {\n entity: entityMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n};\n\n/**\n * Extract the identity payload for a finding.\n * This is what gets hashed to produce the findingId.\n */\nexport function extractIdentityPayload(finding: Finding): Record<string, string> {\n const primary = finding.evidence[0];\n\n // Base identity: invariantId + file + symbol\n const base: Record<string, string> = {\n invariantId: finding.invariantId.toLowerCase(),\n file: normalizePath(primary?.file ?? ''),\n symbol: (primary?.symbol ?? '').toLowerCase(),\n };\n\n // Add invariant-specific anchors\n const extractor = ANCHOR_EXTRACTORS[finding.invariantId];\n if (extractor) {\n const anchors = extractor(finding);\n Object.assign(base, anchors);\n }\n\n return base;\n}\n\n// ============================================================================\n// Path Normalization\n// ============================================================================\n\n/**\n * Normalize file path for consistent hashing.\n * - Use forward slashes\n * - Remove leading ./ or /\n * - Lowercase\n * - Trim whitespace\n */\nfunction normalizePath(path: string): string {\n return path\n .trim()\n .replace(/\\\\/g, '/') // Windows backslashes\n .replace(/^\\.\\//, '') // Leading ./\n .replace(/^\\//, '') // Leading /\n .toLowerCase();\n}\n\n// ============================================================================\n// Hash Generation\n// ============================================================================\n\n/**\n * Generate a short, stable hash from the identity payload.\n * Uses SHA-256 truncated to 12 hex characters.\n */\nfunction hashPayload(payload: Record<string, string>): string {\n // Sort keys for deterministic ordering\n const keys = Object.keys(payload).sort();\n const canonical = keys.map((k) => `${k}:${payload[k]}`).join('|');\n\n const hash = createHash('sha256').update(canonical).digest('hex');\n\n // Take first 12 characters for readability while maintaining uniqueness\n return hash.slice(0, 12);\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Generate a stable findingId for a finding.\n *\n * @example\n * const id = generateFindingId(finding);\n * // \"WEBHOOK.IDEMPOTENT:9c31f0a2b4d1\"\n */\nexport function generateFindingId(finding: Finding): string {\n const payload = extractIdentityPayload(finding);\n const hash = hashPayload(payload);\n return `${finding.invariantId}:${hash}`;\n}\n\n/**\n * Add findingId to a finding (mutates the finding).\n * Returns the same finding for chaining.\n */\nexport function attachFindingId<T extends Finding>(finding: T): T & { findingId: string } {\n const findingId = generateFindingId(finding);\n return Object.assign(finding, { findingId });\n}\n\n/**\n * Add findingIds to all findings in a list.\n */\nexport function attachFindingIds<T extends Finding>(findings: T[]): (T & { findingId: string })[] {\n return findings.map(attachFindingId);\n}\n\n// ============================================================================\n// Baseline/Waiver Types\n// ============================================================================\n\n/**\n * A baseline entry stores known findings that should not fail CI.\n */\nexport interface BaselineEntry {\n findingId: string;\n invariantId: string;\n file: string;\n symbol?: string;\n firstSeenAt: string; // ISO date\n lastSeenAt: string; // ISO date\n}\n\n/**\n * A waiver temporarily suppresses a finding.\n */\nexport interface WaiverEntry {\n findingId: string;\n invariantId: string;\n reasonKey?: string;\n reason: string;\n expiresAt: string; // ISO date\n createdBy: string;\n createdAt: string; // ISO date\n}\n\n/**\n * Convert a finding to a baseline entry.\n */\nexport function toBaselineEntry(finding: Finding & { findingId: string }): BaselineEntry {\n const now = new Date().toISOString();\n return {\n findingId: finding.findingId,\n invariantId: finding.invariantId,\n file: finding.evidence[0]?.file ?? '',\n symbol: finding.evidence[0]?.symbol,\n firstSeenAt: now,\n lastSeenAt: now,\n };\n}\n","/**\n * Baseline and Waiver Schema Versions\n *\n * These versions are CLI-level (separate from collector artifact schema).\n * Bump these when the storage format changes.\n */\n\nexport const BASELINE_SCHEMA_VERSION = '1.0.0';\nexport const WAIVER_SCHEMA_VERSION = '1.1.0';\n\nexport const WAIVER_REASON_KEYS = [\n 'false_positive',\n 'acceptable_risk',\n 'will_fix_later',\n 'not_applicable',\n 'other',\n] as const;\n\nexport type WaiverReasonKey = typeof WAIVER_REASON_KEYS[number];\n\nexport function isValidWaiverReasonKey(value: string): value is WaiverReasonKey {\n return (WAIVER_REASON_KEYS as readonly string[]).includes(value);\n}\n\n// ============================================================================\n// Baseline Types\n// ============================================================================\n\n/**\n * A baseline entry represents a known finding that should not fail CI.\n * Baselines are used to adopt scheck incrementally on existing codebases.\n */\nexport interface BaselineEntry {\n /** Stable finding ID (invariantId:hash) */\n findingId: string;\n /** The invariant this finding belongs to */\n invariantId: string;\n /** File where the finding was detected */\n file: string;\n /** Symbol (function/class name) if available */\n symbol?: string;\n /** When this was first added to baseline */\n createdAt: string; // ISO date\n /** When this was last seen in a run */\n lastSeenAt: string; // ISO date\n /** Optional notes explaining why this is baselined */\n notes?: string;\n}\n\n/**\n * The baseline file format.\n */\nexport interface BaselineFile {\n /** Schema version for baseline file format */\n schemaVersion: string;\n /** CLI version that generated this file */\n toolVersion: string;\n /** Collector schema version used when generating findings */\n collectorSchemaVersion?: string;\n /** Tool identifier (e.g., \"@securitychecks/cli@0.1.0\") */\n generatedBy: string;\n /** When the baseline was last updated (UTC ISO date) */\n updatedAt: string;\n /** Baseline entries keyed by findingId for O(1) lookup */\n entries: Record<string, BaselineEntry>;\n}\n\n// ============================================================================\n// Waiver Types\n// ============================================================================\n\n/**\n * A waiver temporarily suppresses a finding.\n * Unlike baselines, waivers expire and require explicit justification.\n */\nexport interface WaiverEntry {\n /** Stable finding ID (invariantId:hash) */\n findingId: string;\n /** The invariant this waiver applies to */\n invariantId: string;\n /** File where the finding was detected */\n file: string;\n /** Symbol (function/class name) if available */\n symbol?: string;\n /** Structured waiver reason (optional; aligns with web UI) */\n reasonKey?: WaiverReasonKey;\n /** Why this is being waived (required) */\n reason: string;\n /** Who created the waiver */\n owner: string;\n /** When the waiver expires (ISO date) */\n expiresAt: string;\n /** When the waiver was created */\n createdAt: string; // ISO date\n}\n\n/**\n * The waiver file format.\n */\nexport interface WaiverFile {\n /** Schema version for waiver file format */\n schemaVersion: string;\n /** CLI version that generated this file */\n toolVersion: string;\n /** Tool identifier (e.g., \"@securitychecks/cli@0.1.0\") */\n generatedBy: string;\n /** When the waiver file was last updated (UTC ISO date) */\n updatedAt: string;\n /** Waiver entries keyed by findingId */\n entries: Record<string, WaiverEntry>;\n}\n\n// ============================================================================\n// Empty File Factories\n// ============================================================================\n\n/** Package identifier for generatedBy field */\nexport const CLI_PACKAGE_NAME = '@securitychecks/cli';\n\n/** Get the generatedBy string (package@version) */\nexport function getGeneratedBy(version: string): string {\n return `${CLI_PACKAGE_NAME}@${version}`;\n}\n\nexport function createEmptyBaseline(version: string = '0.0.0'): BaselineFile {\n return {\n schemaVersion: BASELINE_SCHEMA_VERSION,\n toolVersion: version,\n generatedBy: getGeneratedBy(version),\n updatedAt: new Date().toISOString(),\n entries: {},\n };\n}\n\nexport function createEmptyWaiverFile(version: string = '0.0.0'): WaiverFile {\n return {\n schemaVersion: WAIVER_SCHEMA_VERSION,\n toolVersion: version,\n generatedBy: getGeneratedBy(version),\n updatedAt: new Date().toISOString(),\n entries: {},\n };\n}\n","/**\n * Baseline and Waiver Storage\n *\n * Handles loading, saving, and managing baseline/waiver files.\n * Files are stored in `.scheck/` directory.\n */\n\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport type { Finding } from '@securitychecks/collector';\nimport { generateFindingId } from '../findings/finding-id.js';\nimport {\n BASELINE_SCHEMA_VERSION,\n WAIVER_SCHEMA_VERSION,\n createEmptyBaseline,\n createEmptyWaiverFile,\n getGeneratedBy,\n type BaselineFile,\n type WaiverFile,\n type WaiverEntry,\n} from './schema.js';\n\n// Version injected at build time via tsup define\nconst CLI_VERSION: string = process.env['CLI_VERSION'] ?? '0.0.0-dev';\n\n// ============================================================================\n// File Paths\n// ============================================================================\n\nconst SCHECK_DIR = '.scheck';\nconst BASELINE_FILE = 'baseline.json';\nconst WAIVER_FILE = 'waivers.json';\n\nexport function getBaselinePath(rootPath: string): string {\n return join(rootPath, SCHECK_DIR, BASELINE_FILE);\n}\n\nexport function getWaiverPath(rootPath: string): string {\n return join(rootPath, SCHECK_DIR, WAIVER_FILE);\n}\n\n// ============================================================================\n// Baseline Storage\n// ============================================================================\n\n/**\n * Load the baseline file, creating an empty one if it doesn't exist.\n */\nexport async function loadBaseline(rootPath: string): Promise<BaselineFile> {\n const path = getBaselinePath(rootPath);\n\n if (!existsSync(path)) {\n return createEmptyBaseline(CLI_VERSION);\n }\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content) as BaselineFile;\n\n // Migrate: add missing fields for older files\n if (!data.schemaVersion) {\n data.schemaVersion = BASELINE_SCHEMA_VERSION;\n }\n if (!data.toolVersion) {\n data.toolVersion = CLI_VERSION;\n }\n if (!data.generatedBy) {\n data.generatedBy = getGeneratedBy(CLI_VERSION);\n }\n\n return data;\n } catch {\n // Corrupted file, return empty baseline\n console.warn(`Warning: Could not parse baseline file at ${path}, using empty baseline`);\n return createEmptyBaseline(CLI_VERSION);\n }\n}\n\n/**\n * Save the baseline file with deterministic ordering.\n */\nexport async function saveBaseline(\n rootPath: string,\n baseline: BaselineFile,\n collectorSchemaVersion?: string\n): Promise<void> {\n const path = getBaselinePath(rootPath);\n\n // Ensure directory exists\n await mkdir(dirname(path), { recursive: true });\n\n // Update metadata\n baseline.updatedAt = new Date().toISOString();\n baseline.toolVersion = CLI_VERSION;\n baseline.generatedBy = getGeneratedBy(CLI_VERSION);\n if (collectorSchemaVersion) {\n baseline.collectorSchemaVersion = collectorSchemaVersion;\n }\n\n // Create deterministically ordered output (field order matters for diffs)\n // Using spread with explicit ordering to ensure consistent JSON output\n const orderedBaseline = {\n schemaVersion: baseline.schemaVersion,\n toolVersion: baseline.toolVersion,\n ...(baseline.collectorSchemaVersion ? { collectorSchemaVersion: baseline.collectorSchemaVersion } : {}),\n generatedBy: baseline.generatedBy,\n updatedAt: baseline.updatedAt,\n entries: sortEntriesByFindingId(baseline.entries),\n };\n\n // Write with 2-space indent and trailing newline\n await writeFile(path, JSON.stringify(orderedBaseline, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Sort entries by findingId for deterministic output.\n */\nfunction sortEntriesByFindingId<T extends { findingId: string }>(\n entries: Record<string, T>\n): Record<string, T> {\n const sorted: Record<string, T> = {};\n const keys = Object.keys(entries).sort();\n for (const key of keys) {\n sorted[key] = entries[key] as T;\n }\n return sorted;\n}\n\n/**\n * Add findings to the baseline.\n * Returns the number of new entries added.\n */\nexport function addToBaseline(\n baseline: BaselineFile,\n findings: Finding[],\n notes?: string\n): number {\n const now = new Date().toISOString();\n let added = 0;\n\n for (const finding of findings) {\n const findingId = generateFindingId(finding);\n\n if (!baseline.entries[findingId]) {\n baseline.entries[findingId] = {\n findingId,\n invariantId: finding.invariantId,\n file: finding.evidence[0]?.file ?? '',\n symbol: finding.evidence[0]?.symbol,\n createdAt: now,\n lastSeenAt: now,\n notes,\n };\n added++;\n } else {\n // Update lastSeenAt for existing entries\n baseline.entries[findingId].lastSeenAt = now;\n }\n }\n\n return added;\n}\n\n/**\n * Check if a finding is in the baseline.\n */\nexport function isInBaseline(baseline: BaselineFile, finding: Finding): boolean {\n const findingId = generateFindingId(finding);\n return findingId in baseline.entries;\n}\n\n/**\n * Remove stale entries that haven't been seen in a certain number of days.\n * Returns the number of entries removed.\n */\nexport function pruneBaseline(baseline: BaselineFile, staleDays: number = 90): number {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - staleDays);\n const cutoffIso = cutoff.toISOString();\n\n let removed = 0;\n for (const [id, entry] of Object.entries(baseline.entries)) {\n if (entry.lastSeenAt < cutoffIso) {\n delete baseline.entries[id];\n removed++;\n }\n }\n\n return removed;\n}\n\n// ============================================================================\n// Waiver Storage\n// ============================================================================\n\n/**\n * Load the waiver file, creating an empty one if it doesn't exist.\n */\nexport async function loadWaivers(rootPath: string): Promise<WaiverFile> {\n const path = getWaiverPath(rootPath);\n\n if (!existsSync(path)) {\n return createEmptyWaiverFile(CLI_VERSION);\n }\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content) as WaiverFile;\n\n // Migrate: add missing fields for older files\n if (!data.schemaVersion) {\n data.schemaVersion = WAIVER_SCHEMA_VERSION;\n }\n if (!data.toolVersion) {\n data.toolVersion = CLI_VERSION;\n }\n if (!data.generatedBy) {\n data.generatedBy = getGeneratedBy(CLI_VERSION);\n }\n\n return data;\n } catch {\n console.warn(`Warning: Could not parse waiver file at ${path}, using empty waivers`);\n return createEmptyWaiverFile(CLI_VERSION);\n }\n}\n\n/**\n * Save the waiver file with deterministic ordering.\n */\nexport async function saveWaivers(rootPath: string, waivers: WaiverFile): Promise<void> {\n const path = getWaiverPath(rootPath);\n\n await mkdir(dirname(path), { recursive: true });\n\n // Update metadata\n waivers.updatedAt = new Date().toISOString();\n waivers.toolVersion = CLI_VERSION;\n waivers.generatedBy = getGeneratedBy(CLI_VERSION);\n\n // Create deterministically ordered output (field order matters for diffs)\n const orderedWaivers = {\n schemaVersion: waivers.schemaVersion,\n toolVersion: waivers.toolVersion,\n generatedBy: waivers.generatedBy,\n updatedAt: waivers.updatedAt,\n entries: sortEntriesByFindingId(waivers.entries),\n };\n\n // Write with 2-space indent and trailing newline\n await writeFile(path, JSON.stringify(orderedWaivers, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Add a waiver for a finding.\n */\nexport function addWaiver(\n waivers: WaiverFile,\n finding: Finding,\n options: {\n reason: string;\n reasonKey?: WaiverEntry['reasonKey'];\n owner: string;\n expiresInDays: number;\n }\n): WaiverEntry {\n const now = new Date();\n const expiresAt = new Date(now);\n expiresAt.setDate(expiresAt.getDate() + options.expiresInDays);\n\n const findingId = generateFindingId(finding);\n\n const entry: WaiverEntry = {\n findingId,\n invariantId: finding.invariantId,\n file: finding.evidence[0]?.file ?? '',\n symbol: finding.evidence[0]?.symbol,\n reasonKey: options.reasonKey,\n reason: options.reason,\n owner: options.owner,\n expiresAt: expiresAt.toISOString(),\n createdAt: now.toISOString(),\n };\n\n waivers.entries[findingId] = entry;\n return entry;\n}\n\n/**\n * Check if a finding has a valid (non-expired) waiver.\n * Returns the waiver if valid, undefined if expired or not found.\n */\nexport function getValidWaiver(waivers: WaiverFile, finding: Finding): WaiverEntry | undefined {\n const findingId = generateFindingId(finding);\n const waiver = waivers.entries[findingId];\n\n if (!waiver) {\n return undefined;\n }\n\n // Check expiration\n const now = new Date();\n const expiresAt = new Date(waiver.expiresAt);\n\n if (expiresAt < now) {\n // Waiver has expired - behaves as if no waiver exists\n return undefined;\n }\n\n return waiver;\n}\n\n/**\n * Remove expired waivers from the file.\n * Returns the number of waivers removed.\n */\nexport function pruneExpiredWaivers(waivers: WaiverFile): number {\n const now = new Date().toISOString();\n let removed = 0;\n\n for (const [id, entry] of Object.entries(waivers.entries)) {\n if (entry.expiresAt < now) {\n delete waivers.entries[id];\n removed++;\n }\n }\n\n return removed;\n}\n\n/**\n * Get all waivers that are about to expire (within N days).\n */\nexport function getExpiringWaivers(waivers: WaiverFile, withinDays: number = 7): WaiverEntry[] {\n const now = new Date();\n const threshold = new Date(now);\n threshold.setDate(threshold.getDate() + withinDays);\n const thresholdIso = threshold.toISOString();\n\n return Object.values(waivers.entries).filter(\n (entry) => entry.expiresAt > now.toISOString() && entry.expiresAt <= thresholdIso\n );\n}\n","/**\n * Baseline and Waiver Matching\n *\n * Applies baselines and waivers to findings, categorizing them for CI decisions.\n */\n\nimport type { Finding, Severity } from '@securitychecks/collector';\nimport { generateFindingId } from '../findings/finding-id.js';\nimport { isInBaseline, getValidWaiver } from './storage.js';\nimport type { BaselineFile, WaiverFile, WaiverEntry } from './schema.js';\n\n// ============================================================================\n// Categorized Finding Types\n// ============================================================================\n\n/**\n * A finding with its baseline/waiver status resolved.\n */\nexport interface CategorizedFinding extends Finding {\n findingId: string;\n /** Whether this finding is in the baseline */\n isBaselined: boolean;\n /** Active waiver if present */\n waiver?: WaiverEntry;\n /** Whether this finding should fail CI */\n shouldFail: boolean;\n}\n\n/**\n * Result of categorizing findings.\n */\nexport interface CategorizationResult {\n /** All findings with status */\n all: CategorizedFinding[];\n /** New findings not in baseline (may fail CI) */\n new: CategorizedFinding[];\n /** Findings in baseline (won't fail CI) */\n baselined: CategorizedFinding[];\n /** Findings with active waivers (won't fail CI) */\n waived: CategorizedFinding[];\n /** Summary counts */\n counts: {\n total: number;\n new: number;\n baselined: number;\n waived: number;\n willFail: number;\n };\n}\n\n// ============================================================================\n// Categorization Logic\n// ============================================================================\n\n/**\n * Categorize findings against baseline and waivers.\n *\n * @param findings - Raw findings from checkers\n * @param baseline - Loaded baseline file\n * @param waivers - Loaded waiver file\n * @param failSeverities - Which severities should fail CI (default: P0, P1)\n */\nexport function categorizeFindings(\n findings: Finding[],\n baseline: BaselineFile,\n waivers: WaiverFile,\n failSeverities: Severity[] = ['P0', 'P1']\n): CategorizationResult {\n const categorized: CategorizedFinding[] = [];\n const newFindings: CategorizedFinding[] = [];\n const baselinedFindings: CategorizedFinding[] = [];\n const waivedFindings: CategorizedFinding[] = [];\n\n for (const finding of findings) {\n const findingId = generateFindingId(finding);\n const isBaselined = isInBaseline(baseline, finding);\n const waiver = getValidWaiver(waivers, finding);\n\n // Determine if this finding should fail CI\n const isFailSeverity = failSeverities.includes(finding.severity);\n const shouldFail = isFailSeverity && !isBaselined && !waiver;\n\n const categorizedFinding: CategorizedFinding = {\n ...finding,\n findingId,\n isBaselined,\n waiver,\n shouldFail,\n };\n\n categorized.push(categorizedFinding);\n\n if (waiver) {\n waivedFindings.push(categorizedFinding);\n } else if (isBaselined) {\n baselinedFindings.push(categorizedFinding);\n } else {\n newFindings.push(categorizedFinding);\n }\n }\n\n return {\n all: categorized,\n new: newFindings,\n baselined: baselinedFindings,\n waived: waivedFindings,\n counts: {\n total: categorized.length,\n new: newFindings.length,\n baselined: baselinedFindings.length,\n waived: waivedFindings.length,\n willFail: categorized.filter((f) => f.shouldFail).length,\n },\n };\n}\n\n/**\n * Determine CI exit status based on categorized findings.\n *\n * @returns 0 for success, 1 for failure\n */\nexport function getCIExitCode(result: CategorizationResult): number {\n return result.counts.willFail > 0 ? 1 : 0;\n}\n\n/**\n * Get a summary message for CI output.\n */\nexport function getCISummary(result: CategorizationResult): string {\n const { counts } = result;\n\n if (counts.total === 0) {\n return 'No findings detected.';\n }\n\n const parts: string[] = [];\n\n if (counts.willFail > 0) {\n parts.push(`${counts.willFail} new finding(s) require attention`);\n }\n\n if (counts.baselined > 0) {\n parts.push(`${counts.baselined} baselined`);\n }\n\n if (counts.waived > 0) {\n parts.push(`${counts.waived} waived`);\n }\n\n if (counts.willFail === 0) {\n parts.unshift('All findings are baselined or waived');\n }\n\n return parts.join(', ') + '.';\n}\n\n// ============================================================================\n// Collision Detection\n// ============================================================================\n\n/**\n * Detect and handle findingId collisions.\n * Returns findings with unique IDs (appending :a, :b, etc. if needed).\n *\n * This is a defensive measure - collisions should be extremely rare with\n * 12 hex chars of SHA-256, but we define the behavior explicitly.\n */\nexport function resolveCollisions(findings: Finding[]): (Finding & { findingId: string })[] {\n const seen = new Map<string, number>();\n const result: (Finding & { findingId: string })[] = [];\n\n for (const finding of findings) {\n let findingId = generateFindingId(finding);\n\n // Check for collision\n const count = seen.get(findingId) ?? 0;\n if (count > 0) {\n // Append suffix: :a, :b, :c, etc.\n const suffix = String.fromCharCode(96 + count); // a=97, so 96+1=a\n findingId = `${findingId}:${suffix}`;\n }\n seen.set(generateFindingId(finding), count + 1);\n\n result.push({\n ...finding,\n findingId,\n });\n }\n\n return result;\n}\n\n/**\n * Check if there are any findingId collisions in a set of findings.\n * Returns true if collisions exist.\n */\nexport function hasCollisions(findings: Finding[]): boolean {\n const ids = new Set<string>();\n\n for (const finding of findings) {\n const id = generateFindingId(finding);\n if (ids.has(id)) {\n return true;\n }\n ids.add(id);\n }\n\n return false;\n}\n","/**\n * Finding Correlation Engine\n *\n * Correlates findings across invariants to detect compounding risks.\n * Multiple findings on the same code path often compound each other,\n * creating worse outcomes than the sum of their parts.\n *\n * Key concepts:\n * - Correlated findings: Multiple findings sharing a code path\n * - Compounding risk: Combined severity is higher than individual\n * - Attack path: Narrative of how findings chain together\n *\n * Example:\n * Route: POST /api/webhooks/stripe\n * ├── WEBHOOK.IDEMPOTENT: ✗ No idempotency check\n * ├── TRANSACTION.POST_COMMIT: ✗ Email inside transaction\n * └── Combined: If replayed, sends duplicate emails AND inconsistent DB\n */\n\nimport type {\n Finding,\n Severity,\n CheckResult,\n Artifact,\n} from '@securitychecks/collector';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CorrelatedFinding {\n /** The primary finding (highest severity) */\n primary: Finding;\n /** Related findings on the same code path */\n related: Finding[];\n /** Shared context between findings */\n sharedContext: SharedContext;\n /** How the findings compound each other */\n compoundingEffect: CompoundingEffect;\n /** Adjusted severity based on correlation */\n adjustedSeverity: Severity;\n /** Attack path narrative */\n attackPath?: AttackPath;\n}\n\nexport interface SharedContext {\n /** Common file */\n file?: string;\n /** Common function */\n functionName?: string;\n /** Common route (if applicable) */\n route?: string;\n /** Shared call chain */\n callChain?: string[];\n /** Number of findings in this correlation */\n findingCount: number;\n}\n\nexport interface CompoundingEffect {\n /** Description of how findings compound */\n description: string;\n /** Risk multiplier (1.0 = no change, 2.0 = double risk) */\n riskMultiplier: number;\n /** Signals explaining the compounding */\n signals: string[];\n}\n\nexport interface AttackPath {\n /** Title of the attack path */\n title: string;\n /** Step-by-step narrative */\n steps: AttackStep[];\n /** Overall exploitability */\n exploitability: 'easy' | 'medium' | 'hard';\n /** Impact level */\n impact: 'low' | 'medium' | 'high' | 'critical';\n /** Time window (if applicable) */\n timeWindow?: string;\n}\n\nexport interface AttackStep {\n /** Step number */\n step: number;\n /** Description of this step */\n description: string;\n /** Which finding enables this step */\n invariantId: string;\n /** File/line reference */\n location?: { file: string; line: number };\n}\n\nexport interface CorrelationResult {\n /** All correlated finding groups */\n correlations: CorrelatedFinding[];\n /** Statistics */\n stats: {\n totalFindings: number;\n correlatedFindings: number;\n correlationGroups: number;\n severityEscalations: number;\n };\n}\n\n// ============================================================================\n// Compounding Rules\n// ============================================================================\n\n/**\n * Rules for how finding combinations compound\n */\nconst COMPOUNDING_RULES: Array<{\n invariants: string[];\n effect: CompoundingEffect;\n attackPathTemplate?: Omit<AttackPath, 'steps'>;\n}> = [\n // Webhook + Transaction = Replay causes inconsistent state\n {\n invariants: ['WEBHOOK.IDEMPOTENT', 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS'],\n effect: {\n description: 'Webhook replay can cause duplicate side effects AND inconsistent database state',\n riskMultiplier: 2.0,\n signals: ['webhook_replay', 'transaction_side_effect', 'data_inconsistency'],\n },\n attackPathTemplate: {\n title: 'Webhook Replay Attack with Data Inconsistency',\n exploitability: 'easy',\n impact: 'high',\n timeWindow: 'Immediate - no time limit on replay',\n },\n },\n\n // No auth + No service auth = Complete bypass\n {\n invariants: ['AUTHZ.SERVICE_LAYER.ENFORCED', 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE'],\n effect: {\n description: 'Missing service-layer auth combined with delayed revocation allows extended unauthorized access',\n riskMultiplier: 2.5,\n signals: ['auth_bypass', 'delayed_revocation', 'privilege_persistence'],\n },\n attackPathTemplate: {\n title: 'Extended Privilege Persistence',\n exploitability: 'medium',\n impact: 'critical',\n timeWindow: 'Until cache expires or session timeout',\n },\n },\n\n // Cache + Membership revocation = Stale permissions\n {\n invariants: ['CACHE.INVALIDATION.ON_AUTH_CHANGE', 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE'],\n effect: {\n description: 'Membership change without cache invalidation allows continued access via stale cache',\n riskMultiplier: 2.0,\n signals: ['stale_cache', 'permission_leak', 'revocation_bypass'],\n },\n attackPathTemplate: {\n title: 'Stale Permission Cache Exploit',\n exploitability: 'medium',\n impact: 'high',\n timeWindow: 'Cache TTL (often 5-15 minutes)',\n },\n },\n\n // Transaction + Cache = Inconsistent read after rollback\n {\n invariants: ['TRANSACTION.POST_COMMIT.SIDE_EFFECTS', 'CACHE.INVALIDATION.ON_AUTH_CHANGE'],\n effect: {\n description: 'Side effect in transaction + missing cache invalidation can leave cache inconsistent after rollback',\n riskMultiplier: 1.5,\n signals: ['rollback_inconsistency', 'cache_stale', 'side_effect_mismatch'],\n },\n },\n\n // Billing + Auth = Free tier bypass\n {\n invariants: ['BILLING.SERVER_ENFORCED', 'AUTHZ.SERVICE_LAYER.ENFORCED'],\n effect: {\n description: 'Missing billing enforcement + auth gap allows access to paid features without payment',\n riskMultiplier: 2.0,\n signals: ['billing_bypass', 'feature_theft', 'revenue_loss'],\n },\n attackPathTemplate: {\n title: 'Billing Bypass via Auth Gap',\n exploitability: 'medium',\n impact: 'high',\n },\n },\n\n // Jobs + Transaction = Retry causes duplicate side effects\n {\n invariants: ['JOBS.RETRY_SAFE', 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS'],\n effect: {\n description: 'Non-idempotent job with side effects in transaction can cause duplicates on retry',\n riskMultiplier: 1.8,\n signals: ['job_retry', 'duplicate_side_effect', 'data_duplication'],\n },\n },\n\n // API Key + Cache = Revoked key still works\n {\n invariants: ['AUTHZ.KEYS.REVOCATION.IMMEDIATE', 'CACHE.INVALIDATION.ON_AUTH_CHANGE'],\n effect: {\n description: 'API key revocation without cache invalidation allows continued API access',\n riskMultiplier: 2.0,\n signals: ['key_still_valid', 'cache_bypass', 'api_access_leak'],\n },\n attackPathTemplate: {\n title: 'API Key Revocation Bypass',\n exploitability: 'easy',\n impact: 'high',\n timeWindow: 'Until cache expires',\n },\n },\n];\n\n// ============================================================================\n// Main Correlation Function\n// ============================================================================\n\n/**\n * Correlate findings to detect compounding risks\n */\nexport function correlateFindings(\n results: CheckResult[],\n artifact: Artifact\n): CorrelationResult {\n // Flatten all findings\n const allFindings = results.flatMap(r => r.findings);\n\n if (allFindings.length === 0) {\n return {\n correlations: [],\n stats: {\n totalFindings: 0,\n correlatedFindings: 0,\n correlationGroups: 0,\n severityEscalations: 0,\n },\n };\n }\n\n // Group findings by location\n const groups = groupFindingsByLocation(allFindings);\n\n // Find correlations\n const correlations: CorrelatedFinding[] = [];\n let severityEscalations = 0;\n\n for (const group of groups.values()) {\n if (group.length < 2) continue;\n\n // Check if this group matches any compounding rules\n const correlation = findCorrelation(group, artifact);\n if (correlation) {\n correlations.push(correlation);\n if (severityToNumber(correlation.adjustedSeverity) > severityToNumber(correlation.primary.severity)) {\n severityEscalations++;\n }\n }\n }\n\n // Count correlated findings\n const correlatedFindingIds = new Set<string>();\n for (const c of correlations) {\n correlatedFindingIds.add(findingId(c.primary));\n for (const r of c.related) {\n correlatedFindingIds.add(findingId(r));\n }\n }\n\n return {\n correlations,\n stats: {\n totalFindings: allFindings.length,\n correlatedFindings: correlatedFindingIds.size,\n correlationGroups: correlations.length,\n severityEscalations,\n },\n };\n}\n\n// ============================================================================\n// Grouping Logic\n// ============================================================================\n\n/**\n * Group findings by their location (file + function)\n */\nfunction groupFindingsByLocation(findings: Finding[]): Map<string, Finding[]> {\n const groups = new Map<string, Finding[]>();\n\n for (const finding of findings) {\n // Get location key from evidence\n const evidence = finding.evidence[0];\n if (!evidence) continue;\n\n const key = `${evidence.file}:${evidence.symbol ?? 'unknown'}`;\n\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n groups.get(key)!.push(finding);\n }\n\n return groups;\n}\n\n/**\n * Find correlation for a group of findings\n */\nfunction findCorrelation(\n findings: Finding[],\n _artifact: Artifact\n): CorrelatedFinding | null {\n // Get invariant IDs in this group\n const invariantIds = new Set(findings.map(f => f.invariantId));\n\n // Find matching compounding rule\n let bestMatch: (typeof COMPOUNDING_RULES)[0] | null = null;\n let matchCount = 0;\n\n for (const rule of COMPOUNDING_RULES) {\n const matches = rule.invariants.filter(inv => invariantIds.has(inv));\n if (matches.length >= 2 && matches.length > matchCount) {\n bestMatch = rule;\n matchCount = matches.length;\n }\n }\n\n if (!bestMatch) {\n // No specific rule, but still correlate if multiple findings\n if (findings.length >= 2) {\n return createGenericCorrelation(findings);\n }\n return null;\n }\n\n // Find the matching findings\n const matchingFindings = findings.filter(f =>\n bestMatch!.invariants.includes(f.invariantId)\n );\n\n // Sort by severity (P0 first)\n matchingFindings.sort((a, b) =>\n severityToNumber(b.severity) - severityToNumber(a.severity)\n );\n\n const primary = matchingFindings[0]!;\n const related = matchingFindings.slice(1);\n\n // Build shared context\n const evidence = primary.evidence[0];\n const sharedContext: SharedContext = {\n file: evidence?.file,\n functionName: evidence?.symbol,\n findingCount: matchingFindings.length,\n };\n\n // Calculate adjusted severity\n const adjustedSeverity = calculateAdjustedSeverity(\n primary.severity,\n bestMatch.effect.riskMultiplier\n );\n\n // Build attack path if template exists\n let attackPath: AttackPath | undefined;\n if (bestMatch.attackPathTemplate) {\n attackPath = buildAttackPath(\n bestMatch.attackPathTemplate,\n matchingFindings\n );\n }\n\n return {\n primary,\n related,\n sharedContext,\n compoundingEffect: bestMatch.effect,\n adjustedSeverity,\n attackPath,\n };\n}\n\n/**\n * Create a generic correlation for findings without specific rules\n */\nfunction createGenericCorrelation(findings: Finding[]): CorrelatedFinding {\n // Sort by severity\n findings.sort((a, b) =>\n severityToNumber(b.severity) - severityToNumber(a.severity)\n );\n\n const primary = findings[0]!;\n const related = findings.slice(1);\n const evidence = primary.evidence[0];\n\n return {\n primary,\n related,\n sharedContext: {\n file: evidence?.file,\n functionName: evidence?.symbol,\n findingCount: findings.length,\n },\n compoundingEffect: {\n description: `Multiple security issues in the same location (${findings.length} findings)`,\n riskMultiplier: 1.0 + (findings.length - 1) * 0.2,\n signals: findings.map(f => f.invariantId),\n },\n adjustedSeverity: primary.severity,\n };\n}\n\n// ============================================================================\n// Attack Path Builder\n// ============================================================================\n\n/**\n * Build an attack path from a template and findings\n */\nfunction buildAttackPath(\n template: Omit<AttackPath, 'steps'>,\n findings: Finding[]\n): AttackPath {\n const steps: AttackStep[] = [];\n\n for (let i = 0; i < findings.length; i++) {\n const finding = findings[i]!;\n const evidence = finding.evidence[0];\n\n steps.push({\n step: i + 1,\n description: getAttackStepDescription(finding),\n invariantId: finding.invariantId,\n location: evidence ? { file: evidence.file, line: evidence.line } : undefined,\n });\n }\n\n return {\n ...template,\n steps,\n };\n}\n\n/**\n * Get a description for an attack step based on the finding\n */\nfunction getAttackStepDescription(finding: Finding): string {\n const invariant = finding.invariantId;\n\n switch (invariant) {\n case 'WEBHOOK.IDEMPOTENT':\n return 'Attacker replays webhook request (no idempotency protection)';\n case 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS':\n return 'Side effect fires inside transaction (may be duplicated or inconsistent)';\n case 'AUTHZ.SERVICE_LAYER.ENFORCED':\n return 'Service function called without authorization check';\n case 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE':\n return 'Membership/role change does not immediately revoke access';\n case 'AUTHZ.KEYS.REVOCATION.IMMEDIATE':\n return 'API key revocation does not immediately invalidate the key';\n case 'CACHE.INVALIDATION.ON_AUTH_CHANGE':\n return 'Auth change does not invalidate cached permissions';\n case 'BILLING.SERVER_ENFORCED':\n return 'Billing/entitlement check bypassed or missing';\n case 'JOBS.RETRY_SAFE':\n return 'Background job is not idempotent (retry causes duplicates)';\n default:\n return finding.message;\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction severityToNumber(severity: Severity): number {\n switch (severity) {\n case 'P0': return 3;\n case 'P1': return 2;\n case 'P2': return 1;\n default: return 0;\n }\n}\n\nfunction numberToSeverity(num: number): Severity {\n if (num >= 3) return 'P0';\n if (num >= 2) return 'P1';\n return 'P2';\n}\n\nfunction calculateAdjustedSeverity(\n baseSeverity: Severity,\n multiplier: number\n): Severity {\n const base = severityToNumber(baseSeverity);\n const adjusted = Math.min(3, Math.ceil(base * multiplier));\n return numberToSeverity(adjusted);\n}\n\nfunction findingId(finding: Finding): string {\n const evidence = finding.evidence[0];\n return `${finding.invariantId}:${evidence?.file ?? 'unknown'}:${evidence?.line ?? 0}`;\n}\n\n// ============================================================================\n// Formatters\n// ============================================================================\n\n/**\n * Format a correlated finding for display\n */\nexport function formatCorrelatedFinding(correlation: CorrelatedFinding): string {\n const lines: string[] = [];\n\n // Header\n const location = correlation.sharedContext.file\n ? `${correlation.sharedContext.file}:${correlation.sharedContext.functionName ?? 'unknown'}`\n : 'Unknown location';\n\n lines.push(`\\n┌─ CORRELATED FINDINGS ─ ${location}`);\n lines.push(`│`);\n\n // Primary finding\n lines.push(`│ [${correlation.adjustedSeverity}] ${correlation.primary.message}`);\n lines.push(`│ └─ ${correlation.primary.invariantId}`);\n\n // Related findings\n for (const related of correlation.related) {\n lines.push(`│ [${related.severity}] ${related.message}`);\n lines.push(`│ └─ ${related.invariantId}`);\n }\n\n lines.push(`│`);\n\n // Compounding effect\n lines.push(`│ ⚠ Compounding Effect:`);\n lines.push(`│ ${correlation.compoundingEffect.description}`);\n lines.push(`│ Risk multiplier: ${correlation.compoundingEffect.riskMultiplier}x`);\n\n // Attack path (if available)\n if (correlation.attackPath) {\n lines.push(`│`);\n lines.push(`│ 🎯 Attack Path: ${correlation.attackPath.title}`);\n lines.push(`│ Exploitability: ${correlation.attackPath.exploitability}`);\n lines.push(`│ Impact: ${correlation.attackPath.impact}`);\n if (correlation.attackPath.timeWindow) {\n lines.push(`│ Time window: ${correlation.attackPath.timeWindow}`);\n }\n lines.push(`│`);\n for (const step of correlation.attackPath.steps) {\n lines.push(`│ ${step.step}. ${step.description}`);\n }\n }\n\n lines.push(`└────────────────────────────────────────`);\n\n return lines.join('\\n');\n}\n\n/**\n * Format correlation statistics\n */\nexport function formatCorrelationStats(result: CorrelationResult): string {\n const { stats } = result;\n\n return `\nCorrelation Analysis:\n Total findings: ${stats.totalFindings}\n Correlated: ${stats.correlatedFindings} (${Math.round(stats.correlatedFindings / stats.totalFindings * 100)}%)\n Correlation groups: ${stats.correlationGroups}\n Severity escalations: ${stats.severityEscalations}\n`.trim();\n}\n\nexport default correlateFindings;\n","/**\n * Correlation Telemetry\n *\n * Reports correlation data to the SecurityChecks SaaS.\n * This builds the data moat around which invariant combinations\n * actually compound risk in production codebases.\n */\n\nimport type { CorrelationResult, CorrelatedFinding } from './correlation.js';\nimport { randomUUID } from 'crypto';\n\n// Default endpoint (can be overridden)\nconst DEFAULT_ENDPOINT = 'https://api.securitychecks.ai/v1/correlations';\n\nexport interface CorrelationTelemetryConfig {\n enabled: boolean;\n endpoint?: string;\n apiKey?: string;\n timeout?: number;\n}\n\ninterface CorrelationObservation {\n invariants: string[];\n context: {\n framework?: string;\n file?: string;\n functionName?: string;\n route?: string;\n };\n stats: {\n findingCount: number;\n severityBefore?: 'P0' | 'P1' | 'P2';\n severityAfter?: 'P0' | 'P1' | 'P2';\n wasEscalated: boolean;\n riskMultiplier?: number;\n };\n attackPath?: {\n title: string;\n exploitability: 'easy' | 'medium' | 'hard';\n impact: 'low' | 'medium' | 'high' | 'critical';\n timeWindow?: string;\n steps: Array<{\n step: number;\n description: string;\n invariantId: string;\n location?: { file: string; line: number };\n }>;\n };\n compoundingEffect?: {\n description: string;\n signals: string[];\n };\n meta: {\n clientVersion: string;\n requestId: string;\n timestamp: string;\n };\n}\n\n/**\n * Convert CorrelatedFinding to observation format for API\n */\nfunction toObservation(\n correlation: CorrelatedFinding,\n framework?: string\n): CorrelationObservation {\n const allFindings = [correlation.primary, ...correlation.related];\n const invariants = [...new Set(allFindings.map(f => f.invariantId))];\n\n return {\n invariants,\n context: {\n framework,\n file: correlation.sharedContext.file,\n functionName: correlation.sharedContext.functionName,\n route: correlation.sharedContext.route,\n },\n stats: {\n findingCount: correlation.sharedContext.findingCount,\n severityBefore: correlation.primary.severity,\n severityAfter: correlation.adjustedSeverity,\n wasEscalated: correlation.adjustedSeverity !== correlation.primary.severity,\n riskMultiplier: correlation.compoundingEffect.riskMultiplier,\n },\n attackPath: correlation.attackPath ? {\n title: correlation.attackPath.title,\n exploitability: correlation.attackPath.exploitability,\n impact: correlation.attackPath.impact,\n timeWindow: correlation.attackPath.timeWindow,\n steps: correlation.attackPath.steps,\n } : undefined,\n compoundingEffect: {\n description: correlation.compoundingEffect.description,\n signals: correlation.compoundingEffect.signals,\n },\n meta: {\n clientVersion: process.env['CLI_VERSION'] ?? '0.0.0',\n requestId: randomUUID(),\n timestamp: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Report correlation results to the SaaS\n */\nexport async function reportCorrelations(\n result: CorrelationResult,\n config: CorrelationTelemetryConfig,\n framework?: string\n): Promise<{ success: boolean; stored?: number; errors?: number }> {\n if (!config.enabled || result.correlations.length === 0) {\n return { success: true, stored: 0 };\n }\n\n const endpoint = config.endpoint ?? DEFAULT_ENDPOINT;\n const timeout = config.timeout ?? 5000;\n\n try {\n const observations = result.correlations.map(c => toObservation(c, framework));\n\n const payload = {\n correlations: observations,\n summary: result.stats,\n meta: {\n clientVersion: process.env['CLI_VERSION'] ?? '0.0.0',\n framework,\n },\n };\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n 'X-Client-Version': process.env['CLI_VERSION'] ?? '0.0.0',\n },\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n return { success: false };\n }\n\n const data = await response.json() as { stored?: number; errors?: number };\n return {\n success: true,\n stored: data.stored ?? observations.length,\n errors: data.errors ?? 0,\n };\n } finally {\n clearTimeout(timeoutId);\n }\n } catch (_error) {\n // Telemetry failures shouldn't break the CLI\n return { success: false };\n }\n}\n\n/**\n * Report feedback on a correlation (user marking as accurate/inaccurate)\n */\nexport async function reportCorrelationFeedback(\n requestId: string,\n wasAccurate: boolean,\n reason?: string,\n config?: CorrelationTelemetryConfig\n): Promise<boolean> {\n const endpoint = config?.endpoint ?? DEFAULT_ENDPOINT;\n\n try {\n const response = await fetch(endpoint, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n ...(config?.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n },\n body: JSON.stringify({\n requestId,\n wasAccurate,\n feedbackReason: reason,\n }),\n });\n\n return response.ok;\n } catch {\n return false;\n }\n}\n\nexport default reportCorrelations;\n","/**\n * Anonymous Telemetry\n *\n * Reports aggregate scan statistics to the SecurityChecks SaaS.\n * NO source code, NO file paths, NO PII - just patterns and numbers.\n *\n * This data powers:\n * - Framework-specific calibration\n * - Pattern effectiveness tracking\n * - Invariant impact analysis\n */\n\nimport { randomUUID } from 'crypto';\nimport type { AuditResult } from '@securitychecks/collector';\nimport type { CorrelationResult } from './correlation.js';\nimport { isValidWaiverReasonKey } from '../baseline/index.js';\nimport type { CategorizationResult } from '../baseline/index.js';\n\n// Default endpoint\nconst DEFAULT_ENDPOINT = 'https://api.securitychecks.ai/v1/telemetry';\n\nexport interface TelemetryConfig {\n enabled: boolean;\n endpoint?: string;\n apiKey?: string;\n timeout?: number;\n}\n\nexport interface ScanTelemetry {\n scanId: string;\n codebase: {\n filesScanned: number;\n servicesCount: number;\n linesOfCode?: number;\n };\n frameworks: string[];\n findings: {\n byInvariant: Record<string, number>;\n byPriority: { P0: number; P1: number; P2: number };\n total: number;\n };\n correlation?: {\n groups: number;\n escalations: number;\n correlatedFindings: number;\n };\n calibration?: {\n calibrated: number;\n suppressed: number;\n };\n patterns?: {\n applied: number;\n findings: number;\n };\n meta: {\n duration?: number;\n clientVersion: string;\n mode?: 'ci' | 'manual' | 'watch';\n ciProvider?: string;\n };\n baseline?: {\n size: number;\n waivers: number;\n newFindings: number;\n };\n feedback?: {\n waivedCount: number;\n waiverReasons: Record<string, number>;\n baselinedCount: number;\n };\n}\n\n/**\n * Build telemetry data from scan results\n */\nexport function buildTelemetry(\n result: AuditResult,\n options: {\n filesScanned: number;\n frameworks: string[];\n correlation?: CorrelationResult;\n categorization?: CategorizationResult;\n calibratedCount?: number;\n suppressedCount?: number;\n patternsApplied?: number;\n patternFindings?: number;\n mode?: 'ci' | 'manual' | 'watch';\n baselineSize?: number;\n waiversCount?: number;\n }\n): ScanTelemetry {\n // Count findings by invariant\n const byInvariant: Record<string, number> = {};\n for (const checkResult of result.results) {\n byInvariant[checkResult.invariantId] = checkResult.findings.length;\n }\n\n // Detect CI provider from environment\n const ciProvider = detectCIProvider();\n\n return {\n scanId: randomUUID(),\n codebase: {\n filesScanned: options.filesScanned,\n servicesCount: result.artifact.services.length,\n },\n frameworks: options.frameworks,\n findings: {\n byInvariant,\n byPriority: result.summary.byPriority,\n total: result.summary.byPriority.P0 + result.summary.byPriority.P1 + result.summary.byPriority.P2,\n },\n correlation: options.correlation ? {\n groups: options.correlation.stats.correlationGroups,\n escalations: options.correlation.stats.severityEscalations,\n correlatedFindings: options.correlation.stats.correlatedFindings,\n } : undefined,\n calibration: (options.calibratedCount !== undefined) ? {\n calibrated: options.calibratedCount,\n suppressed: options.suppressedCount ?? 0,\n } : undefined,\n patterns: (options.patternsApplied !== undefined) ? {\n applied: options.patternsApplied,\n findings: options.patternFindings ?? 0,\n } : undefined,\n meta: {\n duration: result.duration,\n clientVersion: process.env['CLI_VERSION'] ?? '0.0.0',\n mode: options.mode ?? (ciProvider ? 'ci' : 'manual'),\n ciProvider,\n },\n baseline: (options.categorization) ? {\n size: options.baselineSize ?? 0,\n waivers: options.waiversCount ?? 0,\n newFindings: options.categorization.counts.new,\n } : undefined,\n feedback: (options.categorization) ? {\n waivedCount: options.categorization.counts.waived,\n waiverReasons: buildWaiverReasonCounts(options.categorization),\n baselinedCount: options.categorization.counts.baselined,\n } : undefined,\n };\n}\n\n/**\n * Report telemetry to the SaaS\n */\nexport async function reportTelemetry(\n telemetry: ScanTelemetry,\n config: TelemetryConfig\n): Promise<boolean> {\n if (!config.enabled) {\n return true;\n }\n\n const endpoint = config.endpoint ?? DEFAULT_ENDPOINT;\n const timeout = config.timeout ?? 5000;\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n 'X-Client-Version': telemetry.meta.clientVersion,\n },\n body: JSON.stringify(telemetry),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n return response.ok;\n } finally {\n clearTimeout(timeoutId);\n }\n } catch {\n // Telemetry failures are silent\n return false;\n }\n}\n\n/**\n * Build waiver reason distribution from categorization result\n */\nfunction buildWaiverReasonCounts(categorization: CategorizationResult): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const finding of categorization.waived) {\n const waiver = finding.waiver;\n if (!waiver) continue;\n const candidate = waiver.reasonKey ?? waiver.reason;\n const key = candidate && isValidWaiverReasonKey(candidate) ? candidate : 'other';\n counts[key] = (counts[key] ?? 0) + 1;\n }\n return counts;\n}\n\n/**\n * Detect CI provider from environment variables\n */\nfunction detectCIProvider(): string | undefined {\n if (process.env['GITHUB_ACTIONS']) return 'github';\n if (process.env['GITLAB_CI']) return 'gitlab';\n if (process.env['JENKINS_URL']) return 'jenkins';\n if (process.env['CIRCLECI']) return 'circleci';\n if (process.env['TRAVIS']) return 'travis';\n if (process.env['BITBUCKET_BUILD_NUMBER']) return 'bitbucket';\n if (process.env['AZURE_PIPELINES']) return 'azure';\n if (process.env['CI']) return 'unknown';\n return undefined;\n}\n\n/**\n * Check if telemetry is opt-out\n */\nexport function isTelemetryDisabled(): boolean {\n return (\n process.env['SECURITYCHECKS_TELEMETRY'] === 'false' ||\n process.env['DO_NOT_TRACK'] === '1'\n );\n}\n\nexport default reportTelemetry;\n","/**\n * Calibration API Client\n *\n * \"The SaaS advises. The local tool decides.\"\n *\n * This module handles communication with the SecurityChecks Calibration API.\n * The API provides confidence tuning based on aggregate data from many codebases.\n *\n * Key principles:\n * - No source code is ever sent (only patterns and metadata)\n * - API suggestions are advisory only\n * - Local tool retains veto power via minConfidence threshold\n * - Fails safely to local-only mode on network errors\n */\n\nimport type {\n CalibrationConfig,\n CalibrationRequest,\n CalibrationResponse,\n Finding,\n FindingCalibration,\n Severity,\n Artifact,\n} from '@securitychecks/collector';\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { randomUUID } from 'crypto';\n\n// CLI version for telemetry\nconst CLI_VERSION = '0.1.0';\n\n// Default cache path\nconst DEFAULT_CACHE_PATH = '.securitychecks/calibration-cache.json';\n\ninterface CacheEntry {\n response: CalibrationResponse;\n timestamp: number;\n requestHash: string;\n}\n\ninterface CalibrationCache {\n version: '1.0';\n entries: Record<string, CacheEntry>;\n}\n\n/**\n * Create a hash for a calibration request (for caching)\n */\nfunction hashRequest(request: CalibrationRequest): string {\n // Simple hash based on key fields (not crypto-secure, just for caching)\n const key = JSON.stringify({\n invariantId: request.invariantId,\n localSeverity: request.localSeverity,\n pattern: request.pattern,\n context: request.context,\n });\n // Simple string hash\n let hash = 0;\n for (let i = 0; i < key.length; i++) {\n const char = key.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36);\n}\n\n/**\n * Load calibration cache from disk\n */\nasync function loadCache(cachePath: string): Promise<CalibrationCache> {\n try {\n if (existsSync(cachePath)) {\n const content = await readFile(cachePath, 'utf-8');\n return JSON.parse(content);\n }\n } catch {\n // Cache corrupted or unreadable, start fresh\n }\n return { version: '1.0', entries: {} };\n}\n\n/**\n * Save calibration cache to disk\n */\nasync function saveCache(cachePath: string, cache: CalibrationCache): Promise<void> {\n try {\n await mkdir(dirname(cachePath), { recursive: true });\n await writeFile(cachePath, JSON.stringify(cache, null, 2));\n } catch {\n // Failed to save cache, not critical\n }\n}\n\n/**\n * Extract calibration-safe pattern from a finding\n * This is what we send to the API - no source code, just metadata\n */\nexport function extractPatternFromFinding(finding: Finding): CalibrationRequest['pattern'] {\n const pattern: CalibrationRequest['pattern'] = {};\n\n // Extract from structured evidence if available\n if (finding.structuredEvidence) {\n const se = finding.structuredEvidence;\n\n if (se.mutationSite) {\n pattern.functionName = se.mutationSite.functionName;\n pattern.mutationType = se.mutationSite.mutationType;\n pattern.entity = se.mutationSite.entity;\n }\n\n pattern.signals = se.signals;\n pattern.confidence = se.confidence;\n\n pattern.indicators = {\n hasCacheInvalidation: (se.invalidationSites?.length ?? 0) > 0,\n hasTests: (se.testsCovering?.length ?? 0) > 0,\n };\n }\n\n // Extract from basic evidence as fallback\n const firstEvidence = finding.evidence[0];\n if (firstEvidence?.symbol && !pattern.functionName) {\n pattern.functionName = firstEvidence.symbol;\n }\n\n return pattern;\n}\n\n/**\n * Detect framework from artifact\n */\nexport function detectFramework(artifact: Artifact): string | undefined {\n // Check routes for framework hints\n if (artifact.routes && artifact.routes.length > 0) {\n const frameworks = artifact.routes.map((r) => r.framework);\n const counts = new Map<string, number>();\n for (const f of frameworks) {\n counts.set(f, (counts.get(f) ?? 0) + 1);\n }\n // Return most common non-unknown framework\n let maxFramework: string | undefined;\n let maxCount = 0;\n for (const [f, c] of counts) {\n if (f !== 'unknown' && c > maxCount) {\n maxFramework = f;\n maxCount = c;\n }\n }\n return maxFramework;\n }\n return undefined;\n}\n\n/**\n * Build context for calibration request\n */\nexport function buildContext(\n artifact: Artifact,\n invariantId: string,\n allFindings: Finding[]\n): CalibrationRequest['context'] {\n const findingsOfType = allFindings.filter((f) => f.invariantId === invariantId);\n\n return {\n framework: detectFramework(artifact),\n serviceCount: artifact.services.length,\n findingCount: findingsOfType.length,\n hasTests: (artifact.tests?.length ?? 0) > 0,\n };\n}\n\n/**\n * Call the Calibration API for a single finding\n */\nasync function callCalibrationAPI(\n request: CalibrationRequest,\n config: CalibrationConfig\n): Promise<CalibrationResponse | null> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), config.timeout);\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n 'X-Client-Version': CLI_VERSION,\n },\n body: JSON.stringify(request),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n // API error - fail safe to local result\n return null;\n }\n\n const data = await response.json();\n return data as CalibrationResponse;\n } catch {\n // Network error, timeout, etc. - fail safe to local result\n clearTimeout(timeoutId);\n return null;\n }\n}\n\n/**\n * Calibrate a single finding\n */\nexport async function calibrateFinding(\n finding: Finding,\n artifact: Artifact,\n allFindings: Finding[],\n config: CalibrationConfig,\n cache: CalibrationCache\n): Promise<Finding> {\n // Build request\n const request: CalibrationRequest = {\n invariantId: finding.invariantId,\n localSeverity: finding.severity,\n pattern: extractPatternFromFinding(finding),\n context: buildContext(artifact, finding.invariantId, allFindings),\n meta: {\n clientVersion: CLI_VERSION,\n requestId: randomUUID(),\n timestamp: new Date().toISOString(),\n },\n };\n\n const requestHash = hashRequest(request);\n\n // Check cache first\n if (config.cache?.enabled) {\n const cached = cache.entries[requestHash];\n if (cached) {\n const age = Date.now() - cached.timestamp;\n const ttlMs = (config.cache.ttl ?? 86400) * 1000;\n if (age < ttlMs) {\n // Use cached response\n return applyCalibration(finding, cached.response, config);\n }\n }\n }\n\n // Call API\n const response = await callCalibrationAPI(request, config);\n\n if (!response) {\n // API failed - return finding unchanged\n return finding;\n }\n\n // Cache response\n if (config.cache?.enabled) {\n cache.entries[requestHash] = {\n response,\n timestamp: Date.now(),\n requestHash,\n };\n }\n\n return applyCalibration(finding, response, config);\n}\n\n/**\n * Apply calibration response to a finding\n */\nfunction applyCalibration(\n finding: Finding,\n response: CalibrationResponse,\n config: CalibrationConfig\n): Finding {\n const originalSeverity = finding.severity;\n\n // Check if we should apply the recommendation\n const shouldApply = response.confidence >= config.minConfidence && !response.suppress;\n\n const calibration: FindingCalibration = {\n apiRecommendation: response,\n applied: shouldApply,\n originalSeverity,\n reason: shouldApply\n ? `API confidence ${(response.confidence * 100).toFixed(0)}% >= threshold ${(config.minConfidence * 100).toFixed(0)}%`\n : `API confidence ${(response.confidence * 100).toFixed(0)}% < threshold ${(config.minConfidence * 100).toFixed(0)}%`,\n };\n\n // Create new finding with calibration data\n const calibratedFinding: Finding = {\n ...finding,\n calibration,\n };\n\n // Apply severity change if recommended and above threshold\n if (shouldApply && response.recommendedSeverity !== originalSeverity) {\n calibratedFinding.severity = response.recommendedSeverity;\n }\n\n return calibratedFinding;\n}\n\n/**\n * Calibrate all findings in a batch\n * This is the main entry point for calibration\n */\nexport async function calibrateFindings(\n findings: Finding[],\n artifact: Artifact,\n config: CalibrationConfig,\n targetPath: string\n): Promise<Finding[]> {\n if (!config.enabled) {\n return findings;\n }\n\n // Load cache\n const cachePath = config.cache?.path ?? join(targetPath, DEFAULT_CACHE_PATH);\n const cache = await loadCache(cachePath);\n\n // Calibrate each finding\n const calibratedFindings = await Promise.all(\n findings.map((finding) => calibrateFinding(finding, artifact, findings, config, cache))\n );\n\n // Save cache\n if (config.cache?.enabled) {\n await saveCache(cachePath, cache);\n }\n\n return calibratedFindings;\n}\n\n/**\n * Get calibration statistics from findings\n */\nexport function getCalibrationStats(findings: Finding[]): {\n total: number;\n calibrated: number;\n applied: number;\n unchanged: number;\n severityChanges: { from: Severity; to: Severity; count: number }[];\n} {\n const calibrated = findings.filter((f) => f.calibration);\n const applied = calibrated.filter((f) => f.calibration?.applied);\n\n const changes = new Map<string, number>();\n for (const finding of applied) {\n if (finding.calibration && finding.calibration.originalSeverity !== finding.severity) {\n const key = `${finding.calibration.originalSeverity}->${finding.severity}`;\n changes.set(key, (changes.get(key) ?? 0) + 1);\n }\n }\n\n const severityChanges = Array.from(changes.entries()).map(([key, count]) => {\n const [from, to] = key.split('->') as [Severity, Severity];\n return { from, to, count };\n });\n\n return {\n total: findings.length,\n calibrated: calibrated.length,\n applied: applied.length,\n unchanged: findings.length - applied.length,\n severityChanges,\n };\n}\n\n// ============================================================================\n// Aggregate Calibration (from SaaS learning loop)\n// ============================================================================\n\nconst AGGREGATE_CALIBRATION_ENDPOINT = 'https://api.securitychecks.ai/v1/calibration';\n\n// In-memory cache for aggregate data (1 hour TTL)\nconst AGGREGATE_CACHE_TTL_MS = 60 * 60 * 1000;\nlet aggregateCache: AggregateCalibrationData | null = null;\nlet aggregateCacheTimestamp = 0;\n\nexport interface AggregateCalibrationConfig {\n enabled: boolean;\n endpoint?: string;\n apiKey?: string;\n timeout?: number;\n cacheEnabled?: boolean;\n}\n\nexport interface FrameworkBaseline {\n framework: string;\n avgFindings: number;\n avgP0: number;\n avgP1: number;\n avgP2: number;\n scansAnalyzed: number;\n confidence: 'high' | 'medium' | 'low';\n}\n\nexport interface InvariantStats {\n invariantId: string;\n avgPerScan: number;\n hitRate: number;\n p0Rate: number;\n p1Rate: number;\n p2Rate: number;\n}\n\nexport interface PatternStats {\n patternId: string;\n framework: string | null;\n accuracy: number | null;\n matchesPerScan: number;\n confidence: 'high' | 'medium' | 'low';\n}\n\nexport interface CorrelationStats {\n ruleId: string;\n accuracy: number | null;\n escalationRate: number | null;\n isVerified: boolean;\n}\n\nexport interface AggregateCalibrationData {\n version: string;\n generatedAt: string;\n frameworks: FrameworkBaseline[];\n invariants: InvariantStats[];\n patterns: PatternStats[];\n correlations: CorrelationStats[];\n meta: {\n totalScansAnalyzed: number;\n lastUpdated: string | null;\n };\n}\n\nexport interface AggregateCalibrationResult {\n data: AggregateCalibrationData | null;\n fromCache: boolean;\n error?: string;\n}\n\n/**\n * Fetch aggregate calibration data for the specified frameworks\n */\nexport async function fetchAggregateCalibration(\n frameworks: string[],\n config: AggregateCalibrationConfig\n): Promise<AggregateCalibrationResult> {\n if (!config.enabled) {\n return { data: null, fromCache: false, error: 'Aggregate calibration disabled' };\n }\n\n // Check cache first\n if (config.cacheEnabled !== false && aggregateCache && Date.now() - aggregateCacheTimestamp < AGGREGATE_CACHE_TTL_MS) {\n return { data: aggregateCache, fromCache: true };\n }\n\n const endpoint = config.endpoint ?? AGGREGATE_CALIBRATION_ENDPOINT;\n const timeout = config.timeout ?? 5000;\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const url = new URL(endpoint);\n url.searchParams.set('frameworks', frameworks.join(','));\n\n const response = await fetch(url.toString(), {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n ...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n return {\n data: null,\n fromCache: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n const data = await response.json() as AggregateCalibrationData;\n\n // Update cache\n if (config.cacheEnabled !== false) {\n aggregateCache = data;\n aggregateCacheTimestamp = Date.now();\n }\n\n return { data, fromCache: false };\n } finally {\n clearTimeout(timeoutId);\n }\n } catch (err) {\n // Calibration failures are non-fatal\n return {\n data: null,\n fromCache: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n };\n }\n}\n\n/**\n * Clear the aggregate calibration cache\n */\nexport function clearAggregateCache(): void {\n aggregateCache = null;\n aggregateCacheTimestamp = 0;\n}\n\n/**\n * Get the framework baseline for comparison\n */\nexport function getFrameworkBaseline(\n calibration: AggregateCalibrationData,\n framework: string\n): FrameworkBaseline | undefined {\n return calibration.frameworks.find((f) => f.framework === framework);\n}\n\n/**\n * Check if a pattern should be skipped due to low accuracy\n */\nexport function shouldSkipPattern(\n calibration: AggregateCalibrationData,\n patternId: string,\n framework?: string,\n accuracyThreshold = 0.3\n): boolean {\n const pattern = calibration.patterns.find(\n (p) => p.patternId === patternId &&\n (p.framework === framework || p.framework === null)\n );\n\n if (!pattern || pattern.accuracy === null) {\n return false; // No data, don't skip\n }\n\n // Only skip if we have high confidence it's a bad pattern\n if (pattern.confidence !== 'high') {\n return false;\n }\n\n return pattern.accuracy < accuracyThreshold;\n}\n\n/**\n * Get patterns that should be skipped for a framework\n */\nexport function getSkippedPatterns(\n calibration: AggregateCalibrationData,\n framework?: string,\n accuracyThreshold = 0.3\n): string[] {\n return calibration.patterns\n .filter((p) => {\n if (p.accuracy === null || p.confidence !== 'high') {\n return false;\n }\n if (framework && p.framework && p.framework !== framework) {\n return false;\n }\n return p.accuracy < accuracyThreshold;\n })\n .map((p) => p.patternId);\n}\n\n/**\n * Get correlation rules with high confidence\n */\nexport function getVerifiedCorrelations(\n calibration: AggregateCalibrationData\n): CorrelationStats[] {\n return calibration.correlations.filter((c) => c.isVerified);\n}\n\n/**\n * Calculate relative finding severity based on framework baseline\n */\nexport function calculateRelativeSeverity(\n findingCount: number,\n baseline: FrameworkBaseline,\n type: 'total' | 'P0' | 'P1' | 'P2' = 'total'\n): 'below_average' | 'average' | 'above_average' | 'critical' {\n let avg: number;\n switch (type) {\n case 'P0':\n avg = baseline.avgP0;\n break;\n case 'P1':\n avg = baseline.avgP1;\n break;\n case 'P2':\n avg = baseline.avgP2;\n break;\n default:\n avg = baseline.avgFindings;\n }\n\n if (avg === 0) {\n return findingCount > 0 ? 'above_average' : 'average';\n }\n\n const ratio = findingCount / avg;\n\n if (ratio < 0.5) return 'below_average';\n if (ratio < 1.5) return 'average';\n if (ratio < 3) return 'above_average';\n return 'critical';\n}\n\n/**\n * Generate calibration summary for output\n */\nexport function formatAggregateCalibrationSummary(\n calibration: AggregateCalibrationData,\n frameworks: string[],\n findings: { P0: number; P1: number; P2: number; total: number }\n): string {\n const lines: string[] = [];\n\n // Framework comparison\n for (const fw of frameworks) {\n const baseline = getFrameworkBaseline(calibration, fw);\n if (baseline && baseline.confidence !== 'low') {\n const severity = calculateRelativeSeverity(findings.total, baseline);\n const avgStr = baseline.avgFindings.toFixed(1);\n\n if (severity === 'below_average') {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Below average`);\n } else if (severity === 'above_average') {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Above average`);\n } else if (severity === 'critical') {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Significantly above average`);\n } else {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Typical`);\n }\n }\n }\n\n // Skipped patterns\n const skipped = getSkippedPatterns(calibration, frameworks[0]);\n if (skipped.length > 0) {\n lines.push(`Skipped ${skipped.length} low-accuracy patterns`);\n }\n\n // Data confidence\n if (calibration.meta.totalScansAnalyzed < 100) {\n lines.push(`Calibration based on ${calibration.meta.totalScansAnalyzed} scans (limited data)`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Check if aggregate calibration is disabled via environment\n */\nexport function isAggregateCalibrationDisabled(): boolean {\n return process.env['SECURITYCHECKS_CALIBRATION'] === 'false';\n}\n","/**\n * Staff Engineer Templates\n *\n * Shared, stable UX helpers used by:\n * - CLI output (human-readable prompts)\n * - MCP adapters (Claude Code, etc.)\n *\n * Keep these centralized to avoid drift across integration surfaces.\n */\n\nexport type TestFramework = 'jest' | 'vitest' | 'playwright' | (string & {});\n\nexport type InvariantLike = {\n id: string;\n name: string;\n requiredProof?: string;\n};\n\n/**\n * Returns the \"A staff engineer would ask...\" question for each invariant.\n * These are the probing questions that senior engineers ask in code review.\n */\nexport function getStaffQuestion(invariantId: string): string | null {\n const questions: Record<string, string> = {\n 'AUTHZ.SERVICE_LAYER.ENFORCED':\n 'What happens when a background job calls this function directly, bypassing the route?',\n 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE':\n 'If I remove someone from a team right now, can they still access team resources?',\n 'AUTHZ.KEYS.REVOCATION.IMMEDIATE':\n 'If I revoke this API key, does it stop working immediately or is it cached?',\n 'WEBHOOK.IDEMPOTENT':\n 'What happens when Stripe retries this webhook? Will we double-charge the customer?',\n 'WEBHOOK.SIGNATURE.VERIFIED':\n 'Are we verifying webhook signatures before processing any side effects?',\n 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS':\n 'If this transaction rolls back, did we already send an email the user will never receive?',\n 'TESTS.NO_FALSE_CONFIDENCE':\n 'Is this test actually verifying behavior, or just making CI green?',\n 'CACHE.INVALIDATION.ON_AUTH_CHANGE':\n 'When someone loses access, how long until the cache catches up?',\n 'JOBS.RETRY_SAFE':\n 'If this job runs twice, will we have duplicate data or double-bill someone?',\n 'BILLING.SERVER_ENFORCED':\n 'Can someone bypass the paywall by calling the API directly?',\n 'ANALYTICS.SCHEMA.STABLE':\n 'If someone adds a field here, will it break our dashboards?',\n 'DATAFLOW.UNTRUSTED.SQL_QUERY':\n 'Can untrusted input reach a raw SQL/NoSQL query without strict validation?',\n 'DATAFLOW.UNTRUSTED.COMMAND_EXEC':\n 'Can user input make it into exec/spawn/eval and change what runs?',\n 'DATAFLOW.UNTRUSTED.FILE_ACCESS':\n 'Can user input control file paths or write locations here?',\n 'DATAFLOW.UNTRUSTED.RESPONSE':\n 'Can user input drive redirects or HTML output without sanitization?',\n 'SECRETS.HARDCODED':\n 'If this repo were accidentally made public, what credentials would be exposed?',\n 'CRYPTO.ALGORITHM.STRONG':\n 'Is this encryption strong enough for the data it protects?',\n };\n return questions[invariantId] ?? null;\n}\n\nexport function generateTestSkeleton(\n invariant: InvariantLike | null | undefined,\n framework: TestFramework,\n context?: string\n): string {\n if (!invariant) return 'Unknown invariant';\n\n const testFn = framework === 'jest' ? 'test' : framework === 'playwright' ? 'test' : 'it';\n const describe = framework === 'playwright' ? '' : 'describe';\n\n const wrap = (body: string) => {\n if (framework === 'playwright') {\n return body.trim();\n }\n return `\n${describe}('${escapeString(invariant.name)}', () => {\n${indent(body.trim(), 2)}\n});\n`.trim();\n };\n\n switch (invariant.id) {\n case 'AUTHZ.SERVICE_LAYER.ENFORCED':\n return wrap(`\n${testFn}('denies access without valid authorization', async () => {\n // Arrange: create context without auth\n const unauthorizedContext = { userId: null, tenantId: null };\n\n // Act + Assert: service call should throw (or return a forbidden result)\n await expect(\n yourService.sensitiveOperation({ context: unauthorizedContext })\n ).rejects.toThrow(/unauthorized|forbidden/i);\n});\n\n${testFn}('denies access to wrong-tenant resources', async () => {\n // Arrange: user from tenant-1 trying to access tenant-2 resource\n const context = { userId: 'user-1', tenantId: 'tenant-1' };\n const resourceFromOtherTenant = { id: 'resource-1', tenantId: 'tenant-2' };\n\n // Act + Assert\n await expect(\n yourService.getResource({ context, resourceId: resourceFromOtherTenant.id })\n ).rejects.toThrow(/forbidden|access denied/i);\n});\n`);\n\n case 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE':\n return wrap(`\n${testFn}('denies access immediately after membership removal', async () => {\n // Arrange: user with team membership\n const userId = 'user-1';\n const teamId = 'team-1';\n await addMemberToTeam(userId, teamId);\n\n // Act: remove membership\n await removeMemberFromTeam(userId, teamId);\n\n // Assert: immediate access denial (no TTL grace period)\n await expect(accessTeamResource({ userId, teamId })).rejects.toThrow(/forbidden|not a member/i);\n});\n`);\n\n case 'WEBHOOK.IDEMPOTENT':\n return wrap(`\n${testFn}('handles duplicate webhook events idempotently', async () => {\n // Arrange: create a webhook event\n const event = { id: 'evt_test_123', type: 'payment.succeeded', data: { amount: 1000 } };\n\n // Act: process the same event twice\n await processWebhook(event);\n await processWebhook(event); // duplicate\n\n // Assert: side effect only happened once\n const payments = await getPaymentRecords();\n expect(payments.filter((p: any) => p.eventId === event.id)).toHaveLength(1);\n});\n\n${testFn}('stores event IDs to prevent duplicates', async () => {\n const event = { id: 'evt_test_456', type: 'payment.succeeded' };\n\n await processWebhook(event);\n\n // Verify idempotency key was stored\n const stored = await getProcessedEventIds();\n expect(stored).toContain(event.id);\n});\n`);\n\n case 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS':\n return wrap(`\n${testFn}('does not send side effects if transaction rolls back', async () => {\n const emailSpy = vi.spyOn(emailService, 'send');\n\n // Act: trigger action that should fail and rollback\n await expect(createOrderWithInvalidData({ /* invalid data causing rollback */ })).rejects.toThrow();\n\n // Assert: no email was sent\n expect(emailSpy).not.toHaveBeenCalled();\n});\n\n${testFn}('sends side effects only after successful commit', async () => {\n const emailSpy = vi.spyOn(emailService, 'send');\n\n // Act: successful order creation\n await createOrder({ productId: 'prod-1', quantity: 1 });\n\n // Assert: email was sent\n expect(emailSpy).toHaveBeenCalledOnce();\n});\n`);\n\n default: {\n const proof = invariant.requiredProof ? invariant.requiredProof : '(see invariant docs)';\n const contextLine = context ? `// Context: ${context}` : '';\n return wrap(`\n${testFn}('enforces ${invariant.id}', async () => {\n // TODO: implement test for ${invariant.id}\n // Required proof: ${proof}\n ${contextLine}\n\n throw new Error('Test not implemented');\n});\n`);\n }\n }\n}\n\nfunction indent(text: string, spaces: number): string {\n const prefix = ' '.repeat(spaces);\n return text\n .split('\\n')\n .map((line) => (line ? `${prefix}${line}` : line))\n .join('\\n');\n}\n\nfunction escapeString(text: string): string {\n return text.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n","import pc from 'picocolors';\n\nexport type Grade = 'A' | 'B' | 'C' | 'F';\n\nexport interface ReadinessScore {\n score: number;\n grade: Grade;\n total: number;\n passed: number;\n failed: number;\n hasP0: boolean;\n}\n\nexport function getScoreGrade(score: number): Grade {\n if (score >= 90) return 'A';\n if (score >= 70) return 'B';\n if (score >= 50) return 'C';\n return 'F';\n}\n\nexport function computeReadinessScore(summary: {\n total: number;\n passed: number;\n failed: number;\n byPriority: { P0: number; P1: number; P2: number };\n}): ReadinessScore {\n const { total, passed, failed, byPriority } = summary;\n const hasP0 = byPriority.P0 > 0;\n\n if (total === 0) {\n return { score: 100, grade: 'A', total: 0, passed: 0, failed: 0, hasP0: false };\n }\n\n let score = Math.round(100 * passed / total);\n\n // Cap at 49 if any P0 findings exist\n if (hasP0 && score > 49) {\n score = 49;\n }\n\n return {\n score,\n grade: getScoreGrade(score),\n total,\n passed,\n failed,\n hasP0,\n };\n}\n\nexport function formatScoreForCli(rs: ReadinessScore): string {\n const gradeColor =\n rs.grade === 'A' ? pc.green :\n rs.grade === 'B' ? pc.yellow :\n rs.grade === 'C' ? pc.red :\n pc.red;\n\n return gradeColor(`Score: ${rs.score}/100 (${rs.grade})`);\n}\n"]}
1
+ {"version":3,"sources":["../src/lib/cloud-config.ts","../src/lib/license.ts","../src/lib/errors.ts","../src/lib/ci-detect.ts","../src/lib/cloud-eval.ts","../src/lib/project-slug.ts","../src/audit.ts","../src/lib/schema.ts","../src/findings/finding-id.ts","../src/baseline/schema.ts","../src/baseline/storage.ts","../src/baseline/matcher.ts","../src/lib/correlation.ts","../src/lib/correlation-telemetry.ts","../src/lib/telemetry.ts","../src/lib/calibration.ts","../src/lib/staff.ts","../src/lib/score.ts","../src/lib/posture.ts"],"names":["findingId","join","existsSync","readFile","mkdir","writeFile","DEFAULT_ENDPOINT","randomUUID","pc","checked"],"mappings":"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","file":"lib.js","sourcesContent":["/**\n * Cloud Configuration Management\n *\n * Manages CLI configuration for cloud integration with SecurityChecks.ai\n * Configuration is stored in ~/.securitychecks/config.json\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/** Configuration directory path */\nconst CONFIG_DIR = join(homedir(), '.securitychecks');\n\n/** Configuration file path */\nconst CONFIG_FILE = join(CONFIG_DIR, 'config.json');\n\n/** Cloud API base URL */\nconst DEFAULT_API_URL = 'https://api.securitychecks.ai';\n\nexport function normalizeApiBaseUrl(input: string): string {\n const value = input.trim();\n if (!value) {\n throw new Error('API URL is empty');\n }\n\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(`Invalid API URL: ${input}`);\n }\n\n if (url.protocol !== 'https:' && url.protocol !== 'http:') {\n throw new Error('API URL must start with http:// or https://');\n }\n\n if (url.username || url.password) {\n throw new Error('API URL must not include credentials');\n }\n\n url.hash = '';\n url.search = '';\n\n // Accept both base URLs and v1-style aliases, normalize to a base.\n // Examples:\n // - https://api.securitychecks.ai/v1 -> https://api.securitychecks.ai\n // - https://example.com/api/v1 -> https://example.com\n const pathname = url.pathname.replace(/\\/+$/, '');\n const stripped = pathname\n .replace(/\\/api\\/v1$/i, '')\n .replace(/\\/v1$/i, '');\n url.pathname = stripped.length === 0 ? '/' : `${stripped}/`;\n\n // Remove trailing slash (keep origin+path stable).\n return url.toString().replace(/\\/$/, '');\n}\n\n/**\n * Cloud configuration structure\n */\nexport interface CloudConfig {\n /** API key for authentication */\n apiKey?: string;\n\n /** Default project slug */\n project?: string;\n\n /** API base URL (for self-hosted instances) */\n apiUrl?: string;\n\n /** Enable cloud mode by default */\n cloudEnabled?: boolean;\n\n /** User email (for display purposes) */\n email?: string;\n\n /** Organization name (for display purposes) */\n organization?: string;\n\n /** Last sync timestamp */\n lastSync?: string;\n\n /** Suppress periodic usage awareness banner */\n usageBannerDisabled?: boolean;\n}\n\n/**\n * Ensure configuration directory exists\n */\nasync function ensureConfigDir(): Promise<void> {\n if (!existsSync(CONFIG_DIR)) {\n await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });\n }\n}\n\n/**\n * Load cloud configuration from disk\n */\nexport async function loadCloudConfig(): Promise<CloudConfig> {\n try {\n if (!existsSync(CONFIG_FILE)) {\n return {};\n }\n const content = await readFile(CONFIG_FILE, 'utf-8');\n return JSON.parse(content) as CloudConfig;\n } catch {\n return {};\n }\n}\n\n/**\n * Save cloud configuration to disk\n */\nexport async function saveCloudConfig(config: CloudConfig): Promise<void> {\n await ensureConfigDir();\n await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 });\n}\n\n/**\n * Update specific configuration values\n */\nexport async function updateCloudConfig(\n updates: Partial<CloudConfig>\n): Promise<CloudConfig> {\n const config = await loadCloudConfig();\n const updated = { ...config, ...updates };\n await saveCloudConfig(updated);\n return updated;\n}\n\n/**\n * Clear cloud configuration\n */\nexport async function clearCloudConfig(): Promise<void> {\n await saveCloudConfig({});\n}\n\n/**\n * Get the effective API key (from config, env, or CLI option)\n */\nexport function getApiKey(cliOption?: string): string | undefined {\n // CLI option takes precedence\n if (cliOption) return cliOption;\n\n // Then environment variable\n const envKey = process.env['SECURITYCHECKS_API_KEY'];\n if (envKey) return envKey;\n\n // Config is loaded async, so this needs to be called after loading config\n return undefined;\n}\n\n/**\n * Get the effective project slug (from config, env, or CLI option)\n */\nexport function getProject(cliOption?: string): string | undefined {\n if (cliOption) return cliOption;\n return process.env['SECURITYCHECKS_PROJECT'];\n}\n\n/**\n * Get the API base URL\n */\nexport function getApiUrl(config: CloudConfig): string {\n const raw = config.apiUrl || process.env['SECURITYCHECKS_API_URL'] || DEFAULT_API_URL;\n return normalizeApiBaseUrl(raw);\n}\n\n/**\n * Check if cloud mode is enabled\n */\nexport function isCloudEnabled(\n config: CloudConfig,\n cliOption?: boolean\n): boolean {\n if (cliOption !== undefined) return cliOption;\n if (process.env['SECURITYCHECKS_CLOUD'] === 'true') return true;\n return config.cloudEnabled ?? false;\n}\n\n/**\n * Format configuration for display\n */\nexport function formatConfig(config: CloudConfig): string {\n const lines: string[] = [];\n\n lines.push('Cloud Configuration:');\n lines.push('');\n\n if (config.apiKey) {\n const masked = config.apiKey.substring(0, 10) + '...' + config.apiKey.slice(-4);\n lines.push(` API Key: ${masked}`);\n } else {\n lines.push(' API Key: (not set)');\n }\n\n lines.push(` Project: ${config.project || '(not set)'}`);\n lines.push(` API URL: ${config.apiUrl || DEFAULT_API_URL}`);\n lines.push(` Cloud Mode: ${config.cloudEnabled ? 'enabled' : 'disabled'}`);\n\n if (config.email) {\n lines.push(` Email: ${config.email}`);\n }\n\n if (config.organization) {\n lines.push(` Organization: ${config.organization}`);\n }\n\n if (config.lastSync) {\n lines.push(` Last Sync: ${config.lastSync}`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Validate API key format\n */\nexport function isValidApiKey(key: string): boolean {\n // API keys should start with sc_live_ or sc_test_\n return /^sc_(live|test)_[a-zA-Z0-9]{20,}$/.test(key);\n}\n\nexport { CONFIG_DIR, CONFIG_FILE, DEFAULT_API_URL };\n","/**\n * Cloud Access (Thinware)\n *\n * Local scans always run. Cloud features require an API key.\n */\n\nimport { normalizeApiBaseUrl } from './cloud-config.js';\n\nconst CLOUD_API_KEY_ENV_VARS = [\n 'SECURITYCHECKS_API_KEY',\n 'SECURITYCHECKS_LICENSE_KEY',\n];\n\nconst DEFAULT_CLOUD_BASE_URL = 'https://api.securitychecks.ai';\n\nexport function getCloudApiKey(): string | undefined {\n for (const envVar of CLOUD_API_KEY_ENV_VARS) {\n const value = process.env[envVar];\n if (value) {\n return value;\n }\n }\n return undefined;\n}\n\nexport function formatCloudStatus(apiKey?: string): string {\n if (apiKey) {\n return 'local + cloud (API key detected)';\n }\n return 'local-only (cloud features require SECURITYCHECKS_API_KEY)';\n}\n\nexport function getCloudApiBaseUrl(): string {\n const raw = process.env['SECURITYCHECKS_API_URL'] ?? DEFAULT_CLOUD_BASE_URL;\n return normalizeApiBaseUrl(raw);\n}\n\nexport function getCloudEndpoints(baseUrl?: string): {\n patterns: string;\n calibrate: string;\n telemetry: string;\n correlations: string;\n aggregateCalibration: string;\n} {\n const base = baseUrl ?? getCloudApiBaseUrl();\n return {\n patterns: `${base}/v1/patterns`,\n calibrate: `${base}/v1/calibrate`,\n telemetry: `${base}/v1/telemetry`,\n correlations: `${base}/v1/correlations`,\n aggregateCalibration: `${base}/v1/calibration`,\n };\n}\n","/**\n * Deterministic Error Codes for SecurityChecks CLI\n *\n * Format: SC_<CATEGORY>_<NUMBER>\n *\n * Categories:\n * - CONFIG: Configuration errors\n * - PARSE: Parsing/syntax errors\n * - CHECK: Checker execution errors\n * - IO: File system / network errors\n * - CLI: Command line argument errors\n */\n\nexport const ErrorCodes = {\n // CONFIG errors (001-099)\n CONFIG_NOT_FOUND: 'SC_CONFIG_001',\n CONFIG_INVALID: 'SC_CONFIG_002',\n CONFIG_SCHEMA_ERROR: 'SC_CONFIG_003',\n\n // PARSE errors (100-199)\n PARSE_TYPESCRIPT_ERROR: 'SC_PARSE_101',\n PARSE_FILE_NOT_FOUND: 'SC_PARSE_102',\n PARSE_UNSUPPORTED_SYNTAX: 'SC_PARSE_103',\n\n // CHECK errors (200-299)\n CHECK_EXECUTION_ERROR: 'SC_CHECK_201',\n CHECK_TIMEOUT: 'SC_CHECK_202',\n CHECK_INVARIANT_NOT_FOUND: 'SC_CHECK_203',\n\n // IO errors (300-399)\n IO_READ_ERROR: 'SC_IO_301',\n IO_WRITE_ERROR: 'SC_IO_302',\n IO_PERMISSION_DENIED: 'SC_IO_303',\n IO_PATH_NOT_FOUND: 'SC_IO_304',\n\n // CLI errors (400-499)\n CLI_INVALID_ARGUMENT: 'SC_CLI_401',\n CLI_MISSING_ARGUMENT: 'SC_CLI_402',\n CLI_UNKNOWN_COMMAND: 'SC_CLI_403',\n\n // ARTIFACT errors (500-599)\n ARTIFACT_NOT_FOUND: 'SC_ARTIFACT_501',\n ARTIFACT_INVALID: 'SC_ARTIFACT_502',\n ARTIFACT_VERSION_MISMATCH: 'SC_ARTIFACT_503',\n\n // CLOUD errors (600-699)\n CLOUD_AUTH_FAILED: 'SC_CLOUD_601',\n CLOUD_PERMISSION_DENIED: 'SC_CLOUD_602',\n CLOUD_NOT_FOUND: 'SC_CLOUD_603',\n CLOUD_RATE_LIMITED: 'SC_CLOUD_604',\n CLOUD_API_ERROR: 'SC_CLOUD_605',\n CLOUD_NETWORK_ERROR: 'SC_CLOUD_606',\n CLOUD_INVALID_API_KEY: 'SC_CLOUD_607',\n AUTH_REQUIRED: 'SC_CLOUD_608',\n OFFLINE_NOT_SUPPORTED: 'SC_CLOUD_609',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];\n\n/**\n * User-friendly error messages for each error code\n */\nexport const ErrorMessages: Record<ErrorCode, string> = {\n [ErrorCodes.CONFIG_NOT_FOUND]: 'Configuration file not found',\n [ErrorCodes.CONFIG_INVALID]: 'Configuration file is invalid',\n [ErrorCodes.CONFIG_SCHEMA_ERROR]: 'Configuration does not match expected schema',\n\n [ErrorCodes.PARSE_TYPESCRIPT_ERROR]: 'Failed to parse TypeScript file',\n [ErrorCodes.PARSE_FILE_NOT_FOUND]: 'Source file not found',\n [ErrorCodes.PARSE_UNSUPPORTED_SYNTAX]: 'Unsupported syntax encountered',\n\n [ErrorCodes.CHECK_EXECUTION_ERROR]: 'Error executing invariant check',\n [ErrorCodes.CHECK_TIMEOUT]: 'Invariant check timed out',\n [ErrorCodes.CHECK_INVARIANT_NOT_FOUND]: 'Invariant not found',\n\n [ErrorCodes.IO_READ_ERROR]: 'Failed to read file',\n [ErrorCodes.IO_WRITE_ERROR]: 'Failed to write file',\n [ErrorCodes.IO_PERMISSION_DENIED]: 'Permission denied',\n [ErrorCodes.IO_PATH_NOT_FOUND]: 'Path not found',\n\n [ErrorCodes.CLI_INVALID_ARGUMENT]: 'Invalid argument provided',\n [ErrorCodes.CLI_MISSING_ARGUMENT]: 'Required argument missing',\n [ErrorCodes.CLI_UNKNOWN_COMMAND]: 'Unknown command',\n\n [ErrorCodes.ARTIFACT_NOT_FOUND]: 'Artifact file not found',\n [ErrorCodes.ARTIFACT_INVALID]: 'Invalid artifact format',\n [ErrorCodes.ARTIFACT_VERSION_MISMATCH]: 'Artifact version not supported',\n\n [ErrorCodes.CLOUD_AUTH_FAILED]: 'Authentication failed',\n [ErrorCodes.CLOUD_PERMISSION_DENIED]: 'Permission denied',\n [ErrorCodes.CLOUD_NOT_FOUND]: 'Resource not found',\n [ErrorCodes.CLOUD_RATE_LIMITED]: 'Rate limit exceeded',\n [ErrorCodes.CLOUD_API_ERROR]: 'Cloud API error',\n [ErrorCodes.CLOUD_NETWORK_ERROR]: 'Network error',\n [ErrorCodes.CLOUD_INVALID_API_KEY]: 'Invalid API key format',\n [ErrorCodes.AUTH_REQUIRED]: 'API key required for evaluation',\n [ErrorCodes.OFFLINE_NOT_SUPPORTED]: 'Offline mode is not supported',\n};\n\n/**\n * Remediation guidance for each error code\n * Helps users understand what to do when they encounter an error.\n */\nexport const ErrorRemediation: Record<ErrorCode, string> = {\n // CONFIG errors\n [ErrorCodes.CONFIG_NOT_FOUND]: `\nCreate a configuration file in your project root:\n\n scheck init\n\nOr create securitychecks.config.ts manually:\n\n export default {\n include: ['src/**/*.ts'],\n exclude: ['node_modules/**'],\n };\n`.trim(),\n\n [ErrorCodes.CONFIG_INVALID]: `\nCheck your securitychecks.config.ts for syntax errors.\n\nCommon issues:\n- Missing export default\n- Invalid JSON in securitychecks.json\n- Typo in configuration keys\n\nRun with --verbose for more details.\n`.trim(),\n\n [ErrorCodes.CONFIG_SCHEMA_ERROR]: `\nYour configuration has invalid options. Check these common issues:\n\n- 'include' and 'exclude' must be arrays of glob patterns\n- 'testPatterns' must be an array of test file patterns\n- 'servicePatterns' must be an array of service file patterns\n\nSee: https://securitychecks.ai/docs/configuration\n`.trim(),\n\n // PARSE errors\n [ErrorCodes.PARSE_TYPESCRIPT_ERROR]: `\nA TypeScript file failed to parse. This usually means:\n\n1. The file has syntax errors - run tsc to check\n2. The file uses unsupported TypeScript features\n3. There are missing dependencies\n\nTry:\n npx tsc --noEmit\n\nIf the error persists, exclude the problematic file:\n exclude: ['path/to/problematic-file.ts']\n`.trim(),\n\n [ErrorCodes.PARSE_FILE_NOT_FOUND]: `\nThe specified source file doesn't exist. Check:\n\n1. The file path is correct\n2. The file hasn't been moved or deleted\n3. Your include/exclude patterns are correct\n\nRun: ls <path> to verify the file exists.\n`.trim(),\n\n [ErrorCodes.PARSE_UNSUPPORTED_SYNTAX]: `\nThe file contains syntax that can't be parsed. This may happen with:\n\n- Very new TypeScript/JavaScript features\n- Non-standard syntax extensions\n- Malformed source code\n\nTry excluding the file or updating the parser.\n`.trim(),\n\n // CHECK errors\n [ErrorCodes.CHECK_EXECUTION_ERROR]: `\nAn invariant check failed to run. This is usually a bug in scheck.\n\nPlease report this issue with:\n1. The full error message (--verbose)\n2. A minimal reproduction\n3. Your Node.js and @securitychecks/cli versions\n\nReport at: https://github.com/securitychecks/securitychecks.ai/issues\n`.trim(),\n\n [ErrorCodes.CHECK_TIMEOUT]: `\nAn invariant check took too long. This can happen with:\n\n1. Very large codebases\n2. Complex file structures\n3. Slow file system access\n\nTry:\n- Narrowing include patterns to scan fewer files\n- Excluding large generated files\n- Running with --only to check specific invariants\n`.trim(),\n\n [ErrorCodes.CHECK_INVARIANT_NOT_FOUND]: `\nThe specified invariant ID doesn't exist.\n\nList available invariants:\n scheck explain --list\n\nCommon invariant IDs:\n- AUTHZ.SERVICE_LAYER.ENFORCED\n- WEBHOOK.IDEMPOTENT\n- TRANSACTION.POST_COMMIT.SIDE_EFFECTS\n`.trim(),\n\n // IO errors\n [ErrorCodes.IO_READ_ERROR]: `\nFailed to read a file. Check:\n\n1. The file exists and is readable\n2. You have permission to read the file\n3. The file is not locked by another process\n\nTry: cat <file> to verify readability.\n`.trim(),\n\n [ErrorCodes.IO_WRITE_ERROR]: `\nFailed to write a file. Check:\n\n1. The directory exists\n2. You have write permission\n3. There's enough disk space\n4. The file is not locked\n\nTry: touch <file> to verify writability.\n`.trim(),\n\n [ErrorCodes.IO_PERMISSION_DENIED]: `\nPermission denied accessing a file or directory.\n\nOn Unix/Mac:\n chmod +r <file> # Make readable\n chmod +w <file> # Make writable\n\nOn Windows: Check file properties > Security tab.\n`.trim(),\n\n [ErrorCodes.IO_PATH_NOT_FOUND]: `\nThe specified path doesn't exist.\n\nCheck:\n1. You're in the correct directory\n2. The path is spelled correctly\n3. The directory structure is correct\n\nRun: pwd && ls to verify your location.\n`.trim(),\n\n // CLI errors\n [ErrorCodes.CLI_INVALID_ARGUMENT]: `\nInvalid command-line argument.\n\nRun: scheck --help\n\nCommon commands:\n scheck run # Run all checks\n scheck run --ci # CI mode (fails on P0/P1)\n scheck explain <id> # Explain an invariant\n scheck init # Initialize configuration\n`.trim(),\n\n [ErrorCodes.CLI_MISSING_ARGUMENT]: `\nA required argument is missing.\n\nCheck the command syntax:\n scheck --help\n scheck <command> --help\n`.trim(),\n\n [ErrorCodes.CLI_UNKNOWN_COMMAND]: `\nUnknown command. Available commands:\n\n run Run invariant checks\n init Initialize configuration\n explain Explain an invariant\n baseline Manage baseline\n waive Waive a finding\n\nRun: scheck --help\n`.trim(),\n\n // ARTIFACT errors\n [ErrorCodes.ARTIFACT_NOT_FOUND]: `\nArtifact file not found.\n\nThe artifact file stores collected code facts. Options:\n\n1. Let scheck collect automatically (default):\n scheck run\n\n2. Collect manually first:\n npx scc collect -o .securitychecks/artifacts.json\n scheck run --artifact .securitychecks/artifacts.json\n\n3. Check if file was deleted:\n ls .securitychecks/\n`.trim(),\n\n [ErrorCodes.ARTIFACT_INVALID]: `\nThe artifact file is malformed or corrupt.\n\nCommon issues:\n- Incomplete JSON (process was killed during write)\n- Modified manually with syntax errors\n- Wrong file format\n\nFix:\n1. Delete the corrupt artifact:\n rm .securitychecks/artifacts.json\n\n2. Re-collect:\n scheck run\n (or: npx scc collect -o .securitychecks/artifacts.json)\n`.trim(),\n\n [ErrorCodes.ARTIFACT_VERSION_MISMATCH]: `\nThe artifact was created by an incompatible version.\n\nThis happens when:\n- Artifact was created by an older/newer scheck version\n- Artifact schema has changed\n\nFix:\n1. Delete the old artifact:\n rm .securitychecks/artifacts.json\n\n2. Re-collect with current version:\n scheck run\n\nYour current version: scheck --version\n`.trim(),\n\n // CLOUD errors\n [ErrorCodes.CLOUD_AUTH_FAILED]: `\nAuthentication failed. Your API key may be invalid or expired.\n\nFix:\n1. Generate a new API key at https://securitychecks.ai/dashboard/settings/api-keys\n2. Log in again:\n scheck login\n\nEnvironment variable:\n export SECURITYCHECKS_API_KEY=sc_live_...\n`.trim(),\n\n [ErrorCodes.CLOUD_PERMISSION_DENIED]: `\nYou don't have permission for this action.\n\nCheck:\n1. You have access to the project/organization\n2. Your API key has the required scopes\n3. Your subscription is active\n\nManage at: https://securitychecks.ai/dashboard\n`.trim(),\n\n [ErrorCodes.CLOUD_NOT_FOUND]: `\nThe requested resource was not found.\n\nCheck:\n1. The project slug is correct\n2. The project exists and you have access\n3. The resource ID is valid\n\nList your projects:\n scheck config --show\n`.trim(),\n\n [ErrorCodes.CLOUD_RATE_LIMITED]: `\nYou've hit the rate limit. Please try again later.\n\nOptions:\n1. Wait a few minutes and retry\n2. Upgrade your plan for higher limits\n\nPlan limits: https://securitychecks.ai/pricing\n`.trim(),\n\n [ErrorCodes.CLOUD_API_ERROR]: `\nThe SecurityChecks API returned an error.\n\nThis could be:\n1. A temporary service issue - try again shortly\n2. An invalid request - check your parameters\n\nStatus: https://status.securitychecks.ai\nHelp: https://securitychecks.ai/docs/troubleshooting\n`.trim(),\n\n [ErrorCodes.CLOUD_NETWORK_ERROR]: `\nCould not connect to SecurityChecks API.\n\nCheck:\n1. Your internet connection\n2. Firewall/proxy settings\n3. API endpoint accessibility\n\nDefault API: https://api.securitychecks.ai\n`.trim(),\n\n [ErrorCodes.CLOUD_INVALID_API_KEY]: `\nThe API key format is invalid.\n\nAPI keys should start with:\n- sc_live_ for production\n- sc_test_ for testing\n\nGet a key at: https://securitychecks.ai/dashboard/settings/api-keys\n`.trim(),\n\n [ErrorCodes.AUTH_REQUIRED]: `\nAn API key is required to run security checks.\n\nSecurityChecks uses cloud evaluation to protect proprietary patterns.\nYour source code never leaves your machine - only structural facts are sent.\n\nSetup:\n1. Get your API key at https://securitychecks.ai/dashboard/settings/api-keys\n2. Set environment variable:\n export SECURITYCHECKS_API_KEY=sc_live_...\n\nOr add to securitychecks.config.yaml:\n calibration:\n apiKey: sc_live_...\n`.trim(),\n\n [ErrorCodes.OFFLINE_NOT_SUPPORTED]: `\nOffline mode is not supported.\n\nSecurityChecks requires cloud evaluation to protect proprietary patterns.\nYour source code never leaves your machine - only structural facts are sent.\n\nOptions:\n1. Remove --offline flag and ensure network connectivity\n2. For air-gapped environments, contact sales for an enterprise on-premise license:\n https://securitychecks.ai/enterprise\n`.trim(),\n};\n\n/**\n * Structured CLI Error with deterministic error code\n */\nexport class CLIError extends Error {\n public readonly code: ErrorCode;\n public readonly details?: unknown;\n public override readonly cause?: Error;\n\n constructor(code: ErrorCode, message?: string, options?: { details?: unknown; cause?: Error }) {\n const baseMessage = message ?? ErrorMessages[code];\n super(baseMessage, { cause: options?.cause });\n\n this.name = 'CLIError';\n this.code = code;\n this.details = options?.details;\n this.cause = options?.cause;\n\n // Maintains proper stack trace for where error was thrown\n Error.captureStackTrace?.(this, CLIError);\n }\n\n /**\n * Get remediation guidance for this error\n */\n getRemediation(): string {\n return ErrorRemediation[this.code];\n }\n\n /**\n * Format error for user display\n */\n toUserString(verbose = false): string {\n const parts: string[] = [`[${this.code}] ${this.message}`];\n\n if (verbose && this.details) {\n parts.push(`\\nDetails: ${JSON.stringify(this.details, null, 2)}`);\n }\n\n if (verbose && this.cause) {\n parts.push(`\\nCaused by: ${this.cause.message}`);\n if (this.cause.stack) {\n parts.push(`\\n${this.cause.stack}`);\n }\n }\n\n return parts.join('');\n }\n\n /**\n * Format error with remediation for user display\n */\n toUserStringWithRemediation(): string {\n const parts: string[] = [this.toUserString()];\n const remediation = this.getRemediation();\n\n if (remediation) {\n parts.push('\\n\\nHow to fix:\\n');\n // Indent each line of remediation\n const indented = remediation\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n parts.push(indented);\n }\n\n return parts.join('');\n }\n\n /**\n * Format error for JSON output\n */\n toJSON(): Record<string, unknown> {\n return {\n code: this.code,\n message: this.message,\n remediation: this.getRemediation(),\n details: this.details,\n cause: this.cause\n ? {\n message: this.cause.message,\n stack: this.cause.stack,\n }\n : undefined,\n };\n }\n}\n\n/**\n * Check if an error is a CLIError\n */\nexport function isCLIError(error: unknown): error is CLIError {\n return error instanceof CLIError;\n}\n\n/**\n * Wrap an unknown error in a CLIError\n */\nexport function wrapError(error: unknown, code: ErrorCode, message?: string): CLIError {\n if (error instanceof CLIError) {\n return error;\n }\n\n const cause = error instanceof Error ? error : new Error(String(error));\n return new CLIError(code, message, { cause });\n}\n","/**\n * CI Environment Detection\n *\n * Detects CI/CD environment and extracts relevant context\n * (branch, commit SHA, PR number) for proper scan association.\n */\n\nimport { readFileSync } from 'node:fs';\n\nexport interface CIContext {\n /** CI provider name */\n provider: 'github-actions' | 'gitlab-ci' | 'circleci' | 'jenkins' | 'unknown';\n /** Git branch name */\n branch?: string;\n /** Git commit SHA */\n commitSha?: string;\n /** Pull/Merge request number */\n prNumber?: number;\n /** Repository name (owner/repo) */\n repository?: string;\n /** Whether this is a PR/MR event */\n isPullRequest: boolean;\n}\n\n/**\n * Detect CI environment and extract context\n */\nexport function detectCIContext(): CIContext | null {\n // GitHub Actions\n if (process.env['GITHUB_ACTIONS'] === 'true') {\n return detectGitHubActions();\n }\n\n // GitLab CI\n if (process.env['GITLAB_CI'] === 'true') {\n return detectGitLabCI();\n }\n\n // CircleCI\n if (process.env['CIRCLECI'] === 'true') {\n return detectCircleCI();\n }\n\n // Jenkins\n if (process.env['JENKINS_URL']) {\n return detectJenkins();\n }\n\n // Not in CI\n return null;\n}\n\n/**\n * Detect GitHub Actions context\n */\nfunction detectGitHubActions(): CIContext {\n const eventName = process.env['GITHUB_EVENT_NAME'];\n const isPullRequest = eventName === 'pull_request' || eventName === 'pull_request_target';\n const eventPayload = readGitHubEventPayload();\n\n // For PRs, use the head branch; for pushes, parse from GITHUB_REF\n let branch: string | undefined;\n if (isPullRequest) {\n branch = eventPayload?.pull_request?.head?.ref || process.env['GITHUB_HEAD_REF'];\n } else {\n const ref = process.env['GITHUB_REF'] || '';\n // refs/heads/main -> main\n branch = ref.replace(/^refs\\/heads\\//, '');\n }\n\n // In GitHub pull_request workflows, GITHUB_SHA is often the synthetic merge commit.\n // Prefer payload head SHA so we can associate scans to webhook-created PR scans/check-runs.\n const commitSha = isPullRequest\n ? eventPayload?.pull_request?.head?.sha || process.env['GITHUB_SHA']\n : process.env['GITHUB_SHA'];\n\n // Prefer payload PR number, then fallback to refs/pull/<n>/merge parsing.\n let prNumber: number | undefined;\n if (isPullRequest) {\n prNumber = eventPayload?.number;\n if (!prNumber) {\n const prRef = process.env['GITHUB_REF'] || '';\n const match = prRef.match(/refs\\/pull\\/(\\d+)/);\n if (match && match[1]) {\n prNumber = parseInt(match[1], 10);\n }\n }\n }\n\n return {\n provider: 'github-actions',\n branch,\n commitSha,\n prNumber,\n repository: process.env['GITHUB_REPOSITORY'],\n isPullRequest,\n };\n}\n\ninterface GitHubPullRequestPayload {\n number?: number;\n pull_request?: {\n head?: {\n sha?: string;\n ref?: string;\n };\n };\n}\n\nfunction readGitHubEventPayload(): GitHubPullRequestPayload | null {\n const eventPath = process.env['GITHUB_EVENT_PATH'];\n if (!eventPath) {\n return null;\n }\n\n try {\n const raw = readFileSync(eventPath, 'utf8');\n return JSON.parse(raw) as GitHubPullRequestPayload;\n } catch {\n return null;\n }\n}\n\n/**\n * Detect GitLab CI context\n */\nfunction detectGitLabCI(): CIContext {\n const mrIid = process.env['CI_MERGE_REQUEST_IID'];\n const isPullRequest = !!mrIid;\n\n let prNumber: number | undefined;\n if (mrIid) {\n prNumber = parseInt(mrIid, 10);\n }\n\n return {\n provider: 'gitlab-ci',\n branch: process.env['CI_COMMIT_REF_NAME'],\n commitSha: process.env['CI_COMMIT_SHA'],\n prNumber,\n repository: process.env['CI_PROJECT_PATH'],\n isPullRequest,\n };\n}\n\n/**\n * Detect CircleCI context\n */\nfunction detectCircleCI(): CIContext {\n let prNumber: number | undefined;\n const prUrl = process.env['CIRCLE_PULL_REQUEST'];\n if (prUrl) {\n const match = prUrl.match(/\\/pull\\/(\\d+)/);\n if (match && match[1]) {\n prNumber = parseInt(match[1], 10);\n }\n }\n\n return {\n provider: 'circleci',\n branch: process.env['CIRCLE_BRANCH'],\n commitSha: process.env['CIRCLE_SHA1'],\n prNumber,\n repository: `${process.env['CIRCLE_PROJECT_USERNAME']}/${process.env['CIRCLE_PROJECT_REPONAME']}`,\n isPullRequest: !!prUrl,\n };\n}\n\n/**\n * Detect Jenkins context\n */\nfunction detectJenkins(): CIContext {\n const changeId = process.env['CHANGE_ID'];\n const isPullRequest = !!changeId;\n\n let prNumber: number | undefined;\n if (changeId) {\n prNumber = parseInt(changeId, 10);\n }\n\n return {\n provider: 'jenkins',\n branch: process.env['BRANCH_NAME'] || process.env['GIT_BRANCH'],\n commitSha: process.env['GIT_COMMIT'],\n prNumber,\n isPullRequest,\n };\n}\n","/**\n * Cloud Evaluation Client\n *\n * Sends artifacts to the cloud API for async server-side evaluation.\n * Artifacts are stored in R2 and processed by Fly.io workers.\n *\n * Architecture:\n * 1. CLI collects artifact locally (code never leaves)\n * 2. Artifact sent to /api/v1/evaluate, stored in R2\n * 3. Server queues QStash job for Fly.io worker\n * 4. CLI polls /api/v1/scans/{id} until complete\n * 5. Findings returned to CLI for display\n */\n\nimport type { CollectorArtifact, Finding } from '@securitychecks/collector';\nimport { CLIError, ErrorCodes } from './errors.js';\nimport { detectCIContext, type CIContext } from './ci-detect.js';\nimport { gzipSync } from 'node:zlib';\n\n// Re-export for convenience\nexport { detectCIContext, type CIContext } from './ci-detect.js';\n\n/**\n * Build request headers with optional Vercel deployment protection bypass.\n * Set VERCEL_AUTOMATION_BYPASS_SECRET env var to bypass Vercel deployment protection\n * on preview deployments.\n */\nfunction buildHeaders(extra: Record<string, string> = {}): Record<string, string> {\n const headers: Record<string, string> = { ...extra };\n const bypassSecret = process.env['VERCEL_AUTOMATION_BYPASS_SECRET'];\n if (bypassSecret) {\n headers['x-vercel-protection-bypass'] = bypassSecret;\n }\n return headers;\n}\n\nfunction isTruthy(value: string | undefined): boolean {\n if (!value) return false;\n return value === '1' || value.toLowerCase() === 'true' || value.toLowerCase() === 'yes';\n}\n\nexport interface CloudEvaluateOptions {\n /** API key for authentication */\n apiKey: string;\n /** Cloud API base URL */\n baseUrl: string;\n /** Specific invariants to run (default: all) */\n invariants?: string[];\n /** Invariants to skip */\n skip?: string[];\n /** Minimum severity to return */\n severity?: 'P0' | 'P1' | 'P2';\n /** Project slug for scan association */\n projectSlug?: string;\n /** Timeout in ms (default: 300000 = 5 min) */\n timeout?: number;\n /** Poll interval in ms (default: 2000 = 2s) */\n pollInterval?: number;\n /** Progress callback */\n onProgress?: EvaluationProgressCallback;\n /** CI context (auto-detected if not provided) */\n ciContext?: CIContext | null;\n}\n\nexport interface CloudEvaluateResult {\n findings: Finding[];\n stats: {\n invariantsRun: number;\n patternsRun: number;\n findingsCount: number;\n executionMs: number;\n };\n usage: {\n scansUsed: number;\n scansRemaining: number;\n };\n}\n\nexport interface CloudEvaluateError {\n error: string;\n details?: unknown;\n usage?: {\n scansUsed: number;\n scansRemaining: number;\n };\n}\n\n/** Scan status from API */\nexport type ScanStatus = 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED';\n\n/** Progress callback for evaluation */\nexport type EvaluationProgressCallback = (info: {\n status: ScanStatus;\n message?: string;\n}) => void;\n\n/** Response from submit endpoint */\ninterface SubmitResult {\n scanId: string;\n status: ScanStatus;\n pollUrl: string;\n usage?: {\n scansUsed: number;\n scansRemaining: number;\n };\n}\n\n/** Response from scan status endpoint */\ninterface ScanStatusResult {\n id: string;\n status: ScanStatus;\n findings?: Finding[];\n stats?: {\n invariantsRun: number;\n patternsRun: number;\n findingsCount: number;\n executionMs: number;\n };\n usage?: {\n scansUsed: number;\n scansRemaining: number;\n };\n errorMessage?: string;\n}\n\n/**\n * Check if cloud evaluation is available\n */\nexport function isCloudEvalAvailable(apiKey?: string): boolean {\n return !!apiKey;\n}\n\n/**\n * Build the artifact payload for cloud evaluation\n */\nfunction buildEvaluatePayload(artifact: CollectorArtifact, options: CloudEvaluateOptions) {\n // Auto-detect CI context if not provided\n const ciContext = options.ciContext !== undefined ? options.ciContext : detectCIContext();\n\n return {\n artifact: {\n version: artifact.version,\n schemaVersion: artifact.schemaVersion,\n profile: artifact.profile,\n extractedAt: artifact.extractedAt,\n targetPath: artifact.codebase?.root,\n codebase: {\n file_count: artifact.codebase?.filesScanned ?? 0,\n languages: artifact.codebase?.languages ?? [],\n },\n services: artifact.services,\n authzCalls: artifact.authzCalls ?? [],\n cacheOperations: artifact.cacheOperations ?? [],\n transactionScopes: artifact.transactionScopes ?? [],\n webhookHandlers: artifact.webhookHandlers ?? [],\n jobHandlers: artifact.jobHandlers ?? [],\n membershipMutations: artifact.membershipMutations ?? [],\n tests: artifact.tests ?? [],\n routes: artifact.routes ?? [],\n callGraph: artifact.callGraph,\n dataFlow: artifact.dataFlows?.flows ?? [],\n rlsPolicies: artifact.rlsArtifact?.rlsPolicies ?? [],\n },\n options: {\n invariants: options.invariants,\n skip: options.skip,\n severity: options.severity,\n projectSlug: options.projectSlug,\n // CI context for scan association (enables PR comments)\n branch: ciContext?.branch,\n commitSha: ciContext?.commitSha,\n prNumber: ciContext?.prNumber,\n // Opt-in guard for GitHub PR CI mode to enforce webhook + evaluate env alignment.\n // This is intentionally gated to avoid breaking standalone CLI workflows that do not use GitHub App webhooks.\n requireExistingCiScan:\n ciContext?.provider === 'github-actions' &&\n ciContext?.isPullRequest &&\n isTruthy(process.env['SECURITYCHECKS_REQUIRE_EXISTING_CI_SCAN'])\n ? true\n : undefined,\n },\n };\n}\n\n/**\n * Submit artifact for async evaluation\n * Returns scan ID for polling\n */\nasync function submitForEvaluation(\n artifact: CollectorArtifact,\n options: CloudEvaluateOptions\n): Promise<SubmitResult> {\n const endpoint = `${options.baseUrl}/api/v1/evaluate`;\n const payload = buildEvaluatePayload(artifact, options);\n const json = JSON.stringify(payload);\n const gz = gzipSync(Buffer.from(json, 'utf8'));\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: buildHeaders({\n 'Content-Type': 'application/json',\n 'Content-Encoding': 'gzip',\n Authorization: `Bearer ${options.apiKey}`,\n }),\n body: gz,\n });\n\n if (!response.ok) {\n const errorBody = (await response.json().catch(() => ({}))) as CloudEvaluateError;\n const serverMessage = (errorBody as any)?.message as string | undefined;\n const errorText = serverMessage\n ? `${errorBody.error || 'Cloud API error'}: ${serverMessage}`\n : errorBody.error;\n\n if (response.status === 401) {\n throw new CLIError(ErrorCodes.CLOUD_AUTH_FAILED, 'Invalid API key. Check your SECURITYCHECKS_API_KEY.');\n }\n\n if (response.status === 413) {\n throw new CLIError(\n ErrorCodes.CLOUD_API_ERROR,\n `Artifact too large. ${errorBody.details || 'Contact support if this persists.'}`,\n { details: errorBody.details }\n );\n }\n\n if (response.status === 429) {\n const remaining = errorBody.usage?.scansRemaining ?? 0;\n throw new CLIError(\n ErrorCodes.CLOUD_RATE_LIMITED,\n `Monthly scan limit reached (${remaining} remaining). Upgrade at https://securitychecks.ai/pricing`,\n { details: { scansRemaining: remaining } }\n );\n }\n\n if (response.status === 503) {\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, 'Cloud evaluation temporarily unavailable. Try again later.');\n }\n\n throw new CLIError(\n ErrorCodes.CLOUD_API_ERROR,\n errorText || `Cloud API error: ${response.status}`,\n { details: errorBody }\n );\n }\n\n return (await response.json()) as SubmitResult;\n}\n\n/**\n * Poll for evaluation results\n * Blocks until scan completes, fails, or times out\n */\nasync function pollForResults(\n scanId: string,\n options: CloudEvaluateOptions\n): Promise<CloudEvaluateResult> {\n const timeout = options.timeout ?? 300000; // 5 min default\n const pollInterval = options.pollInterval ?? 2000; // 2s default\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeout) {\n const response = await fetch(`${options.baseUrl}/api/v1/scans/${scanId}`, {\n method: 'GET',\n headers: buildHeaders({\n Authorization: `Bearer ${options.apiKey}`,\n }),\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new CLIError(ErrorCodes.CLOUD_NOT_FOUND, `Scan ${scanId} not found`);\n }\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, `Failed to get scan status: ${response.status}`);\n }\n\n const scan = (await response.json()) as ScanStatusResult;\n\n // Report progress\n options.onProgress?.({\n status: scan.status,\n message: scan.status === 'RUNNING' ? 'Evaluating...' : undefined,\n });\n\n if (scan.status === 'COMPLETED') {\n return {\n findings: scan.findings ?? [],\n stats: scan.stats ?? {\n invariantsRun: 0,\n patternsRun: 0,\n findingsCount: scan.findings?.length ?? 0,\n executionMs: Date.now() - startTime,\n },\n usage: scan.usage ?? { scansUsed: 0, scansRemaining: 0 },\n };\n }\n\n if (scan.status === 'FAILED') {\n throw new CLIError(\n ErrorCodes.CLOUD_API_ERROR,\n `Scan failed: ${scan.errorMessage ?? 'Unknown error'}`,\n { details: { scanId, errorMessage: scan.errorMessage } }\n );\n }\n\n if (scan.status === 'CANCELLED') {\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, 'Scan was cancelled', { details: { scanId } });\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n throw new CLIError(\n ErrorCodes.CHECK_TIMEOUT,\n `Scan timed out after ${timeout / 1000}s. Check dashboard for results.`,\n { details: { timeoutMs: timeout, scanId } }\n );\n}\n\n/**\n * Evaluate artifact via cloud API (async with polling)\n *\n * @param artifact The artifact to evaluate\n * @param options Evaluation options\n * @throws Error if evaluation fails or times out\n */\nexport async function evaluateCloud(\n artifact: CollectorArtifact,\n options: CloudEvaluateOptions\n): Promise<CloudEvaluateResult> {\n // Submit artifact for evaluation\n const { scanId } = await submitForEvaluation(artifact, options);\n\n // Report initial status\n options.onProgress?.({\n status: 'PENDING',\n message: 'Submitted for evaluation...',\n });\n\n // Poll for results\n return pollForResults(scanId, options);\n}\n\n/**\n * Check cloud API health\n */\nexport async function checkCloudHealth(baseUrl: string): Promise<boolean> {\n try {\n const response = await fetch(`${baseUrl}/api/health`, {\n method: 'GET',\n headers: buildHeaders(),\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n\n/**\n * Get available invariants from cloud API\n */\nexport async function getCloudInvariants(\n baseUrl: string,\n apiKey: string\n): Promise<Array<{ id: string; name: string; description: string; severity: string }>> {\n const response = await fetch(`${baseUrl}/api/v1/evaluate`, {\n method: 'GET',\n headers: buildHeaders({\n Authorization: `Bearer ${apiKey}`,\n }),\n });\n\n if (!response.ok) {\n throw new CLIError(ErrorCodes.CLOUD_API_ERROR, `Failed to fetch invariants: ${response.status}`);\n }\n\n const data = (await response.json()) as {\n invariants: Array<{ id: string; name: string; description: string; severity: string }>;\n };\n return data.invariants;\n}\n","type Env = Record<string, string | undefined>;\n\nexport function getProjectSlug(env: Env = process.env): string | undefined {\n const raw = env['SECURITYCHECKS_PROJECT'];\n const trimmed = raw?.trim();\n return trimmed ? trimmed : undefined;\n}\n","/**\n * Audit API - Programmatic interface for running the staff check\n *\n * This module provides the core audit functionality that can be used by:\n * - CLI commands\n * - MCP server\n * - Programmatic integration\n *\n * SECURITY NOTE: All audit functions require cloud API authentication.\n * Detection logic runs server-side to protect IP.\n * See: docs/POST_MORTEM_001_ENGINE_EXPOSURE.md\n */\n\nimport {\n collect,\n resolveTargetPath,\n type AuditResult,\n type CollectorArtifact,\n type Artifact,\n} from '@securitychecks/collector';\nimport { getCloudApiKey, getCloudApiBaseUrl } from './lib/license.js';\nimport { evaluateCloud } from './lib/cloud-eval.js';\nimport { CLIError, ErrorCodes } from './lib/errors.js';\nimport { getProjectSlug } from './lib/project-slug.js';\n\n// NOTE: Engine import removed - detection runs server-side only\n// import { runAllCheckers } from '@securitychecks/engine';\n\nexport interface AuditOptions {\n /** Target path to audit (default: current directory) */\n targetPath?: string;\n /** Only run specific invariant checks by ID */\n only?: string[];\n /** Skip specific invariant checks by ID */\n skip?: string[];\n}\n\n/**\n * Convert CollectorArtifact to Artifact for checker compatibility\n */\nfunction toArtifact(collectorArtifact: CollectorArtifact): Artifact {\n return {\n version: '1.0',\n extractedAt: collectorArtifact.extractedAt,\n targetPath: collectorArtifact.codebase.root,\n services: collectorArtifact.services,\n authzCalls: collectorArtifact.authzCalls ?? [],\n cacheOperations: collectorArtifact.cacheOperations ?? [],\n transactionScopes: collectorArtifact.transactionScopes ?? [],\n webhookHandlers: collectorArtifact.webhookHandlers ?? [],\n jobHandlers: collectorArtifact.jobHandlers ?? [],\n membershipMutations: collectorArtifact.membershipMutations ?? [],\n tests: collectorArtifact.tests ?? [],\n routes: collectorArtifact.routes ?? [],\n dataFlows: collectorArtifact.dataFlows,\n callGraph: collectorArtifact.callGraph,\n };\n}\n\n/**\n * Run the full staff check audit\n *\n * This is the main programmatic API for running the staff check.\n * It performs two steps:\n * 1. Collect artifacts from the target codebase (facts)\n * 2. Send to cloud API for evaluation (findings)\n *\n * SECURITY: Detection logic runs server-side to protect IP.\n * An API key is required. Get one at https://securitychecks.ai/dashboard/settings/api-keys\n *\n * @example\n * ```ts\n * import { audit } from '@securitychecks/cli';\n *\n * // Requires SECURITYCHECKS_API_KEY environment variable\n * const result = await audit({\n * targetPath: '/path/to/codebase',\n * only: ['WEBHOOK.IDEMPOTENT'],\n * });\n *\n * console.log(result.summary);\n * ```\n */\nexport async function audit(options: AuditOptions = {}): Promise<AuditResult> {\n const startTime = Date.now();\n\n // SECURITY: Require API key - detection runs server-side to protect IP\n const apiKey = getCloudApiKey();\n if (!apiKey) {\n throw new CLIError(\n ErrorCodes.AUTH_REQUIRED,\n 'API key required for scanning',\n {\n details: {\n remediation: `Set SECURITYCHECKS_API_KEY environment variable.\nGet your API key at https://securitychecks.ai/dashboard/settings/api-keys\n\nFor air-gapped environments, contact sales@securitychecks.ai for enterprise options.`,\n },\n }\n );\n }\n\n const targetPath = resolveTargetPath(options.targetPath);\n\n // Step 1: Collect artifacts (facts) - runs locally\n const collectorArtifact = await collect({\n targetPath,\n profile: 'securitychecks',\n });\n\n // Step 2: Send to cloud for evaluation (findings) - runs server-side\n const cloudResult = await evaluateCloud(collectorArtifact, {\n apiKey,\n baseUrl: getCloudApiBaseUrl(),\n invariants: options.only,\n skip: options.skip,\n projectSlug: getProjectSlug(),\n });\n\n // Step 3: Convert to checker-compatible format for result\n const artifact = toArtifact(collectorArtifact);\n\n // Compute summary from cloud results\n const findings = cloudResult.findings;\n const byPriority = {\n P0: findings.filter((f) => f.severity === 'P0').length,\n P1: findings.filter((f) => f.severity === 'P1').length,\n P2: findings.filter((f) => f.severity === 'P2').length,\n };\n\n // Synthesize results format from cloud response\n const invariantIds = [...new Set(findings.map(f => f.invariantId))];\n const results = invariantIds.map(id => ({\n invariantId: id,\n passed: !findings.some(f => f.invariantId === id),\n findings: findings.filter(f => f.invariantId === id),\n checkedAt: new Date().toISOString(),\n duration: 0,\n }));\n\n const passed = results.filter((r) => r.passed).length;\n const failed = results.filter((r) => !r.passed).length;\n const waived = findings.filter((f) => f.waived).length;\n\n return {\n version: '1.0',\n targetPath,\n runAt: new Date().toISOString(),\n duration: Date.now() - startTime,\n summary: {\n total: cloudResult.stats.invariantsRun,\n passed,\n failed,\n waived,\n byPriority\n },\n results,\n artifact,\n };\n}\n","/**\n * Schema Version Compatibility\n *\n * Ensures CLI can consume artifacts from compatible collector versions.\n *\n * The schema version follows semver:\n * - MAJOR: Breaking changes (fields removed, types changed)\n * - MINOR: Additive changes (new optional fields)\n * - PATCH: Bug fixes, clarifications\n *\n * CLI declares a supported range, collector emits current version.\n */\n\nimport { ARTIFACT_SCHEMA_VERSION } from '@securitychecks/collector';\n\n/**\n * The schema version range this CLI version supports.\n *\n * Format: \"^MAJOR.MINOR.x\" - compatible with any version that has:\n * - Same MAJOR version (no breaking changes)\n * - Same or higher MINOR version (may have new optional fields)\n *\n * When updating:\n * - Bump MINOR when CLI starts using new optional fields\n * - Bump MAJOR when CLI requires breaking schema changes\n */\nexport const SUPPORTED_SCHEMA_RANGE = {\n // Minimum version we can consume\n minMajor: 1,\n minMinor: 0,\n // Maximum major version we understand (breaking changes)\n maxMajor: 1,\n};\n\nexport interface SchemaValidationResult {\n valid: boolean;\n artifactVersion: string;\n currentVersion: string;\n error?: string;\n remediation?: string;\n}\n\n/**\n * Parse a semver string into components\n */\nfunction parseSemver(version: string): { major: number; minor: number; patch: number } | null {\n const match = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)/);\n if (!match || !match[1] || !match[2] || !match[3]) return null;\n\n return {\n major: parseInt(match[1], 10),\n minor: parseInt(match[2], 10),\n patch: parseInt(match[3], 10),\n };\n}\n\n/**\n * Validate that an artifact's schema version is compatible with this CLI.\n *\n * Compatibility rules:\n * - Artifact MAJOR must equal CLI's supported MAJOR (breaking changes)\n * - Artifact MINOR must be >= CLI's minMinor (additive features)\n * - Pre-1.0.0 artifacts (missing schemaVersion) are assumed \"1.0.0\"\n */\nexport function validateSchemaVersion(artifactSchemaVersion?: string): SchemaValidationResult {\n const currentVersion = ARTIFACT_SCHEMA_VERSION;\n\n // Handle missing schemaVersion (pre-versioning artifacts)\n const effectiveVersion = artifactSchemaVersion ?? '1.0.0';\n\n const parsed = parseSemver(effectiveVersion);\n if (!parsed) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Invalid schema version format: \"${effectiveVersion}\" (expected semver like \"1.0.0\")`,\n remediation: 'Re-collect artifacts with: npx scc collect -o .securitychecks/artifacts.json',\n };\n }\n\n const { major, minor } = parsed;\n\n // Check MAJOR version (breaking changes)\n if (major > SUPPORTED_SCHEMA_RANGE.maxMajor) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Artifact schema version ${effectiveVersion} is too new (CLI supports up to ${SUPPORTED_SCHEMA_RANGE.maxMajor}.x.x)`,\n remediation: `Upgrade scheck: npm install -g @securitychecks/cli@latest`,\n };\n }\n\n if (major < SUPPORTED_SCHEMA_RANGE.minMajor) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Artifact schema version ${effectiveVersion} is too old (CLI requires ${SUPPORTED_SCHEMA_RANGE.minMajor}.x.x+)`,\n remediation: 'Re-collect artifacts: npx scc collect -o .securitychecks/artifacts.json',\n };\n }\n\n // Check MINOR version (additive features - older artifacts may lack fields we use)\n if (minor < SUPPORTED_SCHEMA_RANGE.minMinor) {\n return {\n valid: false,\n artifactVersion: effectiveVersion,\n currentVersion,\n error: `Artifact schema version ${effectiveVersion} is missing required fields (CLI requires ${SUPPORTED_SCHEMA_RANGE.minMajor}.${SUPPORTED_SCHEMA_RANGE.minMinor}.x+)`,\n remediation: 'Re-collect artifacts: npx scc collect -o .securitychecks/artifacts.json',\n };\n }\n\n return {\n valid: true,\n artifactVersion: effectiveVersion,\n currentVersion,\n };\n}\n\n/**\n * Get the current collector schema version\n */\nexport function getCurrentSchemaVersion(): string {\n return ARTIFACT_SCHEMA_VERSION;\n}\n","/**\n * Stable Finding ID Generation\n *\n * Generates deterministic, stable IDs for findings that survive:\n * - Re-runs\n * - Ordering changes\n * - Remediation/message tweaks\n * - Minor code refactors\n *\n * IDs are NOT stable across:\n * - Moving code to different files\n * - Renaming functions (these are legitimately different anchors)\n *\n * Format: `${invariantId}:${hash}` (e.g., WEBHOOK.IDEMPOTENT:9c31f0a2b4d1)\n */\n\nimport { createHash } from 'crypto';\nimport type { Finding } from '@securitychecks/collector';\n\n// ============================================================================\n// Identity Payload Extraction\n// ============================================================================\n\n/**\n * Invariant-specific anchor extractors.\n * Each returns additional identity fields beyond the base (invariantId + file + symbol).\n */\ntype AnchorExtractor = (finding: Finding) => Record<string, string>;\n\nconst ANCHOR_EXTRACTORS: Record<string, AnchorExtractor> = {\n // Webhook: include provider from context if available\n 'WEBHOOK.IDEMPOTENT': (finding) => {\n const context = finding.evidence[0]?.context ?? '';\n // Extract provider from context like \"stripe: handleStripeWebhook\"\n const providerMatch = context.match(/^(stripe|github|slack|svix|generic):/i);\n return {\n provider: providerMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n\n // Transaction: include side effect type from message\n 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS': (finding) => {\n // Extract side effect type from message like \"contains email side effect\"\n const typeMatch = finding.message.match(/contains (\\w+) side effect/i);\n return {\n sideEffectType: typeMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n\n // Membership revocation: include mutation type\n 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE': (finding) => {\n const context = finding.evidence[0]?.context ?? '';\n // Extract mutation type from context\n const mutationMatch = context.match(/mutationType[:\\s]+(\\w+)/i);\n return {\n mutationType: mutationMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n\n // Keys revocation: include entity type\n 'AUTHZ.KEYS.REVOCATION.IMMEDIATE': (finding) => {\n const context = finding.evidence[0]?.context ?? '';\n const entityMatch = context.match(/entity[:\\s]+(\\w+)/i);\n return {\n entity: entityMatch?.[1]?.toLowerCase() ?? '',\n };\n },\n};\n\n/**\n * Extract the identity payload for a finding.\n * This is what gets hashed to produce the findingId.\n */\nexport function extractIdentityPayload(finding: Finding): Record<string, string> {\n const primary = finding.evidence[0];\n\n // Base identity: invariantId + file + symbol\n const base: Record<string, string> = {\n invariantId: finding.invariantId.toLowerCase(),\n file: normalizePath(primary?.file ?? ''),\n symbol: (primary?.symbol ?? '').toLowerCase(),\n };\n\n // Add invariant-specific anchors\n const extractor = ANCHOR_EXTRACTORS[finding.invariantId];\n if (extractor) {\n const anchors = extractor(finding);\n Object.assign(base, anchors);\n }\n\n return base;\n}\n\n// ============================================================================\n// Path Normalization\n// ============================================================================\n\n/**\n * Normalize file path for consistent hashing.\n * - Use forward slashes\n * - Remove leading ./ or /\n * - Lowercase\n * - Trim whitespace\n */\nfunction normalizePath(path: string): string {\n return path\n .trim()\n .replace(/\\\\/g, '/') // Windows backslashes\n .replace(/^\\.\\//, '') // Leading ./\n .replace(/^\\//, '') // Leading /\n .toLowerCase();\n}\n\n// ============================================================================\n// Hash Generation\n// ============================================================================\n\n/**\n * Generate a short, stable hash from the identity payload.\n * Uses SHA-256 truncated to 12 hex characters.\n */\nfunction hashPayload(payload: Record<string, string>): string {\n // Sort keys for deterministic ordering\n const keys = Object.keys(payload).sort();\n const canonical = keys.map((k) => `${k}:${payload[k]}`).join('|');\n\n const hash = createHash('sha256').update(canonical).digest('hex');\n\n // Take first 12 characters for readability while maintaining uniqueness\n return hash.slice(0, 12);\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Generate a stable findingId for a finding.\n *\n * @example\n * const id = generateFindingId(finding);\n * // \"WEBHOOK.IDEMPOTENT:9c31f0a2b4d1\"\n */\nexport function generateFindingId(finding: Finding): string {\n const payload = extractIdentityPayload(finding);\n const hash = hashPayload(payload);\n return `${finding.invariantId}:${hash}`;\n}\n\n/**\n * Add findingId to a finding (mutates the finding).\n * Returns the same finding for chaining.\n */\nexport function attachFindingId<T extends Finding>(finding: T): T & { findingId: string } {\n const findingId = generateFindingId(finding);\n return Object.assign(finding, { findingId });\n}\n\n/**\n * Add findingIds to all findings in a list.\n */\nexport function attachFindingIds<T extends Finding>(findings: T[]): (T & { findingId: string })[] {\n return findings.map(attachFindingId);\n}\n\n// ============================================================================\n// Baseline/Waiver Types\n// ============================================================================\n\n/**\n * A baseline entry stores known findings that should not fail CI.\n */\nexport interface BaselineEntry {\n findingId: string;\n invariantId: string;\n file: string;\n symbol?: string;\n firstSeenAt: string; // ISO date\n lastSeenAt: string; // ISO date\n}\n\n/**\n * A waiver temporarily suppresses a finding.\n */\nexport interface WaiverEntry {\n findingId: string;\n invariantId: string;\n reasonKey?: string;\n reason: string;\n expiresAt: string; // ISO date\n createdBy: string;\n createdAt: string; // ISO date\n}\n\n/**\n * Convert a finding to a baseline entry.\n */\nexport function toBaselineEntry(finding: Finding & { findingId: string }): BaselineEntry {\n const now = new Date().toISOString();\n return {\n findingId: finding.findingId,\n invariantId: finding.invariantId,\n file: finding.evidence[0]?.file ?? '',\n symbol: finding.evidence[0]?.symbol,\n firstSeenAt: now,\n lastSeenAt: now,\n };\n}\n","/**\n * Baseline and Waiver Schema Versions\n *\n * These versions are CLI-level (separate from collector artifact schema).\n * Bump these when the storage format changes.\n */\n\nexport const BASELINE_SCHEMA_VERSION = '1.0.0';\nexport const WAIVER_SCHEMA_VERSION = '1.1.0';\n\nexport const WAIVER_REASON_KEYS = [\n 'false_positive',\n 'acceptable_risk',\n 'will_fix_later',\n 'not_applicable',\n 'other',\n] as const;\n\nexport type WaiverReasonKey = typeof WAIVER_REASON_KEYS[number];\n\nexport function isValidWaiverReasonKey(value: string): value is WaiverReasonKey {\n return (WAIVER_REASON_KEYS as readonly string[]).includes(value);\n}\n\n// ============================================================================\n// Baseline Types\n// ============================================================================\n\n/**\n * A baseline entry represents a known finding that should not fail CI.\n * Baselines are used to adopt scheck incrementally on existing codebases.\n */\nexport interface BaselineEntry {\n /** Stable finding ID (invariantId:hash) */\n findingId: string;\n /** The invariant this finding belongs to */\n invariantId: string;\n /** File where the finding was detected */\n file: string;\n /** Symbol (function/class name) if available */\n symbol?: string;\n /** When this was first added to baseline */\n createdAt: string; // ISO date\n /** When this was last seen in a run */\n lastSeenAt: string; // ISO date\n /** Optional notes explaining why this is baselined */\n notes?: string;\n}\n\n/**\n * The baseline file format.\n */\nexport interface BaselineFile {\n /** Schema version for baseline file format */\n schemaVersion: string;\n /** CLI version that generated this file */\n toolVersion: string;\n /** Collector schema version used when generating findings */\n collectorSchemaVersion?: string;\n /** Tool identifier (e.g., \"@securitychecks/cli@0.1.0\") */\n generatedBy: string;\n /** When the baseline was last updated (UTC ISO date) */\n updatedAt: string;\n /** Baseline entries keyed by findingId for O(1) lookup */\n entries: Record<string, BaselineEntry>;\n}\n\n// ============================================================================\n// Waiver Types\n// ============================================================================\n\n/**\n * A waiver temporarily suppresses a finding.\n * Unlike baselines, waivers expire and require explicit justification.\n */\nexport interface WaiverEntry {\n /** Stable finding ID (invariantId:hash) */\n findingId: string;\n /** The invariant this waiver applies to */\n invariantId: string;\n /** File where the finding was detected */\n file: string;\n /** Symbol (function/class name) if available */\n symbol?: string;\n /** Structured waiver reason (optional; aligns with web UI) */\n reasonKey?: WaiverReasonKey;\n /** Why this is being waived (required) */\n reason: string;\n /** Who created the waiver */\n owner: string;\n /** When the waiver expires (ISO date) */\n expiresAt: string;\n /** When the waiver was created */\n createdAt: string; // ISO date\n}\n\n/**\n * The waiver file format.\n */\nexport interface WaiverFile {\n /** Schema version for waiver file format */\n schemaVersion: string;\n /** CLI version that generated this file */\n toolVersion: string;\n /** Tool identifier (e.g., \"@securitychecks/cli@0.1.0\") */\n generatedBy: string;\n /** When the waiver file was last updated (UTC ISO date) */\n updatedAt: string;\n /** Waiver entries keyed by findingId */\n entries: Record<string, WaiverEntry>;\n}\n\n// ============================================================================\n// Empty File Factories\n// ============================================================================\n\n/** Package identifier for generatedBy field */\nexport const CLI_PACKAGE_NAME = '@securitychecks/cli';\n\n/** Get the generatedBy string (package@version) */\nexport function getGeneratedBy(version: string): string {\n return `${CLI_PACKAGE_NAME}@${version}`;\n}\n\nexport function createEmptyBaseline(version: string = '0.0.0'): BaselineFile {\n return {\n schemaVersion: BASELINE_SCHEMA_VERSION,\n toolVersion: version,\n generatedBy: getGeneratedBy(version),\n updatedAt: new Date().toISOString(),\n entries: {},\n };\n}\n\nexport function createEmptyWaiverFile(version: string = '0.0.0'): WaiverFile {\n return {\n schemaVersion: WAIVER_SCHEMA_VERSION,\n toolVersion: version,\n generatedBy: getGeneratedBy(version),\n updatedAt: new Date().toISOString(),\n entries: {},\n };\n}\n","/**\n * Baseline and Waiver Storage\n *\n * Handles loading, saving, and managing baseline/waiver files.\n * Files are stored in `.scheck/` directory.\n */\n\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport type { Finding } from '@securitychecks/collector';\nimport { generateFindingId } from '../findings/finding-id.js';\nimport {\n BASELINE_SCHEMA_VERSION,\n WAIVER_SCHEMA_VERSION,\n createEmptyBaseline,\n createEmptyWaiverFile,\n getGeneratedBy,\n type BaselineFile,\n type WaiverFile,\n type WaiverEntry,\n} from './schema.js';\n\n// Version injected at build time via tsup define\nconst CLI_VERSION: string = process.env['CLI_VERSION'] ?? '0.0.0-dev';\n\n// ============================================================================\n// File Paths\n// ============================================================================\n\nconst SCHECK_DIR = '.scheck';\nconst BASELINE_FILE = 'baseline.json';\nconst WAIVER_FILE = 'waivers.json';\n\nexport function getBaselinePath(rootPath: string): string {\n return join(rootPath, SCHECK_DIR, BASELINE_FILE);\n}\n\nexport function getWaiverPath(rootPath: string): string {\n return join(rootPath, SCHECK_DIR, WAIVER_FILE);\n}\n\n// ============================================================================\n// Baseline Storage\n// ============================================================================\n\n/**\n * Load the baseline file, creating an empty one if it doesn't exist.\n */\nexport async function loadBaseline(rootPath: string): Promise<BaselineFile> {\n const path = getBaselinePath(rootPath);\n\n if (!existsSync(path)) {\n return createEmptyBaseline(CLI_VERSION);\n }\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content) as BaselineFile;\n\n // Migrate: add missing fields for older files\n if (!data.schemaVersion) {\n data.schemaVersion = BASELINE_SCHEMA_VERSION;\n }\n if (!data.toolVersion) {\n data.toolVersion = CLI_VERSION;\n }\n if (!data.generatedBy) {\n data.generatedBy = getGeneratedBy(CLI_VERSION);\n }\n\n return data;\n } catch {\n // Corrupted file, return empty baseline\n console.warn(`Warning: Could not parse baseline file at ${path}, using empty baseline`);\n return createEmptyBaseline(CLI_VERSION);\n }\n}\n\n/**\n * Save the baseline file with deterministic ordering.\n */\nexport async function saveBaseline(\n rootPath: string,\n baseline: BaselineFile,\n collectorSchemaVersion?: string\n): Promise<void> {\n const path = getBaselinePath(rootPath);\n\n // Ensure directory exists\n await mkdir(dirname(path), { recursive: true });\n\n // Update metadata\n baseline.updatedAt = new Date().toISOString();\n baseline.toolVersion = CLI_VERSION;\n baseline.generatedBy = getGeneratedBy(CLI_VERSION);\n if (collectorSchemaVersion) {\n baseline.collectorSchemaVersion = collectorSchemaVersion;\n }\n\n // Create deterministically ordered output (field order matters for diffs)\n // Using spread with explicit ordering to ensure consistent JSON output\n const orderedBaseline = {\n schemaVersion: baseline.schemaVersion,\n toolVersion: baseline.toolVersion,\n ...(baseline.collectorSchemaVersion ? { collectorSchemaVersion: baseline.collectorSchemaVersion } : {}),\n generatedBy: baseline.generatedBy,\n updatedAt: baseline.updatedAt,\n entries: sortEntriesByFindingId(baseline.entries),\n };\n\n // Write with 2-space indent and trailing newline\n await writeFile(path, JSON.stringify(orderedBaseline, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Sort entries by findingId for deterministic output.\n */\nfunction sortEntriesByFindingId<T extends { findingId: string }>(\n entries: Record<string, T>\n): Record<string, T> {\n const sorted: Record<string, T> = {};\n const keys = Object.keys(entries).sort();\n for (const key of keys) {\n sorted[key] = entries[key] as T;\n }\n return sorted;\n}\n\n/**\n * Add findings to the baseline.\n * Returns the number of new entries added.\n */\nexport function addToBaseline(\n baseline: BaselineFile,\n findings: Finding[],\n notes?: string\n): number {\n const now = new Date().toISOString();\n let added = 0;\n\n for (const finding of findings) {\n const findingId = generateFindingId(finding);\n\n if (!baseline.entries[findingId]) {\n baseline.entries[findingId] = {\n findingId,\n invariantId: finding.invariantId,\n file: finding.evidence[0]?.file ?? '',\n symbol: finding.evidence[0]?.symbol,\n createdAt: now,\n lastSeenAt: now,\n notes,\n };\n added++;\n } else {\n // Update lastSeenAt for existing entries\n baseline.entries[findingId].lastSeenAt = now;\n }\n }\n\n return added;\n}\n\n/**\n * Check if a finding is in the baseline.\n */\nexport function isInBaseline(baseline: BaselineFile, finding: Finding): boolean {\n const findingId = generateFindingId(finding);\n return findingId in baseline.entries;\n}\n\n/**\n * Remove stale entries that haven't been seen in a certain number of days.\n * Returns the number of entries removed.\n */\nexport function pruneBaseline(baseline: BaselineFile, staleDays: number = 90): number {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - staleDays);\n const cutoffIso = cutoff.toISOString();\n\n let removed = 0;\n for (const [id, entry] of Object.entries(baseline.entries)) {\n if (entry.lastSeenAt < cutoffIso) {\n delete baseline.entries[id];\n removed++;\n }\n }\n\n return removed;\n}\n\n// ============================================================================\n// Waiver Storage\n// ============================================================================\n\n/**\n * Load the waiver file, creating an empty one if it doesn't exist.\n */\nexport async function loadWaivers(rootPath: string): Promise<WaiverFile> {\n const path = getWaiverPath(rootPath);\n\n if (!existsSync(path)) {\n return createEmptyWaiverFile(CLI_VERSION);\n }\n\n try {\n const content = await readFile(path, 'utf-8');\n const data = JSON.parse(content) as WaiverFile;\n\n // Migrate: add missing fields for older files\n if (!data.schemaVersion) {\n data.schemaVersion = WAIVER_SCHEMA_VERSION;\n }\n if (!data.toolVersion) {\n data.toolVersion = CLI_VERSION;\n }\n if (!data.generatedBy) {\n data.generatedBy = getGeneratedBy(CLI_VERSION);\n }\n\n return data;\n } catch {\n console.warn(`Warning: Could not parse waiver file at ${path}, using empty waivers`);\n return createEmptyWaiverFile(CLI_VERSION);\n }\n}\n\n/**\n * Save the waiver file with deterministic ordering.\n */\nexport async function saveWaivers(rootPath: string, waivers: WaiverFile): Promise<void> {\n const path = getWaiverPath(rootPath);\n\n await mkdir(dirname(path), { recursive: true });\n\n // Update metadata\n waivers.updatedAt = new Date().toISOString();\n waivers.toolVersion = CLI_VERSION;\n waivers.generatedBy = getGeneratedBy(CLI_VERSION);\n\n // Create deterministically ordered output (field order matters for diffs)\n const orderedWaivers = {\n schemaVersion: waivers.schemaVersion,\n toolVersion: waivers.toolVersion,\n generatedBy: waivers.generatedBy,\n updatedAt: waivers.updatedAt,\n entries: sortEntriesByFindingId(waivers.entries),\n };\n\n // Write with 2-space indent and trailing newline\n await writeFile(path, JSON.stringify(orderedWaivers, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Add a waiver for a finding.\n */\nexport function addWaiver(\n waivers: WaiverFile,\n finding: Finding,\n options: {\n reason: string;\n reasonKey?: WaiverEntry['reasonKey'];\n owner: string;\n expiresInDays: number;\n }\n): WaiverEntry {\n const now = new Date();\n const expiresAt = new Date(now);\n expiresAt.setDate(expiresAt.getDate() + options.expiresInDays);\n\n const findingId = generateFindingId(finding);\n\n const entry: WaiverEntry = {\n findingId,\n invariantId: finding.invariantId,\n file: finding.evidence[0]?.file ?? '',\n symbol: finding.evidence[0]?.symbol,\n reasonKey: options.reasonKey,\n reason: options.reason,\n owner: options.owner,\n expiresAt: expiresAt.toISOString(),\n createdAt: now.toISOString(),\n };\n\n waivers.entries[findingId] = entry;\n return entry;\n}\n\n/**\n * Check if a finding has a valid (non-expired) waiver.\n * Returns the waiver if valid, undefined if expired or not found.\n */\nexport function getValidWaiver(waivers: WaiverFile, finding: Finding): WaiverEntry | undefined {\n const findingId = generateFindingId(finding);\n const waiver = waivers.entries[findingId];\n\n if (!waiver) {\n return undefined;\n }\n\n // Check expiration\n const now = new Date();\n const expiresAt = new Date(waiver.expiresAt);\n\n if (expiresAt < now) {\n // Waiver has expired - behaves as if no waiver exists\n return undefined;\n }\n\n return waiver;\n}\n\n/**\n * Remove expired waivers from the file.\n * Returns the number of waivers removed.\n */\nexport function pruneExpiredWaivers(waivers: WaiverFile): number {\n const now = new Date().toISOString();\n let removed = 0;\n\n for (const [id, entry] of Object.entries(waivers.entries)) {\n if (entry.expiresAt < now) {\n delete waivers.entries[id];\n removed++;\n }\n }\n\n return removed;\n}\n\n/**\n * Get all waivers that are about to expire (within N days).\n */\nexport function getExpiringWaivers(waivers: WaiverFile, withinDays: number = 7): WaiverEntry[] {\n const now = new Date();\n const threshold = new Date(now);\n threshold.setDate(threshold.getDate() + withinDays);\n const thresholdIso = threshold.toISOString();\n\n return Object.values(waivers.entries).filter(\n (entry) => entry.expiresAt > now.toISOString() && entry.expiresAt <= thresholdIso\n );\n}\n","/**\n * Baseline and Waiver Matching\n *\n * Applies baselines and waivers to findings, categorizing them for CI decisions.\n */\n\nimport type { Finding, Severity } from '@securitychecks/collector';\nimport { generateFindingId } from '../findings/finding-id.js';\nimport { isInBaseline, getValidWaiver } from './storage.js';\nimport type { BaselineFile, WaiverFile, WaiverEntry } from './schema.js';\n\n// ============================================================================\n// Categorized Finding Types\n// ============================================================================\n\n/**\n * A finding with its baseline/waiver status resolved.\n */\nexport interface CategorizedFinding extends Finding {\n findingId: string;\n /** Whether this finding is in the baseline */\n isBaselined: boolean;\n /** Active waiver if present */\n waiver?: WaiverEntry;\n /** Whether this finding should fail CI */\n shouldFail: boolean;\n}\n\n/**\n * Result of categorizing findings.\n */\nexport interface CategorizationResult {\n /** All findings with status */\n all: CategorizedFinding[];\n /** New findings not in baseline (may fail CI) */\n new: CategorizedFinding[];\n /** Findings in baseline (won't fail CI) */\n baselined: CategorizedFinding[];\n /** Findings with active waivers (won't fail CI) */\n waived: CategorizedFinding[];\n /** Summary counts */\n counts: {\n total: number;\n new: number;\n baselined: number;\n waived: number;\n willFail: number;\n };\n}\n\n// ============================================================================\n// Categorization Logic\n// ============================================================================\n\n/**\n * Categorize findings against baseline and waivers.\n *\n * @param findings - Raw findings from checkers\n * @param baseline - Loaded baseline file\n * @param waivers - Loaded waiver file\n * @param failSeverities - Which severities should fail CI (default: P0, P1)\n */\nexport function categorizeFindings(\n findings: Finding[],\n baseline: BaselineFile,\n waivers: WaiverFile,\n failSeverities: Severity[] = ['P0', 'P1']\n): CategorizationResult {\n const categorized: CategorizedFinding[] = [];\n const newFindings: CategorizedFinding[] = [];\n const baselinedFindings: CategorizedFinding[] = [];\n const waivedFindings: CategorizedFinding[] = [];\n\n for (const finding of findings) {\n const findingId = generateFindingId(finding);\n const isBaselined = isInBaseline(baseline, finding);\n const waiver = getValidWaiver(waivers, finding);\n\n // Determine if this finding should fail CI\n const isFailSeverity = failSeverities.includes(finding.severity);\n const shouldFail = isFailSeverity && !isBaselined && !waiver;\n\n const categorizedFinding: CategorizedFinding = {\n ...finding,\n findingId,\n isBaselined,\n waiver,\n shouldFail,\n };\n\n categorized.push(categorizedFinding);\n\n if (waiver) {\n waivedFindings.push(categorizedFinding);\n } else if (isBaselined) {\n baselinedFindings.push(categorizedFinding);\n } else {\n newFindings.push(categorizedFinding);\n }\n }\n\n return {\n all: categorized,\n new: newFindings,\n baselined: baselinedFindings,\n waived: waivedFindings,\n counts: {\n total: categorized.length,\n new: newFindings.length,\n baselined: baselinedFindings.length,\n waived: waivedFindings.length,\n willFail: categorized.filter((f) => f.shouldFail).length,\n },\n };\n}\n\n/**\n * Determine CI exit status based on categorized findings.\n *\n * @returns 0 for success, 1 for failure\n */\nexport function getCIExitCode(result: CategorizationResult): number {\n return result.counts.willFail > 0 ? 1 : 0;\n}\n\n/**\n * Get a summary message for CI output.\n */\nexport function getCISummary(result: CategorizationResult): string {\n const { counts } = result;\n\n if (counts.total === 0) {\n return 'No findings detected.';\n }\n\n const parts: string[] = [];\n\n if (counts.willFail > 0) {\n parts.push(`${counts.willFail} new finding(s) require attention`);\n }\n\n if (counts.baselined > 0) {\n parts.push(`${counts.baselined} baselined`);\n }\n\n if (counts.waived > 0) {\n parts.push(`${counts.waived} waived`);\n }\n\n if (counts.willFail === 0) {\n parts.unshift('All findings are baselined or waived');\n }\n\n return parts.join(', ') + '.';\n}\n\n// ============================================================================\n// Collision Detection\n// ============================================================================\n\n/**\n * Detect and handle findingId collisions.\n * Returns findings with unique IDs (appending :a, :b, etc. if needed).\n *\n * This is a defensive measure - collisions should be extremely rare with\n * 12 hex chars of SHA-256, but we define the behavior explicitly.\n */\nexport function resolveCollisions(findings: Finding[]): (Finding & { findingId: string })[] {\n const seen = new Map<string, number>();\n const result: (Finding & { findingId: string })[] = [];\n\n for (const finding of findings) {\n let findingId = generateFindingId(finding);\n\n // Check for collision\n const count = seen.get(findingId) ?? 0;\n if (count > 0) {\n // Append suffix: :a, :b, :c, etc.\n const suffix = String.fromCharCode(96 + count); // a=97, so 96+1=a\n findingId = `${findingId}:${suffix}`;\n }\n seen.set(generateFindingId(finding), count + 1);\n\n result.push({\n ...finding,\n findingId,\n });\n }\n\n return result;\n}\n\n/**\n * Check if there are any findingId collisions in a set of findings.\n * Returns true if collisions exist.\n */\nexport function hasCollisions(findings: Finding[]): boolean {\n const ids = new Set<string>();\n\n for (const finding of findings) {\n const id = generateFindingId(finding);\n if (ids.has(id)) {\n return true;\n }\n ids.add(id);\n }\n\n return false;\n}\n","/* eslint-disable max-lines */\n/**\n * Finding Correlation Engine\n *\n * Correlates findings across invariants to detect compounding risks.\n * Multiple findings on the same code path often compound each other,\n * creating worse outcomes than the sum of their parts.\n *\n * Key concepts:\n * - Correlated findings: Multiple findings sharing a code path\n * - Compounding risk: Combined severity is higher than individual\n * - Attack path: Narrative of how findings chain together\n *\n * Example:\n * Route: POST /api/webhooks/stripe\n * ├── WEBHOOK.IDEMPOTENT: ✗ No idempotency check\n * ├── TRANSACTION.POST_COMMIT: ✗ Email inside transaction\n * └── Combined: If replayed, sends duplicate emails AND inconsistent DB\n */\n\nimport type {\n Finding,\n Severity,\n CheckResult,\n Artifact,\n} from '@securitychecks/collector';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CorrelatedFinding {\n /** The primary finding (highest severity) */\n primary: Finding;\n /** Related findings on the same code path */\n related: Finding[];\n /** Shared context between findings */\n sharedContext: SharedContext;\n /** How the findings compound each other */\n compoundingEffect: CompoundingEffect;\n /** Adjusted severity based on correlation */\n adjustedSeverity: Severity;\n /** Attack path narrative */\n attackPath?: AttackPath;\n}\n\nexport interface SharedContext {\n /** Common file */\n file?: string;\n /** Common function */\n functionName?: string;\n /** Common route (if applicable) */\n route?: string;\n /** Shared call chain */\n callChain?: string[];\n /** Number of findings in this correlation */\n findingCount: number;\n}\n\nexport interface CompoundingEffect {\n /** Description of how findings compound */\n description: string;\n /** Risk multiplier (1.0 = no change, 2.0 = double risk) */\n riskMultiplier: number;\n /** Signals explaining the compounding */\n signals: string[];\n}\n\nexport interface AttackPath {\n /** Title of the attack path */\n title: string;\n /** Step-by-step narrative */\n steps: AttackStep[];\n /** Overall exploitability */\n exploitability: 'easy' | 'medium' | 'hard';\n /** Impact level */\n impact: 'low' | 'medium' | 'high' | 'critical';\n /** Time window (if applicable) */\n timeWindow?: string;\n}\n\nexport interface AttackStep {\n /** Step number */\n step: number;\n /** Description of this step */\n description: string;\n /** Which finding enables this step */\n invariantId: string;\n /** File/line reference */\n location?: { file: string; line: number };\n}\n\nexport interface CorrelationResult {\n /** All correlated finding groups */\n correlations: CorrelatedFinding[];\n /** Statistics */\n stats: {\n totalFindings: number;\n correlatedFindings: number;\n correlationGroups: number;\n severityEscalations: number;\n };\n}\n\n// ============================================================================\n// Compounding Rules\n// ============================================================================\n\n/**\n * Rules for how finding combinations compound\n */\nconst COMPOUNDING_RULES: Array<{\n invariants: string[];\n effect: CompoundingEffect;\n attackPathTemplate?: Omit<AttackPath, 'steps'>;\n}> = [\n // Webhook + Transaction = Replay causes inconsistent state\n {\n invariants: ['WEBHOOK.IDEMPOTENT', 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS'],\n effect: {\n description: 'Webhook replay can cause duplicate side effects AND inconsistent database state',\n riskMultiplier: 2.0,\n signals: ['webhook_replay', 'transaction_side_effect', 'data_inconsistency'],\n },\n attackPathTemplate: {\n title: 'Webhook Replay Attack with Data Inconsistency',\n exploitability: 'easy',\n impact: 'high',\n timeWindow: 'Immediate - no time limit on replay',\n },\n },\n\n // No auth + No service auth = Complete bypass\n {\n invariants: ['AUTHZ.SERVICE_LAYER.ENFORCED', 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE'],\n effect: {\n description: 'Missing service-layer auth combined with delayed revocation allows extended unauthorized access',\n riskMultiplier: 2.5,\n signals: ['auth_bypass', 'delayed_revocation', 'privilege_persistence'],\n },\n attackPathTemplate: {\n title: 'Extended Privilege Persistence',\n exploitability: 'medium',\n impact: 'critical',\n timeWindow: 'Until cache expires or session timeout',\n },\n },\n\n // Cache + Membership revocation = Stale permissions\n {\n invariants: ['CACHE.INVALIDATION.ON_AUTH_CHANGE', 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE'],\n effect: {\n description: 'Membership change without cache invalidation allows continued access via stale cache',\n riskMultiplier: 2.0,\n signals: ['stale_cache', 'permission_leak', 'revocation_bypass'],\n },\n attackPathTemplate: {\n title: 'Stale Permission Cache Exploit',\n exploitability: 'medium',\n impact: 'high',\n timeWindow: 'Cache TTL (often 5-15 minutes)',\n },\n },\n\n // Transaction + Cache = Inconsistent read after rollback\n {\n invariants: ['TRANSACTION.POST_COMMIT.SIDE_EFFECTS', 'CACHE.INVALIDATION.ON_AUTH_CHANGE'],\n effect: {\n description: 'Side effect in transaction + missing cache invalidation can leave cache inconsistent after rollback',\n riskMultiplier: 1.5,\n signals: ['rollback_inconsistency', 'cache_stale', 'side_effect_mismatch'],\n },\n },\n\n // Billing + Auth = Free tier bypass\n {\n invariants: ['BILLING.SERVER_ENFORCED', 'AUTHZ.SERVICE_LAYER.ENFORCED'],\n effect: {\n description: 'Missing billing enforcement + auth gap allows access to paid features without payment',\n riskMultiplier: 2.0,\n signals: ['billing_bypass', 'feature_theft', 'revenue_loss'],\n },\n attackPathTemplate: {\n title: 'Billing Bypass via Auth Gap',\n exploitability: 'medium',\n impact: 'high',\n },\n },\n\n // Jobs + Transaction = Retry causes duplicate side effects\n {\n invariants: ['JOBS.RETRY_SAFE', 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS'],\n effect: {\n description: 'Non-idempotent job with side effects in transaction can cause duplicates on retry',\n riskMultiplier: 1.8,\n signals: ['job_retry', 'duplicate_side_effect', 'data_duplication'],\n },\n },\n\n // API Key + Cache = Revoked key still works\n {\n invariants: ['AUTHZ.KEYS.REVOCATION.IMMEDIATE', 'CACHE.INVALIDATION.ON_AUTH_CHANGE'],\n effect: {\n description: 'API key revocation without cache invalidation allows continued API access',\n riskMultiplier: 2.0,\n signals: ['key_still_valid', 'cache_bypass', 'api_access_leak'],\n },\n attackPathTemplate: {\n title: 'API Key Revocation Bypass',\n exploitability: 'easy',\n impact: 'high',\n timeWindow: 'Until cache expires',\n },\n },\n\n // SQL Injection + Tenant Isolation = Cross-tenant data access\n {\n invariants: ['DATAFLOW.UNTRUSTED.SQL_QUERY', 'AUTHZ.TENANT.ISOLATION'],\n effect: {\n description: 'SQL injection bypasses tenant isolation allowing cross-tenant data exfiltration',\n riskMultiplier: 3.0,\n signals: ['sqli', 'tenant_bypass', 'cross_tenant_data'],\n },\n attackPathTemplate: {\n title: 'Cross-Tenant Data Exfiltration via SQL Injection',\n exploitability: 'medium',\n impact: 'critical',\n },\n },\n\n // XSS + No HttpOnly Cookie = Session Hijacking\n {\n invariants: ['XSS.DOM.SINK', 'SESSION.COOKIE.NO_HTTPONLY'],\n effect: {\n description: 'XSS can steal session cookies when HttpOnly flag is missing, enabling session hijacking',\n riskMultiplier: 2.3,\n signals: ['xss', 'cookie_theft', 'session_hijack'],\n },\n attackPathTemplate: {\n title: 'Session Hijacking via XSS Cookie Theft',\n exploitability: 'easy',\n impact: 'critical',\n },\n },\n\n // IDOR + Missing Service Auth = Enumeration attack\n {\n invariants: ['IDOR.SEQUENTIAL_ID', 'AUTHZ.SERVICE_LAYER.ENFORCED'],\n effect: {\n description: 'Sequential IDs make resource enumeration trivial when service-layer auth is missing',\n riskMultiplier: 2.2,\n signals: ['idor', 'enumeration', 'auth_bypass'],\n },\n attackPathTemplate: {\n title: 'Resource Enumeration via Sequential IDs',\n exploitability: 'easy',\n impact: 'high',\n },\n },\n\n // Payment No Idempotency + Race Condition = Double Charges\n {\n invariants: ['PAYMENT.NO_IDEMPOTENCY', 'RACE.BALANCE_CHECK'],\n effect: {\n description: 'Non-idempotent payment endpoint + race condition on balance allows double charges and overdraft',\n riskMultiplier: 2.5,\n signals: ['double_charge', 'race_condition', 'overdraft'],\n },\n attackPathTemplate: {\n title: 'Double Charge via Payment Race Condition',\n exploitability: 'medium',\n impact: 'critical',\n },\n },\n\n // MFA Bypass + Password Reset No Expire = Account Takeover\n {\n invariants: ['AUTH.MFA_BYPASS', 'AUTH.PASSWORD_RESET_NO_EXPIRE'],\n effect: {\n description: 'MFA bypass combined with non-expiring password reset tokens enables full account takeover',\n riskMultiplier: 2.8,\n signals: ['mfa_bypass', 'token_reuse', 'account_takeover'],\n },\n attackPathTemplate: {\n title: 'Account Takeover via MFA Bypass',\n exploitability: 'medium',\n impact: 'critical',\n },\n },\n\n // Middleware Bypass + Missing Service Auth = Unprotected Access\n {\n invariants: ['NEXTJS.MIDDLEWARE_BYPASS', 'AUTHZ.SERVICE_LAYER.ENFORCED'],\n effect: {\n description: 'Middleware bypass combined with missing service-layer auth leaves routes completely unprotected',\n riskMultiplier: 2.4,\n signals: ['middleware_bypass', 'auth_gap', 'unprotected_route'],\n },\n attackPathTemplate: {\n title: 'Complete Auth Bypass via Middleware Gap',\n exploitability: 'easy',\n impact: 'critical',\n },\n },\n\n // Billing + Client Feature Flag = Free Premium Access\n {\n invariants: ['BILLING.SERVER_ENFORCED', 'FEATURE.FLAG_CLIENT_CONTROLLED'],\n effect: {\n description: 'Client-controlled feature flags combined with missing server billing enforcement allows free premium access',\n riskMultiplier: 2.3,\n signals: ['billing_bypass', 'client_flag', 'premium_theft'],\n },\n attackPathTemplate: {\n title: 'Free Premium Access via Client Feature Flag',\n exploitability: 'easy',\n impact: 'high',\n },\n },\n\n // XXE + SSRF = Internal Network Compromise\n {\n invariants: ['XXE.EXTERNAL_ENTITY', 'SSRF.URL'],\n effect: {\n description: 'XXE enables fetching internal URLs via SSRF, accessing cloud metadata and internal services',\n riskMultiplier: 3.0,\n signals: ['xxe', 'ssrf', 'internal_access', 'metadata_leak'],\n },\n attackPathTemplate: {\n title: 'Internal Network Access via XXE-SSRF Chain',\n exploitability: 'medium',\n impact: 'critical',\n },\n },\n\n // Soft Delete Bypass + IDOR = Accessing Deleted Data\n {\n invariants: ['DATA.SOFT_DELETE_BYPASS', 'IDOR.SEQUENTIAL_ID'],\n effect: {\n description: 'Soft-deleted records remain accessible via sequential ID enumeration',\n riskMultiplier: 2.1,\n signals: ['soft_delete', 'idor', 'deleted_data_leak'],\n },\n attackPathTemplate: {\n title: 'Deleted Data Access via IDOR Enumeration',\n exploitability: 'easy',\n impact: 'high',\n },\n },\n];\n\n// ============================================================================\n// Main Correlation Function\n// ============================================================================\n\n/**\n * Correlate findings to detect compounding risks\n */\nexport function correlateFindings(\n results: CheckResult[],\n artifact: Artifact\n): CorrelationResult {\n // Flatten all findings\n const allFindings = results.flatMap(r => r.findings);\n\n if (allFindings.length === 0) {\n return {\n correlations: [],\n stats: {\n totalFindings: 0,\n correlatedFindings: 0,\n correlationGroups: 0,\n severityEscalations: 0,\n },\n };\n }\n\n const correlations: CorrelatedFinding[] = [];\n let severityEscalations = 0;\n const usedFindingIds = new Set<string>();\n\n // Pass 1: Co-located correlations (same file + function)\n const groups = groupFindingsByLocation(allFindings);\n\n for (const group of groups.values()) {\n if (group.length < 2) continue;\n\n const correlation = findCorrelation(group, artifact);\n if (correlation) {\n correlations.push(correlation);\n if (severityToNumber(correlation.adjustedSeverity) > severityToNumber(correlation.primary.severity)) {\n severityEscalations++;\n }\n // Track used findings to avoid duplicates in pass 2\n usedFindingIds.add(findingId(correlation.primary));\n for (const r of correlation.related) {\n usedFindingIds.add(findingId(r));\n }\n }\n }\n\n // Pass 2: Architectural correlations (cross-file)\n // Some vulnerability pairs are dangerous regardless of file co-location.\n // E.g. XSS anywhere + no HttpOnly on cookies = session hijacking.\n const allInvariantIds = new Set(allFindings.map(f => f.invariantId));\n\n for (const rule of COMPOUNDING_RULES) {\n const matchedInvariants = rule.invariants.filter(inv => allInvariantIds.has(inv));\n if (matchedInvariants.length < 2) continue;\n\n // Collect one representative finding per matched invariant\n const representatives: Finding[] = [];\n for (const inv of matchedInvariants) {\n const finding = allFindings.find(f =>\n f.invariantId === inv && !usedFindingIds.has(findingId(f))\n );\n if (finding) representatives.push(finding);\n }\n\n // Need at least 2 unused findings to form a new correlation\n if (representatives.length < 2) continue;\n\n representatives.sort((a, b) =>\n severityToNumber(b.severity) - severityToNumber(a.severity)\n );\n\n const primary = representatives[0]!;\n const related = representatives.slice(1);\n const evidence = primary.evidence[0];\n\n const adjustedSeverity = calculateAdjustedSeverity(\n primary.severity,\n rule.effect.riskMultiplier\n );\n\n let attackPath: AttackPath | undefined;\n if (rule.attackPathTemplate) {\n attackPath = buildAttackPath(rule.attackPathTemplate, representatives);\n }\n\n correlations.push({\n primary,\n related,\n sharedContext: {\n file: evidence?.file,\n functionName: evidence?.symbol,\n findingCount: representatives.length,\n },\n compoundingEffect: rule.effect,\n adjustedSeverity,\n attackPath,\n });\n\n if (severityToNumber(adjustedSeverity) > severityToNumber(primary.severity)) {\n severityEscalations++;\n }\n\n // Mark as used\n usedFindingIds.add(findingId(primary));\n for (const r of related) {\n usedFindingIds.add(findingId(r));\n }\n }\n\n return {\n correlations,\n stats: {\n totalFindings: allFindings.length,\n correlatedFindings: usedFindingIds.size,\n correlationGroups: correlations.length,\n severityEscalations,\n },\n };\n}\n\n// ============================================================================\n// Grouping Logic\n// ============================================================================\n\n/**\n * Group findings by their location (file + function)\n */\nfunction groupFindingsByLocation(findings: Finding[]): Map<string, Finding[]> {\n const groups = new Map<string, Finding[]>();\n\n for (const finding of findings) {\n // Get location key from evidence\n const evidence = finding.evidence[0];\n if (!evidence) continue;\n\n const key = `${evidence.file}:${evidence.symbol ?? 'unknown'}`;\n\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n groups.get(key)!.push(finding);\n }\n\n return groups;\n}\n\n/**\n * Find correlation for a group of findings\n */\nfunction findCorrelation(\n findings: Finding[],\n _artifact: Artifact\n): CorrelatedFinding | null {\n // Get invariant IDs in this group\n const invariantIds = new Set(findings.map(f => f.invariantId));\n\n // Find matching compounding rule\n let bestMatch: (typeof COMPOUNDING_RULES)[0] | null = null;\n let matchCount = 0;\n\n for (const rule of COMPOUNDING_RULES) {\n const matches = rule.invariants.filter(inv => invariantIds.has(inv));\n if (matches.length >= 2 && matches.length > matchCount) {\n bestMatch = rule;\n matchCount = matches.length;\n }\n }\n\n if (!bestMatch) {\n // No specific rule, but still correlate if multiple findings\n if (findings.length >= 2) {\n return createGenericCorrelation(findings);\n }\n return null;\n }\n\n // Find the matching findings\n const matchingFindings = findings.filter(f =>\n bestMatch!.invariants.includes(f.invariantId)\n );\n\n // Sort by severity (P0 first)\n matchingFindings.sort((a, b) =>\n severityToNumber(b.severity) - severityToNumber(a.severity)\n );\n\n const primary = matchingFindings[0]!;\n const related = matchingFindings.slice(1);\n\n // Build shared context\n const evidence = primary.evidence[0];\n const sharedContext: SharedContext = {\n file: evidence?.file,\n functionName: evidence?.symbol,\n findingCount: matchingFindings.length,\n };\n\n // Calculate adjusted severity\n const adjustedSeverity = calculateAdjustedSeverity(\n primary.severity,\n bestMatch.effect.riskMultiplier\n );\n\n // Build attack path if template exists\n let attackPath: AttackPath | undefined;\n if (bestMatch.attackPathTemplate) {\n attackPath = buildAttackPath(\n bestMatch.attackPathTemplate,\n matchingFindings\n );\n }\n\n return {\n primary,\n related,\n sharedContext,\n compoundingEffect: bestMatch.effect,\n adjustedSeverity,\n attackPath,\n };\n}\n\n/**\n * Create a generic correlation for findings without specific rules\n */\nfunction createGenericCorrelation(findings: Finding[]): CorrelatedFinding {\n // Sort by severity\n findings.sort((a, b) =>\n severityToNumber(b.severity) - severityToNumber(a.severity)\n );\n\n const primary = findings[0]!;\n const related = findings.slice(1);\n const evidence = primary.evidence[0];\n\n return {\n primary,\n related,\n sharedContext: {\n file: evidence?.file,\n functionName: evidence?.symbol,\n findingCount: findings.length,\n },\n compoundingEffect: {\n description: `Multiple security issues in the same location (${findings.length} findings)`,\n riskMultiplier: 1.0 + (findings.length - 1) * 0.2,\n signals: findings.map(f => f.invariantId),\n },\n adjustedSeverity: primary.severity,\n };\n}\n\n// ============================================================================\n// Attack Path Builder\n// ============================================================================\n\n/**\n * Build an attack path from a template and findings\n */\nfunction buildAttackPath(\n template: Omit<AttackPath, 'steps'>,\n findings: Finding[]\n): AttackPath {\n const steps: AttackStep[] = [];\n\n for (let i = 0; i < findings.length; i++) {\n const finding = findings[i]!;\n const evidence = finding.evidence[0];\n\n steps.push({\n step: i + 1,\n description: getAttackStepDescription(finding),\n invariantId: finding.invariantId,\n location: evidence ? { file: evidence.file, line: evidence.line } : undefined,\n });\n }\n\n return {\n ...template,\n steps,\n };\n}\n\n/**\n * Get a description for an attack step based on the finding\n */\nfunction getAttackStepDescription(finding: Finding): string {\n const invariant = finding.invariantId;\n\n switch (invariant) {\n case 'WEBHOOK.IDEMPOTENT':\n return 'Attacker replays webhook request (no idempotency protection)';\n case 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS':\n return 'Side effect fires inside transaction (may be duplicated or inconsistent)';\n case 'AUTHZ.SERVICE_LAYER.ENFORCED':\n return 'Service function called without authorization check';\n case 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE':\n return 'Membership/role change does not immediately revoke access';\n case 'AUTHZ.KEYS.REVOCATION.IMMEDIATE':\n return 'API key revocation does not immediately invalidate the key';\n case 'CACHE.INVALIDATION.ON_AUTH_CHANGE':\n return 'Auth change does not invalidate cached permissions';\n case 'BILLING.SERVER_ENFORCED':\n return 'Billing/entitlement check bypassed or missing';\n case 'JOBS.RETRY_SAFE':\n return 'Background job is not idempotent (retry causes duplicates)';\n default:\n return finding.message;\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction severityToNumber(severity: Severity): number {\n switch (severity) {\n case 'P0': return 3;\n case 'P1': return 2;\n case 'P2': return 1;\n default: return 0;\n }\n}\n\nfunction numberToSeverity(num: number): Severity {\n if (num >= 3) return 'P0';\n if (num >= 2) return 'P1';\n return 'P2';\n}\n\nfunction calculateAdjustedSeverity(\n baseSeverity: Severity,\n multiplier: number\n): Severity {\n const base = severityToNumber(baseSeverity);\n const adjusted = Math.min(3, Math.ceil(base * multiplier));\n return numberToSeverity(adjusted);\n}\n\nfunction findingId(finding: Finding): string {\n const evidence = finding.evidence[0];\n return `${finding.invariantId}:${evidence?.file ?? 'unknown'}:${evidence?.line ?? 0}`;\n}\n\n// ============================================================================\n// Formatters\n// ============================================================================\n\n/**\n * Format a correlated finding for display\n */\nexport function formatCorrelatedFinding(correlation: CorrelatedFinding): string {\n const lines: string[] = [];\n\n // Header\n const location = correlation.sharedContext.file\n ? `${correlation.sharedContext.file}:${correlation.sharedContext.functionName ?? 'unknown'}`\n : 'Unknown location';\n\n lines.push(`\\n┌─ CORRELATED FINDINGS ─ ${location}`);\n lines.push(`│`);\n\n // Primary finding\n lines.push(`│ [${correlation.adjustedSeverity}] ${correlation.primary.message}`);\n lines.push(`│ └─ ${correlation.primary.invariantId}`);\n\n // Related findings\n for (const related of correlation.related) {\n lines.push(`│ [${related.severity}] ${related.message}`);\n lines.push(`│ └─ ${related.invariantId}`);\n }\n\n lines.push(`│`);\n\n // Compounding effect\n lines.push(`│ ⚠ Compounding Effect:`);\n lines.push(`│ ${correlation.compoundingEffect.description}`);\n lines.push(`│ Risk multiplier: ${correlation.compoundingEffect.riskMultiplier}x`);\n\n // Attack path (if available)\n if (correlation.attackPath) {\n lines.push(`│`);\n lines.push(`│ 🎯 Attack Path: ${correlation.attackPath.title}`);\n lines.push(`│ Exploitability: ${correlation.attackPath.exploitability}`);\n lines.push(`│ Impact: ${correlation.attackPath.impact}`);\n if (correlation.attackPath.timeWindow) {\n lines.push(`│ Time window: ${correlation.attackPath.timeWindow}`);\n }\n lines.push(`│`);\n for (const step of correlation.attackPath.steps) {\n lines.push(`│ ${step.step}. ${step.description}`);\n }\n }\n\n lines.push(`└────────────────────────────────────────`);\n\n return lines.join('\\n');\n}\n\n/**\n * Format correlation statistics\n */\nexport function formatCorrelationStats(result: CorrelationResult): string {\n const { stats } = result;\n\n return `\nCorrelation Analysis:\n Total findings: ${stats.totalFindings}\n Correlated: ${stats.correlatedFindings} (${stats.totalFindings > 0 ? Math.round(stats.correlatedFindings / stats.totalFindings * 100) : 0}%)\n Correlation groups: ${stats.correlationGroups}\n Severity escalations: ${stats.severityEscalations}\n`.trim();\n}\n\nexport default correlateFindings;\n","/**\n * Correlation Telemetry\n *\n * Reports correlation data to the SecurityChecks SaaS.\n * This builds the data moat around which invariant combinations\n * actually compound risk in production codebases.\n */\n\nimport type { CorrelationResult, CorrelatedFinding } from './correlation.js';\nimport { randomUUID } from 'crypto';\n\n// Default endpoint (can be overridden)\nconst DEFAULT_ENDPOINT = 'https://api.securitychecks.ai/v1/correlations';\n\nexport interface CorrelationTelemetryConfig {\n enabled: boolean;\n endpoint?: string;\n apiKey?: string;\n timeout?: number;\n}\n\ninterface CorrelationObservation {\n invariants: string[];\n context: {\n framework?: string;\n file?: string;\n functionName?: string;\n route?: string;\n };\n stats: {\n findingCount: number;\n severityBefore?: 'P0' | 'P1' | 'P2';\n severityAfter?: 'P0' | 'P1' | 'P2';\n wasEscalated: boolean;\n riskMultiplier?: number;\n };\n attackPath?: {\n title: string;\n exploitability: 'easy' | 'medium' | 'hard';\n impact: 'low' | 'medium' | 'high' | 'critical';\n timeWindow?: string;\n steps: Array<{\n step: number;\n description: string;\n invariantId: string;\n location?: { file: string; line: number };\n }>;\n };\n compoundingEffect?: {\n description: string;\n signals: string[];\n };\n meta: {\n clientVersion: string;\n requestId: string;\n timestamp: string;\n };\n}\n\n/**\n * Convert CorrelatedFinding to observation format for API\n */\nfunction toObservation(\n correlation: CorrelatedFinding,\n framework?: string\n): CorrelationObservation {\n const allFindings = [correlation.primary, ...correlation.related];\n const invariants = [...new Set(allFindings.map(f => f.invariantId))];\n\n return {\n invariants,\n context: {\n framework,\n file: correlation.sharedContext.file,\n functionName: correlation.sharedContext.functionName,\n route: correlation.sharedContext.route,\n },\n stats: {\n findingCount: correlation.sharedContext.findingCount,\n severityBefore: correlation.primary.severity,\n severityAfter: correlation.adjustedSeverity,\n wasEscalated: correlation.adjustedSeverity !== correlation.primary.severity,\n riskMultiplier: correlation.compoundingEffect.riskMultiplier,\n },\n attackPath: correlation.attackPath ? {\n title: correlation.attackPath.title,\n exploitability: correlation.attackPath.exploitability,\n impact: correlation.attackPath.impact,\n timeWindow: correlation.attackPath.timeWindow,\n steps: correlation.attackPath.steps,\n } : undefined,\n compoundingEffect: {\n description: correlation.compoundingEffect.description,\n signals: correlation.compoundingEffect.signals,\n },\n meta: {\n clientVersion: process.env['CLI_VERSION'] ?? '0.0.0',\n requestId: randomUUID(),\n timestamp: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Report correlation results to the SaaS\n */\nexport async function reportCorrelations(\n result: CorrelationResult,\n config: CorrelationTelemetryConfig,\n framework?: string\n): Promise<{ success: boolean; stored?: number; errors?: number }> {\n if (!config.enabled || result.correlations.length === 0) {\n return { success: true, stored: 0 };\n }\n\n const endpoint = config.endpoint ?? DEFAULT_ENDPOINT;\n const timeout = config.timeout ?? 5000;\n\n try {\n const observations = result.correlations.map(c => toObservation(c, framework));\n\n const payload = {\n correlations: observations,\n summary: result.stats,\n meta: {\n clientVersion: process.env['CLI_VERSION'] ?? '0.0.0',\n framework,\n },\n };\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n 'X-Client-Version': process.env['CLI_VERSION'] ?? '0.0.0',\n },\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n return { success: false };\n }\n\n const data = await response.json() as { stored?: number; errors?: number };\n return {\n success: true,\n stored: data.stored ?? observations.length,\n errors: data.errors ?? 0,\n };\n } finally {\n clearTimeout(timeoutId);\n }\n } catch (_error) {\n // Telemetry failures shouldn't break the CLI\n return { success: false };\n }\n}\n\n/**\n * Report feedback on a correlation (user marking as accurate/inaccurate)\n */\nexport async function reportCorrelationFeedback(\n requestId: string,\n wasAccurate: boolean,\n reason?: string,\n config?: CorrelationTelemetryConfig\n): Promise<boolean> {\n const endpoint = config?.endpoint ?? DEFAULT_ENDPOINT;\n\n try {\n const response = await fetch(endpoint, {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n ...(config?.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n },\n body: JSON.stringify({\n requestId,\n wasAccurate,\n feedbackReason: reason,\n }),\n });\n\n return response.ok;\n } catch {\n return false;\n }\n}\n\nexport default reportCorrelations;\n","/**\n * Anonymous Telemetry\n *\n * Reports aggregate scan statistics to the SecurityChecks SaaS.\n * NO source code, NO file paths, NO PII - just patterns and numbers.\n *\n * This data powers:\n * - Framework-specific calibration\n * - Pattern effectiveness tracking\n * - Invariant impact analysis\n */\n\nimport { randomUUID } from 'crypto';\nimport type { AuditResult } from '@securitychecks/collector';\nimport type { CorrelationResult } from './correlation.js';\nimport { isValidWaiverReasonKey } from '../baseline/index.js';\nimport type { CategorizationResult } from '../baseline/index.js';\n\n// Default endpoint\nconst DEFAULT_ENDPOINT = 'https://api.securitychecks.ai/v1/telemetry';\n\nexport interface TelemetryConfig {\n enabled: boolean;\n endpoint?: string;\n apiKey?: string;\n timeout?: number;\n}\n\nexport interface ScanTelemetry {\n scanId: string;\n codebase: {\n filesScanned: number;\n servicesCount: number;\n linesOfCode?: number;\n };\n frameworks: string[];\n findings: {\n byInvariant: Record<string, number>;\n byPriority: { P0: number; P1: number; P2: number };\n total: number;\n };\n correlation?: {\n groups: number;\n escalations: number;\n correlatedFindings: number;\n };\n calibration?: {\n calibrated: number;\n suppressed: number;\n };\n patterns?: {\n applied: number;\n findings: number;\n };\n meta: {\n duration?: number;\n clientVersion: string;\n mode?: 'ci' | 'manual' | 'watch';\n ciProvider?: string;\n };\n baseline?: {\n size: number;\n waivers: number;\n newFindings: number;\n };\n feedback?: {\n waivedCount: number;\n waiverReasons: Record<string, number>;\n baselinedCount: number;\n };\n}\n\n/**\n * Build telemetry data from scan results\n */\nexport function buildTelemetry(\n result: AuditResult,\n options: {\n filesScanned: number;\n frameworks: string[];\n correlation?: CorrelationResult;\n categorization?: CategorizationResult;\n calibratedCount?: number;\n suppressedCount?: number;\n patternsApplied?: number;\n patternFindings?: number;\n mode?: 'ci' | 'manual' | 'watch';\n baselineSize?: number;\n waiversCount?: number;\n }\n): ScanTelemetry {\n // Count findings by invariant\n const byInvariant: Record<string, number> = {};\n for (const checkResult of result.results) {\n byInvariant[checkResult.invariantId] = checkResult.findings.length;\n }\n\n // Detect CI provider from environment\n const ciProvider = detectCIProvider();\n\n return {\n scanId: randomUUID(),\n codebase: {\n filesScanned: options.filesScanned,\n servicesCount: result.artifact.services.length,\n },\n frameworks: options.frameworks,\n findings: {\n byInvariant,\n byPriority: result.summary.byPriority,\n total: result.summary.byPriority.P0 + result.summary.byPriority.P1 + result.summary.byPriority.P2,\n },\n correlation: options.correlation ? {\n groups: options.correlation.stats.correlationGroups,\n escalations: options.correlation.stats.severityEscalations,\n correlatedFindings: options.correlation.stats.correlatedFindings,\n } : undefined,\n calibration: (options.calibratedCount !== undefined) ? {\n calibrated: options.calibratedCount,\n suppressed: options.suppressedCount ?? 0,\n } : undefined,\n patterns: (options.patternsApplied !== undefined) ? {\n applied: options.patternsApplied,\n findings: options.patternFindings ?? 0,\n } : undefined,\n meta: {\n duration: result.duration,\n clientVersion: process.env['CLI_VERSION'] ?? '0.0.0',\n mode: options.mode ?? (ciProvider ? 'ci' : 'manual'),\n ciProvider,\n },\n baseline: (options.categorization) ? {\n size: options.baselineSize ?? 0,\n waivers: options.waiversCount ?? 0,\n newFindings: options.categorization.counts.new,\n } : undefined,\n feedback: (options.categorization) ? {\n waivedCount: options.categorization.counts.waived,\n waiverReasons: buildWaiverReasonCounts(options.categorization),\n baselinedCount: options.categorization.counts.baselined,\n } : undefined,\n };\n}\n\n/**\n * Report telemetry to the SaaS\n */\nexport async function reportTelemetry(\n telemetry: ScanTelemetry,\n config: TelemetryConfig\n): Promise<boolean> {\n if (!config.enabled) {\n return true;\n }\n\n const endpoint = config.endpoint ?? DEFAULT_ENDPOINT;\n const timeout = config.timeout ?? 5000;\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n 'X-Client-Version': telemetry.meta.clientVersion,\n },\n body: JSON.stringify(telemetry),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n return response.ok;\n } finally {\n clearTimeout(timeoutId);\n }\n } catch {\n // Telemetry failures are silent\n return false;\n }\n}\n\n/**\n * Build waiver reason distribution from categorization result\n */\nfunction buildWaiverReasonCounts(categorization: CategorizationResult): Record<string, number> {\n const counts: Record<string, number> = {};\n for (const finding of categorization.waived) {\n const waiver = finding.waiver;\n if (!waiver) continue;\n const candidate = waiver.reasonKey ?? waiver.reason;\n const key = candidate && isValidWaiverReasonKey(candidate) ? candidate : 'other';\n counts[key] = (counts[key] ?? 0) + 1;\n }\n return counts;\n}\n\n/**\n * Detect CI provider from environment variables\n */\nfunction detectCIProvider(): string | undefined {\n if (process.env['GITHUB_ACTIONS']) return 'github';\n if (process.env['GITLAB_CI']) return 'gitlab';\n if (process.env['JENKINS_URL']) return 'jenkins';\n if (process.env['CIRCLECI']) return 'circleci';\n if (process.env['TRAVIS']) return 'travis';\n if (process.env['BITBUCKET_BUILD_NUMBER']) return 'bitbucket';\n if (process.env['AZURE_PIPELINES']) return 'azure';\n if (process.env['CI']) return 'unknown';\n return undefined;\n}\n\n/**\n * Check if telemetry is opt-out\n */\nexport function isTelemetryDisabled(): boolean {\n return (\n process.env['SECURITYCHECKS_TELEMETRY'] === 'false' ||\n process.env['DO_NOT_TRACK'] === '1'\n );\n}\n\nexport default reportTelemetry;\n","/**\n * Calibration API Client\n *\n * \"The SaaS advises. The local tool decides.\"\n *\n * This module handles communication with the SecurityChecks Calibration API.\n * The API provides confidence tuning based on aggregate data from many codebases.\n *\n * Key principles:\n * - No source code is ever sent (only patterns and metadata)\n * - API suggestions are advisory only\n * - Local tool retains veto power via minConfidence threshold\n * - Fails safely to local-only mode on network errors\n */\n\nimport type {\n CalibrationConfig,\n CalibrationRequest,\n CalibrationResponse,\n Finding,\n FindingCalibration,\n Severity,\n Artifact,\n} from '@securitychecks/collector';\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { randomUUID } from 'crypto';\n\n// CLI version for telemetry\nconst CLI_VERSION = '0.1.0';\n\n// Default cache path\nconst DEFAULT_CACHE_PATH = '.securitychecks/calibration-cache.json';\n\ninterface CacheEntry {\n response: CalibrationResponse;\n timestamp: number;\n requestHash: string;\n}\n\ninterface CalibrationCache {\n version: '1.0';\n entries: Record<string, CacheEntry>;\n}\n\n/**\n * Create a hash for a calibration request (for caching)\n */\nfunction hashRequest(request: CalibrationRequest): string {\n // Simple hash based on key fields (not crypto-secure, just for caching)\n const key = JSON.stringify({\n invariantId: request.invariantId,\n localSeverity: request.localSeverity,\n pattern: request.pattern,\n context: request.context,\n });\n // Simple string hash\n let hash = 0;\n for (let i = 0; i < key.length; i++) {\n const char = key.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36);\n}\n\n/**\n * Load calibration cache from disk\n */\nasync function loadCache(cachePath: string): Promise<CalibrationCache> {\n try {\n if (existsSync(cachePath)) {\n const content = await readFile(cachePath, 'utf-8');\n return JSON.parse(content);\n }\n } catch {\n // Cache corrupted or unreadable, start fresh\n }\n return { version: '1.0', entries: {} };\n}\n\n/**\n * Save calibration cache to disk\n */\nasync function saveCache(cachePath: string, cache: CalibrationCache): Promise<void> {\n try {\n await mkdir(dirname(cachePath), { recursive: true });\n await writeFile(cachePath, JSON.stringify(cache, null, 2));\n } catch {\n // Failed to save cache, not critical\n }\n}\n\n/**\n * Extract calibration-safe pattern from a finding\n * This is what we send to the API - no source code, just metadata\n */\nexport function extractPatternFromFinding(finding: Finding): CalibrationRequest['pattern'] {\n const pattern: CalibrationRequest['pattern'] = {};\n\n // Extract from structured evidence if available\n if (finding.structuredEvidence) {\n const se = finding.structuredEvidence;\n\n if (se.mutationSite) {\n pattern.functionName = se.mutationSite.functionName;\n pattern.mutationType = se.mutationSite.mutationType;\n pattern.entity = se.mutationSite.entity;\n }\n\n pattern.signals = se.signals;\n pattern.confidence = se.confidence;\n\n pattern.indicators = {\n hasCacheInvalidation: (se.invalidationSites?.length ?? 0) > 0,\n hasTests: (se.testsCovering?.length ?? 0) > 0,\n };\n }\n\n // Extract from basic evidence as fallback\n const firstEvidence = finding.evidence[0];\n if (firstEvidence?.symbol && !pattern.functionName) {\n pattern.functionName = firstEvidence.symbol;\n }\n\n return pattern;\n}\n\n/**\n * Detect framework from artifact\n */\nexport function detectFramework(artifact: Artifact): string | undefined {\n // Check routes for framework hints\n if (artifact.routes && artifact.routes.length > 0) {\n const frameworks = artifact.routes.map((r) => r.framework);\n const counts = new Map<string, number>();\n for (const f of frameworks) {\n counts.set(f, (counts.get(f) ?? 0) + 1);\n }\n // Return most common non-unknown framework\n let maxFramework: string | undefined;\n let maxCount = 0;\n for (const [f, c] of counts) {\n if (f !== 'unknown' && c > maxCount) {\n maxFramework = f;\n maxCount = c;\n }\n }\n return maxFramework;\n }\n return undefined;\n}\n\n/**\n * Build context for calibration request\n */\nexport function buildContext(\n artifact: Artifact,\n invariantId: string,\n allFindings: Finding[]\n): CalibrationRequest['context'] {\n const findingsOfType = allFindings.filter((f) => f.invariantId === invariantId);\n\n return {\n framework: detectFramework(artifact),\n serviceCount: artifact.services.length,\n findingCount: findingsOfType.length,\n hasTests: (artifact.tests?.length ?? 0) > 0,\n };\n}\n\n/**\n * Call the Calibration API for a single finding\n */\nasync function callCalibrationAPI(\n request: CalibrationRequest,\n config: CalibrationConfig\n): Promise<CalibrationResponse | null> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), config.timeout);\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n 'X-Client-Version': CLI_VERSION,\n },\n body: JSON.stringify(request),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n // API error - fail safe to local result\n return null;\n }\n\n const data = await response.json();\n return data as CalibrationResponse;\n } catch {\n // Network error, timeout, etc. - fail safe to local result\n clearTimeout(timeoutId);\n return null;\n }\n}\n\n/**\n * Calibrate a single finding\n */\nexport async function calibrateFinding(\n finding: Finding,\n artifact: Artifact,\n allFindings: Finding[],\n config: CalibrationConfig,\n cache: CalibrationCache\n): Promise<Finding> {\n // Build request\n const request: CalibrationRequest = {\n invariantId: finding.invariantId,\n localSeverity: finding.severity,\n pattern: extractPatternFromFinding(finding),\n context: buildContext(artifact, finding.invariantId, allFindings),\n meta: {\n clientVersion: CLI_VERSION,\n requestId: randomUUID(),\n timestamp: new Date().toISOString(),\n },\n };\n\n const requestHash = hashRequest(request);\n\n // Check cache first\n if (config.cache?.enabled) {\n const cached = cache.entries[requestHash];\n if (cached) {\n const age = Date.now() - cached.timestamp;\n const ttlMs = (config.cache.ttl ?? 86400) * 1000;\n if (age < ttlMs) {\n // Use cached response\n return applyCalibration(finding, cached.response, config);\n }\n }\n }\n\n // Call API\n const response = await callCalibrationAPI(request, config);\n\n if (!response) {\n // API failed - return finding unchanged\n return finding;\n }\n\n // Cache response\n if (config.cache?.enabled) {\n cache.entries[requestHash] = {\n response,\n timestamp: Date.now(),\n requestHash,\n };\n }\n\n return applyCalibration(finding, response, config);\n}\n\n/**\n * Apply calibration response to a finding\n */\nfunction applyCalibration(\n finding: Finding,\n response: CalibrationResponse,\n config: CalibrationConfig\n): Finding {\n const originalSeverity = finding.severity;\n\n // Check if we should apply the recommendation\n const shouldApply = response.confidence >= config.minConfidence && !response.suppress;\n\n const calibration: FindingCalibration = {\n apiRecommendation: response,\n applied: shouldApply,\n originalSeverity,\n reason: shouldApply\n ? `API confidence ${(response.confidence * 100).toFixed(0)}% >= threshold ${(config.minConfidence * 100).toFixed(0)}%`\n : `API confidence ${(response.confidence * 100).toFixed(0)}% < threshold ${(config.minConfidence * 100).toFixed(0)}%`,\n };\n\n // Create new finding with calibration data\n const calibratedFinding: Finding = {\n ...finding,\n calibration,\n };\n\n // Apply severity change if recommended and above threshold\n if (shouldApply && response.recommendedSeverity !== originalSeverity) {\n calibratedFinding.severity = response.recommendedSeverity;\n }\n\n return calibratedFinding;\n}\n\n/**\n * Calibrate all findings in a batch\n * This is the main entry point for calibration\n */\nexport async function calibrateFindings(\n findings: Finding[],\n artifact: Artifact,\n config: CalibrationConfig,\n targetPath: string\n): Promise<Finding[]> {\n if (!config.enabled) {\n return findings;\n }\n\n // Load cache\n const cachePath = config.cache?.path ?? join(targetPath, DEFAULT_CACHE_PATH);\n const cache = await loadCache(cachePath);\n\n // Calibrate each finding\n const calibratedFindings = await Promise.all(\n findings.map((finding) => calibrateFinding(finding, artifact, findings, config, cache))\n );\n\n // Save cache\n if (config.cache?.enabled) {\n await saveCache(cachePath, cache);\n }\n\n return calibratedFindings;\n}\n\n/**\n * Get calibration statistics from findings\n */\nexport function getCalibrationStats(findings: Finding[]): {\n total: number;\n calibrated: number;\n applied: number;\n unchanged: number;\n severityChanges: { from: Severity; to: Severity; count: number }[];\n} {\n const calibrated = findings.filter((f) => f.calibration);\n const applied = calibrated.filter((f) => f.calibration?.applied);\n\n const changes = new Map<string, number>();\n for (const finding of applied) {\n if (finding.calibration && finding.calibration.originalSeverity !== finding.severity) {\n const key = `${finding.calibration.originalSeverity}->${finding.severity}`;\n changes.set(key, (changes.get(key) ?? 0) + 1);\n }\n }\n\n const severityChanges = Array.from(changes.entries()).map(([key, count]) => {\n const [from, to] = key.split('->') as [Severity, Severity];\n return { from, to, count };\n });\n\n return {\n total: findings.length,\n calibrated: calibrated.length,\n applied: applied.length,\n unchanged: findings.length - applied.length,\n severityChanges,\n };\n}\n\n// ============================================================================\n// Aggregate Calibration (from SaaS learning loop)\n// ============================================================================\n\nconst AGGREGATE_CALIBRATION_ENDPOINT = 'https://api.securitychecks.ai/v1/calibration';\n\n// In-memory cache for aggregate data (1 hour TTL)\nconst AGGREGATE_CACHE_TTL_MS = 60 * 60 * 1000;\nlet aggregateCache: AggregateCalibrationData | null = null;\nlet aggregateCacheTimestamp = 0;\n\nexport interface AggregateCalibrationConfig {\n enabled: boolean;\n endpoint?: string;\n apiKey?: string;\n timeout?: number;\n cacheEnabled?: boolean;\n}\n\nexport interface FrameworkBaseline {\n framework: string;\n avgFindings: number;\n avgP0: number;\n avgP1: number;\n avgP2: number;\n scansAnalyzed: number;\n confidence: 'high' | 'medium' | 'low';\n}\n\nexport interface InvariantStats {\n invariantId: string;\n avgPerScan: number;\n hitRate: number;\n p0Rate: number;\n p1Rate: number;\n p2Rate: number;\n}\n\nexport interface PatternStats {\n patternId: string;\n framework: string | null;\n accuracy: number | null;\n matchesPerScan: number;\n confidence: 'high' | 'medium' | 'low';\n}\n\nexport interface CorrelationStats {\n ruleId: string;\n accuracy: number | null;\n escalationRate: number | null;\n isVerified: boolean;\n}\n\nexport interface AggregateCalibrationData {\n version: string;\n generatedAt: string;\n frameworks: FrameworkBaseline[];\n invariants: InvariantStats[];\n patterns: PatternStats[];\n correlations: CorrelationStats[];\n meta: {\n totalScansAnalyzed: number;\n lastUpdated: string | null;\n };\n}\n\nexport interface AggregateCalibrationResult {\n data: AggregateCalibrationData | null;\n fromCache: boolean;\n error?: string;\n}\n\n/**\n * Fetch aggregate calibration data for the specified frameworks\n */\nexport async function fetchAggregateCalibration(\n frameworks: string[],\n config: AggregateCalibrationConfig\n): Promise<AggregateCalibrationResult> {\n if (!config.enabled) {\n return { data: null, fromCache: false, error: 'Aggregate calibration disabled' };\n }\n\n // Check cache first\n if (config.cacheEnabled !== false && aggregateCache && Date.now() - aggregateCacheTimestamp < AGGREGATE_CACHE_TTL_MS) {\n return { data: aggregateCache, fromCache: true };\n }\n\n const endpoint = config.endpoint ?? AGGREGATE_CALIBRATION_ENDPOINT;\n const timeout = config.timeout ?? 5000;\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try {\n const url = new URL(endpoint);\n url.searchParams.set('frameworks', frameworks.join(','));\n\n const response = await fetch(url.toString(), {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n ...(config.apiKey && { Authorization: `Bearer ${config.apiKey}` }),\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n return {\n data: null,\n fromCache: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n };\n }\n\n const data = await response.json() as AggregateCalibrationData;\n\n // Update cache\n if (config.cacheEnabled !== false) {\n aggregateCache = data;\n aggregateCacheTimestamp = Date.now();\n }\n\n return { data, fromCache: false };\n } finally {\n clearTimeout(timeoutId);\n }\n } catch (err) {\n // Calibration failures are non-fatal\n return {\n data: null,\n fromCache: false,\n error: err instanceof Error ? err.message : 'Unknown error',\n };\n }\n}\n\n/**\n * Clear the aggregate calibration cache\n */\nexport function clearAggregateCache(): void {\n aggregateCache = null;\n aggregateCacheTimestamp = 0;\n}\n\n/**\n * Get the framework baseline for comparison\n */\nexport function getFrameworkBaseline(\n calibration: AggregateCalibrationData,\n framework: string\n): FrameworkBaseline | undefined {\n return calibration.frameworks.find((f) => f.framework === framework);\n}\n\n/**\n * Check if a pattern should be skipped due to low accuracy\n */\nexport function shouldSkipPattern(\n calibration: AggregateCalibrationData,\n patternId: string,\n framework?: string,\n accuracyThreshold = 0.3\n): boolean {\n const pattern = calibration.patterns.find(\n (p) => p.patternId === patternId &&\n (p.framework === framework || p.framework === null)\n );\n\n if (!pattern || pattern.accuracy === null) {\n return false; // No data, don't skip\n }\n\n // Only skip if we have high confidence it's a bad pattern\n if (pattern.confidence !== 'high') {\n return false;\n }\n\n return pattern.accuracy < accuracyThreshold;\n}\n\n/**\n * Get patterns that should be skipped for a framework\n */\nexport function getSkippedPatterns(\n calibration: AggregateCalibrationData,\n framework?: string,\n accuracyThreshold = 0.3\n): string[] {\n return calibration.patterns\n .filter((p) => {\n if (p.accuracy === null || p.confidence !== 'high') {\n return false;\n }\n if (framework && p.framework && p.framework !== framework) {\n return false;\n }\n return p.accuracy < accuracyThreshold;\n })\n .map((p) => p.patternId);\n}\n\n/**\n * Get correlation rules with high confidence\n */\nexport function getVerifiedCorrelations(\n calibration: AggregateCalibrationData\n): CorrelationStats[] {\n return calibration.correlations.filter((c) => c.isVerified);\n}\n\n/**\n * Calculate relative finding severity based on framework baseline\n */\nexport function calculateRelativeSeverity(\n findingCount: number,\n baseline: FrameworkBaseline,\n type: 'total' | 'P0' | 'P1' | 'P2' = 'total'\n): 'below_average' | 'average' | 'above_average' | 'critical' {\n let avg: number;\n switch (type) {\n case 'P0':\n avg = baseline.avgP0;\n break;\n case 'P1':\n avg = baseline.avgP1;\n break;\n case 'P2':\n avg = baseline.avgP2;\n break;\n default:\n avg = baseline.avgFindings;\n }\n\n if (avg === 0) {\n return findingCount > 0 ? 'above_average' : 'average';\n }\n\n const ratio = findingCount / avg;\n\n if (ratio < 0.5) return 'below_average';\n if (ratio < 1.5) return 'average';\n if (ratio < 3) return 'above_average';\n return 'critical';\n}\n\n/**\n * Generate calibration summary for output\n */\nexport function formatAggregateCalibrationSummary(\n calibration: AggregateCalibrationData,\n frameworks: string[],\n findings: { P0: number; P1: number; P2: number; total: number }\n): string {\n const lines: string[] = [];\n\n // Framework comparison\n for (const fw of frameworks) {\n const baseline = getFrameworkBaseline(calibration, fw);\n if (baseline && baseline.confidence !== 'low') {\n const severity = calculateRelativeSeverity(findings.total, baseline);\n const avgStr = baseline.avgFindings.toFixed(1);\n\n if (severity === 'below_average') {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Below average`);\n } else if (severity === 'above_average') {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Above average`);\n } else if (severity === 'critical') {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Significantly above average`);\n } else {\n lines.push(`${fw}: ${findings.total} findings (${avgStr} avg) - Typical`);\n }\n }\n }\n\n // Skipped patterns\n const skipped = getSkippedPatterns(calibration, frameworks[0]);\n if (skipped.length > 0) {\n lines.push(`Skipped ${skipped.length} low-accuracy patterns`);\n }\n\n // Data confidence\n if (calibration.meta.totalScansAnalyzed < 100) {\n lines.push(`Calibration based on ${calibration.meta.totalScansAnalyzed} scans (limited data)`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Check if aggregate calibration is disabled via environment\n */\nexport function isAggregateCalibrationDisabled(): boolean {\n return process.env['SECURITYCHECKS_CALIBRATION'] === 'false';\n}\n","/**\n * Staff Engineer Templates\n *\n * Shared, stable UX helpers used by:\n * - CLI output (human-readable prompts)\n * - MCP adapters (Claude Code, etc.)\n *\n * Keep these centralized to avoid drift across integration surfaces.\n */\n\nexport type TestFramework = 'jest' | 'vitest' | 'playwright' | (string & {});\n\nexport type InvariantLike = {\n id: string;\n name: string;\n requiredProof?: string;\n};\n\n/**\n * Returns the \"A staff engineer would ask...\" question for each invariant.\n * These are the probing questions that senior engineers ask in code review.\n */\nexport function getStaffQuestion(invariantId: string): string | null {\n const questions: Record<string, string> = {\n 'AUTHZ.SERVICE_LAYER.ENFORCED':\n 'What happens when a background job calls this function directly, bypassing the route?',\n 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE':\n 'If I remove someone from a team right now, can they still access team resources?',\n 'AUTHZ.KEYS.REVOCATION.IMMEDIATE':\n 'If I revoke this API key, does it stop working immediately or is it cached?',\n 'WEBHOOK.IDEMPOTENT':\n 'What happens when Stripe retries this webhook? Will we double-charge the customer?',\n 'WEBHOOK.SIGNATURE.VERIFIED':\n 'Are we verifying webhook signatures before processing any side effects?',\n 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS':\n 'If this transaction rolls back, did we already send an email the user will never receive?',\n 'TESTS.NO_FALSE_CONFIDENCE':\n 'Is this test actually verifying behavior, or just making CI green?',\n 'CACHE.INVALIDATION.ON_AUTH_CHANGE':\n 'When someone loses access, how long until the cache catches up?',\n 'JOBS.RETRY_SAFE':\n 'If this job runs twice, will we have duplicate data or double-bill someone?',\n 'BILLING.SERVER_ENFORCED':\n 'Can someone bypass the paywall by calling the API directly?',\n 'ANALYTICS.SCHEMA.STABLE':\n 'If someone adds a field here, will it break our dashboards?',\n 'DATAFLOW.UNTRUSTED.SQL_QUERY':\n 'Can untrusted input reach a raw SQL/NoSQL query without strict validation?',\n 'DATAFLOW.UNTRUSTED.COMMAND_EXEC':\n 'Can user input make it into exec/spawn/eval and change what runs?',\n 'DATAFLOW.UNTRUSTED.FILE_ACCESS':\n 'Can user input control file paths or write locations here?',\n 'DATAFLOW.UNTRUSTED.RESPONSE':\n 'Can user input drive redirects or HTML output without sanitization?',\n 'SECRETS.HARDCODED':\n 'If this repo were accidentally made public, what credentials would be exposed?',\n 'CRYPTO.ALGORITHM.STRONG':\n 'Is this encryption strong enough for the data it protects?',\n 'CONFIG.ENV_HARDCODED':\n 'What happens when this runs in staging vs production?',\n 'CONFIG.HEALTH_CHECK_MISSING':\n 'How does the load balancer know this instance is healthy?',\n 'CONFIG.ERROR_STACK_LEAK':\n 'If this endpoint throws, what does the user see?',\n 'CONFIG.GRACEFUL_SHUTDOWN_MISSING':\n 'What happens to in-flight requests when this pod is terminated?',\n };\n return questions[invariantId] ?? null;\n}\n\nexport function generateTestSkeleton(\n invariant: InvariantLike | null | undefined,\n framework: TestFramework,\n context?: string\n): string {\n if (!invariant) return 'Unknown invariant';\n\n const testFn = framework === 'jest' ? 'test' : framework === 'playwright' ? 'test' : 'it';\n const describe = framework === 'playwright' ? '' : 'describe';\n\n const wrap = (body: string) => {\n if (framework === 'playwright') {\n return body.trim();\n }\n return `\n${describe}('${escapeString(invariant.name)}', () => {\n${indent(body.trim(), 2)}\n});\n`.trim();\n };\n\n switch (invariant.id) {\n case 'AUTHZ.SERVICE_LAYER.ENFORCED':\n return wrap(`\n${testFn}('denies access without valid authorization', async () => {\n // Arrange: create context without auth\n const unauthorizedContext = { userId: null, tenantId: null };\n\n // Act + Assert: service call should throw (or return a forbidden result)\n await expect(\n yourService.sensitiveOperation({ context: unauthorizedContext })\n ).rejects.toThrow(/unauthorized|forbidden/i);\n});\n\n${testFn}('denies access to wrong-tenant resources', async () => {\n // Arrange: user from tenant-1 trying to access tenant-2 resource\n const context = { userId: 'user-1', tenantId: 'tenant-1' };\n const resourceFromOtherTenant = { id: 'resource-1', tenantId: 'tenant-2' };\n\n // Act + Assert\n await expect(\n yourService.getResource({ context, resourceId: resourceFromOtherTenant.id })\n ).rejects.toThrow(/forbidden|access denied/i);\n});\n`);\n\n case 'AUTHZ.MEMBERSHIP.REVOCATION.IMMEDIATE':\n return wrap(`\n${testFn}('denies access immediately after membership removal', async () => {\n // Arrange: user with team membership\n const userId = 'user-1';\n const teamId = 'team-1';\n await addMemberToTeam(userId, teamId);\n\n // Act: remove membership\n await removeMemberFromTeam(userId, teamId);\n\n // Assert: immediate access denial (no TTL grace period)\n await expect(accessTeamResource({ userId, teamId })).rejects.toThrow(/forbidden|not a member/i);\n});\n`);\n\n case 'WEBHOOK.IDEMPOTENT':\n return wrap(`\n${testFn}('handles duplicate webhook events idempotently', async () => {\n // Arrange: create a webhook event\n const event = { id: 'evt_test_123', type: 'payment.succeeded', data: { amount: 1000 } };\n\n // Act: process the same event twice\n await processWebhook(event);\n await processWebhook(event); // duplicate\n\n // Assert: side effect only happened once\n const payments = await getPaymentRecords();\n expect(payments.filter((p: any) => p.eventId === event.id)).toHaveLength(1);\n});\n\n${testFn}('stores event IDs to prevent duplicates', async () => {\n const event = { id: 'evt_test_456', type: 'payment.succeeded' };\n\n await processWebhook(event);\n\n // Verify idempotency key was stored\n const stored = await getProcessedEventIds();\n expect(stored).toContain(event.id);\n});\n`);\n\n case 'TRANSACTION.POST_COMMIT.SIDE_EFFECTS':\n return wrap(`\n${testFn}('does not send side effects if transaction rolls back', async () => {\n const emailSpy = vi.spyOn(emailService, 'send');\n\n // Act: trigger action that should fail and rollback\n await expect(createOrderWithInvalidData({ /* invalid data causing rollback */ })).rejects.toThrow();\n\n // Assert: no email was sent\n expect(emailSpy).not.toHaveBeenCalled();\n});\n\n${testFn}('sends side effects only after successful commit', async () => {\n const emailSpy = vi.spyOn(emailService, 'send');\n\n // Act: successful order creation\n await createOrder({ productId: 'prod-1', quantity: 1 });\n\n // Assert: email was sent\n expect(emailSpy).toHaveBeenCalledOnce();\n});\n`);\n\n case 'CONFIG.ENV_HARDCODED':\n return wrap(`\n${testFn}('does not contain hardcoded environment values', () => {\n // Grep source files for hardcoded URLs and connection strings\n const sourceFiles = getSourceFiles('src/');\n const hardcodedPatterns = [\n /localhost:\\\\d+/,\n /127\\\\.0\\\\.0\\\\.1:\\\\d+/,\n /mongodb:\\\\/\\\\//,\n /postgres:\\\\/\\\\//,\n /redis:\\\\/\\\\//,\n ];\n\n for (const file of sourceFiles) {\n for (const pattern of hardcodedPatterns) {\n expect(file.content).not.toMatch(pattern);\n }\n }\n});\n`);\n\n case 'CONFIG.HEALTH_CHECK_MISSING':\n return wrap(`\n${testFn}('exposes a health check endpoint', async () => {\n const response = await request(app).get('/health');\n expect(response.status).toBe(200);\n});\n`);\n\n case 'CONFIG.ERROR_STACK_LEAK':\n return wrap(`\n${testFn}('does not leak stack traces in production errors', async () => {\n // Arrange: force an internal error\n const response = await request(app)\n .get('/api/will-throw')\n .set('Accept', 'application/json');\n\n // Assert: response body does not contain stack trace\n expect(response.body.stack).toBeUndefined();\n expect(JSON.stringify(response.body)).not.toMatch(/at \\\\w+\\\\s*\\\\(/);\n});\n`);\n\n case 'CONFIG.GRACEFUL_SHUTDOWN_MISSING':\n return wrap(`\n${testFn}('handles SIGTERM gracefully', async () => {\n // Arrange: start server and make in-flight request\n const server = startServer();\n const inflightRequest = fetch(server.url + '/slow-endpoint');\n\n // Act: send SIGTERM\n process.kill(server.pid, 'SIGTERM');\n\n // Assert: in-flight request completes successfully\n const response = await inflightRequest;\n expect(response.ok).toBe(true);\n});\n`);\n\n default: {\n const proof = invariant.requiredProof ? invariant.requiredProof : '(see invariant docs)';\n const contextLine = context ? `// Context: ${context}` : '';\n return wrap(`\n${testFn}('enforces ${invariant.id}', async () => {\n // TODO: implement test for ${invariant.id}\n // Required proof: ${proof}\n ${contextLine}\n\n throw new Error('Test not implemented');\n});\n`);\n }\n }\n}\n\n/**\n * Generates a structured AI fix prompt from a finding.\n * Designed to be copy-pasted into any AI coding assistant.\n */\nexport function generateFixPrompt(\n invariant: InvariantLike | null | undefined,\n options?: {\n file?: string;\n line?: number;\n message?: string;\n framework?: TestFramework;\n }\n): string {\n if (!invariant) return 'Unknown invariant';\n\n const framework = options?.framework || 'vitest';\n const severity = (invariant as { severity?: string }).severity || 'P1';\n const staffQuestion = getStaffQuestion(invariant.id);\n const testSkeleton = generateTestSkeleton(invariant, framework);\n\n const lines: string[] = [\n `## Security Issue: ${invariant.name} [${severity}]`,\n '',\n ];\n\n // What was found\n lines.push('### What was found');\n if (options?.file) {\n lines.push(`File: ${options.file}${options.line ? `:${options.line}` : ''}`);\n }\n if (options?.message) {\n lines.push(options.message);\n }\n if (!options?.file && !options?.message) {\n lines.push(`Invariant \\`${invariant.id}\\` is violated.`);\n }\n lines.push('');\n\n // What's required\n lines.push('### What\\'s required');\n lines.push(invariant.requiredProof || `Satisfy the ${invariant.id} invariant.`);\n lines.push('');\n\n // Staff engineer asks\n if (staffQuestion) {\n lines.push('### Staff engineer asks');\n lines.push(`\"${staffQuestion}\"`);\n lines.push('');\n }\n\n // Test to prove the fix\n lines.push('### Test to prove the fix');\n lines.push('```typescript');\n lines.push(testSkeleton);\n lines.push('```');\n lines.push('');\n\n lines.push('Fix the code to satisfy this invariant, then run the test to verify.');\n\n return lines.join('\\n');\n}\n\nfunction indent(text: string, spaces: number): string {\n const prefix = ' '.repeat(spaces);\n return text\n .split('\\n')\n .map((line) => (line ? `${prefix}${line}` : line))\n .join('\\n');\n}\n\nfunction escapeString(text: string): string {\n return text.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n","import pc from 'picocolors';\n\nexport type Grade = 'A' | 'B' | 'C' | 'F';\n\nexport interface ReadinessScore {\n score: number;\n grade: Grade;\n total: number;\n passed: number;\n failed: number;\n hasP0: boolean;\n}\n\nexport function getScoreGrade(score: number): Grade {\n if (score >= 90) return 'A';\n if (score >= 70) return 'B';\n if (score >= 50) return 'C';\n return 'F';\n}\n\nexport function computeReadinessScore(summary: {\n total: number;\n passed: number;\n failed: number;\n byPriority: { P0: number; P1: number; P2: number };\n}): ReadinessScore {\n const { total, passed, failed, byPriority } = summary;\n const hasP0 = byPriority.P0 > 0;\n\n if (total === 0) {\n return { score: 100, grade: 'A', total: 0, passed: 0, failed: 0, hasP0: false };\n }\n\n let score = Math.round(100 * passed / total);\n\n // Cap at 49 if any P0 findings exist\n if (hasP0 && score > 49) {\n score = 49;\n }\n\n return {\n score,\n grade: getScoreGrade(score),\n total,\n passed,\n failed,\n hasP0,\n };\n}\n\nexport function formatScoreForCli(rs: ReadinessScore): string {\n const gradeColor =\n rs.grade === 'A' ? pc.green :\n rs.grade === 'B' ? pc.yellow :\n rs.grade === 'C' ? pc.red :\n pc.red;\n\n return gradeColor(`Score: ${rs.score}/100 (${rs.grade})`);\n}\n","/**\n * Posture Report — invariant-by-invariant security posture view.\n *\n * Transforms an AuditResult into a posture view showing every invariant\n * checked, whether it passed, and exportable proof for auditors/CI.\n */\n\nimport pc from 'picocolors';\nimport type {\n AuditResult,\n InvariantDefinition,\n Severity,\n} from '@securitychecks/collector';\nimport type { ReadinessScore } from './score.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface PostureReportEntry {\n invariantId: string;\n name: string;\n category: string;\n severity: Severity;\n status: 'passed' | 'failed' | 'skipped';\n findingCount: number;\n violations?: Array<{ file: string; line: number; message: string }>;\n}\n\nexport interface PostureSummary {\n invariantsChecked: number;\n passed: number;\n failed: number;\n skipped: number;\n coveragePercent: number;\n byCategory: Record<string, { total: number; passed: number; failed: number }>;\n bySeverity: Record<string, { total: number; passed: number; failed: number }>;\n}\n\nexport interface PostureProofArtifact {\n version: '1.0';\n metadata: {\n generatedAt: string;\n generatedBy: string;\n cliVersion: string;\n targetPath: string;\n scanDurationMs: number;\n filesAnalyzed: number;\n scope: {\n totalInvariantsAvailable: number;\n invariantsChecked: number;\n onlyFilter?: string[];\n skipFilter?: string[];\n };\n };\n score: { value: number; grade: string; hasP0: boolean };\n summary: PostureSummary;\n invariants: PostureReportEntry[];\n}\n\n// ---------------------------------------------------------------------------\n// Builders\n// ---------------------------------------------------------------------------\n\nexport interface PostureOptions {\n only?: string[];\n skip?: string[];\n}\n\n/**\n * Build posture entries from an AuditResult + full invariant catalog.\n *\n * - Invariants with CheckResults → passed/failed based on findings.\n * - Invariants not in results → \"skipped\" (honest about scope).\n * - Respects --only / --skip filters.\n */\nexport function buildPostureEntries(\n result: AuditResult,\n allInvariants: InvariantDefinition[],\n options?: PostureOptions,\n): PostureReportEntry[] {\n // Determine which invariants are in scope\n let invariantsInScope = allInvariants;\n\n if (options?.only && options.only.length > 0) {\n const onlySet = new Set(options.only);\n invariantsInScope = invariantsInScope.filter((inv) => onlySet.has(inv.id));\n }\n\n if (options?.skip && options.skip.length > 0) {\n const skipSet = new Set(options.skip);\n invariantsInScope = invariantsInScope.filter((inv) => !skipSet.has(inv.id));\n }\n\n // Index check results by invariant id\n const resultMap = new Map<string, (typeof result.results)[number]>();\n for (const r of result.results) {\n resultMap.set(r.invariantId, r);\n }\n\n return invariantsInScope.map((inv) => {\n const checkResult = resultMap.get(inv.id);\n\n if (!checkResult) {\n return {\n invariantId: inv.id,\n name: inv.name,\n category: inv.category,\n severity: inv.severity,\n status: 'skipped' as const,\n findingCount: 0,\n };\n }\n\n const failed = checkResult.findings.length > 0;\n const violations = failed\n ? checkResult.findings.flatMap((f) =>\n f.evidence.map((e) => ({\n file: e.file,\n line: e.line,\n message: f.message,\n })),\n )\n : undefined;\n\n return {\n invariantId: inv.id,\n name: inv.name,\n category: inv.category,\n severity: inv.severity,\n status: (failed ? 'failed' : 'passed') as 'passed' | 'failed',\n findingCount: checkResult.findings.length,\n violations,\n };\n });\n}\n\n/**\n * Aggregate posture entries into a summary.\n */\nexport function computePostureSummary(entries: PostureReportEntry[]): PostureSummary {\n const passed = entries.filter((e) => e.status === 'passed').length;\n const failed = entries.filter((e) => e.status === 'failed').length;\n const skipped = entries.filter((e) => e.status === 'skipped').length;\n const checked = passed + failed;\n\n const byCategory: PostureSummary['byCategory'] = {};\n const bySeverity: PostureSummary['bySeverity'] = {};\n\n for (const entry of entries) {\n // Category\n if (!byCategory[entry.category]) {\n byCategory[entry.category] = { total: 0, passed: 0, failed: 0 };\n }\n const cat = byCategory[entry.category]!;\n cat.total++;\n if (entry.status === 'passed') cat.passed++;\n if (entry.status === 'failed') cat.failed++;\n\n // Severity\n if (!bySeverity[entry.severity]) {\n bySeverity[entry.severity] = { total: 0, passed: 0, failed: 0 };\n }\n const sev = bySeverity[entry.severity]!;\n sev.total++;\n if (entry.status === 'passed') sev.passed++;\n if (entry.status === 'failed') sev.failed++;\n }\n\n return {\n invariantsChecked: checked,\n passed,\n failed,\n skipped,\n coveragePercent: entries.length > 0 ? Math.round((100 * checked) / entries.length) : 0,\n byCategory,\n bySeverity,\n };\n}\n\n/**\n * Build the exportable proof artifact (JSON).\n */\nexport function buildPostureProofArtifact(\n result: AuditResult,\n readiness: ReadinessScore,\n entries: PostureReportEntry[],\n summary: PostureSummary,\n allInvariantsCount: number,\n options?: PostureOptions,\n): PostureProofArtifact {\n const cliVersion = process.env['CLI_VERSION'] ?? '0.0.0-dev';\n const filesAnalyzed = result.artifact?.services?.length ?? 0;\n\n return {\n version: '1.0',\n metadata: {\n generatedAt: new Date().toISOString(),\n generatedBy: 'securitychecks-cli',\n cliVersion,\n targetPath: result.targetPath,\n scanDurationMs: result.duration,\n filesAnalyzed,\n scope: {\n totalInvariantsAvailable: allInvariantsCount,\n invariantsChecked: summary.invariantsChecked,\n ...(options?.only && options.only.length > 0 ? { onlyFilter: options.only } : {}),\n ...(options?.skip && options.skip.length > 0 ? { skipFilter: options.skip } : {}),\n },\n },\n score: {\n value: readiness.score,\n grade: readiness.grade,\n hasP0: readiness.hasP0,\n },\n summary,\n invariants: entries,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Terminal display\n// ---------------------------------------------------------------------------\n\n/**\n * Render the posture report to the terminal.\n *\n * Grouped by category, severity badges color-coded, PASS/FAIL with count.\n * No individual violation details — that's what the default view is for.\n */\nexport function displayPosture(\n entries: PostureReportEntry[],\n summary: PostureSummary,\n readiness: ReadinessScore,\n): void {\n console.log(pc.bold('\\nPosture Report\\n'));\n\n // Group by category\n const byCategory = new Map<string, PostureReportEntry[]>();\n for (const entry of entries) {\n if (!byCategory.has(entry.category)) {\n byCategory.set(entry.category, []);\n }\n byCategory.get(entry.category)!.push(entry);\n }\n\n // Render each category\n for (const [category, catEntries] of byCategory) {\n const checked = catEntries.filter((e) => e.status !== 'skipped').length;\n const label = category.charAt(0).toUpperCase() + category.slice(1);\n console.log(` ${pc.bold(label)} (${checked} checked)`);\n\n // Sort: P0 first, then P1, then P2\n const severityOrder: Record<string, number> = { P0: 0, P1: 1, P2: 2 };\n const sorted = [...catEntries].sort(\n (a, b) => (severityOrder[a.severity] ?? 3) - (severityOrder[b.severity] ?? 3),\n );\n\n for (const entry of sorted) {\n const sevColor =\n entry.severity === 'P0' ? pc.red :\n entry.severity === 'P1' ? pc.yellow :\n pc.dim;\n const sevBadge = sevColor(`[${entry.severity}]`);\n\n const id = entry.invariantId.padEnd(44);\n\n if (entry.status === 'skipped') {\n console.log(` ${sevBadge} ${pc.dim(id)}${pc.dim('SKIP')}`);\n } else if (entry.status === 'passed') {\n console.log(` ${sevBadge} ${id}${pc.green('PASS')}`);\n } else {\n const count = entry.findingCount;\n const violationLabel = count === 1 ? '1 violation' : `${count} violations`;\n console.log(` ${sevBadge} ${id}${pc.red('FAIL')} ${pc.red(violationLabel)}`);\n }\n }\n console.log('');\n }\n\n // Summary\n const total = entries.length;\n const checked = summary.invariantsChecked;\n const coverage = summary.coveragePercent;\n console.log(` Checked: ${checked}/${total} invariants (${coverage}%)`);\n console.log(` Passed: ${summary.passed}/${checked} Failed: ${summary.failed}/${checked}`);\n console.log('');\n\n // Score\n const gradeColor =\n readiness.grade === 'A' ? pc.green :\n readiness.grade === 'B' ? pc.yellow :\n pc.red;\n console.log(` ${gradeColor(`Score: ${readiness.score}/100 (${readiness.grade})`)}`);\n console.log('');\n}\n"]}