seaworthycode 1.1.0 → 1.1.2

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cli-action.ts","../src/commands/scan.ts","../src/copy/index.ts","../src/commands/createCommand.ts","../src/config/store.ts","../src/auth/fs-credential-provider.ts","../src/update-notifier.ts","../src/commands/config.ts"],"sourcesContent":["import { config as loadEnv } from 'dotenv'\nimport { existsSync } from 'fs'\nimport { dirname, resolve } from 'path'\nimport { fileURLToPath } from 'url'\nimport { cac } from 'cac'\nimport { createRequire } from 'module'\nimport { runCli } from './cli-action.js'\n\nloadEnv({ path: resolve(process.cwd(), '.env') })\n\nconst repoRootEnv = resolve(dirname(fileURLToPath(import.meta.url)), '../../..', '.env')\nif (existsSync(repoRootEnv)) {\n loadEnv({ path: repoRootEnv, override: false })\n}\nimport { configCommand, type ConfigArgs } from './commands/config.js'\nimport { getCopy, type CopyKey } from './copy/index.js'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json')\n\nconst cli = cac('seaworthy')\n\ncli.version(version)\n\ncli\n .command('[path]', 'Scan a directory for issues')\n .option('--json', 'Output JSON to stdout')\n .option('--output <path>', 'Write HTML report to file')\n .option('--sarif <path>', 'Write SARIF report to file')\n .option('--sarif-stdout', 'Write SARIF report to stdout')\n .option('--fail-on-findings', 'Exit with code 5 when findings are found')\n .option('--tier <tier>', 'Select tier (free, pro)')\n .option('--provider <provider>', 'LLM provider (anthropic, openai, kimi, deepseek, gemini, minimax, ollama, openrouter)')\n .option('--max-file-size <bytes>', 'Skip files larger than this (default: 1 MB)')\n .option('--debug', 'Enable debug logging')\n .option('--baseline [ref]', 'Compare against a baseline file or save current findings as baseline (--baseline save)')\n .option('--min-confidence <level>', 'Hide findings below this confidence (high, medium, low)')\n .action(async (targetDir: string | undefined, options: { json?: boolean; output?: string; sarif?: string; sarifStdout?: boolean; failOnFindings?: boolean; tier?: string; provider?: string; maxFileSize?: string; debug?: boolean; baseline?: string; minConfidence?: string }) => {\n const maxFileSize = options.maxFileSize ? Number(options.maxFileSize) : undefined\n const tier = options.tier as 'free' | 'pro' | undefined\n const baseline = options.baseline === 'save' ? 'save' : options.baseline\n const minConfidence = options.minConfidence as 'high' | 'medium' | 'low' | undefined\n const result = await runCli({ targetDir, json: options.json, output: options.output, sarif: options.sarif, sarifStdout: options.sarifStdout, failOnFindings: options.failOnFindings, tier, provider: options.provider, maxFileSize, debug: options.debug, baseline, minConfidence })\n\n if (result.updateMessage) {\n console.error(result.updateMessage)\n }\n\n if (result.error) {\n console.error(result.error)\n process.exit(result.code)\n }\n\n if (result.output) {\n console.log(result.output)\n }\n })\n\ncli\n .command('config <action> [key] [value]', 'Manage configuration')\n .action(async (action: string, key?: string, value?: string) => {\n const args: ConfigArgs = { action: action as ConfigArgs['action'], key, value }\n const result = await configCommand.handler(args, { tier: 'free', licensedTo: 'free tier' })\n\n if (!result.ok) {\n const message = result.detail\n ? `${getCopy(result.code as CopyKey)} (${result.detail})`\n : getCopy(result.code as CopyKey)\n console.error(message)\n process.exit(2)\n }\n\n if (result.output) {\n console.log(result.output)\n }\n })\n\ncli.help(() => {\n return [\n {\n title: 'Examples',\n body: ` $ npx seaworthy ./my-project\n $ npx seaworthy ./my-project --json\n $ npx seaworthy ./my-project --output report.html\n $ npx seaworthy ./my-project --sarif report.sarif\n $ npx seaworthy --provider kimi ./my-project`,\n },\n {\n title: 'Options',\n body: ` --json Output JSON to stdout\n --output <path> Write HTML report to file\n --sarif <path> ${getCopy('cli.help.flag.sarif')}\n --sarif-stdout ${getCopy('cli.help.flag.sarifStdout')}\n --fail-on-findings Exit with code 5 when findings are found\n --tier <tier> Override tier (free, pro)\n --provider <name> LLM provider (anthropic, openai, kimi, deepseek, gemini, minimax, ollama, openrouter)\n --max-file-size <n> Skip files larger than n bytes (default: 1 MB)\n --baseline [ref] Compare against baseline file or save (--baseline save)\n --min-confidence <level> Hide findings below confidence (high, medium, low)\n --debug Enable debug logging`,\n },\n {\n title: 'Configuration',\n body: ` ~/.seaworthy/config # license key, LLM provider, API key, model, url`,\n },\n {\n title: 'Environment',\n body: ` ANTHROPIC_API_KEY, OPENAI_API_KEY`,\n },\n {\n title: '',\n body: getCopy('cli.help.learnMore'),\n },\n ]\n})\n\ncli.parse()\n","import { stat } from 'fs/promises'\nimport { resolve } from 'path'\nimport { scanCommand, type ScanArgs } from './commands/scan.js'\nimport { getCopy } from './copy/index.js'\nimport { FsCredentialProvider } from './auth/index.js'\nimport {\n LicenseClient,\n resolveAuth,\n LICENSE_SERVER_URL,\n resolveErrorMessage,\n} from '@seaworthy/core'\nimport { checkUpdate } from './update-notifier.js'\n\nexport interface CliOptions {\n targetDir?: string\n json?: boolean\n output?: string\n sarif?: string\n sarifStdout?: boolean\n failOnFindings?: boolean\n tier?: 'free' | 'pro'\n provider?: string\n maxFileSize?: number\n debug?: boolean\n baseline?: 'save' | string\n minConfidence?: 'high' | 'medium' | 'low'\n}\n\nexport interface CliResult {\n code: number\n output?: string\n error?: string\n updateMessage?: string\n}\n\nfunction resolveExitCode(code: string): number {\n const normalized = code.replace(/^errors\\./, '')\n\n // License invalid / expired\n if (['license.invalid', 'license.expired'].includes(normalized)) return 1\n\n // User config error\n if (\n [\n 'config.invalid',\n 'fs.not_a_directory',\n 'fs.not_found',\n 'fs.permission_denied',\n ].includes(normalized) ||\n code.startsWith('cli.error.') ||\n code.startsWith('cli.sarif.')\n )\n return 2\n\n // Network / LLM unavailable\n if (\n [\n 'license.server_unreachable',\n 'license.rate_limited',\n 'network.unreachable',\n 'llm.timeout',\n 'llm.rate_limited',\n ].includes(normalized)\n )\n return 3\n\n // Scan failed (unhandled)\n if (['scan.failed', 'scan.timed_out'].includes(normalized)) return 4\n\n // No findings (when --fail-on-findings)\n if (normalized === 'scan.findings_found') return 5\n\n return 4\n}\n\nexport async function runCli(options: CliOptions): Promise<CliResult> {\n const dir = options.targetDir ?? '.'\n\n if (options.json && options.output) {\n return {\n code: resolveExitCode('cli.error.mutuallyExclusive'),\n error: getCopy('cli.error.mutuallyExclusive'),\n }\n }\n\n if (options.sarif && options.sarifStdout) {\n return {\n code: resolveExitCode('cli.sarif.mutually_exclusive'),\n error: getCopy('cli.sarif.mutually_exclusive'),\n }\n }\n\n if (options.sarifStdout && options.json) {\n return {\n code: resolveExitCode('cli.sarif.stdout_conflict'),\n error: getCopy('cli.sarif.stdout_conflict'),\n }\n }\n\n const outputPath = options.output ? resolve(options.output) : undefined\n\n try {\n const s = await stat(dir)\n if (!s.isDirectory()) {\n return {\n code: resolveExitCode('fs.not_a_directory'),\n error: getCopy('cli.error.notADirectory', dir),\n }\n }\n } catch {\n return {\n code: resolveExitCode('fs.not_found'),\n error: getCopy('cli.error.notFound', dir),\n }\n }\n\n const provider = new FsCredentialProvider()\n const license = new LicenseClient({ baseUrl: LICENSE_SERVER_URL })\n\n const authResult = await resolveAuth(provider, license)\n if (!authResult.ok) {\n const message = resolveErrorMessage(authResult.code)\n return { code: resolveExitCode(authResult.code), error: message }\n }\n\n const auth = authResult.value\n\n // CLI --tier overrides license tier when explicitly provided, but cannot exceed it\n const allowedTiers: Record<'free' | 'pro', Array<'free' | 'pro'>> = {\n free: ['free'],\n pro: ['free', 'pro'],\n }\n\n const effectiveTier = options.tier ?? auth.tier\n if (!Object.prototype.hasOwnProperty.call(allowedTiers, auth.tier) || !allowedTiers[auth.tier as 'free' | 'pro'].includes(effectiveTier)) {\n return {\n code: resolveExitCode('invalid.tier'),\n error: resolveErrorMessage('invalid.tier'),\n }\n }\n\n const format = options.json ? 'json' : outputPath ? 'html' : 'terminal'\n\n const selectedProvider = options.provider ?? auth.llmProvider\n const providerChanged = Boolean(options.provider && options.provider !== auth.llmProvider)\n\n const args: ScanArgs = {\n targetDir: dir,\n format,\n output: outputPath,\n sarif: options.sarif,\n sarifStdout: options.sarifStdout,\n failOnFindings: options.failOnFindings,\n llmApiKey: auth.llmApiKey,\n llmProvider: selectedProvider,\n llmModel: providerChanged ? undefined : auth.llmModel,\n llmApiUrl: providerChanged ? undefined : auth.llmApiUrl,\n maxFileSize: options.maxFileSize,\n debug: options.debug,\n baseline: options.baseline,\n minConfidence: options.minConfidence,\n }\n\n const updateStart = Date.now()\n const updatePromise = checkUpdate().catch(() => undefined)\n\n let result\n try {\n result = await scanCommand.handler(args, { tier: effectiveTier, licensedTo: auth.licensedTo })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { code: resolveExitCode('scan.failed'), error: message }\n }\n\n if (!result.ok) {\n const message = resolveErrorMessage(result.code)\n return { code: resolveExitCode(result.code), error: message }\n }\n\n const remaining = Math.max(0, 3_000 - (Date.now() - updateStart))\n const updateMessage = await Promise.race([\n updatePromise,\n new Promise<undefined>((resolve) => setTimeout(() => resolve(undefined), remaining)),\n ])\n\n return {\n code: 0,\n output: result.output ?? '',\n updateMessage,\n }\n}\n","import {\n ScanRunner,\n TerminalReporter,\n JSONReporter,\n HTMLReporter,\n SarifReporter,\n createProvider,\n getCopy as getCoreCopy,\n type ScanResult,\n type Tier,\n type Confidence,\n} from '@seaworthy/core'\nimport { promises as fs } from 'fs'\nimport { dirname, resolve, relative, isAbsolute } from 'path'\nimport { getCopy } from '../copy/index.js'\nimport { createCommand, type CommandContext, type CommandResult } from './createCommand.js'\n\nconst FREE_SCAN_TIMEOUT_MS = 60_000\nconst PRO_SCAN_TIMEOUT_MS = 600_000\n\nfunction resolveScanTimeoutMs(tier: Tier): number {\n const env = process.env.SEAWORTHY_SCAN_TIMEOUT_MS\n if (env) {\n const parsed = Number(env)\n if (Number.isFinite(parsed) && parsed > 0) {\n return parsed\n }\n }\n\n return tier === 'free' ? FREE_SCAN_TIMEOUT_MS : PRO_SCAN_TIMEOUT_MS\n}\n\nexport interface ScanArgs {\n targetDir: string\n format: 'terminal' | 'json' | 'html'\n output?: string\n sarif?: string\n sarifStdout?: boolean\n failOnFindings?: boolean\n llmApiKey?: string\n llmProvider?: string\n llmModel?: string\n llmApiUrl?: string\n maxFileSize?: number\n debug?: boolean\n baseline?: 'save' | string\n minConfidence?: 'high' | 'medium' | 'low'\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(message)), ms)\n promise\n .then((value) => {\n clearTimeout(timer)\n resolve(value)\n })\n .catch((err) => {\n clearTimeout(timer)\n reject(err)\n })\n })\n}\n\n/**\n * Determine whether `outputPath` lies inside `targetDir` (including sub-directories).\n */\nfunction isInsideDirectory(outputPath: string, targetDir: string): boolean {\n const resolvedOutput = resolve(outputPath)\n const resolvedTarget = resolve(targetDir)\n const rel = relative(resolvedTarget, resolvedOutput)\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))\n}\n\nasync function executeScan(args: ScanArgs, ctx: CommandContext): Promise<CommandResult> {\n if (args.sarif && args.sarifStdout) {\n return { ok: false, code: 'cli.sarif.mutually_exclusive' }\n }\n if (args.sarifStdout && args.format === 'json') {\n return { ok: false, code: 'cli.sarif.stdout_conflict' }\n }\n\n if (ctx.tier === 'pro' && !args.llmApiKey && !process.env.SEAWORTHY_SKIP_LLM_CHECK) {\n console.error(getCopy('cli.warn.llmSkipped'))\n }\n\n let llm = null\n if (args.llmApiKey && args.llmProvider && !process.env.SEAWORTHY_SKIP_LLM_CHECK) {\n llm = createProvider({ provider: args.llmProvider, apiKey: args.llmApiKey, model: args.llmModel, baseUrl: args.llmApiUrl })\n }\n\n const runner = new ScanRunner()\n const scanTimeoutMs = resolveScanTimeoutMs(ctx.tier!)\n const result: ScanResult = await withTimeout(\n runner.run({\n targetDir: args.targetDir,\n tier: ctx.tier!,\n llm,\n maxFileSize: args.maxFileSize,\n debug: args.debug,\n baseline: args.baseline,\n minConfidence: args.minConfidence as Confidence | undefined,\n }),\n scanTimeoutMs,\n getCoreCopy('errors.scan.timed_out', Math.round(scanTimeoutMs / 1000))\n )\n\n const reportInput = {\n findings: result.findings,\n targetDir: args.targetDir,\n tier: ctx.tier!,\n licensedTo: ctx.licensedTo ?? 'free tier',\n scannedFileCount: result.scannedFileCount,\n }\n\n let primaryOutput: string\n switch (args.format) {\n case 'json':\n primaryOutput = new JSONReporter().generate(reportInput)\n break\n case 'html':\n primaryOutput = new HTMLReporter().generate(reportInput)\n break\n case 'terminal':\n default:\n primaryOutput = new TerminalReporter().generate(reportInput)\n break\n }\n\n let sarifOutput: string | undefined\n if (args.sarif || args.sarifStdout) {\n sarifOutput = new SarifReporter().generate(reportInput)\n }\n\n if (args.sarif && sarifOutput) {\n const sarifPath = resolve(args.sarif)\n if (isInsideDirectory(sarifPath, args.targetDir)) {\n return { ok: false, code: 'cli.error.outputInsideTarget' }\n }\n await fs.mkdir(dirname(sarifPath), { recursive: true })\n await fs.writeFile(sarifPath, sarifOutput)\n }\n\n if (args.output) {\n const outputPath = resolve(args.output)\n if (isInsideDirectory(outputPath, args.targetDir)) {\n return { ok: false, code: 'cli.error.outputInsideTarget' }\n }\n await fs.mkdir(dirname(outputPath), { recursive: true })\n await fs.writeFile(outputPath, primaryOutput)\n if (args.failOnFindings && result.findings.length > 0) {\n return { ok: false, code: 'scan.findings_found' }\n }\n return { ok: true, output: getCopy('cli.reportWritten', outputPath) }\n }\n\n if (args.failOnFindings && result.findings.length > 0) {\n return { ok: false, code: 'scan.findings_found' }\n }\n\n const stdoutOutput = args.sarifStdout ? sarifOutput! : primaryOutput\n return { ok: true, output: stdoutOutput }\n}\n\nexport const scanCommand = createCommand<ScanArgs>({\n name: 'scan',\n description: 'Scan a directory for issues',\n handler: executeScan,\n})\n","import { SITE_URL } from '@seaworthy/core'\n\nconst copy = {\n 'cli.help.description': 'Seaworthy — static analysis for vibe coders',\n 'cli.help.usage': 'Usage: seaworthy [path] [options]',\n 'cli.help.options': 'Options',\n 'cli.help.learnMore': `Documentation: ${SITE_URL}/docs`,\n 'cli.scanning': 'Scanning...',\n 'cli.reportWritten': (path: string) => `Report written to ${path}`,\n 'cli.error.notADirectory': (path: string) => `Path is not a directory: ${path}`,\n 'cli.error.notFound': (path: string) => `Path not found: ${path}`,\n 'cli.error.mutuallyExclusive': '--json and --output cannot be used together',\n 'cli.error.outputInsideTarget': 'Cannot write report inside the scanned directory.',\n 'cli.help.flag.sarif': 'Write SARIF report to file',\n 'cli.help.flag.sarifStdout': 'Write SARIF report to stdout',\n 'cli.sarif.mutually_exclusive': 'Flags --sarif and --sarif-stdout cannot be used together.',\n 'cli.sarif.stdout_conflict': 'Flags --sarif-stdout and --json cannot be used together. Use --output to send JSON to a file.',\n 'cli.error.llmRequired':\n 'LLM API key required for Pro checks. Set it with seaworthy config or the SEAWORTHY_LLM_API_KEY environment variable.',\n 'cli.warn.llmSkipped':\n 'Pro checks skipped: no LLM API key configured. Set it with seaworthy config or the SEAWORTHY_LLM_API_KEY environment variable to enable semantic analysis.',\n 'cli.error.config.missingKey': 'Missing config key. Usage: seaworthy config <set|get> <key>',\n 'cli.error.config.missingValue': 'Missing config value. Usage: seaworthy config set <key> <value>',\n 'cli.error.config.unknownKey': 'Unknown config key. Valid keys: licenseKey, llmProvider, llmApiKey, llmModel, llmApiUrl',\n 'cli.error.config.invalidProvider': 'Invalid provider. Valid providers: anthropic, openai, kimi, moonshot, deepseek, gemini, ollama, openrouter',\n 'cli.error.config.invalidAction': 'Invalid config action. Usage: seaworthy config <set|get|list>',\n 'cli.config.setSuccess': (key: string) => `${key} updated.`,\n} as const\n\nexport type CopyKey = keyof typeof copy\n\ntype CopyValue<K extends CopyKey> = (typeof copy)[K]\n\ntype CopyArgs<K extends CopyKey> = CopyValue<K> extends (...args: infer P) => unknown\n ? P\n : never[]\n\nexport function getCopy<K extends CopyKey>(key: K, ...args: CopyArgs<K>): string {\n const value = copy[key]\n if (typeof value === 'function') {\n return (value as (...args: unknown[]) => string)(...args)\n }\n return value as string\n}\n","import type { LicenseTier } from '@seaworthy/core'\n\nexport interface CommandContext {\n tier?: LicenseTier\n licensedTo?: string\n}\n\nexport type CommandResult =\n | { ok: true; output?: string; filePath?: string }\n | { ok: false; code: string; detail?: string }\n\nexport interface CommandDefinition<TArgs> {\n name: string\n description: string\n handler: (args: TArgs, ctx: CommandContext) => Promise<CommandResult>\n}\n\nexport interface CreateCommandOptions {\n requireLicense?: boolean\n}\n\n/**\n * Factory for CLI commands. Wraps the raw handler to enforce license\n * validation and consistent error handling. Every `seaworthy` subcommand\n * (scan, config, logout) must use this factory per `route_handlers.md`.\n *\n * Wraps the handler in a try/catch so that infrastructure failures\n * (network, disk, LLM) produce a `{ ok: false }` result instead of\n * crashing the process.\n */\nexport function createCommand<TArgs>(\n definition: CommandDefinition<TArgs>,\n options?: CreateCommandOptions\n): CommandDefinition<TArgs> {\n const requireLicense = options?.requireLicense ?? true\n return {\n ...definition,\n handler: async (args: TArgs, ctx: CommandContext): Promise<CommandResult> => {\n if (requireLicense && !ctx.tier) {\n return { ok: false, code: 'errors.license.invalid' }\n }\n\n try {\n return await definition.handler(args, ctx)\n } catch (err) {\n return {\n ok: false,\n code: 'errors.unexpected',\n detail: err instanceof Error ? err.message : String(err),\n }\n }\n },\n }\n}\n","import { promises as fs } from 'fs'\nimport { homedir } from 'os'\nimport { join } from 'path'\n\nfunction getConfigDir(): string {\n return process.env.SEAWORTHY_CONFIG_DIR ?? join(homedir(), '.seaworthy')\n}\n\nfunction getConfigFile(): string {\n return join(getConfigDir(), 'config')\n}\n\nexport interface UserConfig {\n licenseKey?: string\n llmProvider?: string\n llmApiKey?: string\n llmModel?: string\n llmApiUrl?: string\n}\n\nexport async function readConfig(): Promise<UserConfig> {\n try {\n const raw = await fs.readFile(getConfigFile(), 'utf-8')\n return JSON.parse(raw) as UserConfig\n } catch {\n return {}\n }\n}\n\nexport async function writeConfig(config: UserConfig): Promise<void> {\n await fs.mkdir(getConfigDir(), { recursive: true })\n await fs.writeFile(getConfigFile(), JSON.stringify(config, null, 2), {\n mode: 0o600,\n })\n await fs.chmod(getConfigFile(), 0o600)\n}\n","import type { CredentialProvider } from '@seaworthy/core'\nimport { readConfig } from '../config/store.js'\n\n/**\n * Credential provider that reads from the local filesystem\n * (`~/.seaworthy/config`).\n */\nexport class FsCredentialProvider implements CredentialProvider {\n async getCredentials() {\n const config = await readConfig()\n return {\n licenseKey: config.licenseKey,\n llmApiKey: config.llmApiKey,\n llmProvider: config.llmProvider,\n llmModel: config.llmModel,\n llmApiUrl: config.llmApiUrl,\n }\n }\n}\n","import { readFile } from 'fs/promises'\nimport { fileURLToPath } from 'url'\nimport { dirname, join } from 'path'\n\nconst NPM_REGISTRY_URL = 'https://registry.npmjs.org/seaworthy'\nconst UPDATE_TIMEOUT_MS = 3_000\n\ninterface NpmRegistryResponse {\n 'dist-tags'?: {\n latest?: string\n }\n}\n\n/**\n * Compare two semantic version strings (simple x.y.z comparison).\n *\n * @param current - The currently installed version.\n * @param latest - The latest version from the registry.\n * @returns True when `current` is strictly lower than `latest`.\n */\nfunction isLowerVersion(current: string, latest: string): boolean {\n const parse = (v: string) => v.split('.').map((n) => Number(n))\n const [cMajor = 0, cMinor = 0, cPatch = 0] = parse(current)\n const [lMajor = 0, lMinor = 0, lPatch = 0] = parse(latest)\n\n if (lMajor > cMajor) return true\n if (lMajor < cMajor) return false\n if (lMinor > cMinor) return true\n if (lMinor < cMinor) return false\n return lPatch > cPatch\n}\n\n/**\n * Read the version field from this package's package.json.\n */\nasync function getInstalledVersion(): Promise<string> {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '../package.json')\n const pkg = JSON.parse(await readFile(pkgPath, 'utf-8')) as { version: string }\n return pkg.version\n}\n\n/**\n * Check the npm registry for a newer version of Seaworthy.\n *\n * @returns An update notification string when a newer version exists,\n * otherwise `undefined`. Never throws.\n */\nexport async function checkUpdate(): Promise<string | undefined> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), UPDATE_TIMEOUT_MS)\n\n try {\n const response = await fetch(NPM_REGISTRY_URL, { signal: controller.signal })\n clearTimeout(timeout)\n\n if (!response.ok) {\n return undefined\n }\n\n const data = (await response.json()) as NpmRegistryResponse\n const latest = data['dist-tags']?.latest\n\n if (!latest) {\n return undefined\n }\n\n const installed = await getInstalledVersion()\n\n if (isLowerVersion(installed, latest)) {\n return `Update available: ${installed} → ${latest}. Run npm i -g seaworthy to update.`\n }\n\n return undefined\n } catch {\n clearTimeout(timeout)\n return undefined\n }\n}\n","import { readConfig, writeConfig, type UserConfig } from '../config/store.js'\nimport { getCopy } from '../copy/index.js'\nimport { listPresetProviders } from '@seaworthy/core'\nimport { createCommand, type CommandResult } from './createCommand.js'\n\nconst VALID_KEYS: (keyof UserConfig)[] = ['licenseKey', 'llmProvider', 'llmApiKey', 'llmModel', 'llmApiUrl']\n\nexport interface ConfigArgs {\n action: 'set' | 'get' | 'list'\n key?: string\n value?: string\n}\n\nfunction formatOutputValue(key: keyof UserConfig, value: UserConfig[keyof UserConfig]): string {\n if (value === undefined) return ''\n if (key === 'llmApiKey' || key === 'licenseKey') return '********'\n return value\n}\n\nasync function executeConfig(args: ConfigArgs): Promise<CommandResult> {\n const config = await readConfig()\n\n if (args.action === 'list') {\n const lines: string[] = []\n for (const key of VALID_KEYS) {\n const value = config[key]\n lines.push(`${key}=${formatOutputValue(key, value)}`)\n }\n return { ok: true, output: lines.join('\\n') }\n }\n\n if (!args.key) {\n return { ok: false, code: 'cli.error.config.missingKey' }\n }\n\n if (!VALID_KEYS.includes(args.key as keyof UserConfig)) {\n return { ok: false, code: 'cli.error.config.unknownKey', detail: args.key }\n }\n\n const key = args.key as keyof UserConfig\n\n if (args.action === 'get') {\n const value = config[key]\n return { ok: true, output: formatOutputValue(key, value) }\n }\n\n if (args.action === 'set') {\n if (args.value === undefined) {\n return { ok: false, code: 'cli.error.config.missingValue' }\n }\n\n if (key === 'llmProvider' && !listPresetProviders().includes(args.value)) {\n return { ok: false, code: 'cli.error.config.invalidProvider', detail: args.value }\n }\n\n const next: UserConfig = { ...config, [key]: args.value }\n await writeConfig(next)\n return { ok: true, output: getCopy('cli.config.setSuccess', args.key) }\n }\n\n return { ok: false, code: 'cli.error.config.invalidAction' }\n}\n\nexport const configCommand = createCommand<ConfigArgs>(\n {\n name: 'config',\n description: 'Manage Seaworthy configuration',\n handler: async (args) => executeConfig(args),\n },\n { requireLicense: false }\n)\n"],"mappings":"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","names":["dirname","resolve","fileURLToPath","resolve","resolve","fs","dirname","join","resolve","key","resolve","dirname","fileURLToPath","require"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cli-action.ts","../../core/src/types/result.ts","../../core/src/config/reader.ts","../../core/src/config/paths.ts","../../core/src/registry/index.ts","../../core/src/crawler.ts","../../core/src/config/ignore-patterns.ts","../../core/src/runner/dedupe.ts","../../core/src/runner/dedupe-cross-check.ts","../../core/src/runner/sort-findings.ts","../../core/src/reporting/dedupe-degraded.ts","../../core/src/config/path-exclusions.ts","../../core/src/checks/helpers/confidence.ts","../../core/src/config/urls.ts","../../core/src/copy/why-copy.ts","../../core/src/copy/index.ts","../../core/src/baseline.ts","../../core/src/runner/scan-runner.ts","../../core/src/git.ts","../../core/src/parser/index.ts","../../core/src/providers/llm-provider.ts","../../core/src/providers/anthropic-provider.ts","../../core/src/providers/openai-provider.ts","../../core/src/providers/circuit-breaker.ts","../../core/src/providers/presets.ts","../../core/src/providers/index.ts","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js","../../core/src/reporting/tokens/chalk.ts","../../core/src/reporting/tokens/text.ts","../../core/src/reporting/terminal-reporter.ts","../../core/src/reporting/json-reporter.ts","../../core/src/reporting/html-reporter.ts","../../core/src/reporting/sarif-reporter.ts","../../core/package.json","../../core/src/license/client.ts","../../core/src/license/validate.ts","../../core/src/license/config.ts","../../core/src/auth/merge-env-credentials.ts","../../core/src/auth/resolve-auth.ts","../../core/src/cache/file-cache.ts","../../core/src/cache/ast-cache.ts","../../core/src/cache/dep-cache.ts","../../core/src/checks/manifest.ts","../../core/src/errors/resolve-error-message.ts","../../core/src/ast/query.ts","../../core/src/ast/language-map.ts","../../core/src/runtime/paths.ts","../../core/src/checks/helpers/finding-builder.ts","../../core/src/checks/create-tree-sitter-check.ts","../../core/src/checks/merge-findings.ts","../../core/src/checks/security/hardcoded-secrets.ts","../../core/src/checks/security/committed-env.ts","../../core/src/checks/helpers/bash-patterns.ts","../../core/src/checks/ops/debug-mode-enabled.ts","../../core/src/checks/ops/no-version-control.ts","../../core/src/checks/ops/hardcoded-localhost.ts","../../core/src/checks/dependencies/missing-lockfile.ts","../../core/src/checks/dependencies/known-cves.ts","../../core/src/checks/dependencies/dev-deps-in-prod.ts","../../core/src/checks/dependencies/unpinned-versions.ts","../../core/src/checks/helpers/html-cdn.ts","../../core/src/checks/dependencies/known-cdn-vulns.json","../../core/src/checks/dependencies/html-cdn-vulnerable-versions.ts","../../core/src/checks/dependencies/html-cdn-unpinned-versions.ts","../../core/src/checks/configuration/secrets-in-source.ts","../../core/src/prompts/parse-response.ts","../../core/src/cache/llm-cache.ts","../../core/src/checks/pro-check-runner.ts","../../core/src/prompts/security.auth-missing-endpoints.ts","../../core/src/checks/security/auth-missing-endpoints.ts","../../core/src/prompts/security.cors-too-permissive.ts","../../core/src/checks/security/cors-too-permissive.ts","../../core/src/prompts/security.sql-injection-surface.ts","../../core/src/checks/security/sql-injection-surface.ts","../../core/src/prompts/security.sensitive-data-in-logs.ts","../../core/src/checks/security/sensitive-data-in-logs.ts","../../core/src/prompts/resilience.no-rate-limiting.ts","../../core/src/checks/resilience/no-rate-limiting.ts","../../core/src/prompts/resilience.no-input-validation.ts","../../core/src/checks/resilience/no-input-validation.ts","../../core/src/prompts/resilience.missing-error-handling.ts","../../core/src/checks/resilience/missing-error-handling.ts","../../core/src/prompts/resilience.no-pagination.ts","../../core/src/checks/resilience/no-pagination.ts","../../core/src/prompts/resilience.missing-timeout.ts","../../core/src/checks/resilience/missing-timeout.ts","../../core/src/prompts/resilience.no-retry-logic.ts","../../core/src/checks/resilience/no-retry-logic.ts","../../core/src/prompts/resilience.webhook-processing-defects.ts","../../core/src/checks/resilience/webhook-processing-defects.ts","../../core/src/checks/resilience/html-inline-resilience.ts","../../core/src/prompts/ops.no-health-check.ts","../../core/src/checks/ops/no-health-check.ts","../../core/src/prompts/ops.missing-structured-logging.ts","../../core/src/checks/ops/missing-structured-logging.ts","../../core/src/prompts/ops.no-graceful-shutdown.ts","../../core/src/checks/ops/no-graceful-shutdown.ts","../../core/src/prompts/configuration.no-env-separation.ts","../../core/src/checks/configuration/no-env-separation.ts","../../core/src/prompts/configuration.default-credentials.ts","../../core/src/checks/helpers/sql-ast.ts","../../core/src/checks/configuration/default-credentials.ts","../../core/src/prompts/data-exposure.verbose-errors.ts","../../core/src/checks/data-exposure/verbose-errors.ts","../../core/src/prompts/data-exposure.pii-in-responses.ts","../../core/src/checks/data-exposure/pii-in-responses.ts","../../core/src/prompts/data-exposure.no-response-filtering.ts","../../core/src/checks/data-exposure/no-response-filtering.ts","../../core/src/checks/data-exposure/html-form-pii-exposure.ts","../../core/src/checks/security/xss-surface.ts","../../core/src/checks/security/os-command-injection.ts","../../core/src/checks/security/shell-arbitrary-evaluation.ts","../../core/src/checks/security/shell-unescaped-path-deletion.ts","../../core/src/checks/security/file-inclusion.ts","../../core/src/checks/security/open-redirect.ts","../../core/src/checks/security/unsafe-file-upload.ts","../../core/src/checks/security/unsafe-deserialization.ts","../../core/src/checks/security/hardcoded-passwords.ts","../../core/src/checks/helpers/html-static-host.ts","../../core/src/checks/helpers/html-css-ast.ts","../../core/src/checks/security/html-missing-csp.ts","../../core/src/checks/security/html-static-host-headers.ts","../../core/src/checks/security/html-inline-unsafe-script.ts","../../core/src/checks/security/html-referrer-leak.ts","../../core/src/checks/security/html-css-comments-secrets.ts","../../core/src/checks/security/css-insecure-import.ts","../../core/src/checks/security/html-mixed-content.ts","../../core/src/checks/security/html-external-asset-integrity.ts","../../core/src/checks/security/html-insecure-form-action.ts","../../core/src/checks/security/html-iframe-sandbox.ts","../../core/src/checks/security/html-unsafe-embed.ts","../../core/src/checks/security/html-meta-redirect.ts","../../core/src/checks/security/html-base-tag-hijack.ts","../../core/src/checks/security/html-javascript-uri.ts","../../core/src/checks/security/html-import-map-integrity.ts","../../core/src/checks/security/css-data-exfiltration.ts","../../core/src/checks/security/css-external-font-integrity.ts","../../core/src/checks/security/insecure-random.ts","../../core/src/checks/security/weak-key-entropy.ts","../../core/src/checks/security/insecure-api-url-default.ts","../../core/src/checks/security/dynamic-sql-columns.ts","../../core/src/checks/security/weak-email-validation.ts","../../core/src/checks/security/idempotency-key-leak.ts","../../core/src/checks/data-exposure/plaintext-secret-in-email.ts","../../core/src/taint/bfs.ts","../../core/src/taint/loader.ts","../../core/src/checks/helpers/severity-rubric.ts","../../core/src/checks/helpers/global-symbols.ts","../../core/src/checks/helpers/taint-check.ts","../../core/src/checks/security/taint-xss.ts","../../core/src/checks/security/taint-sql-injection.ts","../../core/src/checks/security/taint-command-injection.ts","../../core/src/checks/security/taint-path-traversal.ts","../../core/src/checks/security/taint-open-redirect.ts","../../core/src/checks/security/taint-prototype-pollution.ts","../../core/src/checks/security/taint-code-execution.ts","../../core/src/checks/security/missing-csrf-protection.ts","../../core/src/checks/security/weak-session-id.ts","../../core/src/checks/security/rails-mass-assignment.ts","../../core/src/checks/security/rails-insecure-session-config.ts","../../core/src/checks/security/xxe-surface.ts","../../core/src/prompts/resilience.swallowed-catch.ts","../../core/src/checks/resilience/swallowed-catch.ts","../../core/src/prompts/resilience.no-backoff-jitter.ts","../../core/src/checks/resilience/no-backoff-jitter.ts","../../core/src/prompts/resilience.no-circuit-breaker.ts","../../core/src/checks/resilience/no-circuit-breaker.ts","../../core/src/prompts/resilience.infinite-retry.ts","../../core/src/checks/resilience/infinite-retry.ts","../../core/src/prompts/ops.missing-observability.ts","../../core/src/checks/ops/missing-observability.ts","../../core/src/prompts/ops.secret-rotation-friction.ts","../../core/src/checks/ops/secret-rotation-friction.ts","../../core/src/prompts/ops.env-drift.ts","../../core/src/checks/ops/env-drift.ts","../../core/src/prompts/data-exposure.composite-pii.ts","../../core/src/checks/data-exposure/composite-pii.ts","../../core/src/prompts/data-exposure.derived-identifiers.ts","../../core/src/checks/data-exposure/derived-identifiers.ts","../../core/src/prompts/data-exposure.unredacted-logs.ts","../../core/src/checks/data-exposure/unredacted-logs.ts","../../core/src/checks/security/permissive-grants.ts","../../core/src/checks/helpers/sql-dialect.ts","../../core/src/checks/security/sql-rls-static.ts","../../core/src/checks/security/sql-security-definer-search-path.ts","../../core/src/checks/resilience/missing-transaction-guard.ts","../../core/src/checks/resilience/destructive-sql-migration.ts","../../core/src/checks/resilience/sql-broad-mutation.ts","../../core/src/checks/data-exposure/unprotected-sensitive-sql-columns.ts","../../core/src/prompts/security.sql-missing-rls.ts","../../core/src/checks/security/sql-missing-rls.ts","../../core/src/checks/security/rust-unsafe-blocks.ts","../../core/src/checks/resilience/rust-handler-panics.ts","../../core/src/checks/dependencies/cargo-unpinned-versions.ts","../../core/src/checks/dependencies/cargo-known-cves.ts","../../core/src/checks/dependencies/bundler-known-cves.ts","../../core/src/rules/loader.ts","../../core/src/rules/schema.ts","../../core/src/index.ts","../src/commands/scan.ts","../src/copy/index.ts","../src/commands/createCommand.ts","../src/commands/setup.ts","../src/config/store.ts","../src/auth/fs-credential-provider.ts","../src/update-notifier.ts","../src/commands/config.ts"],"sourcesContent":["import { config as loadEnv } from 'dotenv'\nimport { existsSync } from 'fs'\nimport { dirname, resolve } from 'path'\nimport { fileURLToPath } from 'url'\nimport { cac } from 'cac'\nimport { createRequire } from 'module'\nimport { runCli } from './cli-action.js'\n\nloadEnv({ path: resolve(process.cwd(), '.env') })\n\nconst repoRootEnv = resolve(dirname(fileURLToPath(import.meta.url)), '../../..', '.env')\nif (existsSync(repoRootEnv)) {\n loadEnv({ path: repoRootEnv, override: false })\n}\nimport { resolveErrorMessage } from '@seaworthy/core'\nimport { configCommand, type ConfigArgs } from './commands/config.js'\nimport { setupCommand } from './commands/setup.js'\nimport { getCopy, type CopyKey } from './copy/index.js'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json')\n\nconst cli = cac('seaworthy')\n\ncli.version(version)\n\ncli\n .command('[path]', 'Scan a directory for issues')\n .option('--json', 'Output JSON to stdout')\n .option('--output <path>', 'Write HTML report to file')\n .option('--sarif <path>', 'Write SARIF report to file')\n .option('--sarif-stdout', 'Write SARIF report to stdout')\n .option('--fail-on-findings', 'Exit with code 5 when findings are found')\n .option('--tier <tier>', 'Select tier (free, pro)')\n .option('--provider <provider>', 'LLM provider (anthropic, openai, kimi, moonshot, deepseek, gemini, minimax, ollama, openrouter)')\n .option('--max-file-size <bytes>', 'Skip files larger than this (default: 1 MB)')\n .option('--show-ids', 'Show check IDs alongside names in terminal output')\n .option('--debug', 'Enable debug logging')\n .option('--baseline [ref]', 'Compare against a baseline file or save current findings as baseline (--baseline save)')\n .option('--min-confidence <level>', 'Hide findings below this confidence (high, medium, low)')\n .action(async (targetDir: string | undefined, options: { json?: boolean; output?: string; sarif?: string; sarifStdout?: boolean; failOnFindings?: boolean; tier?: string; provider?: string; maxFileSize?: string; showIds?: boolean; debug?: boolean; baseline?: string; minConfidence?: string }) => {\n const maxFileSize = options.maxFileSize ? Number(options.maxFileSize) : undefined\n const tier = options.tier as 'free' | 'pro' | undefined\n const baseline = options.baseline === 'save' ? 'save' : options.baseline\n const minConfidence = options.minConfidence as 'high' | 'medium' | 'low' | undefined\n const result = await runCli({ targetDir, json: options.json, output: options.output, sarif: options.sarif, sarifStdout: options.sarifStdout, failOnFindings: options.failOnFindings, tier, provider: options.provider, maxFileSize, showIds: options.showIds, debug: options.debug, baseline, minConfidence })\n\n if (result.updateMessage) {\n console.error(result.updateMessage)\n }\n\n if (result.error) {\n console.error(result.error)\n process.exit(result.code)\n }\n\n if (result.output) {\n console.log(result.output)\n }\n })\n\ncli\n .command('config <action> [key] [value]', 'Manage configuration')\n .action(async (action: string, key?: string, value?: string) => {\n const args: ConfigArgs = { action: action as ConfigArgs['action'], key, value }\n const result = await configCommand.handler(args, { tier: 'free', licensedTo: 'free tier' })\n\n if (!result.ok) {\n const message = result.detail\n ? `${getCopy(result.code as CopyKey)} (${result.detail})`\n : getCopy(result.code as CopyKey)\n console.error(message)\n process.exit(2)\n }\n\n if (result.output) {\n console.log(result.output)\n }\n })\n\ncli\n .command('setup', 'Interactive setup for license key and LLM provider')\n .action(async () => {\n const result = await setupCommand.handler({ action: 'run' }, { tier: 'free', licensedTo: 'free tier' })\n if (!result.ok) {\n console.error(resolveErrorMessage(result.code))\n process.exit(2)\n }\n })\n\ncli.help(() => {\n return [\n {\n title: 'Examples',\n body: ` $ npx seaworthycode ./my-project\n $ npx seaworthycode ./my-project --json\n $ npx seaworthycode ./my-project --output report.html\n $ npx seaworthycode ./my-project --sarif report.sarif\n $ npx seaworthycode --provider kimi ./my-project`,\n },\n {\n title: 'Options',\n body: ` --json Output JSON to stdout\n --output <path> Write HTML report to file\n --sarif <path> ${getCopy('cli.help.flag.sarif')}\n --sarif-stdout ${getCopy('cli.help.flag.sarifStdout')}\n --fail-on-findings Exit with code 5 when findings are found\n --tier <tier> Override tier (free, pro)\n --provider <name> LLM provider (anthropic, openai, kimi, moonshot, deepseek, gemini, minimax, ollama, openrouter)\n --max-file-size <n> Skip files larger than n bytes (default: 1 MB)\n --baseline [ref] Compare against baseline file or save (--baseline save)\n --min-confidence <level> Hide findings below confidence (high, medium, low)\n --show-ids Show check IDs alongside names\n --debug Enable debug logging`,\n },\n {\n title: 'Commands',\n body: ` seaworthy setup Interactive first-run setup`,\n },\n {\n title: 'Configuration',\n body: ` ~/.seaworthy/config # license key, LLM provider, API key, model, url`,\n },\n {\n title: 'Environment',\n body: ` ANTHROPIC_API_KEY, OPENAI_API_KEY`,\n },\n {\n title: '',\n body: getCopy('cli.help.learnMore'),\n },\n ]\n})\n\ncli.parse()\n","import { stat, access } from 'fs/promises'\nimport { resolve } from 'path'\nimport { homedir } from 'os'\nimport { join } from 'path'\nimport { scanCommand, type ScanArgs } from './commands/scan.js'\nimport { setupCommand } from './commands/setup.js'\nimport { getCopy } from './copy/index.js'\nimport { FsCredentialProvider } from './auth/index.js'\nimport {\n LicenseClient,\n resolveAuth,\n LICENSE_SERVER_URL,\n resolveErrorMessage,\n} from '@seaworthy/core'\nimport { checkUpdate } from './update-notifier.js'\n\nexport interface CliOptions {\n targetDir?: string\n json?: boolean\n output?: string\n sarif?: string\n sarifStdout?: boolean\n failOnFindings?: boolean\n tier?: 'free' | 'pro'\n provider?: string\n maxFileSize?: number\n debug?: boolean\n baseline?: 'save' | string\n minConfidence?: 'high' | 'medium' | 'low'\n showIds?: boolean\n}\n\nfunction getConfigFile(): string {\n return join(process.env.SEAWORTHY_CONFIG_DIR ?? join(homedir(), '.seaworthy'), 'config')\n}\n\nasync function isFirstRun(options: CliOptions): Promise<boolean> {\n if (\n options.json ||\n options.output ||\n options.sarif ||\n options.sarifStdout ||\n process.env.CI ||\n process.env.SEAWORTHY_LICENSE_KEY ||\n process.env.ANTHROPIC_API_KEY ||\n process.env.OPENAI_API_KEY ||\n !process.stdin.isTTY ||\n !process.stdout.isTTY\n ) {\n return false\n }\n try {\n await access(getConfigFile())\n return false\n } catch {\n return true\n }\n}\n\nexport interface CliResult {\n code: number\n output?: string\n error?: string\n updateMessage?: string\n}\n\nfunction resolveExitCode(code: string): number {\n const normalized = code.replace(/^errors\\./, '')\n\n // License invalid / expired\n if (['license.invalid', 'license.expired'].includes(normalized)) return 1\n\n // User config error\n if (\n [\n 'config.invalid',\n 'fs.not_a_directory',\n 'fs.not_found',\n 'fs.permission_denied',\n ].includes(normalized) ||\n code.startsWith('cli.error.') ||\n code.startsWith('cli.sarif.')\n )\n return 2\n\n // Network / LLM unavailable\n if (\n [\n 'license.server_unreachable',\n 'license.rate_limited',\n 'network.unreachable',\n 'llm.timeout',\n 'llm.rate_limited',\n ].includes(normalized)\n )\n return 3\n\n // Scan failed (unhandled)\n if (['scan.failed', 'scan.timed_out'].includes(normalized)) return 4\n\n // No findings (when --fail-on-findings)\n if (normalized === 'scan.findings_found') return 5\n\n return 4\n}\n\nexport async function runCli(options: CliOptions): Promise<CliResult> {\n const dir = options.targetDir ?? '.'\n\n if (options.json && options.output) {\n return {\n code: resolveExitCode('cli.error.mutuallyExclusive'),\n error: getCopy('cli.error.mutuallyExclusive'),\n }\n }\n\n if (options.sarif && options.sarifStdout) {\n return {\n code: resolveExitCode('cli.sarif.mutually_exclusive'),\n error: getCopy('cli.sarif.mutually_exclusive'),\n }\n }\n\n if (options.sarifStdout && options.json) {\n return {\n code: resolveExitCode('cli.sarif.stdout_conflict'),\n error: getCopy('cli.sarif.stdout_conflict'),\n }\n }\n\n const outputPath = options.output ? resolve(options.output) : undefined\n\n try {\n const s = await stat(dir)\n if (!s.isDirectory()) {\n return {\n code: resolveExitCode('fs.not_a_directory'),\n error: getCopy('cli.error.notADirectory', dir),\n }\n }\n } catch {\n return {\n code: resolveExitCode('fs.not_found'),\n error: getCopy('cli.error.notFound', dir),\n }\n }\n\n if (await isFirstRun(options)) {\n console.error(getCopy('cli.firstRun'))\n await setupCommand.handler({ action: 'run' }, { tier: 'free', licensedTo: 'free tier' })\n }\n\n const provider = new FsCredentialProvider()\n const license = new LicenseClient({ baseUrl: LICENSE_SERVER_URL })\n\n const authResult = await resolveAuth(provider, license)\n\n if (!authResult.ok) {\n const normalized = authResult.code.replace(/^errors\\./, '')\n const softCodes = ['license.invalid', 'license.expired']\n if (!softCodes.includes(normalized)) {\n const message = resolveErrorMessage(authResult.code)\n return { code: resolveExitCode(authResult.code), error: message }\n }\n }\n\n const auth = authResult.ok\n ? authResult.value\n : { tier: 'free' as const, token: '', licensedTo: 'free tier' }\n\n // CLI --tier overrides license tier when explicitly provided, but cannot exceed it\n const allowedTiers: Record<'free' | 'pro', Array<'free' | 'pro'>> = {\n free: ['free'],\n pro: ['free', 'pro'],\n }\n\n const effectiveTier = options.tier ?? auth.tier\n if (!Object.prototype.hasOwnProperty.call(allowedTiers, auth.tier) || !allowedTiers[auth.tier as 'free' | 'pro'].includes(effectiveTier)) {\n return {\n code: resolveExitCode('invalid.tier'),\n error: resolveErrorMessage('invalid.tier'),\n }\n }\n\n const format = options.json ? 'json' : outputPath ? 'html' : 'terminal'\n\n const selectedProvider = options.provider ?? auth.llmProvider\n const providerChanged = Boolean(options.provider && options.provider !== auth.llmProvider)\n\n const args: ScanArgs = {\n targetDir: dir,\n format,\n output: outputPath,\n sarif: options.sarif,\n sarifStdout: options.sarifStdout,\n failOnFindings: options.failOnFindings,\n llmApiKey: auth.llmApiKey,\n llmProvider: selectedProvider,\n llmModel: providerChanged ? undefined : auth.llmModel,\n llmApiUrl: providerChanged ? undefined : auth.llmApiUrl,\n maxFileSize: options.maxFileSize,\n debug: options.debug,\n baseline: options.baseline,\n minConfidence: options.minConfidence,\n showIds: options.showIds,\n }\n\n const updateStart = Date.now()\n const updatePromise = checkUpdate().catch(() => undefined)\n\n let result\n try {\n result = await scanCommand.handler(args, { tier: effectiveTier, licensedTo: auth.licensedTo })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return { code: resolveExitCode('scan.failed'), error: message }\n }\n\n if (!result.ok) {\n const message = resolveErrorMessage(result.code)\n return { code: resolveExitCode(result.code), error: message }\n }\n\n const remaining = Math.max(0, 3_000 - (Date.now() - updateStart))\n const updateMessage = await Promise.race([\n updatePromise,\n new Promise<undefined>((resolve) => setTimeout(() => resolve(undefined), remaining)),\n ])\n\n return {\n code: 0,\n output: result.output ?? '',\n updateMessage,\n }\n}\n","export type ErrorCode = string\n\nexport interface OkResult<T> {\n ok: true\n value: T\n}\n\nexport interface FailResult {\n ok: false\n code: ErrorCode\n detail?: string\n}\n\nexport type Result<T> = OkResult<T> | FailResult\n\nexport function ok<T>(value: T): OkResult<T> {\n return { ok: true, value }\n}\n\nexport function fail(code: ErrorCode, detail?: string): FailResult {\n return { ok: false, code, detail }\n}\n","import { readFileSync } from 'fs'\nimport { join } from 'path'\nimport { CONFIG_DIR } from './paths.js'\n\nexport type DisableCategory =\n | 'security'\n | 'resilience'\n | 'ops'\n | 'data-exposure'\n | 'dependency'\n | 'configuration'\n | 'taint'\n\nconst VALID_CATEGORIES: Set<DisableCategory> = new Set([\n 'security',\n 'resilience',\n 'ops',\n 'data-exposure',\n 'dependency',\n 'configuration',\n 'taint',\n])\n\nfunction isValidCategory(c: string): c is DisableCategory {\n return VALID_CATEGORIES.has(c as DisableCategory)\n}\n\n/**\n * Read the disabled categories from:\n * 1. SEAWORTHY_DISABLE_CATEGORIES env var (comma-separated, takes precedence)\n * 2. ~/.seaworthy/config JSON file's disableCategories array\n *\n * Invalid category names are ignored with a debug log.\n */\nexport function getDisabledCategories(debug?: boolean): DisableCategory[] {\n const env = process.env.SEAWORTHY_DISABLE_CATEGORIES\n if (env !== undefined) {\n return parseCategoryList(env, debug)\n }\n\n try {\n const configPath = join(CONFIG_DIR, 'config')\n const raw = readFileSync(configPath, 'utf-8')\n const parsed = JSON.parse(raw) as { disableCategories?: string[] }\n if (Array.isArray(parsed.disableCategories)) {\n return parsed.disableCategories\n .filter((c): c is string => typeof c === 'string')\n .flatMap((c) => {\n if (isValidCategory(c)) return [c]\n if (debug) {\n console.error(`[debug] Invalid disable category in config: ${c}`)\n }\n return []\n })\n }\n } catch (err) {\n // Config file missing or unreadable — graceful fallback\n if (debug) {\n console.error(`[debug] Failed to read or parse config at ${join(CONFIG_DIR, 'config')}:`, err)\n }\n }\n\n return []\n}\n\nfunction parseCategoryList(input: string, debug?: boolean): DisableCategory[] {\n const result: DisableCategory[] = []\n for (const part of input.split(',')) {\n const trimmed = part.trim()\n if (trimmed === '') continue\n if (isValidCategory(trimmed)) {\n result.push(trimmed)\n } else if (debug) {\n console.error(`[debug] Invalid disable category in env var: ${trimmed}`)\n }\n }\n return result\n}\n","import { join } from 'path'\nimport { homedir } from 'os'\n\nexport const CONFIG_DIR = process.env.SEAWORTHY_CONFIG_DIR ?? join(homedir(), '.seaworthy')\n\nexport const CACHE_DIR = join(CONFIG_DIR, 'cache')\n\nexport const AST_CACHE_DIR = join(CACHE_DIR, 'ast')\n\nexport const DEP_CACHE_DIR = join(CACHE_DIR, 'deps')\n\nexport const LLM_CACHE_DIR = join(CACHE_DIR, 'llm')\n","import type { Check, Tier, Category } from '../types/check.js'\nimport type { DisableCategory } from '../config/reader.js'\nimport { getDisabledCategories } from '../config/reader.js'\n\n/**\n * Registry of all available checks. Checks self-register as a side effect\n * of importing their module files.\n */\nclass CheckRegistry {\n private checks: Map<string, Check> = new Map()\n\n /**\n * Register a new check. Throws if a check with the same ID is already\n * registered.\n */\n register(check: Check): void {\n if (this.checks.has(check.id)) {\n throw new Error(`Check \"${check.id}\" is already registered`)\n }\n this.checks.set(check.id, check)\n }\n\n /**\n * Return all checks available to the given tier, including lower tiers.\n * Filters out checks whose category is in the disabled set.\n * The disabled set is read at call time so runtime env-var changes take effect.\n */\n getForTier(tier: Tier): Check[] {\n const tiers: Tier[] = ['free', 'pro']\n const tierIndex = tiers.indexOf(tier)\n const disabled = new Set(getDisabledCategories(true))\n\n return Array.from(this.checks.values()).filter((check) => {\n if (tiers.indexOf(check.minTier) > tierIndex) return false\n if (disabled.has(check.category as DisableCategory)) return false\n if (disabled.has('taint') && check.id.startsWith('security.taint-')) return false\n return true\n })\n }\n\n /**\n * Return the unique set of categories across all registered checks.\n */\n getCategories(): Category[] {\n const set = new Set<Category>()\n for (const check of this.checks.values()) {\n set.add(check.category)\n }\n return Array.from(set)\n }\n\n /**\n * Return all checks regardless of tier.\n */\n all(): Check[] {\n return Array.from(this.checks.values())\n }\n\n /**\n * Return a single check by its registered id, or undefined.\n */\n getById(id: string): Check | undefined {\n return this.checks.get(id)\n }\n\n /**\n * Return metadata for checks excluded at the given tier.\n */\n getSkippedChecks(tier: Tier): Pick<Check, 'id' | 'name' | 'category'>[] {\n const tiers: Tier[] = ['free', 'pro']\n const tierIndex = tiers.indexOf(tier)\n return Array.from(this.checks.values())\n .filter((check) => tiers.indexOf(check.minTier) > tierIndex)\n .map(({ id, name, category }) => ({ id, name, category }))\n }\n}\n\n/** Singleton registry instance. */\nexport const registry = new CheckRegistry()\n","import { promises as fs } from 'fs'\nimport { join, relative } from 'path'\nimport ignore from 'ignore'\nimport type { Language, SourceFile } from './types/source-file.js'\nimport { SKIP_DIRS, SKIP_EXTENSIONS, BINARY_PEEK_SIZE, DEFAULT_MAX_FILE_SIZE } from './config/ignore-patterns.js'\n\n/** True when `.js` content looks minified (single-line bundle or very long average lines). */\nexport function isMinifiedJavaScript(content: string): boolean {\n if (content.length === 0) return false\n const lines = content.split('\\n')\n const totalChars = content.length\n const longestLine = lines.reduce((max, line) => Math.max(max, line.length), 0)\n // Bundled output is usually a large single line (>95% of bytes on one line).\n if (longestLine / totalChars > 0.95 && totalChars >= 8192) return true\n const avgLineLength = totalChars / lines.length\n return avgLineLength > 500\n}\n\nasync function shouldSkipMinifiedJs(filePath: string, filename: string): Promise<boolean> {\n if (!filename.endsWith('.js')) return false\n const content = await fs.readFile(filePath, 'utf-8')\n return isMinifiedJavaScript(content)\n}\n\nfunction inferLanguage(filename: string): Language {\n const base = filename.includes('/') ? filename.slice(filename.lastIndexOf('/') + 1) : filename\n if (base === 'Dockerfile' || base.startsWith('Dockerfile.')) return 'dockerfile'\n if (filename.endsWith('.tsx')) return 'tsx'\n if (filename.endsWith('.ts')) return 'typescript'\n if (filename.endsWith('.js') || filename.endsWith('.jsx')) return 'javascript'\n if (filename.endsWith('.html') || filename.endsWith('.htm')) return 'html'\n if (filename.endsWith('.css')) return 'css'\n if (filename.endsWith('.py')) return 'python'\n if (filename.endsWith('.go')) return 'go'\n if (\n filename.endsWith('.rb') ||\n filename.endsWith('.rake') ||\n filename.endsWith('.gemspec') ||\n base === 'Gemfile' ||\n base === 'Rakefile' ||\n base === 'config.ru'\n ) return 'ruby'\n if (filename.endsWith('.java')) return 'java'\n if (filename.endsWith('.rs')) return 'rust'\n if (filename.endsWith('.php')) return 'php'\n if (filename.endsWith('.sh') || filename.endsWith('.bash') || filename.endsWith('.zsh')) return 'bash'\n if (filename.endsWith('.json')) return 'json'\n if (filename.endsWith('.yaml') || filename.endsWith('.yml')) return 'yaml'\n if (filename.endsWith('.sql') || filename.endsWith('.pgsql') || filename.endsWith('.psql')) return 'sql'\n return 'plaintext'\n}\n\nconst GENERATED_MARKERS = [\n 'generated-code:',\n '@generated',\n 'auto-generated',\n 'do not edit',\n 'this file was generated by',\n 'code generated by',\n]\n\ninterface PeekResult {\n isBinary: boolean\n isGenerated: boolean\n}\n\nasync function peekFileHead(filePath: string): Promise<PeekResult> {\n const handle = await fs.open(filePath, 'r')\n try {\n const buf = Buffer.alloc(BINARY_PEEK_SIZE)\n const { bytesRead } = await handle.read(buf, 0, BINARY_PEEK_SIZE, 0)\n let isBinary = false\n for (let i = 0; i < bytesRead; i++) {\n if (buf[i] === 0) {\n isBinary = true\n break\n }\n }\n const text = buf.toString('utf-8', 0, bytesRead).toLowerCase()\n const isGenerated = GENERATED_MARKERS.some((marker) => text.includes(marker))\n return { isBinary, isGenerated }\n } finally {\n await handle.close()\n }\n}\n\nasync function isEmptyDir(dir: string): Promise<boolean> {\n try {\n const entries = await fs.readdir(dir)\n return entries.length === 0\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return true\n throw err\n }\n}\n\nasync function readSubmodulePaths(targetDir: string): Promise<Set<string>> {\n const gitmodulesPath = join(targetDir, '.gitmodules')\n const paths = new Set<string>()\n try {\n const content = await fs.readFile(gitmodulesPath, 'utf-8')\n for (const line of content.split('\\n')) {\n const match = line.match(/^\\s*path\\s*=\\s*(.+)$/)\n if (match) paths.add(match[1]!.trim())\n }\n } catch {\n // no .gitmodules\n }\n return paths\n}\n\nexport interface CrawlOptions {\n targetDir: string\n maxFileSize?: number\n debug?: boolean\n}\n\nexport interface CrawlMeta {\n isMonorepo: boolean\n submodulePaths: Set<string>\n}\n\nexport async function detectMonorepo(targetDir: string): Promise<boolean> {\n const indicators = ['pnpm-workspace.yaml', 'lerna.json', 'nx.json']\n for (const name of indicators) {\n try {\n await fs.access(join(targetDir, name))\n return true\n } catch {\n continue\n }\n }\n return false\n}\n\nexport async function crawl(options: CrawlOptions): Promise<{ files: SourceFile[]; meta: CrawlMeta }> {\n const { targetDir, maxFileSize = DEFAULT_MAX_FILE_SIZE, debug = false } = options\n const files: SourceFile[] = []\n const visitedRealPaths = new Set<string>()\n\n let ig = ignore()\n try {\n const gitignoreContent = await fs.readFile(\n join(targetDir, '.gitignore'),\n 'utf-8'\n )\n ig = ignore().add(gitignoreContent)\n } catch {\n // No .gitignore — that's fine\n }\n\n const submodulePaths = await readSubmodulePaths(targetDir)\n const isMonorepo = await detectMonorepo(targetDir)\n\n async function walk(dir: string): Promise<void> {\n let realDir: string\n try {\n realDir = await fs.realpath(dir)\n } catch {\n return\n }\n if (visitedRealPaths.has(realDir)) {\n if (debug) console.error(`Symlink loop detected at ${dir}, skipping.`)\n return\n }\n visitedRealPaths.add(realDir)\n\n let entries\n try {\n entries = await fs.readdir(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n const relPath = relative(targetDir, fullPath).split('\\\\').join('/')\n\n const isSymlink = entry.isSymbolicLink()\n const isDirEntry = entry.isDirectory() || (isSymlink && await isDirSymlink(fullPath))\n\n if (isDirEntry) {\n if (isSymlink) {\n if (debug) console.error(`Directory symlink skipped: ${relPath}.`)\n continue\n }\n\n if (SKIP_DIRS.has(entry.name)) continue\n if (ig.ignores(relPath + '/')) continue\n\n const isSubmoduleDir = submodulePaths.has(relPath)\n if (isSubmoduleDir && await isEmptyDir(fullPath)) {\n if (debug) console.error(`Submodule ${relPath} not initialised, skipping.`)\n continue\n }\n\n await walk(fullPath)\n continue\n }\n\n if (entry.isSymbolicLink()) {\n if (ig.ignores(relPath)) continue\n const ext = entry.name.includes('.') ? entry.name.slice(entry.name.lastIndexOf('.')) : ''\n if (SKIP_EXTENSIONS.has(ext)) continue\n\n try {\n const stat = await fs.stat(fullPath)\n if (!stat.isFile()) continue\n if (stat.size > maxFileSize) continue\n\n const { isBinary, isGenerated } = await peekFileHead(fullPath)\n if (isBinary || isGenerated) continue\n if (await shouldSkipMinifiedJs(fullPath, entry.name)) continue\n\n files.push({\n path: fullPath,\n relativePath: relPath,\n content: () => fs.readFile(fullPath, 'utf-8'),\n language: inferLanguage(entry.name),\n })\n } catch {\n // broken symlink — skip\n }\n continue\n }\n\n if (!entry.isFile()) continue\n if (ig.ignores(relPath)) continue\n\n const ext = entry.name.includes('.') ? entry.name.slice(entry.name.lastIndexOf('.')) : ''\n if (SKIP_EXTENSIONS.has(ext)) continue\n\n const stat = await fs.stat(fullPath)\n if (stat.size > maxFileSize) continue\n\n const { isBinary, isGenerated } = await peekFileHead(fullPath)\n if (isBinary || isGenerated) continue\n if (await shouldSkipMinifiedJs(fullPath, entry.name)) continue\n\n files.push({\n path: fullPath,\n relativePath: relPath,\n content: () => fs.readFile(fullPath, 'utf-8'),\n language: inferLanguage(entry.name),\n })\n }\n }\n\n await walk(targetDir)\n return { files, meta: { isMonorepo, submodulePaths } }\n}\n\nasync function isDirSymlink(path: string): Promise<boolean> {\n try {\n const stat = await fs.stat(path)\n return stat.isDirectory()\n } catch {\n return false\n }\n}\n","export const SKIP_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n 'coverage',\n '.venv',\n 'venv',\n '__pycache__',\n '.turbo',\n '.cache',\n 'storybook-static',\n '.storybook',\n 'out',\n '.output',\n])\n\nexport const SKIP_EXTENSIONS = new Set([\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.svg',\n '.ico',\n '.woff',\n '.woff2',\n '.ttf',\n '.eot',\n '.mp4',\n '.mp3',\n '.webm',\n '.pdf',\n '.zip',\n '.tar',\n '.gz',\n '.exe',\n '.dll',\n '.so',\n '.dylib',\n '.bin',\n '.lockb',\n])\n\nexport const BINARY_PEEK_SIZE = 8 * 1024\n\nexport const DEFAULT_MAX_FILE_SIZE = 1024 * 1024\n","import type { Finding } from '../types/finding.js'\n\n/**\n * Remove duplicate findings. Two findings are considered duplicates when\n * they share the same `checkId`, `file`, and `line`. The first occurrence\n * is kept.\n */\nexport function dedupeFindings(findings: Finding[]): Finding[] {\n const seen = new Set<string>()\n const result: Finding[] = []\n\n for (const f of findings) {\n const key = JSON.stringify([f.checkId, f.file ?? '', f.line ?? 0])\n if (seen.has(key)) continue\n seen.add(key)\n result.push(f)\n }\n\n return result\n}\n","import type { Finding } from '../types/finding.js'\n\n/** Higher value = more specific; kept when multiple checks hit the same line. */\nconst CHECK_PRECEDENCE: Record<string, number> = {\n 'security.hardcoded-secrets': 4,\n 'security.hardcoded-passwords': 3,\n 'configuration.secrets-in-source': 2,\n 'configuration.default-credentials': 1,\n}\n\nconst CROSS_DEDUPE_CHECK_IDS = new Set(Object.keys(CHECK_PRECEDENCE))\n\nfunction crossCheckKey(finding: Finding): string {\n return `${finding.file ?? ''}:${finding.line ?? 0}`\n}\n\nfunction precedence(checkId: string): number {\n return CHECK_PRECEDENCE[checkId] ?? 0\n}\n\n/**\n * Collapse overlapping secret/credential findings at the same file:line.\n * Per-check dedupe runs first; this pass merges across related check IDs.\n */\nexport function dedupeCrossCheck(findings: Finding[]): Finding[] {\n const crossFindings: Finding[] = []\n const otherFindings: Finding[] = []\n\n for (const finding of findings) {\n if (CROSS_DEDUPE_CHECK_IDS.has(finding.checkId)) {\n crossFindings.push(finding)\n } else {\n otherFindings.push(finding)\n }\n }\n\n const groups = new Map<string, Finding[]>()\n for (const finding of crossFindings) {\n const key = crossCheckKey(finding)\n const group = groups.get(key) ?? []\n group.push(finding)\n groups.set(key, group)\n }\n\n const mergedCrossFindings: Finding[] = []\n for (const group of groups.values()) {\n if (group.length === 1) {\n mergedCrossFindings.push(group[0]!)\n continue\n }\n\n const sorted = [...group].sort((a, b) => precedence(b.checkId) - precedence(a.checkId))\n const winner = { ...sorted[0]! }\n const suppressed = sorted.slice(1).map((f) => f.checkId)\n if (suppressed.length > 0) {\n winner.properties = {\n ...winner.properties,\n suppressedCheckIds: suppressed,\n }\n }\n mergedCrossFindings.push(winner)\n }\n\n return [...otherFindings, ...mergedCrossFindings]\n}\n\nexport const _CHECK_PRECEDENCE = CHECK_PRECEDENCE\n","import type { Finding, Severity } from '../types/finding.js'\n\nconst SEVERITY_ORDER: Record<Severity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n info: 4,\n}\n\n/**\n * Sort findings by severity (critical → info), then by file path, then\n * by line number.\n */\nexport function sortFindings(findings: Finding[]): Finding[] {\n return [...findings].sort((a, b) => {\n const sevDiff = SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]\n if (sevDiff !== 0) return sevDiff\n const fileA = a.file ?? ''\n const fileB = b.file ?? ''\n if (fileA !== fileB) return fileA.localeCompare(fileB)\n return (a.line ?? 0) - (b.line ?? 0)\n })\n}\n","import type { Finding } from '../types/finding.js'\n\n/**\n * Deduplicate info-severity degraded findings by (checkId, language).\n * A repo with 100 Dockerfiles should produce one degraded finding per taint check,\n * not 400.\n *\n * File-level degraded findings (no line number) are omitted from user-facing\n * output — they are not actionable and clutter reports on files like about.php\n * or Dockerfile where mechanical checks already cover the file.\n *\n * The language is extracted from the finding id, which ends with\n * `:degraded:<language>` (e.g. \"checkId:path:degraded:dockerfile\").\n */\nexport function dedupeDegradedFindings(findings: Finding[]): Finding[] {\n const filesWithMechanicalCoverage = new Set<string>()\n for (const f of findings) {\n if (f.file && !isDegradedFinding(f) && f.severity !== 'info') {\n filesWithMechanicalCoverage.add(f.file)\n }\n }\n\n const seen = new Set<string>()\n const result: Finding[] = []\n\n for (const f of findings) {\n if (isDegradedFinding(f)) {\n if (f.file && filesWithMechanicalCoverage.has(f.file)) {\n continue\n }\n if (f.line == null) {\n continue\n }\n const lang = extractLanguage(f)\n const key = `${f.checkId}:${lang}`\n if (seen.has(key)) continue\n seen.add(key)\n }\n result.push(f)\n }\n\n return result\n}\n\nfunction isDegradedFinding(finding: Finding): boolean {\n return finding.severity === 'info' && finding.id.includes(':degraded:')\n}\n\nfunction extractLanguage(finding: Finding): string {\n const parts = finding.id.split(':')\n if (parts.length >= 3 && parts[parts.length - 2] === 'degraded') {\n return parts[parts.length - 1]!\n }\n if (finding.message) {\n const firstWord = finding.message.split(' ')[0]\n if (firstWord) return firstWord\n }\n return 'unknown'\n}\n","export const NON_PRODUCTION_PATH_PATTERNS = [\n /\\.test\\.[^/]+$/,\n /\\.spec\\.[^/]+$/,\n /\\.example\\.[^/]+$/,\n /(?:^|[\\\\/])[^\\\\/]*_test\\.go$/,\n /\\.stories\\.(tsx?|jsx?|mdx)$/,\n /(?:^|[\\\\/])__tests__(?:[\\\\/]|$)/,\n /(?:^|[\\\\/])test(?:[\\\\/]|$)/,\n /(?:^|[\\\\/])(?:fixtures?|mocks?|examples?)(?:[\\\\/]|$)/i,\n /(?:^|[\\\\/])(?:dummy|placeholder|fake)(?:[\\\\/]|$)/i,\n]\n\nexport const DOCUMENTATION_PATH_PATTERNS = [\n /\\.md$/i,\n /(?:^|[\\\\/])docs?(?:[\\\\/]|$)/i,\n /(?:^|[\\\\/])CHANGELOG(?:\\.md)?$/i,\n /(?:^|[\\\\/])README(?:\\.[^/]+)?$/i,\n]\n\nexport function isNonProductionPath(path: string): boolean {\n return NON_PRODUCTION_PATH_PATTERNS.some((p) => p.test(path))\n}\n\nexport function isDocumentationPath(path: string): boolean {\n return DOCUMENTATION_PATH_PATTERNS.some((p) => p.test(path))\n}\n\n/** Paths skipped by mechanical checks (non-production + documentation). */\nexport function isMechanicalCheckExcludedPath(path: string): boolean {\n return isNonProductionPath(path) || isDocumentationPath(path)\n}\n","import type { Confidence, Finding } from '../../types/finding.js'\nimport { isDocumentationPath } from '../../config/path-exclusions.js'\n\nexport const CONFIDENCE_LEVELS: Confidence[] = ['high', 'medium', 'low']\n\nexport const KNOWN_SECRET_PREFIX =\n /^(?:sk_(?:live|test)_|sk-|ghp_|gho_|ghu_|ghs_|ghr_|xox[baprs]-|AKIA[A-Z0-9]|whsec_)/\n\nexport const FORMAT_LIKE_VALUE = /^[A-Za-z0-9+/=_-]{16,}$/\n\nexport type DetectionMethod = 'known-format' | 'ast' | 'regex'\n\nexport function downgradeConfidence(confidence: Confidence): Confidence {\n const idx = CONFIDENCE_LEVELS.indexOf(confidence)\n if (idx < 0 || idx >= CONFIDENCE_LEVELS.length - 1) return confidence\n return CONFIDENCE_LEVELS[idx + 1]!\n}\n\nexport function isKnownSecretFormat(value: string): boolean {\n const clean = value.replace(/^['\"`]|['\"`]$/g, '')\n return KNOWN_SECRET_PREFIX.test(clean) || FORMAT_LIKE_VALUE.test(clean)\n}\n\nexport function applyDocumentationDowngrade(\n confidence: Confidence,\n filePath: string | undefined,\n): Confidence {\n if (filePath && isDocumentationPath(filePath)) {\n return downgradeConfidence(confidence)\n }\n return confidence\n}\n\n/**\n * Confidence for mechanical pattern / AST findings.\n * Known secret formats rank highest; AST compound-name matches medium; regex-only low.\n */\nexport function mechanicalConfidence(\n method: DetectionMethod,\n filePath?: string,\n value?: string,\n): Confidence {\n let base: Confidence\n if (method === 'known-format' || (value !== undefined && isKnownSecretFormat(value))) {\n base = 'high'\n } else if (method === 'ast') {\n base = 'medium'\n } else {\n base = 'low'\n }\n return applyDocumentationDowngrade(base, filePath)\n}\n\nexport function llmCorroboratedConfidence(filePath?: string): Confidence {\n return applyDocumentationDowngrade('high', filePath)\n}\n\nexport function llmOnlyConfidence(filePath?: string): Confidence {\n return applyDocumentationDowngrade('low', filePath)\n}\n\nexport function meetsMinConfidence(\n findingConfidence: Confidence | undefined,\n minConfidence: Confidence,\n): boolean {\n const effective = findingConfidence ?? 'medium'\n return CONFIDENCE_LEVELS.indexOf(effective) <= CONFIDENCE_LEVELS.indexOf(minConfidence)\n}\n\nexport function filterByMinConfidence(\n findings: Finding[],\n minConfidence: Confidence | undefined,\n): Finding[] {\n if (!minConfidence) return findings\n return findings.filter((f) => meetsMinConfidence(f.confidence, minConfidence))\n}\n","export const SITE_URL = process.env.SEAWORTHY_SITE_URL ?? 'https://seaworthycode.com'\n","// Generated \"Why it matters\" explanations for Seaworthy checks\nexport const whyCopy = {\n 'checks.no-document-write.why':\n \"Cross-site scripting (XSS) allows attackers to inject malicious client-side scripts. This can lead to session hijacking, cookie theft, or unauthorized actions on behalf of users (CWE-79).\",\n 'checks.dangerous-eval.why':\n \"Unsafe execution of dynamic strings as code or shell commands can lead to arbitrary code execution, letting attackers take complete control of the host machine (CWE-94).\",\n 'checks.hardcoded-secrets.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.secrets-in-source.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.debug-mode-enabled.why':\n \"Improper logging and monitoring configurations can expose sensitive debugging details to attackers or fail to provide alert visibility during active service outages.\",\n 'checks.sql-injection-surface.why':\n \"Unsafe database interactions and weak permissions allow SQL injection or unauthorized data exposure, compromising data confidentiality and integrity.\",\n 'checks.html-referrer-leak.why':\n \"Weak HTTP headers, CORS policies, or referrer configurations expose the site to clickjacking, data exfiltration, and sensitive data leakage to third parties.\",\n 'checks.html-missing-csp.why':\n \"Weak HTTP headers, CORS policies, or referrer configurations expose the site to clickjacking, data exfiltration, and sensitive data leakage to third parties.\",\n 'checks.html-static-host-headers.why':\n \"Weak HTTP headers, CORS policies, or referrer configurations expose the site to clickjacking, data exfiltration, and sensitive data leakage to third parties.\",\n 'checks.html-inline-unsafe-script.why':\n \"Cross-site scripting (XSS) allows attackers to inject malicious client-side scripts. This can lead to session hijacking, cookie theft, or unauthorized actions on behalf of users (CWE-79).\",\n 'checks.html-css-comments-secrets.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.css-insecure-import.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-mixed-content.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-external-asset-integrity.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-insecure-form-action.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-iframe-sandbox.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-unsafe-embed.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-meta-redirect.why':\n \"Unvalidated redirects allow attackers to redirect users to malicious websites, facilitating phishing campaigns and social engineering attacks.\",\n 'checks.html-base-tag-hijack.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-javascript-uri.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.html-import-map-integrity.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.css-data-exfiltration.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.css-external-font-integrity.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-cdn-vulnerable-versions.why':\n \"Dependencies with known CVEs introduce documented vulnerabilities that attackers can exploit to compromise the application. Keeping packages updated is a core security baseline.\",\n 'checks.html-cdn-unpinned-versions.why':\n \"Unpinned dependency versions make builds non-deterministic and expose the application to unexpected breaking updates or supply-chain attacks.\",\n 'checks.html-form-pii-exposure.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-inline-resilience.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.xss-surface.why':\n \"Cross-site scripting (XSS) allows attackers to inject malicious client-side scripts. This can lead to session hijacking, cookie theft, or unauthorized actions on behalf of users (CWE-79).\",\n 'checks.os-command-injection.why':\n \"Unsafe execution of dynamic strings as code or shell commands can lead to arbitrary code execution, letting attackers take complete control of the host machine (CWE-94).\",\n 'checks.shell-arbitrary-evaluation.why':\n \"Unsafe execution of dynamic strings as code or shell commands can lead to arbitrary code execution, letting attackers take complete control of the host machine (CWE-94).\",\n 'checks.shell-unescaped-path-deletion.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.file-inclusion.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.open-redirect.why':\n \"Unvalidated redirects allow attackers to redirect users to malicious websites, facilitating phishing campaigns and social engineering attacks.\",\n 'checks.unsafe-file-upload.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.unsafe-deserialization.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.hardcoded-passwords.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.insecure-random.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.rust-unsafe-blocks.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.rust-handler-panics.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.cargo-unpinned-versions.why':\n \"Unpinned dependency versions make builds non-deterministic and expose the application to unexpected breaking updates or supply-chain attacks.\",\n 'checks.cargo-known-cves.why':\n \"Dependencies with known CVEs introduce documented vulnerabilities that attackers can exploit to compromise the application. Keeping packages updated is a core security baseline.\",\n 'checks.bundler-known-cves.why':\n \"Dependencies with known CVEs introduce documented vulnerabilities that attackers can exploit to compromise the application. Keeping packages updated is a core security baseline.\",\n 'checks.critical-check.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.high-check.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.medium-check.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.low-check.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.info-check.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.no-version-control.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.committed-env.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.hardcoded-localhost.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.dev-deps-in-prod.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.unpinned-versions.why':\n \"Unpinned dependency versions make builds non-deterministic and expose the application to unexpected breaking updates or supply-chain attacks.\",\n 'checks.known-cves.why':\n \"Dependencies with known CVEs introduce documented vulnerabilities that attackers can exploit to compromise the application. Keeping packages updated is a core security baseline.\",\n 'checks.auth-missing-endpoints.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.cors-too-permissive.why':\n \"Weak HTTP headers, CORS policies, or referrer configurations expose the site to clickjacking, data exfiltration, and sensitive data leakage to third parties.\",\n 'checks.sensitive-data-in-logs.why':\n \"Improper logging and monitoring configurations can expose sensitive debugging details to attackers or fail to provide alert visibility during active service outages.\",\n 'checks.no-rate-limiting.why':\n \"Without resource limits, timeouts, or circuit breakers, failures in external dependencies or traffic spikes can consume system threads and exhaust resources, causing outages.\",\n 'checks.no-input-validation.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-error-handling.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.no-pagination.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-timeout.why':\n \"Without resource limits, timeouts, or circuit breakers, failures in external dependencies or traffic spikes can consume system threads and exhaust resources, causing outages.\",\n 'checks.no-retry-logic.why':\n \"Without resource limits, timeouts, or circuit breakers, failures in external dependencies or traffic spikes can consume system threads and exhaust resources, causing outages.\",\n 'checks.webhook-processing-defects.why':\n \"Relying on payments provider webhooks without verifying signatures leads to security bypasses, while missing idempotency, sequence checks, or active sync checks causes out-of-sync subscriptions and payment processing loops.\",\n 'checks.no-health-check.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-structured-logging.why':\n \"Improper logging and monitoring configurations can expose sensitive debugging details to attackers or fail to provide alert visibility during active service outages.\",\n 'checks.no-graceful-shutdown.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.no-env-separation.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.default-credentials.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.verbose-errors.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.pii-in-responses.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.no-response-filtering.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-lockfile.why':\n \"Unpinned dependency versions make builds non-deterministic and expose the application to unexpected breaking updates or supply-chain attacks.\",\n 'checks.test-check.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.html-semantic-xss-review.why':\n \"Cross-site scripting (XSS) allows attackers to inject malicious client-side scripts. This can lead to session hijacking, cookie theft, or unauthorized actions on behalf of users (CWE-79).\",\n 'checks.html-semantic-cdn-review.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.weak-hash-algorithm.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.untrusted-deserialization.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.xxe-parsing.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.http-no-tls.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.path-traversal.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-csrf-protection.why':\n \"Cross-Site Request Forgery (CSRF) allows malicious sites to perform actions on behalf of authenticated users without their consent, potentially leading to unauthorized state modifications.\",\n 'checks.broken-crypto-algorithm.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.debug-artifacts.why':\n \"Improper logging and monitoring configurations can expose sensitive debugging details to attackers or fail to provide alert visibility during active service outages.\",\n 'checks.stack-trace-leak.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.hardcoded-ip.why':\n \"Exposing secrets or environment configuration details in source code makes them accessible to unauthorized users and increases the threat surface of the infrastructure.\",\n 'checks.insecure-cookie-flags.why':\n \"Weak session identifiers or insecure cookies can be intercepted or predicted by attackers, leading to session hijacking and unauthorized account access.\",\n 'checks.sensitive-error-messages.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.weak-encryption-mode.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.deprecated-functions.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.http-method-override.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-ssl-verification.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.localstorage-sensitive-data.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.unsafe-innerhtml.why':\n \"Cross-site scripting (XSS) allows attackers to inject malicious client-side scripts. This can lead to session hijacking, cookie theft, or unauthorized actions on behalf of users (CWE-79).\",\n 'checks.hardcoded-port.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.insecure-file-permissions.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-content-security-policy.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.missing-memory-limit.why':\n \"Without resource limits, timeouts, or circuit breakers, failures in external dependencies or traffic spikes can consume system threads and exhaust resources, causing outages.\",\n 'checks.missing-timeout-config.why':\n \"Without resource limits, timeouts, or circuit breakers, failures in external dependencies or traffic spikes can consume system threads and exhaust resources, causing outages.\",\n 'checks.swallowed-catch.why':\n \"Swallowed errors hide bugs, make debugging impossible in production, and can mask security incidents such as failed authentication attempts or database corruption (CWE-391).\",\n 'checks.no-backoff-jitter.why':\n \"Without jitter, all retries from multiple clients can align and overwhelm a recovering service, causing cascading failures (CWE-770).\",\n 'checks.no-circuit-breaker.why':\n \"Without a circuit breaker, a failing downstream service can tie up all your connections and threads, causing your own service to fail (CWE-1042).\",\n 'checks.infinite-retry.why':\n \"Infinite retries can exhaust memory, CPU, and network resources. They also delay failure detection, making incident response harder (CWE-834).\",\n 'checks.missing-observability.why':\n \"Without observability, you cannot detect outages, debug performance regressions, or measure the impact of deployments. Incidents become blind hunts (CWE-778).\",\n 'checks.secret-rotation-friction.why':\n \"When secrets are hardcoded, rotating them requires a code change, review, build, and deployment. This friction leads to long-lived secrets and increases blast radius if a credential is leaked (CWE-798).\",\n 'checks.env-drift.why':\n \"Drift between `.env.example` and runtime usage causes deployment failures, hidden misconfigurations, and secret sprawl. New developers may miss required variables (CWE-1188).\",\n 'checks.taint-xss.why':\n \"An attacker who can control data sent to an XSS sink can inject malicious scripts that execute in victims' browsers. This can lead to session hijacking, credential theft, or defacement.\",\n 'checks.taint-sql-injection.why':\n \"SQL injection allows attackers to read, modify, or delete database records. It is consistently one of the most common and damaging web vulnerabilities (CWE-89).\",\n 'checks.taint-command-injection.why':\n \"Command injection lets attackers execute arbitrary operating-system commands on your server. This can lead to full server compromise, data exfiltration, or ransomware deployment (CWE-78).\",\n 'checks.taint-path-traversal.why':\n \"Path traversal allows attackers to read or write files outside the intended directory, potentially exposing source code, configuration files, or secrets (CWE-22).\",\n 'checks.taint-open-redirect.why':\n \"Unvalidated redirects allow attackers to redirect users to malicious websites, facilitating phishing campaigns and social engineering attacks.\",\n 'checks.taint-prototype-pollution.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.taint-code-execution.why':\n \"Unsafe execution of dynamic strings as code or shell commands can lead to arbitrary code execution, letting attackers take complete control of the host machine (CWE-94).\",\n 'checks.weak-session-id.why':\n \"Weak session identifiers or insecure cookies can be intercepted or predicted by attackers, leading to session hijacking and unauthorized account access.\",\n 'checks.rails-mass-assignment.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.rails-insecure-session-config.why':\n \"Weak session identifiers or insecure cookies can be intercepted or predicted by attackers, leading to session hijacking and unauthorized account access.\",\n 'checks.xxe-surface.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.composite-pii.why':\n \"Combining seemingly harmless fields can uniquely identify individuals. This violates privacy regulations (GDPR, CCPA) and exposes users to identity theft (CWE-359).\",\n 'checks.derived-identifiers.why':\n \"Derived identifiers can re-identify pseudonymised users and track them without their consent. This undermines privacy guarantees and may violate regulations (CWE-359).\",\n 'checks.unredacted-logs.why':\n \"Logs are often stored in plaintext, aggregated across services, and accessible to many engineers. Unredacted PII in logs is a frequent source of data breaches and compliance violations (CWE-532).\",\n 'checks.permissive-grants.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.sql-rls-static.why':\n \"Unsafe database interactions and weak permissions allow SQL injection or unauthorized data exposure, compromising data confidentiality and integrity.\",\n 'checks.sql-security-definer-search-path.why':\n \"Unsafe database interactions and weak permissions allow SQL injection or unauthorized data exposure, compromising data confidentiality and integrity.\",\n 'checks.missing-transaction-guard.why':\n \"Failing to address this issue can lead to security vulnerabilities, operational failures, or data exposure, compromising the safety and reliability of your application.\",\n 'checks.destructive-sql-migration.why':\n \"Unsafe database interactions and weak permissions allow SQL injection or unauthorized data exposure, compromising data confidentiality and integrity.\",\n 'checks.sql-broad-mutation.why':\n \"Unsafe database interactions and weak permissions allow SQL injection or unauthorized data exposure, compromising data confidentiality and integrity.\",\n 'checks.unprotected-sensitive-sql-columns.why':\n \"Unsafe database interactions and weak permissions allow SQL injection or unauthorized data exposure, compromising data confidentiality and integrity.\",\n 'checks.sql-missing-rls.why':\n \"Unsafe database interactions and weak permissions allow SQL injection or unauthorized data exposure, compromising data confidentiality and integrity.\",\n 'checks.weak-key-entropy.why':\n \"Low-entropy keys or tokens can be predicted or brute-forced by attackers, leading to bypass of authentication or cryptographic controls (CWE-326).\",\n 'checks.insecure-api-url-default.why':\n \"Using cleartext HTTP defaults for API endpoints exposes communication to man-in-the-middle (MITM) attacks, potentially leaking sensitive data or allowing traffic interception (CWE-319).\",\n 'checks.dynamic-sql-columns.why':\n \"Interpolating dynamic column names in SQL queries bypasses parameterized query protection, introducing SQL injection risks where attackers can manipulate database structures (CWE-89).\",\n 'checks.weak-email-validation.why':\n \"Overly permissive email validation patterns allow malformed, spoofed, or malicious inputs to bypass business rules, leading to account validation issues or data corruption (CWE-20).\",\n 'checks.idempotency-key-leak.why':\n \"Embedding structured internal identifiers in idempotency keys leaks business-sensitive data (such as subscription or license IDs) to payment providers or third-party log systems (CWE-200).\",\n 'checks.plaintext-secret-in-email.why':\n \"Sending license keys or credentials in plaintext email bodies exposes them to interception or unauthorized access, as standard email is not encrypted in transit (CWE-319).\",\n} as const;\n","import { SITE_URL } from '../config/urls.js'\nimport { whyCopy } from './why-copy.js'\n\nconst copy = {\n ...whyCopy,\n // Report copy\n 'report.header': (targetDir: string, count: number) =>\n `Seaworthy — ${targetDir} — ${count} issue(s) found`,\n 'report.noIssues': 'No issues found.',\n 'report.scannedFiles': (count: number) => `Scanned ${count} files.`,\n 'report.summary': 'Summary',\n 'report.bySeverity': 'By severity',\n 'report.tierWatermark': (licensedTo: string) => `⚓ Pro · ${licensedTo}`,\n 'report.scanProgress.starting': (targetDir: string) => `⚓ Scanning ${targetDir}...`,\n 'report.scanProgress.category': (label: string, count: number) =>\n count > 0 ? ` ⚓ ${label} — ${count} issue(s)` : ` ⚓ ${label} ✓`,\n 'report.cta.clean': `✓ All clear — your project is shipshape!`,\n 'report.cta.hasFindings': `Fix these before you ship. ${SITE_URL}/docs`,\n 'report.cta.critical': `⚠ Critical issues found — patch before you deploy. ${SITE_URL}/docs`,\n 'report.proUpsellNamed': (names: string, count: number) =>\n `⚓ Pro unlocks ${count} more check${count === 1 ? '' : 's'} (${names}). ${SITE_URL}`,\n 'report.llmPrivacyWarning':\n 'Pro checks will send code context to your LLM provider via your API key. No data is sent to Seaworthy servers.',\n 'report.confidenceHigh': 'high confidence',\n 'report.confidenceMedium': 'medium confidence',\n 'report.confidenceLow': 'low confidence',\n\n // Check names & descriptions\n 'checks.no-document-write.name': 'Unsafe document.write usage',\n 'checks.no-document-write.description':\n 'Detects the use of document.write which can lead to XSS vulnerabilities',\n 'checks.no-document-write.message': (match: string) =>\n `Unsafe DOM API detected: ${match}`,\n 'checks.no-document-write.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.dangerous-eval.name': 'Dangerous eval usage',\n 'checks.dangerous-eval.description':\n 'Detects dangerous dynamic code execution such as eval(), exec(), and new Function()',\n\n 'checks.hardcoded-secrets.name': 'Hardcoded secrets',\n 'checks.hardcoded-secrets.description':\n 'API keys, tokens, passwords, connection strings in source',\n\n 'checks.secrets-in-source.name': 'Secrets in source',\n 'checks.secrets-in-source.description':\n 'Secrets in source rather than environment variables',\n\n 'checks.debug-mode-enabled.name': 'Debug mode enabled',\n 'checks.debug-mode-enabled.description':\n 'Debug / verbose logging enabled in production config or source code',\n\n 'checks.sql-injection-surface.name': 'SQL injection surface',\n 'checks.sql-injection-surface.description':\n 'Raw string concatenation in SQL queries',\n\n // Check messages\n 'checks.dangerous-eval.message': (nodeText: string) =>\n `Dangerous code execution detected: ${nodeText}()`,\n 'checks.dangerous-eval.degraded': (path: string) =>\n `Analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.hardcoded-secrets.message': (patternName: string) =>\n `Potential hardcoded ${patternName}`,\n 'checks.hardcoded-secrets.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.secrets-in-source.message': (_nodeText: string) =>\n 'Secret-like value assigned directly in source. Use environment variables instead.',\n 'checks.secrets-in-source.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-referrer-leak.name': 'HTML referrer leak',\n 'checks.html-referrer-leak.description':\n 'target=\"_blank\" anchors or forms without rel protection can leak the referrer and enable tabnabbing',\n 'checks.html-referrer-leak.message': (match: string) =>\n `Potential referrer leak or tabnabbing risk: ${match}`,\n 'checks.html-referrer-leak.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-missing-csp.name': 'HTML missing CSP',\n 'checks.html-missing-csp.description':\n 'Full HTML pages should include a robust Content Security Policy or receive one from static-host headers',\n 'checks.html-missing-csp.message': (match: string) =>\n `Missing or weak Content Security Policy: ${match}`,\n 'checks.html-missing-csp.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-static-host-headers.name': 'HTML static host headers',\n 'checks.html-static-host-headers.description':\n 'Static site host config should supply route-wide security headers for browser pages',\n 'checks.html-static-host-headers.message': (match: string) =>\n `Static host security headers are incomplete: ${match}`,\n 'checks.html-static-host-headers.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-inline-unsafe-script.name': 'HTML inline unsafe script',\n 'checks.html-inline-unsafe-script.description':\n 'Inline HTML scripts and event handlers should not perform unsafe DOM writes or execute dynamic code',\n 'checks.html-inline-unsafe-script.message': (match: string) =>\n `Unsafe inline script or event handler detected: ${match}`,\n 'checks.html-inline-unsafe-script.locationHint':\n 'Check embedded <script> blocks and inline event handlers in the surrounding HTML.',\n 'checks.html-inline-unsafe-script.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-css-comments-secrets.name': 'HTML/CSS comment secrets',\n 'checks.html-css-comments-secrets.description':\n 'Hardcoded secrets inside HTML or CSS comments and commented JSON/config snippets',\n 'checks.html-css-comments-secrets.message': (match: string) =>\n `Secret-like value found in comment or embedded JSON: ${match}`,\n 'checks.html-css-comments-secrets.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.css-insecure-import.name': 'CSS insecure import',\n 'checks.css-insecure-import.description':\n 'External CSS imports or URL loads over HTTP can leak content and enable network interception',\n 'checks.css-insecure-import.message': (match: string) =>\n `Insecure CSS import or URL load detected: ${match}`,\n 'checks.css-insecure-import.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-mixed-content.name': 'HTML mixed content',\n 'checks.html-mixed-content.description':\n 'Page resources or embedded styles load over unencrypted HTTP instead of HTTPS',\n 'checks.html-mixed-content.message': (match: string) =>\n `Mixed content resource detected: ${match}`,\n 'checks.html-mixed-content.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-external-asset-integrity.name': 'HTML external asset integrity',\n 'checks.html-external-asset-integrity.description':\n 'Third-party scripts and stylesheets should include subresource integrity and compatible crossorigin attributes',\n 'checks.html-external-asset-integrity.message': (match: string) =>\n `External asset missing integrity or crossorigin protection: ${match}`,\n 'checks.html-external-asset-integrity.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-insecure-form-action.name': 'HTML insecure form action',\n 'checks.html-insecure-form-action.description':\n 'Forms submitting over cleartext or scheme-relative URLs can leak user input and bypass transport security',\n 'checks.html-insecure-form-action.message': (match: string) =>\n `Insecure form action detected: ${match}`,\n 'checks.html-insecure-form-action.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-iframe-sandbox.name': 'HTML iframe sandbox',\n 'checks.html-iframe-sandbox.description':\n 'External iframes should use restrictive sandboxing to limit script and origin access',\n 'checks.html-iframe-sandbox.message': (match: string) =>\n `Unsafe iframe sandbox configuration detected: ${match}`,\n 'checks.html-iframe-sandbox.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-unsafe-embed.name': 'HTML unsafe embed',\n 'checks.html-unsafe-embed.description':\n 'External object and embed elements should not load active plugin content without tight type restrictions',\n 'checks.html-unsafe-embed.message': (match: string) =>\n `Unsafe external object or embed detected: ${match}`,\n 'checks.html-unsafe-embed.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-meta-redirect.name': 'HTML meta refresh redirect',\n 'checks.html-meta-redirect.description':\n 'Short-delay meta refresh redirects can be used for phishing, open redirects, or policy bypasses',\n 'checks.html-meta-redirect.message': (match: string) =>\n `Suspicious meta refresh redirect detected: ${match}`,\n 'checks.html-meta-redirect.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-base-tag-hijack.name': 'HTML base tag hijack',\n 'checks.html-base-tag-hijack.description':\n 'External or mispositioned base tags can rewrite relative URLs and alter page navigation',\n 'checks.html-base-tag-hijack.message': (match: string) =>\n `Suspicious base tag detected: ${match}`,\n 'checks.html-base-tag-hijack.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-javascript-uri.name': 'HTML javascript URI',\n 'checks.html-javascript-uri.description':\n 'javascript: URLs execute code directly from HTML attributes and can enable XSS-style execution',\n 'checks.html-javascript-uri.message': (match: string) =>\n `javascript: URI detected: ${match}`,\n 'checks.html-javascript-uri.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-import-map-integrity.name': 'HTML import map integrity',\n 'checks.html-import-map-integrity.description':\n 'Import maps should not redirect module specifiers to external origins without trust controls',\n 'checks.html-import-map-integrity.message': (match: string) =>\n `Suspicious import map mapping detected: ${match}`,\n 'checks.html-import-map-integrity.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.css-data-exfiltration.name': 'CSS data exfiltration',\n 'checks.css-data-exfiltration.description':\n 'Attribute selectors combined with external HTTP URLs can exfiltrate sensitive values from forms',\n 'checks.css-data-exfiltration.message': (match: string) =>\n `Potential CSS data exfiltration detected: ${match}`,\n 'checks.css-data-exfiltration.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.css-external-font-integrity.name': 'CSS external font integrity',\n 'checks.css-external-font-integrity.description':\n 'External CDN fonts loaded from @font-face can be supply-chain risks when self-hosting is not used',\n 'checks.css-external-font-integrity.message': (match: string) =>\n `External font loaded from public CDN: ${match}`,\n 'checks.css-external-font-integrity.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-cdn-vulnerable-versions.name': 'HTML CDN vulnerable versions',\n 'checks.html-cdn-vulnerable-versions.description':\n 'CDN-loaded scripts and stylesheets can expose known-vulnerable library versions',\n 'checks.html-cdn-vulnerable-versions.message': (match: string) =>\n `Known vulnerable CDN dependency detected: ${match}`,\n 'checks.html-cdn-vulnerable-versions.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-cdn-unpinned-versions.name': 'HTML CDN unpinned versions',\n 'checks.html-cdn-unpinned-versions.description':\n 'CDN dependencies without exact versions can change unexpectedly and should be pinned',\n 'checks.html-cdn-unpinned-versions.message': (match: string) =>\n `Unpinned or ambiguous CDN dependency detected: ${match}`,\n 'checks.html-cdn-unpinned-versions.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-form-pii-exposure.name': 'HTML form PII exposure',\n 'checks.html-form-pii-exposure.description':\n 'Forms should not keep PII in hidden inputs or expose sensitive autofill settings on fields',\n 'checks.html-form-pii-exposure.message': (match: string) =>\n `Potential form PII exposure detected: ${match}`,\n 'checks.html-form-pii-exposure.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.html-inline-resilience.name': 'HTML inline resilience',\n 'checks.html-inline-resilience.description':\n 'Inline script blocks should handle network failures explicitly and avoid infinite retries or swallowed errors',\n 'checks.html-inline-resilience.message': (match: string) =>\n `Inline script resilience issue detected: ${match}`,\n 'checks.html-inline-resilience.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.debug-mode-enabled.message': (_nodeText: string) =>\n 'Debug or verbose mode may be enabled in production configuration',\n 'checks.debug-mode-enabled.code-message': (_nodeText: string) =>\n 'Debug logging call detected in production source code',\n 'checks.debug-mode-enabled.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.sql-injection-surface.message': (_nodeText: string) =>\n 'SQL query appears to use string interpolation or concatenation',\n 'checks.sql-injection-surface.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.xss-surface.name': 'XSS surface',\n 'checks.xss-surface.description':\n 'Detects XSS-prone APIs such as innerHTML and document.write()',\n 'checks.xss-surface.message': (nodeText: string) =>\n `XSS-vulnerable API detected: ${nodeText}`,\n 'checks.xss-surface.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.os-command-injection.name': 'OS command injection surface',\n 'checks.os-command-injection.description':\n 'Detects OS command execution with potentially unsafe arguments',\n 'checks.os-command-injection.message': (nodeText: string) =>\n `OS command execution detected: ${nodeText}`,\n 'checks.os-command-injection.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.shell-arbitrary-evaluation.name': 'Shell arbitrary evaluation',\n 'checks.shell-arbitrary-evaluation.description':\n 'Shell eval or source command uses an unquoted dynamic argument.',\n 'checks.shell-arbitrary-evaluation.message': (match: string) =>\n `Unquoted shell evaluation detected: ${match}`,\n 'checks.shell-arbitrary-evaluation.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.shell-unescaped-path-deletion.name': 'Unescaped shell path deletion',\n 'checks.shell-unescaped-path-deletion.description':\n 'rm command uses an unquoted variable path that may expand unexpectedly.',\n 'checks.shell-unescaped-path-deletion.message': (match: string) =>\n `Unquoted destructive path detected: ${match}`,\n 'checks.shell-unescaped-path-deletion.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.file-inclusion.name': 'Dynamic file inclusion',\n 'checks.file-inclusion.description':\n 'Detects include/require with user-controlled or dynamic paths',\n 'checks.file-inclusion.message': (nodeText: string) =>\n `Dynamic file inclusion detected: ${nodeText}`,\n 'checks.file-inclusion.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.open-redirect.name': 'Open redirect',\n 'checks.open-redirect.description':\n 'Detects redirects that may use user-controlled URLs',\n 'checks.open-redirect.message': (nodeText: string) =>\n `Open redirect surface detected: ${nodeText}`,\n 'checks.open-redirect.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.unsafe-file-upload.name': 'Unsafe file upload',\n 'checks.unsafe-file-upload.description':\n 'Detects file uploads that use user-controlled destination paths',\n 'checks.unsafe-file-upload.message': (nodeText: string) =>\n `Unsafe file upload detected: ${nodeText}`,\n 'checks.unsafe-file-upload.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.unsafe-deserialization.name': 'Unsafe deserialization',\n 'checks.unsafe-deserialization.description':\n 'Detects deserialization of untrusted data with pickle, yaml.load, or marshal',\n 'checks.unsafe-deserialization.message': (nodeText: string) =>\n `Unsafe deserialization detected: ${nodeText}`,\n 'checks.unsafe-deserialization.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.hardcoded-passwords.name': 'Hardcoded passwords',\n 'checks.hardcoded-passwords.description':\n 'Detects password values assigned directly in source code',\n 'checks.hardcoded-passwords.message': (nodeText: string) =>\n `Hardcoded password detected: ${nodeText}`,\n 'checks.hardcoded-passwords.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.weak-key-entropy.name': 'Weak key/token entropy',\n 'checks.weak-key-entropy.description':\n 'Detects low-entropy random generation (under 16 bytes / 128 bits) used for keys, tokens, or identifiers',\n 'checks.weak-key-entropy.message': (match: string, byteCount: string) =>\n `Weak entropy for security value: ${match} generates only ${byteCount} bytes — use at least 16 bytes (128 bits)`,\n 'checks.weak-key-entropy.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.insecure-api-url-default.name': 'Insecure API URL default',\n 'checks.insecure-api-url-default.description':\n 'Detects HTTP (non-HTTPS) default URLs for API endpoints in configuration code',\n 'checks.insecure-api-url-default.message': (match: string) =>\n `Insecure API URL default: ${match} — API URLs should default to HTTPS`,\n 'checks.insecure-api-url-default.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.dynamic-sql-columns.name': 'Dynamic SQL column names',\n 'checks.dynamic-sql-columns.description':\n 'Detects template literal or string interpolation used to build SQL column names, which can allow injection if values come from user input',\n 'checks.dynamic-sql-columns.message': (match: string) =>\n `Dynamic SQL column interpolation: ${match} — use a whitelist of allowed column names instead`,\n 'checks.dynamic-sql-columns.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.weak-email-validation.name': 'Weak email validation regex',\n 'checks.weak-email-validation.description':\n 'Detects overly permissive email validation regexes that accept invalid or unsafe inputs',\n 'checks.weak-email-validation.message': (match: string) =>\n `Weak email validation regex: ${match} — use a stricter pattern or a dedicated validation library`,\n 'checks.weak-email-validation.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.idempotency-key-leak.name': 'Structured idempotency key',\n 'checks.idempotency-key-leak.description':\n 'Detects idempotency keys containing structured identifiers (subscription IDs, license IDs) that leak business data to external providers',\n 'checks.idempotency-key-leak.message': (match: string) =>\n `Structured idempotency key: ${match} — use an opaque UUID or HMAC instead of embedding business identifiers`,\n 'checks.idempotency-key-leak.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.plaintext-secret-in-email.name': 'Secret in plaintext email',\n 'checks.plaintext-secret-in-email.description':\n 'Detects license keys, tokens, or API keys rendered in plain-text email bodies without warning that email is not encrypted in transit',\n 'checks.plaintext-secret-in-email.message': (match: string) =>\n `Secret value in plain-text email body: ${match} — add a warning that email is not encrypted in transit, or omit the secret from the text body`,\n 'checks.plaintext-secret-in-email.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'remediation.security.weak-key-entropy': 'Use at least randomBytes(16) (128 bits) for keys, tokens, and identifiers. For license keys, prefer randomBytes(16) or crypto.getRandomValues() with 16+ bytes.',\n 'remediation.security.insecure-api-url-default': 'Default all API URLs to HTTPS. Override via environment variable if needed for local development, but never default to cleartext HTTP for production endpoints.',\n 'remediation.security.dynamic-sql-columns': 'Use a whitelist mapping from input keys to allowed column names. Never interpolate user-supplied strings into SQL column positions.',\n 'remediation.security.weak-email-validation': 'Use a stricter regex pattern (e.g. RFC 5322 subset) or a dedicated email validation library (e.g. Zod .email(), validator.js isEmail). At minimum, require a domain with a TLD of 2+ characters.',\n 'remediation.security.idempotency-key-leak': 'Generate idempotency keys using randomUUID() or an HMAC derived from the operation key. Never embed subscription IDs, license IDs, or other business identifiers that external providers could log.',\n 'remediation.data-exposure.plaintext-secret-in-email': 'Add a warning to the plain-text email body that email is not encrypted in transit. Consider omitting the secret from the plain-text part entirely, or linking to a secure dashboard instead.',\n\n 'checks.insecure-random.name': 'Insecure random number generator',\n 'checks.insecure-random.description':\n 'Detects use of non-cryptographic random in security-sensitive contexts',\n 'checks.insecure-random.message': (nodeText: string) =>\n `Insecure RNG detected: ${nodeText}`,\n 'checks.insecure-random.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.rust-unsafe-blocks.name': 'Unhedged unsafe blocks',\n 'checks.rust-unsafe-blocks.description': 'Usage of unsafe blocks without a preceding safety documentation comment.',\n 'checks.rust-unsafe-blocks.message': (_nodeText: string) => `Unhedged unsafe block: unsafe block lacks a preceding comment explaining why it is safe to execute.`,\n 'checks.rust-unsafe-blocks.degraded': (path: string, _language: string) => `Rust analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.rust-handler-panics.name': 'Routing handler thread-panics',\n 'checks.rust-handler-panics.description': 'Use of panicking methods like unwrap or expect inside asynchronous routing handlers.',\n 'checks.rust-handler-panics.message': (nodeText: string) => `Routing handler thread-panic: potential uncaught panic detected inside an asynchronous routing handler via ${nodeText}.`,\n 'checks.rust-handler-panics.degraded': (path: string, _language: string) => `Rust analysis was incomplete for ${path} (no grammar available)`,\n\n 'checks.cargo-unpinned-versions.name': 'Unpinned Cargo dependency versions',\n 'checks.cargo-unpinned-versions.description': 'Cargo.toml dependency with wildcard, bare semver, or unpinned git reference. Pin to an exact version.',\n 'checks.cargo-unpinned-versions.message': (match: string) => `Unpinned Cargo dependency: ${match}`,\n 'checks.cargo-unpinned-versions.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (could not parse manifest)`,\n\n 'checks.cargo-known-cves.name': 'Known CVEs in Cargo dependencies',\n 'checks.cargo-known-cves.description': 'Cargo.lock dependencies have known security advisories from the RustSec database.',\n 'checks.cargo-known-cves.message': (match: string) => `Cargo dependency CVE: ${match}`,\n 'checks.cargo-known-cves.degraded': (path: string, _language: string) => `Cargo CVE audit was unavailable for ${path} (cargo audit not installed or failed)`,\n\n 'checks.bundler-known-cves.name': 'Known CVEs in Bundler dependencies',\n 'checks.bundler-known-cves.description':\n 'Gemfile.lock dependencies have known security advisories from the Ruby advisory database.',\n 'checks.bundler-known-cves.message': (match: string) => `Bundler dependency CVE: ${match}`,\n 'checks.bundler-known-cves.degraded': (path: string, _language: string) =>\n `Bundler CVE audit was unavailable for ${path} (bundler-audit not installed or failed)`,\n\n 'checks.critical-check.name': 'Critical check',\n 'checks.critical-check.description': 'Critical severity test check',\n 'checks.high-check.name': 'High check',\n 'checks.high-check.description': 'High severity test check',\n 'checks.medium-check.name': 'Medium check',\n 'checks.medium-check.description': 'Medium severity test check',\n 'checks.low-check.name': 'Low check',\n 'checks.low-check.description': 'Low severity test check',\n 'checks.info-check.name': 'Info check',\n 'checks.info-check.description': 'Info severity test check',\n\n 'checks.no-version-control.name': 'No version control',\n 'checks.no-version-control.description':\n 'No Git repository detected. Version control is essential for collaboration and code recovery.',\n 'checks.committed-env.name': 'Committed .env file',\n 'checks.committed-env.description':\n 'A .env file is tracked by Git, exposing configuration and potential secrets in version history.',\n 'checks.hardcoded-localhost.name': 'Hardcoded localhost',\n 'checks.hardcoded-localhost.description':\n 'localhost URL is hardcoded rather than configured via environment variables.',\n 'checks.dev-deps-in-prod.name': 'Dev dependencies in production',\n 'checks.dev-deps-in-prod.description':\n 'Development-only dependencies are installed in the production dependency tree.',\n 'checks.unpinned-versions.name': 'Unpinned dependency versions',\n 'checks.unpinned-versions.description':\n 'Package.json contains version ranges (^, ~, *, latest) instead of exact pinned versions.',\n 'checks.known-cves.name': 'Known CVEs in dependencies',\n 'checks.known-cves.description':\n 'Dependencies have known security vulnerabilities with published CVEs.',\n 'checks.auth-missing-endpoints.name': 'Missing authentication',\n 'checks.auth-missing-endpoints.description':\n 'Route handler lacks authentication middleware, leaving endpoints unprotected.',\n 'checks.cors-too-permissive.name': 'Overly permissive CORS',\n 'checks.cors-too-permissive.description':\n 'CORS configuration uses a wildcard origin, allowing requests from any domain.',\n 'checks.sensitive-data-in-logs.name': 'Sensitive data in logs',\n 'checks.sensitive-data-in-logs.description':\n 'Logging statements may leak sensitive data such as credentials or PII.',\n 'checks.no-rate-limiting.name': 'No rate limiting',\n 'checks.no-rate-limiting.description':\n 'Public API endpoints lack rate limiting, making them vulnerable to abuse and DoS attacks.',\n 'checks.no-input-validation.name': 'No input validation',\n 'checks.no-input-validation.description':\n 'User input is not validated before processing, increasing risk of injection and data corruption.',\n 'checks.missing-error-handling.name': 'Missing error handling',\n 'checks.missing-error-handling.description':\n 'Async operations lack error handling, which may cause unhandled rejections or crashes.',\n 'checks.no-pagination.name': 'No pagination',\n 'checks.no-pagination.description':\n 'List endpoints return unlimited results without pagination, risking performance degradation.',\n 'checks.missing-timeout.name': 'Missing timeout',\n 'checks.missing-timeout.description':\n 'HTTP requests or database queries lack timeouts, potentially causing indefinite hangs.',\n 'checks.no-retry-logic.name': 'No retry logic',\n 'checks.no-retry-logic.description':\n 'External service calls lack retry logic, reducing resilience to transient failures.',\n 'checks.webhook-processing-defects.name': 'Webhook and Subscription Processing Defects',\n 'checks.webhook-processing-defects.description':\n 'Checks webhook handlers for missing signature checks, missing idempotency, out-of-order delivery race conditions, and lack of reconciliation fallbacks.',\n 'checks.no-health-check.name': 'No health check endpoint',\n 'checks.no-health-check.description':\n 'No health check endpoint is defined, making it harder to monitor service availability.',\n 'checks.missing-structured-logging.name': 'Missing structured logging',\n 'checks.missing-structured-logging.description':\n 'Logging uses unstructured format, making log analysis and monitoring more difficult.',\n 'checks.no-graceful-shutdown.name': 'No graceful shutdown',\n 'checks.no-graceful-shutdown.description':\n 'Server lacks graceful shutdown handling, risking dropped requests and data loss on restart.',\n 'checks.no-env-separation.name': 'No environment separation',\n 'checks.no-env-separation.description':\n 'Configuration does not differentiate between development, staging, and production environments.',\n 'checks.default-credentials.name': 'Default credentials',\n 'checks.default-credentials.description':\n 'Default or hardcoded credentials are used instead of unique, environment-specific credentials.',\n 'checks.default-credentials.message': (match: string) =>\n `Default or weak credential detected: ${match}`,\n 'checks.default-credentials.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'checks.verbose-errors.name': 'Verbose error messages',\n 'checks.verbose-errors.description':\n 'Error responses include stack traces or internal details, leaking implementation information to clients.',\n 'checks.pii-in-responses.name': 'PII in API responses',\n 'checks.pii-in-responses.description':\n 'API responses include personally identifiable information without proper filtering.',\n 'checks.no-response-filtering.name': 'No response filtering',\n 'checks.no-response-filtering.description':\n 'API responses return full database rows without filtering sensitive or unnecessary fields.',\n 'checks.missing-lockfile.name': 'Missing lockfile',\n 'checks.missing-lockfile.description':\n 'No lockfile found. Unpinned dependencies are a reproducibility and supply-chain risk.',\n 'checks.missing-lockfile.message':\n 'No lockfile found. Unpinned dependencies are a reproducibility and supply-chain risk.',\n 'checks.missing-lockfile.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n\n // Test fixtures\n 'checks.test-check.name': 'Test check',\n 'checks.test-check.description': 'A test check for unit tests',\n 'remediation.test.check': 'Test remediation for test.check',\n\n // Remediation hints\n 'remediation.security.hardcoded-secrets': 'Move this value to an environment variable and reference it via process.env.',\n 'remediation.security.dangerous-eval':\n 'Avoid eval(), exec(), and new Function(). Use safer alternatives like JSON.parse for data parsing, or refactor to eliminate dynamic code execution.',\n 'remediation.security.committed-env': 'Add .env to .gitignore. If the file is already tracked, use git rm --cached to untrack it without deleting, or rotate any exposed secrets.',\n 'remediation.security.auth-missing-endpoints': 'Apply authentication middleware to this route handler. Use requireAuth, passport, JWT verification, or session-based auth.',\n 'remediation.security.cors-too-permissive': 'Restrict Access-Control-Allow-Origin to your specific frontend domains rather than using a wildcard.',\n 'remediation.security.sql-injection-surface': 'Use parameterised queries or an ORM instead of string interpolation. Never concatenate user input into SQL strings.',\n 'remediation.security.sensitive-data-in-logs': 'Redact sensitive fields before logging. Use a logging library with automatic PII scrubbing or log only non-sensitive summary data.',\n 'remediation.resilience.no-rate-limiting': 'Add rate-limiting middleware to public routes. Use express-rate-limit, rate-limiter-flexible, or a gateway-level limiter.',\n 'remediation.resilience.no-input-validation': 'Validate user input with a schema library like zod, joi, or yup. Set request size limits on your HTTP server.',\n 'remediation.resilience.missing-error-handling': 'Add try/catch blocks around async operations. Ensure all promises have .catch() handlers or are inside an async function with error handling.',\n 'remediation.resilience.no-pagination': 'Add LIMIT and OFFSET (or .limit() / .skip() in your ORM) to list queries. Use cursor-based pagination for large datasets.',\n 'remediation.resilience.missing-timeout': 'Add a timeout to this HTTP call. Use AbortSignal.timeout() for fetch, or the timeout option for axios.',\n 'remediation.resilience.no-retry-logic': 'Wrap external calls with retry logic using p-retry, async-retry, or implement exponential backoff manually.',\n 'remediation.resilience.webhook-processing-defects':\n 'Validate headers using webhook signature secrets, log and check event IDs in a persistent cache or database, compare events occurred_at timestamps, and implement a cron fallback or check-on-access reconciliation mechanism to query the payments provider API.',\n 'remediation.ops.no-health-check': 'Add a /health or /healthz endpoint that returns a 200 status when your service is operational.',\n 'remediation.ops.hardcoded-localhost': 'Replace localhost with a configurable base URL. Use environment variables or a config module.',\n 'remediation.ops.debug-mode-enabled': 'Disable debug logging and verbose mode in production. Use environment-specific config files or flags.',\n 'remediation.ops.missing-structured-logging': 'Use a structured logging library like pino or winston with JSON output for machine-readable logs.',\n 'remediation.ops.no-graceful-shutdown': 'Listen for SIGTERM and SIGINT signals. Gracefully close server connections and drain in-flight requests before exiting.',\n 'remediation.ops.no-version-control': 'Initialize a Git repository with git init and commit your code. Regular commits provide history, collaboration, and a safety net for recovery.',\n 'remediation.dependencies.known-cves': 'Run npm audit fix or upgrade the affected dependency to a patched version.',\n 'remediation.dependencies.missing-lockfile':\n 'Commit a lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml, Gemfile.lock, go.sum, composer.lock) or Maven/Gradle reproducibility artifacts (mvnw, gradle.lockfile) to pin exact dependency versions.',\n 'remediation.dependencies.dev-deps-in-prod': 'Move this dependency from dependencies to devDependencies in package.json.',\n 'remediation.dependencies.unpinned-versions': 'Pin this dependency to an exact version. Replace ^, ~, *, or latest with a specific version number.',\n 'remediation.configuration.secrets-in-source': 'Use environment variables instead. Store the secret value in process.env and reference it by key name.',\n 'remediation.configuration.no-env-separation': 'Create separate config files per environment or use environment variables to differentiate dev/staging/prod settings.',\n 'remediation.configuration.default-credentials': 'Change default credentials immediately. Use strong, unique passwords and store them in environment variables.',\n 'remediation.data-exposure.verbose-errors': 'Catch errors in your middleware and return generic error messages to clients. Log the full error server-side only.',\n 'remediation.data-exposure.pii-in-responses': 'Filter API responses to exclude PII fields. Use select or projection to return only necessary fields.',\n 'remediation.data-exposure.no-response-filtering': 'Select only the fields you need from database queries. Never return full rows to clients without filtering.',\n 'remediation.security.no-document-write': 'Avoid document.write(). Use DOM APIs like appendChild(), innerHTML with sanitization, or a templating system instead.',\n 'remediation.security.xss-surface': 'Use textContent, React children, or a sanitization library like DOMPurify instead of innerHTML or document.write().',\n 'remediation.security.os-command-injection': 'Avoid shell execution with interpolated strings. Use parameterised APIs (e.g. execFile with args array, subprocess.run with list args).',\n 'remediation.security.shell-arbitrary-evaluation': 'Avoid eval and source for dynamic input. If a shell command is required, validate against an allow-list and pass quoted, fixed arguments.',\n 'remediation.security.shell-unescaped-path-deletion': 'Quote shell path variables and validate them before deletion. Prefer rm -rf -- \"$TARGET_DIR\" after checking the path is non-empty and under an expected base directory.',\n 'remediation.security.file-inclusion': 'Avoid dynamic include/require paths from user input. Use an allow-list of permitted files and resolve paths against a trusted base directory.',\n 'remediation.security.open-redirect': 'Validate redirect targets against an allow-list of trusted domains. Never pass raw user input into Location headers.',\n 'remediation.security.unsafe-file-upload': 'Validate file type and extension server-side, generate random filenames, and store uploads outside the web root.',\n 'remediation.security.unsafe-deserialization': 'Never deserialize untrusted data. Use yaml.safe_load, JSON, or signed formats. Avoid pickle and marshal on external input.',\n 'remediation.security.hardcoded-passwords': 'Store passwords in environment variables or a secrets manager. Never commit credentials to source code.',\n 'remediation.security.html-referrer-leak': 'Add rel=\"noopener noreferrer\" to target=\"_blank\" anchors and forms. Avoid opening untrusted destinations in a new tab without rel protection.',\n 'remediation.security.html-missing-csp': 'Add a strong Content Security Policy via the HTML head or static-host headers. Avoid unsafe wildcards and inline execution where possible.',\n 'remediation.security.html-static-host-headers': 'Configure route-wide security headers in the static host config, including CSP, Referrer-Policy, X-Content-Type-Options, frame protection, and Permissions-Policy.',\n 'remediation.security.html-inline-unsafe-script': 'Replace unsafe inline DOM writes and dynamic code with safe DOM APIs, escaped text nodes, and validated event handling.',\n 'remediation.security.html-css-comments-secrets': 'Remove secrets from comments and sample config blocks. Move credentials to runtime environment variables or a secure secret manager.',\n 'remediation.security.css-insecure-import': 'Load CSS and fonts over HTTPS only. Remove cleartext HTTP imports and URL loads from stylesheets.',\n 'remediation.security.html-mixed-content': 'Upgrade all embedded resource URLs to HTTPS. Avoid loading page assets or embedded styles over cleartext HTTP.',\n 'remediation.security.html-external-asset-integrity': 'Add integrity and crossorigin to third-party scripts and stylesheets, or self-host the asset.',\n 'remediation.security.html-insecure-form-action': 'Submit forms over HTTPS or to a same-origin relative endpoint. Avoid cleartext HTTP and scheme-relative action URLs for sensitive submissions.',\n 'remediation.security.html-iframe-sandbox': 'Add a restrictive sandbox attribute to third-party iframes. Avoid combining allow-scripts and allow-same-origin unless the content is fully trusted.',\n 'remediation.security.html-unsafe-embed': 'Prefer sandboxed iframes or self-hosted assets. Avoid loading third-party plugin content with object or embed, and restrict MIME types to safe passive content where possible.',\n 'remediation.security.html-meta-redirect': 'Replace meta refresh redirects with server-side redirects or validated client navigation. Avoid short-delay refreshes that point to external URLs or internal paths.',\n 'remediation.security.html-base-tag-hijack': 'Remove external base tags or place a same-origin base URL inside <head>. Avoid base target=\"_blank\" on untrusted pages.',\n 'remediation.security.html-javascript-uri': 'Replace javascript: URLs with normal links or buttons and event handlers. Avoid direct script execution in HTML attributes.',\n 'remediation.security.html-import-map-integrity': 'Keep import map entries on same-origin or relative URLs. Avoid mapping module specifiers to external CDNs unless you can trust and verify the source.',\n 'remediation.security.css-data-exfiltration': 'Remove attribute-selector rules that fetch external URLs. Keep sensitive form value matching and URL loads out of untrusted CSS.',\n 'remediation.security.css-external-font-integrity': 'Self-host font files or use a trusted local font source. Avoid loading fonts from public CDNs in production stylesheets.',\n 'remediation.dependencies.html-cdn-vulnerable-versions': 'Upgrade the CDN asset to a patched version or self-host the library with a pinned release and integrity controls.',\n 'remediation.dependencies.html-cdn-unpinned-versions': 'Pin the CDN asset to an exact version and use Subresource Integrity or self-host the dependency.',\n 'remediation.resilience.html-inline-resilience': 'Add timeout, retry, and explicit error handling to inline fetch/XHR logic. Avoid empty catch blocks and infinite retry loops in page scripts.',\n 'remediation.data-exposure.html-form-pii-exposure': 'Avoid storing PII in hidden inputs and set autocomplete=\"off\" on sensitive fields. Keep sensitive data server-side when possible.',\n\n 'checks.html-semantic-xss-review.name': 'HTML semantic XSS review',\n 'checks.html-semantic-xss-review.description': 'Complex inline scripts, CSP configurations, and sensitive form combinations may have subtle XSS or policy bypass risks that require deeper semantic analysis.',\n 'checks.html-semantic-xss-review.message': (match: string) => `Semantic XSS risk detected: ${match}`,\n 'checks.html-semantic-xss-review.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.html-semantic-xss-review': 'Review complex inline scripts and CSP policies for bypass paths. Sanitize all DOM inputs, use strict CSP, and avoid mixing third-party scripts with sensitive data collection.',\n\n 'checks.html-semantic-cdn-review.name': 'HTML semantic CDN review',\n 'checks.html-semantic-cdn-review.description': 'Pages loading multiple CDN scripts may have supply-chain risks from abandoned packages, typosquatting, or unverified origins.',\n 'checks.html-semantic-cdn-review.message': (match: string) => `Semantic CDN supply-chain risk detected: ${match}`,\n 'checks.html-semantic-cdn-review.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.dependencies.html-semantic-cdn-review': 'Audit all CDN dependencies for trustworthiness. Prefer self-hosting for security-critical libraries, verify publisher identities, and monitor for supply-chain compromises.',\n 'remediation.security.insecure-random': 'Use a cryptographically secure random generator (e.g. crypto.getRandomValues() in JS, secrets module in Python, SecureRandom in Java, crypto/rand in Go).',\n 'remediation.security.rust-unsafe-blocks': 'Document every unsafe block with a preceding \"// SAFETY: <explanation>\" comment explaining why the invariants are satisfied.',\n 'remediation.resilience.rust-handler-panics': 'Avoid calling unwrap(), expect(), or panic!() inside async routing handlers. Propagate errors using the \"?\" operator, or return a Result with a proper error response.',\n 'remediation.dependencies.cargo-unpinned-versions': 'Pin to an exact semver version (e.g. \"1.2.3\"). For git dependencies, include a rev, tag, or branch.',\n 'remediation.dependencies.cargo-known-cves': 'Run `cargo update` to upgrade to a patched version. Check the RustSec advisory for migration guidance.',\n 'remediation.dependencies.bundler-known-cves':\n 'Run `bundle update` to upgrade affected gems, or `bundle audit check` to list advisories. Pin patched versions in your Gemfile.',\n\n // Phase 6: external vendored rules\n\n 'checks.weak-hash-algorithm.name': 'Weak hash algorithm',\n 'checks.weak-hash-algorithm.description': 'Use of a cryptographically weak hash function such as MD5 or SHA1.',\n 'checks.weak-hash-algorithm.message': (match: string) => `Weak hash algorithm detected: ${match}`,\n 'checks.weak-hash-algorithm.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.weak-hash-algorithm': 'Use SHA-256 or stronger. For password hashing use bcrypt, scrypt, or Argon2.',\n\n 'checks.untrusted-deserialization.name': 'Untrusted deserialization',\n 'checks.untrusted-deserialization.description': 'Deserialization of user-controlled data without validation, enabling code execution attacks.',\n 'checks.untrusted-deserialization.message': (match: string) => `Untrusted deserialization detected: ${match}`,\n 'checks.untrusted-deserialization.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.untrusted-deserialization': 'Validate and sanitise deserialized data. Prefer safe parsers with type schemas. Avoid pickle.loads on untrusted input.',\n\n 'checks.xxe-parsing.name': 'XML external entity parsing',\n 'checks.xxe-parsing.description': 'XML parser called without disabling external entity expansion, enabling XXE attacks.',\n 'checks.xxe-parsing.message': (match: string) => `Potentially unsafe XML parser detected: ${match}`,\n 'checks.xxe-parsing.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.xxe-parsing': 'Disable external entity expansion in the XML parser. Use a library that is XXE-safe by default.',\n\n 'checks.http-no-tls.name': 'HTTP URL without TLS',\n 'checks.http-no-tls.description': 'Hardcoded HTTP URL that should use HTTPS for transport security.',\n 'checks.http-no-tls.message': (match: string) => `Insecure HTTP URL detected: ${match}`,\n 'checks.http-no-tls.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.http-no-tls': 'Use HTTPS URLs. Configure HSTS and redirect HTTP to HTTPS at the server level.',\n\n 'checks.path-traversal.name': 'Path traversal surface',\n 'checks.path-traversal.description': 'File path constructed by concatenating user input, enabling directory traversal attacks.',\n 'checks.path-traversal.message': (match: string) => `Path traversal surface detected: ${match}`,\n 'checks.path-traversal.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.path-traversal': 'Resolve and validate file paths against a base directory. Reject paths containing ../ or absolute paths from user input.',\n\n 'checks.missing-csrf-protection.name': 'Missing CSRF protection',\n 'checks.missing-csrf-protection.description': 'State-changing route handler without visible CSRF token verification.',\n 'checks.missing-csrf-protection.message': (match: string) => `State-changing endpoint without visible CSRF protection: ${match}`,\n 'checks.missing-csrf-protection.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.missing-csrf-protection': 'Add CSRF token verification to all state-changing endpoints. Use a CSRF middleware for your framework.',\n\n 'checks.broken-crypto-algorithm.name': 'Broken cryptographic algorithm',\n 'checks.broken-crypto-algorithm.description': 'Use of a deprecated or broken encryption algorithm such as DES or RC4.',\n 'checks.broken-crypto-algorithm.message': (match: string) => `Broken cryptographic algorithm detected: ${match}`,\n 'checks.broken-crypto-algorithm.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.broken-crypto-algorithm': 'Use AES-256-GCM or ChaCha20-Poly1305. Never use DES, RC4, or ECB mode.',\n\n 'checks.debug-artifacts.name': 'Debugger or production debug statement',\n 'checks.debug-artifacts.description': 'Debugger statement or debug import left in production code, potentially exposing runtime state.',\n 'checks.debug-artifacts.message': (match: string) => `Debug statement detected in production code: ${match}`,\n 'checks.debug-artifacts.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.debug-artifacts': 'Remove debugger statements and debug imports before deploying to production.',\n\n 'checks.stack-trace-leak.name': 'Stack trace exposure',\n 'checks.stack-trace-leak.description': 'Raw error object sent in a response, potentially leaking stack traces to clients.',\n 'checks.stack-trace-leak.message': (match: string) => `Stack trace exposure detected: ${match}`,\n 'checks.stack-trace-leak.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.stack-trace-leak': 'Send generic error messages to clients. Log the full error server-side.',\n\n 'checks.hardcoded-ip.name': 'Hardcoded IP address',\n 'checks.hardcoded-ip.description': 'A literal IP address in source code, which may leak internal infrastructure details.',\n 'checks.hardcoded-ip.message': (match: string) => `Hardcoded IP address detected: ${match}`,\n 'checks.hardcoded-ip.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.hardcoded-ip': 'Move IP addresses to configuration or environment variables. Use DNS names where possible.',\n\n 'checks.insecure-cookie-flags.name': 'Cookie missing secure flags',\n 'checks.insecure-cookie-flags.description': 'Cookie set without explicit security flags (HttpOnly, Secure, SameSite).',\n 'checks.insecure-cookie-flags.message': (match: string) => `Cookie set without visible security flags: ${match}`,\n 'checks.insecure-cookie-flags.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.configuration.insecure-cookie-flags': 'Set HttpOnly, Secure, and SameSite=Strict on session cookies.',\n\n 'checks.sensitive-error-messages.name': 'Sensitive error response',\n 'checks.sensitive-error-messages.description': 'Error response includes stack trace or internal details, leaking implementation information.',\n 'checks.sensitive-error-messages.message': (match: string) => `Sensitive error details in response: ${match}`,\n 'checks.sensitive-error-messages.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.ops.sensitive-error-messages': 'Return generic error messages to clients. Log full error details server-side only.',\n\n 'checks.weak-encryption-mode.name': 'Weak encryption mode',\n 'checks.weak-encryption-mode.description': 'Use of a raw cipher initialisation that may lack authentication (AEAD).',\n 'checks.weak-encryption-mode.message': (match: string) => `Weak encryption mode detected: ${match}`,\n 'checks.weak-encryption-mode.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.weak-encryption-mode': 'Use authenticated encryption (AES-256-GCM, ChaCha20-Poly1305). Avoid raw CBC/CTR without a MAC.',\n\n 'checks.deprecated-functions.name': 'Deprecated function usage',\n 'checks.deprecated-functions.description': 'Use of a Node.js or library function that has been deprecated.',\n 'checks.deprecated-functions.message': (match: string) => `Deprecated function detected: ${match}`,\n 'checks.deprecated-functions.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.dependencies.deprecated-functions': 'Replace deprecated functions with their recommended alternatives. Check the library migration guide.',\n\n 'checks.http-method-override.name': 'HTTP method override',\n 'checks.http-method-override.description': 'methodOverride middleware enabled, allowing clients to override HTTP methods via query parameters or headers.',\n 'checks.http-method-override.message': (match: string) => `HTTP method override detected: ${match}`,\n 'checks.http-method-override.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.http-method-override': 'Disable methodOverride or restrict it to trusted clients. Prefer standard HTTP methods.',\n\n 'checks.missing-ssl-verification.name': 'TLS verification disabled',\n 'checks.missing-ssl-verification.description': 'rejectUnauthorized set to false, disabling TLS certificate validation.',\n 'checks.missing-ssl-verification.message': (match: string) => `TLS verification disabled: ${match}`,\n 'checks.missing-ssl-verification.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.configuration.missing-ssl-verification': 'Never set rejectUnauthorized to false in production. Use proper TLS certificates.',\n\n 'checks.localstorage-sensitive-data.name': 'Sensitive data in localStorage',\n 'checks.localstorage-sensitive-data.description': 'Storing sensitive data (password, token, secret) in localStorage is insecure.',\n 'checks.localstorage-sensitive-data.message': (match: string) => `Sensitive data stored in localStorage: ${match}`,\n 'checks.localstorage-sensitive-data.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.localstorage-sensitive-data': 'Do not store sensitive data in localStorage. Use httpOnly cookies or secure server-side storage.',\n\n 'checks.unsafe-innerhtml.name': 'Unsafe innerHTML assignment',\n 'checks.unsafe-innerhtml.description': 'Assignment to innerHTML can lead to XSS if user input is included.',\n 'checks.unsafe-innerhtml.message': (match: string) => `Unsafe innerHTML assignment detected: ${match}`,\n 'checks.unsafe-innerhtml.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.unsafe-innerhtml': 'Use textContent or sanitize HTML before assigning to innerHTML. Use a library like DOMPurify.',\n\n 'checks.hardcoded-port.name': 'Hardcoded port',\n 'checks.hardcoded-port.description': 'Server port number hardcoded rather than configured via environment variables.',\n 'checks.hardcoded-port.message': (match: string) => `Hardcoded port detected: ${match}`,\n 'checks.hardcoded-port.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.ops.hardcoded-port': 'Use process.env.PORT with a fallback value. Never hardcode port numbers in source.',\n\n 'checks.insecure-file-permissions.name': 'Insecure file permissions',\n 'checks.insecure-file-permissions.description': 'fs.chmod call that may set overly permissive file permissions.',\n 'checks.insecure-file-permissions.message': (match: string) => `Insecure file permission operation detected: ${match}`,\n 'checks.insecure-file-permissions.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.ops.insecure-file-permissions': 'Use the most restrictive file permissions possible. Prefer 0o600 for secrets, 0o644 for config.',\n\n 'checks.missing-content-security-policy.name': 'Missing Content Security Policy',\n 'checks.missing-content-security-policy.description': 'Express app.use middleware chain detected; verify CSP header is set.',\n 'checks.missing-content-security-policy.message': (match: string) => `App middleware chain detected; verify CSP is configured: ${match}`,\n 'checks.missing-content-security-policy.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.configuration.missing-content-security-policy': 'Add a Content-Security-Policy header via helmet or a custom middleware.',\n\n 'checks.missing-memory-limit.name': 'Missing memory limit',\n 'checks.missing-memory-limit.description': 'Buffer.alloc used without a maximum size check for user-controlled sizes.',\n 'checks.missing-memory-limit.message': (match: string) => `Memory allocation without visible limit: ${match}`,\n 'checks.missing-memory-limit.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.missing-memory-limit': 'Enforce a maximum allocation size before calling Buffer.alloc. Reject user-controlled sizes above a safe threshold.',\n\n 'checks.missing-timeout-config.name': 'Missing timeout configuration',\n 'checks.missing-timeout-config.description': 'HTTP client call without an explicit timeout configuration.',\n 'checks.missing-timeout-config.message': (match: string) => `HTTP request without visible timeout: ${match}`,\n 'checks.missing-timeout-config.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.missing-timeout-config': 'Add a timeout to HTTP requests. Use AbortSignal.timeout() for fetch or the timeout option for axios.',\n\n // Phase 8a: Resilience checks\n 'checks.swallowed-catch.name': 'Swallowed catch block',\n 'checks.swallowed-catch.description': 'Empty catch blocks swallow errors without handling',\n 'checks.swallowed-catch.message': (match: string) => `Empty catch block swallows errors: ${match}`,\n 'checks.swallowed-catch.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.swallowed-catch': 'Add proper error handling in catch blocks. Log errors, re-throw when appropriate, or handle the specific error case.',\n\n 'checks.no-backoff-jitter.name': 'Missing backoff jitter',\n 'checks.no-backoff-jitter.description': 'Retry loops without jitter cause thundering herd',\n 'checks.no-backoff-jitter.message': (match: string) => `Retry logic lacks exponential backoff or jitter: ${match}`,\n 'checks.no-backoff-jitter.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.no-backoff-jitter': 'Add exponential backoff with jitter to retry logic. Use a library like p-retry or implement jitter with Math.random().',\n\n 'checks.no-circuit-breaker.name': 'Missing circuit breaker',\n 'checks.no-circuit-breaker.description': 'Missing circuit breaker around external calls',\n 'checks.no-circuit-breaker.message': (match: string) => `External call without circuit breaker: ${match}`,\n 'checks.no-circuit-breaker.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.no-circuit-breaker': 'Add a circuit breaker around external service calls. Use a library like opossum or implement a simple state machine.',\n\n 'checks.infinite-retry.name': 'Infinite retry loop',\n 'checks.infinite-retry.description': 'Retry loops without max-attempts',\n 'checks.infinite-retry.message': (match: string) => `Retry loop has no maximum attempt limit: ${match}`,\n 'checks.infinite-retry.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.infinite-retry': 'Add a maximum attempt counter to retry loops. Use a for loop with a fixed limit or a while loop with a counter and break condition.',\n\n // Phase 8b: Ops checks\n 'checks.missing-observability.name': 'Missing observability',\n 'checks.missing-observability.description': 'No metrics, tracing, or structured telemetry hooks',\n 'checks.missing-observability.message': (match: string) => `Missing observability hooks: ${match}`,\n 'checks.missing-observability.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.ops.missing-observability': 'Add metrics, tracing, or structured logging to your service. Use libraries like prom-client, dd-trace, or OpenTelemetry to emit observable telemetry.',\n\n 'checks.secret-rotation-friction.name': 'Secret rotation friction',\n 'checks.secret-rotation-friction.description': 'Hardcoded secret paths impeding automated rotation',\n 'checks.secret-rotation-friction.message': (match: string) => `Secret rotation friction detected: ${match}`,\n 'checks.secret-rotation-friction.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.ops.secret-rotation-friction': 'Load secrets from a secret manager (e.g., AWS Secrets Manager, HashiCorp Vault, Azure Key Vault) instead of hardcoding them. This enables automated rotation without redeploying code.',\n\n 'checks.env-drift.name': 'Environment drift',\n 'checks.env-drift.description': '.env.example is out of sync with runtime environment variable usage',\n 'checks.env-drift.message': (match: string) => `Environment variable drift detected: ${match}`,\n 'checks.env-drift.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.ops.env-drift': 'Keep .env.example in sync with the variables your code reads at runtime. Add a CI check or lint rule that flags missing or unused environment variables.',\n\n // Errors\n 'errors.unexpected': 'An unexpected error occurred.',\n 'errors.license.invalid': 'License key is invalid or has been revoked.',\n 'errors.license.server_unreachable': 'License server unreachable. Aborting.',\n 'errors.license.rate_limited': 'Too many license validation requests. Please try again later.',\n 'errors.license.invalid_response': 'License server returned an invalid response.',\n 'errors.license.expired': 'License token has expired. Please re-validate.',\n 'errors.license.server_error': 'License server returned an unexpected error.',\n 'errors.config.invalid': 'Invalid configuration.',\n 'errors.network.unreachable': 'Network unavailable.',\n 'errors.llm.timeout': 'LLM request timed out. Please try again later.',\n 'errors.llm.rate_limited':\n 'LLM rate limit reached. Please wait a moment and retry.',\n 'errors.llm.invalid_response': 'LLM returned an invalid response.',\n 'errors.scan.failed': 'Scan failed.',\n 'errors.scan.timed_out': (seconds: number) => `Scan timed out after ${seconds} seconds.`,\n 'errors.fs.not_a_directory': (path: string) =>\n `Path is not a directory: ${path}`,\n 'errors.fs.not_found': (path: string) => `Path not found: ${path}`,\n 'errors.fs.permission_denied': (path: string) =>\n `Permission denied: ${path}`,\n 'errors.cli.mutually_exclusive':\n 'Flags --json and --output cannot be used together.',\n 'errors.cli.sarif.mutually_exclusive':\n 'Flags --sarif and --sarif-stdout cannot be used together.',\n 'errors.cli.sarif.stdout_conflict':\n 'Flags --sarif-stdout and --json cannot be used together. Use --output to send JSON to a file.',\n 'errors.cli.findings_found':\n 'Scan found issues and --fail-on-findings was set.',\n 'cli.sarif.mutually_exclusive':\n 'Flags --sarif and --sarif-stdout cannot be used together.',\n 'cli.sarif.stdout_conflict':\n 'Flags --sarif-stdout and --json cannot be used together. Use --output to send JSON to a file.',\n 'cli.error.outputInsideTarget':\n 'Cannot write report inside the scanned directory.',\n 'errors.parse.binary_file': 'File appears to be binary and was skipped.',\n\n // Warnings\n 'warnings.deps.tree_exceeded':\n 'Dependency tree exceeded 500 packages. Results may be incomplete.',\n\n // Debug\n 'debug.submodule_skipped': (path: string) =>\n `Submodule ${path} not initialised, skipping.`,\n 'debug.symlink_loop': (path: string) =>\n `Symlink loop detected at ${path}, skipping.`,\n 'debug.symlink_dir_skipped': (path: string) =>\n `Directory symlink skipped: ${path}.`,\n 'debug.cache_read_failed': (key: string) =>\n `Cache read failed for key ${key}, will re-parse.`,\n 'debug.cache_write_failed': (key: string) =>\n `Cache write failed for key ${key}, skipping.`,\n\n // CLI\n 'cli.help.description': 'Seaworthy — static analysis for vibe coders',\n 'cli.help.usage': 'Usage: seaworthy [path] [options]',\n 'cli.help.options': 'Options',\n 'cli.scanning': 'Scanning...',\n 'cli.reportWritten': (path: string) => `Report written to ${path}`,\n\n // Taint checks\n 'checks.taint-xss.name': 'XSS via tainted data',\n 'checks.taint-xss.description': 'User-controlled data flows to an XSS sink without sanitisation.',\n 'checks.taint-xss.message': (_sourceId: string, _sinkId: string) =>\n 'Tainted data reaches an XSS sink without sanitisation',\n 'checks.taint-xss.degraded': (path: string, language: string) =>\n `${language} taint analysis was incomplete for ${path} (no taint table available)`,\n 'checks.taint-xss.suggestion':\n 'Sanitise user input before rendering. Use a library like DOMPurify for HTML or validator.escape for text content.',\n 'remediation.security.taint-xss': 'Sanitise user input before rendering. Use encodeURIComponent for URLs, or a library like DOMPurify for HTML.',\n\n 'checks.taint-sql-injection.name': 'SQL injection via tainted data',\n 'checks.taint-sql-injection.description': 'User-controlled data flows to a SQL query sink without parameterisation.',\n 'checks.taint-sql-injection.message': (_sourceId: string, _sinkId: string) =>\n 'Tainted data reaches a SQL sink without parameterisation',\n 'checks.taint-sql-injection.degraded': (path: string, language: string) =>\n `${language} taint analysis was incomplete for ${path} (no taint table available)`,\n 'remediation.security.taint-sql-injection': 'Use parameterised queries or an ORM. Never concatenate user input into SQL strings.',\n\n 'checks.taint-command-injection.name': 'Command injection via tainted data',\n 'checks.taint-command-injection.description': 'User-controlled data flows to a command execution sink without sanitisation.',\n 'checks.taint-command-injection.message': (_sourceId: string, _sinkId: string) =>\n 'Tainted data reaches a command sink without sanitisation',\n 'checks.taint-command-injection.degraded': (path: string, language: string) =>\n `${language} taint analysis was incomplete for ${path} (no taint table available)`,\n 'remediation.security.taint-command-injection': 'Avoid shell execution with interpolated strings. Use parameterised APIs (e.g. execFile with args array).',\n\n 'checks.taint-path-traversal.name': 'Path traversal via tainted data',\n 'checks.taint-path-traversal.description': 'User-controlled data flows to a filesystem sink without path validation.',\n 'checks.taint-path-traversal.message': (_sourceId: string, _sinkId: string) =>\n 'Tainted data reaches a filesystem sink without path validation',\n 'checks.taint-path-traversal.degraded': (path: string, language: string) =>\n `${language} taint analysis was incomplete for ${path} (no taint table available)`,\n 'checks.taint-path-traversal.suggestion':\n 'Resolve the user-provided path against a configured base directory. Example: path.resolve(SAFE_ROOT, userPath) where SAFE_ROOT is defined in your project config.',\n 'remediation.security.taint-path-traversal': 'Resolve paths against a trusted base directory, reject parent-segment sequences, and avoid passing raw user strings into fs APIs.',\n\n 'checks.taint-open-redirect.name': 'Open redirect via tainted data',\n 'checks.taint-open-redirect.description': 'User-controlled data flows to a redirect sink without URL validation.',\n 'checks.taint-open-redirect.message': (_sourceId: string, _sinkId: string) =>\n 'Tainted data reaches a redirect sink without URL validation',\n 'checks.taint-open-redirect.degraded': (path: string, language: string) =>\n `${language} taint analysis was incomplete for ${path} (no taint table available)`,\n 'remediation.security.taint-open-redirect':\n 'Validate redirect targets against an allow-list of trusted domains. Never pass raw user input into redirect helpers or Location headers.',\n\n 'checks.taint-prototype-pollution.name': 'Prototype pollution via tainted data',\n 'checks.taint-prototype-pollution.description':\n 'User-controlled data flows to an object merge or assignment sink without sanitisation.',\n 'checks.taint-prototype-pollution.message': (_sourceId: string, _sinkId: string) =>\n 'Tainted data reaches a prototype pollution sink without sanitisation',\n 'checks.taint-prototype-pollution.degraded': (path: string, language: string) =>\n `${language} taint analysis was incomplete for ${path} (no taint table available)`,\n 'remediation.security.taint-prototype-pollution':\n 'Validate and block __proto__, constructor, and prototype keys before merging objects. Use Object.create(null) for dictionaries.',\n\n 'checks.taint-code-execution.name': 'Code execution via tainted data',\n 'checks.taint-code-execution.description':\n 'User-controlled data flows to a dynamic code execution sink without sanitisation.',\n 'checks.taint-code-execution.message': (_sourceId: string, _sinkId: string) =>\n 'Tainted data reaches a code execution sink without sanitisation',\n 'checks.taint-code-execution.degraded': (path: string, language: string) =>\n `${language} taint analysis was incomplete for ${path} (no taint table available)`,\n 'remediation.security.taint-code-execution':\n 'Avoid eval(), exec(), and new Function() with user input. Use safer alternatives like JSON.parse for data parsing.',\n\n 'checks.weak-session-id.name': 'Weak session identifier',\n 'checks.weak-session-id.description':\n 'Session identifier derived from user-controlled or predictable input.',\n 'checks.weak-session-id.message': (match: string) => `User-influenced session identifier: ${match}`,\n 'checks.weak-session-id.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.weak-session-id':\n 'Generate session identifiers server-side with a cryptographically secure random source. Never accept client-supplied session IDs.',\n\n 'checks.rails-mass-assignment.name': 'Rails mass assignment',\n 'checks.rails-mass-assignment.description': 'Active Record model created or updated with raw params hash, bypassing strong parameters.',\n 'checks.rails-mass-assignment.message': (match: string) => `Unprotected mass assignment detected: ${match}`,\n 'checks.rails-mass-assignment.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.rails-mass-assignment': 'Use strong parameters with params.require(:model).permit(:attr1, :attr2) to whitelist allowed attributes.',\n\n 'checks.rails-insecure-session-config.name': 'Rails insecure session config',\n 'checks.rails-insecure-session-config.description': 'Session cookie is missing secure flags (secure, httponly, same_site).',\n 'checks.rails-insecure-session-config.message': (match: string) => `Session cookie missing security flag: ${match}`,\n 'checks.rails-insecure-session-config.degraded': (path: string, language: string) => `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.rails-insecure-session-config': 'Set secure: true, httponly: true, and same_site: :strict on session cookies in config/initializers/session_store.rb.',\n\n 'checks.xxe-surface.name': 'XXE-vulnerable XML parsing',\n 'checks.xxe-surface.description':\n 'XML parser invoked with external entity expansion enabled (e.g. libxml noent: true), enabling XXE attacks.',\n 'checks.xxe-surface.message': (match: string) => `XXE-vulnerable XML parser detected: ${match}`,\n 'checks.xxe-surface.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.xxe-surface':\n 'Disable external entity expansion in the XML parser. Use a library that is XXE-safe by default.',\n\n // Phase 8c: Data exposure checks\n 'checks.composite-pii.name': 'Composite PII fields',\n 'checks.composite-pii.description': 'Multiple PII attributes collected together enabling re-identification',\n 'checks.composite-pii.message': (match: string) => `Composite PII detected: ${match}`,\n 'checks.composite-pii.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.composite-pii': 'Split or pseudonymise composite PII fields. Avoid storing multiple identifying attributes in the same record or API response.',\n\n 'checks.derived-identifiers.name': 'Derived identifiers',\n 'checks.derived-identifiers.description': 'Derived or synthetic identifiers that enable record linkage across sessions or datasets',\n 'checks.derived-identifiers.message': (match: string) => `Derived identifier detected: ${match}`,\n 'checks.derived-identifiers.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.derived-identifiers': 'Avoid creating derived identifiers from user data for tracking or correlation. Use anonymous session tokens that cannot be reversed to identify the user.',\n\n 'checks.unredacted-logs.name': 'Unredacted logs',\n 'checks.unredacted-logs.description': 'PII or sensitive data written to logs without redaction',\n 'checks.unredacted-logs.message': (match: string) => `Sensitive data logged without redaction: ${match}`,\n 'checks.unredacted-logs.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.unredacted-logs': 'Redact or mask sensitive fields before logging. Use a structured logging library with automatic PII scrubbing or log only non-sensitive summary data.',\n\n // SQL check copy keys\n 'checks.permissive-grants.name': 'Permissive grants',\n 'checks.permissive-grants.description': 'Granting extensive privileges (like GRANT ALL) to public or anonymous roles is insecure.',\n 'checks.permissive-grants.message': (match: string) => `Broad privileges granted to public/anonymous roles: ${match}`,\n 'checks.permissive-grants.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.permissive-grants': 'Restrict privileges by granting only necessary permissions (e.g. SELECT, INSERT) to specific, authorized roles rather than PUBLIC or anonymous roles.',\n\n 'checks.sql-rls-static.name': 'Missing or weak row-level security',\n 'checks.sql-rls-static.description': 'PostgreSQL tables containing private tenant data must enable and enforce Row-Level Security (RLS).',\n 'checks.sql-rls-static.message': (match: string) => `Row-Level Security is not enabled or lacks restriction on a private/tenant table: ${match}`,\n 'checks.sql-rls-static.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.sql-rls-static': 'Enable Row-Level Security via ALTER TABLE ... ENABLE ROW LEVEL SECURITY and FORCE ROW LEVEL SECURITY, and define restrictive policies with user boundary checks.',\n\n 'checks.sql-security-definer-search-path.name': 'Security definer function search path',\n 'checks.sql-security-definer-search-path.description': 'Functions defined as SECURITY DEFINER execute with privileges of the owner and must lock the search_path to prevent hijacking.',\n 'checks.sql-security-definer-search-path.message': (match: string) => `SECURITY DEFINER function is missing a locked search_path: ${match}`,\n 'checks.sql-security-definer-search-path.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.sql-security-definer-search-path': 'Add an explicit \"SET search_path = public\" or trusted schema when creating SECURITY DEFINER functions to lock execution context.',\n\n 'checks.missing-transaction-guard.name': 'Missing transaction guard in large migrations',\n 'checks.missing-transaction-guard.description': 'Large migrations with multiple data mutations should run inside a transaction to prevent partial applications and state corruption.',\n 'checks.missing-transaction-guard.message': 'Large migration script lacks BEGIN/COMMIT transaction boundaries.',\n 'checks.missing-transaction-guard.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.missing-transaction-guard': 'Wrap the entire migration script inside a transaction using BEGIN; and COMMIT; statements.',\n\n 'checks.destructive-sql-migration.name': 'Destructive migration operation',\n 'checks.destructive-sql-migration.description': 'Destructive operations like DROP TABLE, DROP COLUMN, or TRUNCATE pose high risk of data loss.',\n 'checks.destructive-sql-migration.message': (match: string) => `Destructive database migration operation detected: ${match}`,\n 'checks.destructive-sql-migration.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.destructive-sql-migration': 'Verify that this destructive change is intended and has safe rollback/data preservation procedures in place.',\n\n 'checks.sql-broad-mutation.name': 'Broad data mutation',\n 'checks.sql-broad-mutation.description': 'UPDATE or DELETE statements without a WHERE clause (or with a tautology like WHERE true) mutate the entire table.',\n 'checks.sql-broad-mutation.message': (match: string) => `Broad UPDATE/DELETE statement lacks selective WHERE boundaries: ${match}`,\n 'checks.sql-broad-mutation.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.resilience.sql-broad-mutation': 'Specify a restrictive WHERE clause on the UPDATE or DELETE statement to target only intended rows.',\n\n 'checks.unprotected-sensitive-sql-columns.name': 'Sensitive columns without protection',\n 'checks.unprotected-sensitive-sql-columns.description': 'Storing highly sensitive fields (like SSNs, cards, or plain API keys) without encryption or hashing poses high data exposure risks.',\n 'checks.unprotected-sensitive-sql-columns.message': (match: string) => `Highly sensitive column name is stored without evident encryption or protection: ${match}`,\n 'checks.unprotected-sensitive-sql-columns.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.data-exposure.unprotected-sensitive-sql-columns': 'Encrypt sensitive data columns at rest, or use hashed/digest representations for fields like passwords or API tokens.',\n\n 'checks.sql-missing-rls.name': 'Missing RLS on sensitive tables (Pro)',\n 'checks.sql-missing-rls.description': 'PostgreSQL tables containing private tenant data must enable and enforce Row-Level Security (RLS).',\n 'checks.sql-missing-rls.message': (match: string) => `RLS is not enabled or lacks restriction on a private/tenant table: ${match}`,\n 'checks.sql-missing-rls.degraded': (path: string, language: string) =>\n `${language} analysis was incomplete for ${path} (no grammar available)`,\n 'remediation.security.sql-missing-rls': 'Define a policy with CREATE POLICY ... ON ... USING (...) to restrict data access to authorized users.',\n\n // Reporting labels\n 'reporting.analysisType.pattern': 'pattern',\n 'reporting.analysisType.semantic': 'semantic',\n} as const\n\nexport type CopyKey = keyof typeof copy\n\ntype CopyValue<K extends CopyKey> = (typeof copy)[K]\n\ntype CopyArgs<K extends CopyKey> = CopyValue<K> extends (...args: infer P) => unknown\n ? P\n : never[]\n\n/**\n * Retrieve a user-facing string from the copy registry.\n *\n * @param key - The copy key to look up.\n * @param args - Arguments required by the copy entry (if it is a function).\n * @returns The resolved copy string.\n */\nexport function getCopy<K extends CopyKey>(key: K, ...args: CopyArgs<K>): string {\n const value = copy[key]\n if (value === undefined) {\n throw new Error(`Copy key \"${key}\" not found`)\n }\n if (typeof value === 'function') {\n return (value as (...args: unknown[]) => string)(...args)\n }\n return value as string\n}\n","import type { Finding } from './types/finding.js'\nimport { readFileSync, writeFileSync, existsSync } from 'fs'\nimport { join } from 'path'\n\nexport type BaselineState = 'new' | 'existing' | 'absent'\n\nexport interface BaselineEntry {\n checkId: string\n file?: string\n line?: number\n column?: number\n message: string\n severity: Finding['severity']\n}\n\nexport interface BaselineDocument {\n version: 1\n createdAt: string\n targetDir: string\n findings: BaselineEntry[]\n}\n\nconst BASELINE_FILENAME = 'seaworthy.baseline.json'\n\nfunction findingKey(f: BaselineEntry | Finding): string {\n return `${f.checkId}::${f.file ?? ''}::${f.line ?? 0}::${f.column ?? 0}::${f.message}`\n}\n\nexport function toBaselineEntries(findings: Finding[]): BaselineEntry[] {\n return findings.map((f) => ({\n checkId: f.checkId,\n file: f.file,\n line: f.line,\n column: f.column,\n message: f.message,\n severity: f.severity,\n }))\n}\n\nexport function computeBaseline(\n current: Finding[],\n baseline: BaselineEntry[]\n): Finding[] {\n const baselineMap = new Map<string, BaselineEntry>()\n for (const b of baseline) {\n baselineMap.set(findingKey(b), b)\n }\n\n const result: Finding[] = []\n for (const f of current) {\n const key = findingKey(f)\n const state: BaselineState = baselineMap.has(key) ? 'existing' : 'new'\n result.push({ ...f, baselineState: state })\n }\n\n return result\n}\n\nexport function resolveBaselinePath(targetDir: string, explicitPath?: string): string {\n if (explicitPath) {\n return explicitPath\n }\n return join(targetDir, BASELINE_FILENAME)\n}\n\nexport function loadBaseline(path: string): BaselineEntry[] | null {\n if (!existsSync(path)) {\n return null\n }\n try {\n const doc: BaselineDocument = JSON.parse(readFileSync(path, 'utf-8'))\n if (doc.version !== 1 || !Array.isArray(doc.findings)) {\n return null\n }\n return doc.findings\n } catch {\n return null\n }\n}\n\nexport function saveBaseline(\n path: string,\n targetDir: string,\n findings: Finding[]\n): void {\n const doc: BaselineDocument = {\n version: 1,\n createdAt: new Date().toISOString(),\n targetDir,\n findings: toBaselineEntries(findings),\n }\n writeFileSync(path, JSON.stringify(doc, null, 2))\n}\n","import type { Check, ScanContext, Tier, LLMProvider, Category } from '../types/check.js'\nimport type { Finding, Confidence } from '../types/finding.js'\nimport type { AnalyseResult } from '../taint/bfs.js'\nimport { registry } from '../registry/index.js'\nimport { crawl } from '../crawler.js'\nimport { dedupeFindings } from './dedupe.js'\nimport { dedupeCrossCheck } from './dedupe-cross-check.js'\nimport { sortFindings } from './sort-findings.js'\nimport { dedupeDegradedFindings } from '../reporting/dedupe-degraded.js'\nimport { filterByMinConfidence } from '../checks/helpers/confidence.js'\nimport { getCopy } from '../copy/index.js'\nimport { computeBaseline, loadBaseline, saveBaseline, resolveBaselinePath } from '../baseline.js'\n\nexport interface ScanOptions {\n targetDir: string\n tier: Tier\n llm?: LLMProvider | null\n concurrency?: number\n maxFileSize?: number\n debug?: boolean\n /**\n * Baseline mode:\n * - `save`: Save current findings as baseline (overwrites existing)\n * - `string` path: Load baseline from file and diff against current findings\n */\n baseline?: 'save' | string\n /** Omit findings below this confidence level (high > medium > low). */\n minConfidence?: Confidence\n /** Called once per category when all checks in that category complete. */\n onCategoryComplete?: (category: Category, findingsCount: number) => void\n}\n\nexport interface ScanResult {\n findings: Finding[]\n scannedFileCount: number\n skippedChecks: Array<{ id: string; name: string; category: Category }>\n}\n\nasync function runWithConcurrency<T>(\n items: T[],\n fn: (item: T) => Promise<void>,\n concurrency: number\n): Promise<void> {\n let idx = 0\n const workers: Promise<void>[] = []\n\n for (let w = 0; w < concurrency; w++) {\n workers.push(\n (async () => {\n while (idx < items.length) {\n const i = idx++\n await fn(items[i]!)\n }\n })()\n )\n }\n\n await Promise.all(workers)\n}\n\nexport async function runWithConcurrencyCollect<T, R>(\n items: T[],\n fn: (item: T) => Promise<R>,\n concurrency: number\n): Promise<R[]> {\n const results: R[] = new Array(items.length)\n let idx = 0\n const workers: Promise<void>[] = []\n\n for (let w = 0; w < concurrency; w++) {\n workers.push(\n (async () => {\n while (idx < items.length) {\n const i = idx++\n results[i] = await fn(items[i]!)\n }\n })()\n )\n }\n\n await Promise.all(workers)\n return results\n}\n\nexport class ScanRunner {\n async run(options: ScanOptions): Promise<ScanResult> {\n const { concurrency = 4 } = options\n const { files, meta } = await crawl({ targetDir: options.targetDir, maxFileSize: options.maxFileSize, debug: options.debug })\n const checks = registry.getForTier(options.tier)\n const skippedChecks = registry.getSkippedChecks(options.tier)\n\n if (options.llm) {\n console.error(getCopy('report.llmPrivacyWarning'))\n }\n\n const ctx: ScanContext = {\n targetDir: options.targetDir,\n llm: options.llm ?? null,\n tier: options.tier,\n files,\n meta,\n taintCache: new Map<string, Promise<AnalyseResult>>(),\n astCache: new Map<string, Promise<{ tree: import('web-tree-sitter').Tree; source: string }>>(),\n }\n\n const results: Finding[] = []\n const mutex: Finding[] = []\n\n const inFlight = new Map<Category, number>()\n const findingsPerCategory = new Map<Category, number>()\n for (const check of checks) {\n inFlight.set(check.category, (inFlight.get(check.category) ?? 0) + 1)\n }\n\n await runWithConcurrency(\n checks,\n async (check: Check) => {\n try {\n const findings = await check.run(ctx)\n mutex.push(...findings)\n if (options.onCategoryComplete) {\n findingsPerCategory.set(check.category, (findingsPerCategory.get(check.category) ?? 0) + findings.length)\n }\n } catch (err) {\n console.error(`Check \"${check.id}\" failed: ${String(err)}`)\n } finally {\n if (options.onCategoryComplete) {\n const remaining = (inFlight.get(check.category) ?? 1) - 1\n inFlight.set(check.category, remaining)\n if (remaining === 0) {\n options.onCategoryComplete(check.category, findingsPerCategory.get(check.category) ?? 0)\n }\n }\n }\n },\n concurrency\n )\n\n results.push(...mutex)\n\n // Clean up cached AST trees to free WASM memory\n if (ctx.astCache) {\n for (const promise of ctx.astCache.values()) {\n try {\n const { tree } = await promise\n if (tree) {\n tree.delete()\n }\n } catch {\n // ignore failed parses\n }\n }\n ctx.astCache.clear()\n }\n\n let findings = sortFindings(\n dedupeDegradedFindings(dedupeCrossCheck(dedupeFindings(results))),\n )\n\n findings = filterByMinConfidence(findings, options.minConfidence)\n\n // Baseline handling\n if (options.baseline) {\n if (options.baseline === 'save') {\n const baselinePath = resolveBaselinePath(options.targetDir)\n saveBaseline(baselinePath, options.targetDir, findings)\n } else {\n const baselinePath = resolveBaselinePath(options.targetDir, options.baseline)\n const baselineFindings = loadBaseline(baselinePath)\n if (baselineFindings) {\n findings = computeBaseline(findings, baselineFindings)\n }\n }\n }\n\n return {\n findings,\n scannedFileCount: files.length,\n skippedChecks,\n }\n }\n}\n","import { execSync } from 'child_process'\nimport { resolve, relative } from 'path'\n\nfunction gitTopLevel(dir: string): string | null {\n try {\n const output = execSync('git rev-parse --show-toplevel', {\n cwd: dir,\n stdio: 'pipe',\n encoding: 'utf-8',\n })\n return resolve(output.trim())\n } catch {\n return null\n }\n}\n\nfunction pathsUnderTarget(topLevel: string, targetDir: string, repoRelativePath: string): boolean {\n const absTarget = resolve(targetDir)\n const scopePrefix = relative(topLevel, absTarget).replace(/\\\\/g, '/')\n const normalized = repoRelativePath.replace(/\\\\/g, '/')\n\n if (scopePrefix === '' || scopePrefix === '.') {\n return true\n }\n\n return normalized === scopePrefix || normalized.startsWith(`${scopePrefix}/`)\n}\n\n/**\n * Determine whether the given directory is inside a Git repository.\n */\nexport function isInsideGitRepo(dir: string): boolean {\n return gitTopLevel(dir) !== null\n}\n\n/**\n * Return the list of file paths currently tracked by Git in `dir`.\n * Returns an empty array if Git is unavailable or the directory is not a repo.\n */\nexport function listTrackedFiles(dir: string): string[] {\n try {\n const output = execSync('git ls-files', {\n cwd: dir,\n stdio: 'pipe',\n encoding: 'utf-8',\n })\n return output.split(/\\r?\\n/).filter((line) => line.length > 0)\n } catch {\n return []\n }\n}\n\n/**\n * Return `true` if any file ever committed in `dir`'s git history matches\n * the supplied `pattern`. Uses `git log` to search across all commits.\n * Only paths under `dir` relative to the repository root are considered.\n */\nexport function hasFileInGitHistory(\n dir: string,\n pattern: RegExp\n): boolean {\n const topLevel = gitTopLevel(dir)\n if (!topLevel) {\n return false\n }\n\n try {\n const output = execSync(\n 'git log --all --pretty=format: --name-only --diff-filter=A',\n {\n cwd: dir,\n stdio: 'pipe',\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n }\n )\n const files = output.split(/\\r?\\n/).filter((line) => line.length > 0)\n return files.some((f) => pathsUnderTarget(topLevel, dir, f) && pattern.test(f))\n } catch {\n return false\n }\n}\n","import { parse } from 'acorn'\nimport type { Node } from 'acorn'\nimport { fail, type Result } from '../types/result.js'\n\n/** Legacy Acorn parser for JS/TS syntax checks only; scan pipeline uses tree-sitter. */\n\nexport type ASTNode = Node\n\nexport function parseJsTs(source: string): ASTNode | null {\n try {\n const ast = parse(source, {\n ecmaVersion: 'latest',\n sourceType: 'module',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n })\n return ast\n } catch {\n return null\n }\n}\n\nexport function parseJsTsSafe(source: string): Result<ASTNode> {\n if (source.includes('\\0')) {\n return fail('parse.binary_file')\n }\n try {\n const ast = parse(source, {\n ecmaVersion: 'latest',\n sourceType: 'module',\n allowReturnOutsideFunction: true,\n allowImportExportEverywhere: true,\n })\n return { ok: true, value: ast }\n } catch {\n return fail('parse.unparseable')\n }\n}\n","/** Abstract interface for LLM providers. */\nexport interface LLMProvider {\n /** Provider identifier, e.g. 'anthropic', 'openai'. */\n providerId?: string\n /** Model identifier, e.g. 'claude-3-5-sonnet-latest', 'gpt-4o-mini'. */\n modelId?: string\n /** Send a prompt and return the generated completion text. */\n complete(prompt: string): Promise<string>\n}\n\n/**\n * Token-bucket rate limiter wrapping an inner LLM provider.\n *\n * Requests are queued when the bucket is empty and executed once a token\n * becomes available. Never drops requests.\n */\nexport class RateLimitedProvider implements LLMProvider {\n private inner: LLMProvider\n private rpm: number\n private tokens: number\n private lastRefill: number\n private queue: Array<() => void> = []\n private nextTimer: ReturnType<typeof setTimeout> | null = null\n\n get providerId(): string | undefined {\n return this.inner.providerId\n }\n\n get modelId(): string | undefined {\n return this.inner.modelId\n }\n\n constructor(inner: LLMProvider, rpm = 10) {\n this.inner = inner\n this.rpm = rpm\n this.tokens = rpm\n this.lastRefill = Date.now()\n }\n\n /** Adjust the rate limit at runtime (useful for testing). */\n setRateLimit(rpm: number): void {\n this.rpm = rpm\n this.tokens = Math.min(this.tokens, rpm)\n }\n\n async complete(prompt: string): Promise<string> {\n await this.acquireToken()\n return this.inner.complete(prompt)\n }\n\n private async acquireToken(): Promise<void> {\n this.refillTokens()\n\n if (this.tokens >= 1) {\n this.tokens -= 1\n return\n }\n\n // Wait until a token is available\n return new Promise<void>((resolve) => {\n this.queue.push(resolve)\n this.scheduleNext()\n })\n }\n\n private refillTokens(): void {\n const now = Date.now()\n const elapsedMinutes = (now - this.lastRefill) / (1000 * 60)\n const newTokens = Math.floor(elapsedMinutes * this.rpm)\n if (newTokens > 0) {\n this.tokens = Math.min(this.rpm, this.tokens + newTokens)\n this.lastRefill = now\n }\n }\n\n private scheduleNext(): void {\n if (this.queue.length === 0 || this.nextTimer) return\n const now = Date.now()\n const msPerToken = (60 * 1000) / this.rpm\n const timeUntilNext = Math.max(0, this.lastRefill + msPerToken - now)\n\n this.nextTimer = setTimeout(() => {\n this.nextTimer = null\n this.refillTokens()\n while (this.tokens >= 1 && this.queue.length > 0) {\n this.tokens -= 1\n this.queue.shift()!()\n }\n this.scheduleNext()\n }, timeUntilNext)\n }\n}\n","import type { LLMProvider } from './llm-provider.js'\nimport Anthropic from '@anthropic-ai/sdk'\n\nexport class AnthropicProvider implements LLMProvider {\n readonly providerId: string\n readonly modelId: string\n private client: Anthropic\n\n constructor(apiKey: string, model?: string, baseUrl?: string, providerId?: string) {\n this.client = new Anthropic({\n apiKey,\n baseURL: baseUrl ?? process.env.ANTHROPIC_API_URL,\n })\n this.modelId = model ?? 'claude-3-5-sonnet-latest'\n this.providerId = providerId ?? 'anthropic'\n }\n\n async complete(prompt: string): Promise<string> {\n try {\n const response = await this.client.messages.create({\n model: this.modelId,\n max_tokens: 1024,\n temperature: 0,\n messages: [{ role: 'user', content: prompt }],\n })\n const content = response.content[0]\n if (content && content.type === 'text') {\n return content.text\n }\n return ''\n } catch (err) {\n const error = err as { status?: number; message?: string }\n if (error.status === 401) {\n throw new Error('Invalid Anthropic API key. Check your credentials.')\n }\n if (error.status === 429) {\n throw new Error('Anthropic rate limit exceeded. Please wait and retry.')\n }\n throw new Error(`Anthropic API error: ${error.message ?? String(err)}`)\n }\n }\n}\n","import type { LLMProvider } from './llm-provider.js'\nimport OpenAI from 'openai'\n\nexport class OpenAIProvider implements LLMProvider {\n readonly providerId: string\n readonly modelId: string\n private client: OpenAI\n\n constructor(apiKey: string, model?: string, baseUrl?: string, providerId?: string) {\n this.client = new OpenAI({\n apiKey,\n baseURL: baseUrl ?? process.env.OPENAI_API_URL,\n })\n this.modelId = model ?? 'gpt-4o-mini'\n this.providerId = providerId ?? 'openai'\n }\n\n async complete(prompt: string): Promise<string> {\n try {\n const response = await this.client.chat.completions.create({\n model: this.modelId,\n temperature: 0,\n messages: [{ role: 'user', content: prompt }],\n max_tokens: 1024,\n })\n return response.choices[0]?.message?.content ?? ''\n } catch (err) {\n const error = err as { status?: number; message?: string }\n if (error.status === 401) {\n throw new Error('Invalid OpenAI API key. Check your credentials.')\n }\n if (error.status === 429) {\n throw new Error('OpenAI rate limit exceeded. Please wait and retry.')\n }\n throw new Error(`OpenAI API error: ${error.message ?? String(err)}`)\n }\n }\n}\n","import type { LLMProvider } from './llm-provider.js'\n\ninterface CircuitBreakerState {\n status: 'closed' | 'open' | 'half-open'\n failures: number\n lastFailure: number\n nextRetry: number\n}\n\nexport interface CircuitBreakerConfig {\n failureThreshold: number\n resetTimeoutMs: number\n halfOpenMaxCalls: number\n}\n\nconst DEFAULT_CONFIG: CircuitBreakerConfig = {\n failureThreshold: 5,\n resetTimeoutMs: 30_000,\n halfOpenMaxCalls: 1,\n}\n\n/**\n * Circuit-breaker wrapper for an LLMProvider.\n *\n * After `failureThreshold` consecutive failures the breaker opens\n * and fast-fails every call for `resetTimeoutMs`. Then it allows\n * `halfOpenMaxCalls` probe(s); success closes the breaker, failure\n * re-opens it.\n *\n * This prevents cost spirals when the provider is down or rate-limiting.\n */\nexport class CircuitBreakerProvider implements LLMProvider {\n private inner: LLMProvider\n private state: CircuitBreakerState\n private config: CircuitBreakerConfig\n private halfOpenCalls = 0\n\n get providerId(): string | undefined {\n return this.inner.providerId\n }\n\n get modelId(): string | undefined {\n return this.inner.modelId\n }\n\n constructor(inner: LLMProvider, config: Partial<CircuitBreakerConfig> = {}) {\n this.inner = inner\n this.config = { ...DEFAULT_CONFIG, ...config }\n this.state = {\n status: 'closed',\n failures: 0,\n lastFailure: 0,\n nextRetry: 0,\n }\n }\n\n async complete(prompt: string): Promise<string> {\n if (this.state.status === 'open') {\n if (Date.now() >= this.state.nextRetry) {\n this.transition('half-open')\n } else {\n throw new Error(\n `llm.circuit_open: breaker open until ${new Date(this.state.nextRetry).toISOString()}`\n )\n }\n }\n\n if (this.state.status === 'half-open' && this.halfOpenCalls >= this.config.halfOpenMaxCalls) {\n throw new Error('llm.circuit_open: half-open quota exhausted')\n }\n\n if (this.state.status === 'half-open') {\n this.halfOpenCalls++\n }\n\n try {\n const result = await this.inner.complete(prompt)\n this.onSuccess()\n return result\n } catch (err) {\n this.onFailure()\n throw err\n }\n }\n\n /** Expose breaker state for health checks / debugging. */\n getState(): Readonly<CircuitBreakerState> {\n return { ...this.state }\n }\n\n private transition(status: 'closed' | 'open' | 'half-open'): void {\n this.state.status = status\n if (status === 'closed') {\n this.state.failures = 0\n this.halfOpenCalls = 0\n } else if (status === 'open') {\n this.state.nextRetry = Date.now() + this.config.resetTimeoutMs\n this.halfOpenCalls = 0\n } else if (status === 'half-open') {\n this.halfOpenCalls = 0\n }\n }\n\n private onSuccess(): void {\n if (this.state.status === 'half-open') {\n this.transition('closed')\n } else {\n this.state.failures = 0\n }\n }\n\n private onFailure(): void {\n this.state.failures++\n this.state.lastFailure = Date.now()\n if (this.state.failures >= this.config.failureThreshold) {\n this.transition('open')\n }\n }\n}\n","export interface ProviderPreset {\n /** Which SDK to use under the hood. */\n sdk: 'anthropic' | 'openai'\n /** Default base URL for the API. If omitted, the SDK uses its own default. */\n baseUrl?: string\n /** Sensible default model when the user does not specify one. */\n defaultModel: string\n}\n\n/**\n * Well-known provider presets so vibe coders don't need to remember\n * base URLs or SDK compatibility details.\n */\nexport const PROVIDER_PRESETS: Record<string, ProviderPreset> = {\n anthropic: {\n sdk: 'anthropic',\n defaultModel: 'claude-3-5-sonnet-latest',\n },\n openai: {\n sdk: 'openai',\n defaultModel: 'gpt-4o-mini',\n },\n kimi: {\n sdk: 'openai',\n baseUrl: 'https://api.moonshot.cn/v1',\n defaultModel: 'kimi-k2-5',\n },\n moonshot: {\n sdk: 'openai',\n baseUrl: 'https://api.moonshot.cn/v1',\n defaultModel: 'kimi-k2-5',\n },\n deepseek: {\n sdk: 'openai',\n baseUrl: 'https://api.deepseek.com/v1',\n defaultModel: 'deepseek-chat',\n },\n gemini: {\n sdk: 'openai',\n baseUrl: 'https://generativelanguage.googleapis.com/v1beta/openai/',\n defaultModel: 'gemini-2.0-flash',\n },\n ollama: {\n sdk: 'openai',\n baseUrl: 'http://localhost:11434/v1',\n defaultModel: 'llama3.2',\n },\n openrouter: {\n sdk: 'openai',\n baseUrl: 'https://openrouter.ai/api/v1',\n defaultModel: 'anthropic/claude-3.5-sonnet',\n },\n minimax: {\n sdk: 'openai',\n baseUrl: 'https://api.minimax.io/v1',\n defaultModel: 'MiniMax-M2.7',\n },\n}\n\n/** Return the list of preset names for validation / help text. */\nexport function listPresetProviders(): string[] {\n return Object.keys(PROVIDER_PRESETS)\n}\n\n/** Resolve a nickname like \"kimi\" to its preset. Returns undefined if not found. */\nexport function resolvePreset(nickname: string): ProviderPreset | undefined {\n return PROVIDER_PRESETS[nickname]\n}\n","import { type LLMProvider, RateLimitedProvider } from './llm-provider.js'\nimport { AnthropicProvider } from './anthropic-provider.js'\nimport { OpenAIProvider } from './openai-provider.js'\nimport { CircuitBreakerProvider } from './circuit-breaker.js'\nimport { resolvePreset } from './presets.js'\n\nexport type { LLMProvider }\nexport { RateLimitedProvider, AnthropicProvider, OpenAIProvider, CircuitBreakerProvider }\nexport { resolvePreset, listPresetProviders, PROVIDER_PRESETS } from './presets.js'\n\ninterface CreateProviderConfig {\n provider: string\n apiKey: string\n model?: string\n baseUrl?: string\n}\n\nexport function createProvider(config: CreateProviderConfig): RateLimitedProvider {\n const preset = resolvePreset(config.provider)\n\n const sdk = preset?.sdk ?? (config.provider === 'anthropic' ? 'anthropic' : 'openai')\n const baseUrl = config.baseUrl ?? preset?.baseUrl\n const model = config.model ?? preset?.defaultModel\n\n const base =\n sdk === 'anthropic'\n ? new AnthropicProvider(config.apiKey, model, baseUrl, config.provider)\n : new OpenAIProvider(config.apiKey, model, baseUrl, config.provider)\n return new RateLimitedProvider(base)\n}\n","const ANSI_BACKGROUND_OFFSET = 10;\n\nconst wrapAnsi16 = (offset = 0) => code => `\\u001B[${code + offset}m`;\n\nconst wrapAnsi256 = (offset = 0) => code => `\\u001B[${38 + offset};5;${code}m`;\n\nconst wrapAnsi16m = (offset = 0) => (red, green, blue) => `\\u001B[${38 + offset};2;${red};${green};${blue}m`;\n\nconst styles = {\n\tmodifier: {\n\t\treset: [0, 0],\n\t\t// 21 isn't widely supported and 22 does the same thing\n\t\tbold: [1, 22],\n\t\tdim: [2, 22],\n\t\titalic: [3, 23],\n\t\tunderline: [4, 24],\n\t\toverline: [53, 55],\n\t\tinverse: [7, 27],\n\t\thidden: [8, 28],\n\t\tstrikethrough: [9, 29],\n\t},\n\tcolor: {\n\t\tblack: [30, 39],\n\t\tred: [31, 39],\n\t\tgreen: [32, 39],\n\t\tyellow: [33, 39],\n\t\tblue: [34, 39],\n\t\tmagenta: [35, 39],\n\t\tcyan: [36, 39],\n\t\twhite: [37, 39],\n\n\t\t// Bright color\n\t\tblackBright: [90, 39],\n\t\tgray: [90, 39], // Alias of `blackBright`\n\t\tgrey: [90, 39], // Alias of `blackBright`\n\t\tredBright: [91, 39],\n\t\tgreenBright: [92, 39],\n\t\tyellowBright: [93, 39],\n\t\tblueBright: [94, 39],\n\t\tmagentaBright: [95, 39],\n\t\tcyanBright: [96, 39],\n\t\twhiteBright: [97, 39],\n\t},\n\tbgColor: {\n\t\tbgBlack: [40, 49],\n\t\tbgRed: [41, 49],\n\t\tbgGreen: [42, 49],\n\t\tbgYellow: [43, 49],\n\t\tbgBlue: [44, 49],\n\t\tbgMagenta: [45, 49],\n\t\tbgCyan: [46, 49],\n\t\tbgWhite: [47, 49],\n\n\t\t// Bright color\n\t\tbgBlackBright: [100, 49],\n\t\tbgGray: [100, 49], // Alias of `bgBlackBright`\n\t\tbgGrey: [100, 49], // Alias of `bgBlackBright`\n\t\tbgRedBright: [101, 49],\n\t\tbgGreenBright: [102, 49],\n\t\tbgYellowBright: [103, 49],\n\t\tbgBlueBright: [104, 49],\n\t\tbgMagentaBright: [105, 49],\n\t\tbgCyanBright: [106, 49],\n\t\tbgWhiteBright: [107, 49],\n\t},\n};\n\nexport const modifierNames = Object.keys(styles.modifier);\nexport const foregroundColorNames = Object.keys(styles.color);\nexport const backgroundColorNames = Object.keys(styles.bgColor);\nexport const colorNames = [...foregroundColorNames, ...backgroundColorNames];\n\nfunction assembleStyles() {\n\tconst codes = new Map();\n\n\tfor (const [groupName, group] of Object.entries(styles)) {\n\t\tfor (const [styleName, style] of Object.entries(group)) {\n\t\t\tstyles[styleName] = {\n\t\t\t\topen: `\\u001B[${style[0]}m`,\n\t\t\t\tclose: `\\u001B[${style[1]}m`,\n\t\t\t};\n\n\t\t\tgroup[styleName] = styles[styleName];\n\n\t\t\tcodes.set(style[0], style[1]);\n\t\t}\n\n\t\tObject.defineProperty(styles, groupName, {\n\t\t\tvalue: group,\n\t\t\tenumerable: false,\n\t\t});\n\t}\n\n\tObject.defineProperty(styles, 'codes', {\n\t\tvalue: codes,\n\t\tenumerable: false,\n\t});\n\n\tstyles.color.close = '\\u001B[39m';\n\tstyles.bgColor.close = '\\u001B[49m';\n\n\tstyles.color.ansi = wrapAnsi16();\n\tstyles.color.ansi256 = wrapAnsi256();\n\tstyles.color.ansi16m = wrapAnsi16m();\n\tstyles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);\n\n\t// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js\n\tObject.defineProperties(styles, {\n\t\trgbToAnsi256: {\n\t\t\tvalue(red, green, blue) {\n\t\t\t\t// We use the extended greyscale palette here, with the exception of\n\t\t\t\t// black and white. normal palette only has 4 greyscale shades.\n\t\t\t\tif (red === green && green === blue) {\n\t\t\t\t\tif (red < 8) {\n\t\t\t\t\t\treturn 16;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (red > 248) {\n\t\t\t\t\t\treturn 231;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Math.round(((red - 8) / 247) * 24) + 232;\n\t\t\t\t}\n\n\t\t\t\treturn 16\n\t\t\t\t\t+ (36 * Math.round(red / 255 * 5))\n\t\t\t\t\t+ (6 * Math.round(green / 255 * 5))\n\t\t\t\t\t+ Math.round(blue / 255 * 5);\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToRgb: {\n\t\t\tvalue(hex) {\n\t\t\t\tconst matches = /[a-f\\d]{6}|[a-f\\d]{3}/i.exec(hex.toString(16));\n\t\t\t\tif (!matches) {\n\t\t\t\t\treturn [0, 0, 0];\n\t\t\t\t}\n\n\t\t\t\tlet [colorString] = matches;\n\n\t\t\t\tif (colorString.length === 3) {\n\t\t\t\t\tcolorString = [...colorString].map(character => character + character).join('');\n\t\t\t\t}\n\n\t\t\t\tconst integer = Number.parseInt(colorString, 16);\n\n\t\t\t\treturn [\n\t\t\t\t\t/* eslint-disable no-bitwise */\n\t\t\t\t\t(integer >> 16) & 0xFF,\n\t\t\t\t\t(integer >> 8) & 0xFF,\n\t\t\t\t\tinteger & 0xFF,\n\t\t\t\t\t/* eslint-enable no-bitwise */\n\t\t\t\t];\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi256: {\n\t\t\tvalue: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t\tansi256ToAnsi: {\n\t\t\tvalue(code) {\n\t\t\t\tif (code < 8) {\n\t\t\t\t\treturn 30 + code;\n\t\t\t\t}\n\n\t\t\t\tif (code < 16) {\n\t\t\t\t\treturn 90 + (code - 8);\n\t\t\t\t}\n\n\t\t\t\tlet red;\n\t\t\t\tlet green;\n\t\t\t\tlet blue;\n\n\t\t\t\tif (code >= 232) {\n\t\t\t\t\tred = (((code - 232) * 10) + 8) / 255;\n\t\t\t\t\tgreen = red;\n\t\t\t\t\tblue = red;\n\t\t\t\t} else {\n\t\t\t\t\tcode -= 16;\n\n\t\t\t\t\tconst remainder = code % 36;\n\n\t\t\t\t\tred = Math.floor(code / 36) / 5;\n\t\t\t\t\tgreen = Math.floor(remainder / 6) / 5;\n\t\t\t\t\tblue = (remainder % 6) / 5;\n\t\t\t\t}\n\n\t\t\t\tconst value = Math.max(red, green, blue) * 2;\n\n\t\t\t\tif (value === 0) {\n\t\t\t\t\treturn 30;\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\tlet result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));\n\n\t\t\t\tif (value === 2) {\n\t\t\t\t\tresult += 60;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\trgbToAnsi: {\n\t\t\tvalue: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi: {\n\t\t\tvalue: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t});\n\n\treturn styles;\n}\n\nconst ansiStyles = assembleStyles();\n\nexport default ansiStyles;\n","import process from 'node:process';\nimport os from 'node:os';\nimport tty from 'node:tty';\n\n// From: https://github.com/sindresorhus/has-flag/blob/main/index.js\n/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {\nfunction hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) {\n\tconst prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');\n\tconst position = argv.indexOf(prefix + flag);\n\tconst terminatorPosition = argv.indexOf('--');\n\treturn position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);\n}\n\nconst {env} = process;\n\nlet flagForceColor;\nif (\n\thasFlag('no-color')\n\t|| hasFlag('no-colors')\n\t|| hasFlag('color=false')\n\t|| hasFlag('color=never')\n) {\n\tflagForceColor = 0;\n} else if (\n\thasFlag('color')\n\t|| hasFlag('colors')\n\t|| hasFlag('color=true')\n\t|| hasFlag('color=always')\n) {\n\tflagForceColor = 1;\n}\n\nfunction envForceColor() {\n\tif ('FORCE_COLOR' in env) {\n\t\tif (env.FORCE_COLOR === 'true') {\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (env.FORCE_COLOR === 'false') {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);\n\t}\n}\n\nfunction translateLevel(level) {\n\tif (level === 0) {\n\t\treturn false;\n\t}\n\n\treturn {\n\t\tlevel,\n\t\thasBasic: true,\n\t\thas256: level >= 2,\n\t\thas16m: level >= 3,\n\t};\n}\n\nfunction _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {\n\tconst noFlagForceColor = envForceColor();\n\tif (noFlagForceColor !== undefined) {\n\t\tflagForceColor = noFlagForceColor;\n\t}\n\n\tconst forceColor = sniffFlags ? flagForceColor : noFlagForceColor;\n\n\tif (forceColor === 0) {\n\t\treturn 0;\n\t}\n\n\tif (sniffFlags) {\n\t\tif (hasFlag('color=16m')\n\t\t\t|| hasFlag('color=full')\n\t\t\t|| hasFlag('color=truecolor')) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (hasFlag('color=256')) {\n\t\t\treturn 2;\n\t\t}\n\t}\n\n\t// Check for Azure DevOps pipelines.\n\t// Has to be above the `!streamIsTTY` check.\n\tif ('TF_BUILD' in env && 'AGENT_NAME' in env) {\n\t\treturn 1;\n\t}\n\n\tif (haveStream && !streamIsTTY && forceColor === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst min = forceColor || 0;\n\n\tif (env.TERM === 'dumb') {\n\t\treturn min;\n\t}\n\n\tif (process.platform === 'win32') {\n\t\t// Windows 10 build 10586 is the first Windows release that supports 256 colors.\n\t\t// Windows 10 build 14931 is the first release that supports 16m/TrueColor.\n\t\tconst osRelease = os.release().split('.');\n\t\tif (\n\t\t\tNumber(osRelease[0]) >= 10\n\t\t\t&& Number(osRelease[2]) >= 10_586\n\t\t) {\n\t\t\treturn Number(osRelease[2]) >= 14_931 ? 3 : 2;\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\tif ('CI' in env) {\n\t\tif (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key in env)) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn min;\n\t}\n\n\tif ('TEAMCITY_VERSION' in env) {\n\t\treturn /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;\n\t}\n\n\tif (env.COLORTERM === 'truecolor') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-kitty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-ghostty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'wezterm') {\n\t\treturn 3;\n\t}\n\n\tif ('TERM_PROGRAM' in env) {\n\t\tconst version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);\n\n\t\tswitch (env.TERM_PROGRAM) {\n\t\t\tcase 'iTerm.app': {\n\t\t\t\treturn version >= 3 ? 3 : 2;\n\t\t\t}\n\n\t\t\tcase 'Apple_Terminal': {\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\n\tif (/-256(color)?$/i.test(env.TERM)) {\n\t\treturn 2;\n\t}\n\n\tif (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {\n\t\treturn 1;\n\t}\n\n\tif ('COLORTERM' in env) {\n\t\treturn 1;\n\t}\n\n\treturn min;\n}\n\nexport function createSupportsColor(stream, options = {}) {\n\tconst level = _supportsColor(stream, {\n\t\tstreamIsTTY: stream && stream.isTTY,\n\t\t...options,\n\t});\n\n\treturn translateLevel(level);\n}\n\nconst supportsColor = {\n\tstdout: createSupportsColor({isTTY: tty.isatty(1)}),\n\tstderr: createSupportsColor({isTTY: tty.isatty(2)}),\n};\n\nexport default supportsColor;\n","// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`.\nexport function stringReplaceAll(string, substring, replacer) {\n\tlet index = string.indexOf(substring);\n\tif (index === -1) {\n\t\treturn string;\n\t}\n\n\tconst substringLength = substring.length;\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\treturnValue += string.slice(endIndex, index) + substring + replacer;\n\t\tendIndex = index + substringLength;\n\t\tindex = string.indexOf(substring, endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n\nexport function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\tconst gotCR = string[index - 1] === '\\r';\n\t\treturnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\\r\\n' : '\\n') + postfix;\n\t\tendIndex = index + 1;\n\t\tindex = string.indexOf('\\n', endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n","import ansiStyles from '#ansi-styles';\nimport supportsColor from '#supports-color';\nimport { // eslint-disable-line import/order\n\tstringReplaceAll,\n\tstringEncaseCRLFWithFirstIndex,\n} from './utilities.js';\n\nconst {stdout: stdoutColor, stderr: stderrColor} = supportsColor;\n\nconst GENERATOR = Symbol('GENERATOR');\nconst STYLER = Symbol('STYLER');\nconst IS_EMPTY = Symbol('IS_EMPTY');\n\n// `supportsColor.level` → `ansiStyles.color[name]` mapping\nconst levelMapping = [\n\t'ansi',\n\t'ansi',\n\t'ansi256',\n\t'ansi16m',\n];\n\nconst styles = Object.create(null);\n\nconst applyOptions = (object, options = {}) => {\n\tif (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {\n\t\tthrow new Error('The `level` option should be an integer from 0 to 3');\n\t}\n\n\t// Detect level if not set manually\n\tconst colorLevel = stdoutColor ? stdoutColor.level : 0;\n\tobject.level = options.level === undefined ? colorLevel : options.level;\n};\n\nexport class Chalk {\n\tconstructor(options) {\n\t\t// eslint-disable-next-line no-constructor-return\n\t\treturn chalkFactory(options);\n\t}\n}\n\nconst chalkFactory = options => {\n\tconst chalk = (...strings) => strings.join(' ');\n\tapplyOptions(chalk, options);\n\n\tObject.setPrototypeOf(chalk, createChalk.prototype);\n\n\treturn chalk;\n};\n\nfunction createChalk(options) {\n\treturn chalkFactory(options);\n}\n\nObject.setPrototypeOf(createChalk.prototype, Function.prototype);\n\nfor (const [styleName, style] of Object.entries(ansiStyles)) {\n\tstyles[styleName] = {\n\t\tget() {\n\t\t\tconst builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);\n\t\t\tObject.defineProperty(this, styleName, {value: builder});\n\t\t\treturn builder;\n\t\t},\n\t};\n}\n\nstyles.visible = {\n\tget() {\n\t\tconst builder = createBuilder(this, this[STYLER], true);\n\t\tObject.defineProperty(this, 'visible', {value: builder});\n\t\treturn builder;\n\t},\n};\n\nconst getModelAnsi = (model, level, type, ...arguments_) => {\n\tif (model === 'rgb') {\n\t\tif (level === 'ansi16m') {\n\t\t\treturn ansiStyles[type].ansi16m(...arguments_);\n\t\t}\n\n\t\tif (level === 'ansi256') {\n\t\t\treturn ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));\n\t\t}\n\n\t\treturn ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));\n\t}\n\n\tif (model === 'hex') {\n\t\treturn getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_));\n\t}\n\n\treturn ansiStyles[type][model](...arguments_);\n};\n\nconst usedModels = ['rgb', 'hex', 'ansi256'];\n\nfor (const model of usedModels) {\n\tstyles[model] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n\n\tconst bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);\n\tstyles[bgModel] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n}\n\nconst proto = Object.defineProperties(() => {}, {\n\t...styles,\n\tlevel: {\n\t\tenumerable: true,\n\t\tget() {\n\t\t\treturn this[GENERATOR].level;\n\t\t},\n\t\tset(level) {\n\t\t\tthis[GENERATOR].level = level;\n\t\t},\n\t},\n});\n\nconst createStyler = (open, close, parent) => {\n\tlet openAll;\n\tlet closeAll;\n\tif (parent === undefined) {\n\t\topenAll = open;\n\t\tcloseAll = close;\n\t} else {\n\t\topenAll = parent.openAll + open;\n\t\tcloseAll = close + parent.closeAll;\n\t}\n\n\treturn {\n\t\topen,\n\t\tclose,\n\t\topenAll,\n\t\tcloseAll,\n\t\tparent,\n\t};\n};\n\nconst createBuilder = (self, _styler, _isEmpty) => {\n\t// Single argument is hot path, implicit coercion is faster than anything\n\t// eslint-disable-next-line no-implicit-coercion\n\tconst builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));\n\n\t// We alter the prototype because we must return a function, but there is\n\t// no way to create a function with a different prototype\n\tObject.setPrototypeOf(builder, proto);\n\n\tbuilder[GENERATOR] = self;\n\tbuilder[STYLER] = _styler;\n\tbuilder[IS_EMPTY] = _isEmpty;\n\n\treturn builder;\n};\n\nconst applyStyle = (self, string) => {\n\tif (self.level <= 0 || !string) {\n\t\treturn self[IS_EMPTY] ? '' : string;\n\t}\n\n\tlet styler = self[STYLER];\n\n\tif (styler === undefined) {\n\t\treturn string;\n\t}\n\n\tconst {openAll, closeAll} = styler;\n\tif (string.includes('\\u001B')) {\n\t\twhile (styler !== undefined) {\n\t\t\t// Replace any instances already present with a re-opening code\n\t\t\t// otherwise only the part of the string until said closing code\n\t\t\t// will be colored, and the rest will simply be 'plain'.\n\t\t\tstring = stringReplaceAll(string, styler.close, styler.open);\n\n\t\t\tstyler = styler.parent;\n\t\t}\n\t}\n\n\t// We can move both next actions out of loop, because remaining actions in loop won't have\n\t// any/visible effect on parts we add here. Close the styling before a linebreak and reopen\n\t// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92\n\tconst lfIndex = string.indexOf('\\n');\n\tif (lfIndex !== -1) {\n\t\tstring = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);\n\t}\n\n\treturn openAll + string + closeAll;\n};\n\nObject.defineProperties(createChalk.prototype, styles);\n\nconst chalk = createChalk();\nexport const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0});\n\nexport {\n\tmodifierNames,\n\tforegroundColorNames,\n\tbackgroundColorNames,\n\tcolorNames,\n\n\t// TODO: Remove these aliases in the next major version\n\tmodifierNames as modifiers,\n\tforegroundColorNames as foregroundColors,\n\tbackgroundColorNames as backgroundColors,\n\tcolorNames as colors,\n} from './vendor/ansi-styles/index.js';\n\nexport {\n\tstdoutColor as supportsColor,\n\tstderrColor as supportsColorStderr,\n};\n\nexport default chalk;\n","// Semantic colour tokens for terminal output.\n// All colours come from this file — no raw hex or chalk colours elsewhere.\n\nexport const tokens = {\n // Severity\n error: '#FF6B6B',\n warning: '#FFD166',\n info: '#0CC8D4',\n success: '#52B788',\n\n // Brand / UI\n primary: '#0CC8D4',\n secondary: '#5A7A8A',\n muted: '#5A7A8A',\n} as const\n","import chalk from 'chalk'\nimport { tokens } from './chalk.js'\n\n// Terminal text style tokens.\n// All ANSI styling comes through here — no raw escape codes elsewhere.\n\nexport const text = {\n heading: (s: string) => chalk.bold.hex(tokens.primary)(s),\n body: (s: string) => s,\n meta: (s: string) => chalk.dim.hex(tokens.secondary)(s),\n code: (s: string) => chalk.bold(s),\n label: (s: string) => chalk.bold(s.toUpperCase()),\n link: (s: string) => chalk.underline.hex(tokens.info)(s),\n error: (s: string) => chalk.hex(tokens.error)(s),\n warning: (s: string) => chalk.hex(tokens.warning)(s),\n info: (s: string) => chalk.hex(tokens.info)(s),\n success: (s: string) => chalk.hex(tokens.success)(s),\n} as const\n","import type { ReportInput } from './types.js'\nimport { text } from './tokens/text.js'\nimport { getCopy } from '../copy/index.js'\nimport type { Severity } from '../types/finding.js'\nimport { dedupeDegradedFindings } from './dedupe-degraded.js'\n\nconst SEVERITY_ORDER: Severity[] = ['critical', 'high', 'medium', 'low', 'info']\n\nfunction checkNameOf(checkId: string): string {\n const short = checkId.replace(/^[^.]+\\./, '')\n try {\n return getCopy(`checks.${short}.name` as Parameters<typeof getCopy>[0])\n } catch {\n return short\n }\n}\n\n/**\n * Generate a coloured terminal report suitable for stdout.\n */\nexport class TerminalReporter {\n generate(input: ReportInput): string {\n const { findings: rawFindings, targetDir, tier, licensedTo, scannedFileCount, skippedChecks = [], showIds = false } = input\n const findings = dedupeDegradedFindings(rawFindings)\n\n if (findings.length === 0) {\n const lines: string[] = []\n lines.push(text.success(getCopy('report.cta.clean')))\n lines.push(text.meta(getCopy('report.scannedFiles', scannedFileCount)))\n if (tier === 'pro') {\n lines.push('')\n lines.push(text.meta(getCopy('report.tierWatermark', licensedTo)))\n }\n if (skippedChecks.length > 0) {\n lines.push('')\n lines.push(text.link(buildProUpsell(skippedChecks)))\n }\n return lines.join('\\n')\n }\n\n const lines: string[] = []\n lines.push(text.heading(getCopy('report.header', targetDir, findings.length)))\n lines.push('')\n\n for (const f of findings) {\n const severityLabel = textForSeverity(f.severity)\n const baselineLabel = f.baselineState === 'new' ? text.success(' [NEW]') : ''\n const loc = f.file ? text.meta(` (${f.file}:${f.line ?? '-'})`) : ''\n const confidenceLabel = f.confidence && f.confidence !== 'high'\n ? text.meta(` [${f.confidence} confidence]`)\n : ''\n const rawAnalysisType = f.properties?.analysisType\n const analysisTypeValue =\n rawAnalysisType === 'pattern' || rawAnalysisType === 'semantic'\n ? rawAnalysisType\n : undefined\n const analysisType = analysisTypeValue\n ? text.meta(` [${getCopy(`reporting.analysisType.${analysisTypeValue}` as Parameters<typeof getCopy>[0])}]`)\n : ''\n const name = checkNameOf(f.checkId)\n const idSuffix = showIds ? text.meta(` · ${f.checkId}`) : ''\n lines.push(`${severityLabel}${baselineLabel} ${name}${idSuffix}${analysisType} — ${f.message}${loc}${confidenceLabel}`)\n if (f.remediation) {\n lines.push(` ${text.meta(`→ ${f.remediation}`)}`)\n }\n if (f.properties?.suggestion) {\n lines.push(` ${text.meta(`💡 ${f.properties.suggestion}`)}`)\n }\n }\n\n lines.push('')\n lines.push(text.heading(getCopy('report.summary')))\n const counts = countBySeverity(findings)\n for (const sev of SEVERITY_ORDER) {\n const count = counts[sev] ?? 0\n if (count > 0) {\n lines.push(` ${textForSeverity(sev)} ${count}`)\n }\n }\n\n lines.push('')\n const hasCriticalOrHigh = findings.some(f => f.severity === 'critical' || f.severity === 'high')\n lines.push(text.link(hasCriticalOrHigh ? getCopy('report.cta.critical') : getCopy('report.cta.hasFindings')))\n\n if (tier === 'pro') {\n lines.push(text.meta(getCopy('report.tierWatermark', licensedTo)))\n }\n\n if (skippedChecks.length > 0) {\n lines.push(text.link(buildProUpsell(skippedChecks)))\n }\n\n return lines.join('\\n')\n }\n}\n\nfunction buildProUpsell(skippedChecks: Array<{ name: string }>): string {\n const count = skippedChecks.length\n const names = skippedChecks\n .slice(0, 2)\n .map(c => c.name.toLowerCase())\n .join(', ')\n const suffix = count > 2 ? ', …' : ''\n return getCopy('report.proUpsellNamed', names + suffix, count)\n}\n\nfunction textForSeverity(severity: Severity): string {\n switch (severity) {\n case 'critical':\n return text.error('CRITICAL')\n case 'high':\n return text.error('HIGH')\n case 'medium':\n return text.warning('MEDIUM')\n case 'low':\n return text.info('LOW')\n case 'info':\n return text.meta('INFO')\n }\n}\n\nfunction countBySeverity(findings: ReportInput['findings']): Record<Severity, number> {\n const counts: Partial<Record<Severity, number>> = {}\n for (const f of findings) {\n counts[f.severity] = (counts[f.severity] ?? 0) + 1\n }\n return counts as Record<Severity, number>\n}\n","import type { ReportInput } from './types.js'\nimport type { Severity } from '../types/finding.js'\nimport { SITE_URL } from '../config/urls.js'\nimport { dedupeDegradedFindings } from './dedupe-degraded.js'\n\n/**\n * Generate a JSON report matching the schema defined in\n * `req-output-formats.md`.\n */\nexport class JSONReporter {\n generate(input: ReportInput): string {\n const { findings: rawFindings, targetDir, tier } = input\n const findings = dedupeDegradedFindings(rawFindings)\n\n const bySeverity: Record<Severity, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n }\n for (const f of findings) {\n bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1\n }\n\n const output = {\n url: SITE_URL,\n scannedAt: new Date().toISOString(),\n target: targetDir,\n tier,\n licensedTo: input.licensedTo,\n findings: findings.map((f) => ({\n id: f.id,\n checkId: f.checkId,\n category: f.category,\n severity: f.severity,\n confidence: f.confidence,\n message: f.message,\n remediation: f.remediation,\n file: f.file,\n line: f.line,\n column: f.column,\n ...(f.baselineState ? { baselineState: f.baselineState } : {}),\n ...(f.properties ? { properties: f.properties } : {}),\n })),\n summary: {\n total: findings.length,\n bySeverity,\n },\n }\n\n return JSON.stringify(output, null, 2)\n }\n}\n","import type { ReportInput } from './types.js'\nimport type { Severity } from '../types/finding.js'\nimport { SITE_URL } from '../config/urls.js'\nimport { getCopy } from '../copy/index.js'\nimport { dedupeDegradedFindings } from './dedupe-degraded.js'\n\n/**\n * Generate a self-contained single-file HTML report with inlined CSS and\n * vanilla JS for sorting, filtering, and collapsible detail rows.\n */\nexport class HTMLReporter {\n generate(input: ReportInput): string {\n const { findings: rawFindings, targetDir, tier, licensedTo } = input\n const findings = dedupeDegradedFindings(rawFindings)\n\n const bySeverity: Record<Severity, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n }\n for (const f of findings) {\n bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1\n }\n\n const rows = findings\n .map(\n (f, idx) => `\n <tr data-category=\"${escapeHtml(f.category)}\" data-severity=\"${escapeHtml(f.severity)}\">\n <td><span class=\"badge ${f.severity}\">${f.severity.toUpperCase()}</span>${f.confidence && f.confidence !== 'high' ? ` <span class=\"badge ${f.confidence}\">${f.confidence}</span>` : ''}${f.properties?.analysisType && isValidAnalysisType(f.properties.analysisType) ? ` <span class=\"badge ${f.properties.analysisType}\">${getCopy(`reporting.analysisType.${f.properties.analysisType}`)}</span>` : ''}</td>\n <td>${escapeHtml(f.category)}</td>\n <td>${escapeHtml(f.checkId)}</td>\n <td>${escapeHtml(f.message)}</td>\n <td>${escapeHtml(f.file ?? '')}:${f.line ?? '-'}</td>\n <td><button type=\"button\" class=\"toggle\" data-index=\"${idx}\">Details</button></td>\n </tr>\n <tr class=\"detail\" id=\"detail-${idx}\">\n <td colspan=\"6\">\n <div class=\"detail-content\">\n <p><strong>File:</strong> ${escapeHtml(f.file ?? 'N/A')}</p>\n <p><strong>Line:</strong> ${f.line ?? 'N/A'}</p>\n <p><strong>Message:</strong> ${escapeHtml(f.message)}</p>\n <p><strong>Confidence:</strong> ${f.confidence ?? 'high'}</p>\n ${f.properties?.analysisType && isValidAnalysisType(f.properties.analysisType) ? `<p><strong>Analysis Type:</strong> ${getCopy(`reporting.analysisType.${f.properties.analysisType}`)}</p>` : ''}\n <p><strong>Remediation:</strong> ${escapeHtml(f.remediation ?? 'No specific remediation available.')}</p>\n ${f.properties?.suggestion ? `<p><strong>Suggestion:</strong> ${escapeHtml(f.properties.suggestion)}</p>` : ''}\n </div>\n </td>\n </tr>\n `\n )\n .join('')\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Seaworthy Report</title>\n<style>\n :root {\n --color-primary: #0CC8D4;\n --color-primary-dark: #0A9FAA;\n --color-primary-light: #E0F9FB;\n --color-accent: #FF6B6B;\n --color-accent-light: #FFE8E8;\n --color-highlight: #FFD166;\n --color-highlight-light: #FFF8E1;\n --color-success: #52B788;\n --color-success-light: #A8E6CF;\n --color-danger: #FF6B6B;\n --color-danger-bg: #FFE8E8;\n --color-warning: #FFD166;\n --color-warning-bg: #FFF8E1;\n --color-bg-page: #FFF9F0;\n --color-bg-surface: #FFFFFF;\n --color-bg-subtle: #EBF7FD;\n --color-bg-navy: #1A3A4A;\n --color-text-primary: #1A3A4A;\n --color-text-secondary: #5A7A8A;\n --color-text-inverse: #FFFFFF;\n --color-text-link: #0A9FAA;\n --color-border-default: #D0F2F5;\n --color-border-strong: #0CC8D4;\n --color-border-muted: #E8EFF2;\n --font-display: 'Inter', sans-serif;\n --font-body: 'Inter', sans-serif;\n --font-mono: 'JetBrains Mono', monospace;\n --text-xs: 12px;\n --text-sm: 14px;\n --text-base: 16px;\n --text-lg: 18px;\n --text-xl: 24px;\n --text-2xl: 32px;\n }\n * { box-sizing: border-box; }\n body {\n font-family: var(--font-body);\n background: var(--color-bg-page);\n color: var(--color-text-primary);\n margin: 0;\n padding: 24px;\n font-size: var(--text-base);\n }\n h1 {\n font-family: var(--font-display);\n font-size: var(--text-2xl);\n margin: 0 0 8px;\n }\n .meta {\n color: var(--color-text-secondary);\n font-size: var(--text-sm);\n margin-bottom: 24px;\n }\n .summary {\n display: flex;\n gap: 16px;\n margin-bottom: 24px;\n flex-wrap: wrap;\n }\n .summary-card {\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border-default);\n border-radius: 8px;\n padding: 16px 24px;\n min-width: 120px;\n text-align: center;\n }\n .summary-card .count {\n font-family: var(--font-display);\n font-size: var(--text-xl);\n font-weight: bold;\n }\n .summary-card .label {\n font-size: var(--text-xs);\n color: var(--color-text-secondary);\n text-transform: uppercase;\n font-weight: bold;\n }\n .filters {\n display: flex;\n gap: 12px;\n margin-bottom: 16px;\n flex-wrap: wrap;\n }\n .filters label {\n font-size: var(--text-sm);\n color: var(--color-text-secondary);\n }\n .filters select {\n padding: 6px 10px;\n border: 1px solid var(--color-border-default);\n border-radius: 4px;\n font-size: var(--text-sm);\n background: var(--color-bg-surface);\n }\n table {\n width: 100%;\n border-collapse: collapse;\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border-default);\n border-radius: 8px;\n overflow: hidden;\n }\n th, td {\n padding: 12px 16px;\n text-align: left;\n font-size: var(--text-sm);\n border-bottom: 1px solid var(--color-border-muted);\n }\n th {\n background: var(--color-bg-subtle);\n font-weight: bold;\n cursor: pointer;\n user-select: none;\n }\n th:hover {\n background: var(--color-primary-light);\n }\n tr.detail { display: none; }\n tr.detail.open { display: table-row; }\n .detail-content {\n padding: 16px;\n background: var(--color-bg-page);\n border-left: 3px solid var(--color-primary);\n }\n .detail-content p { margin: 4px 0; }\n .detail-content p strong {\n color: var(--color-text-secondary);\n }\n .badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 4px;\n font-size: var(--text-xs);\n font-weight: bold;\n text-transform: uppercase;\n }\n .badge.critical { background: var(--color-danger-bg); color: var(--color-danger); }\n .badge.high { background: var(--color-danger-bg); color: var(--color-danger); }\n .badge.medium { background: var(--color-warning-bg); color: var(--color-warning); }\n .badge.low { background: var(--color-primary-light); color: var(--color-primary-dark); }\n .badge.info { background: var(--color-bg-subtle); color: var(--color-text-secondary); }\n .badge.pattern { background: var(--color-bg-subtle); color: var(--color-text-secondary); }\n .badge.semantic { background: var(--color-primary-light); color: var(--color-primary-dark); }\n .toggle {\n background: var(--color-bg-subtle);\n border: 1px solid var(--color-border-default);\n border-radius: 4px;\n padding: 4px 10px;\n cursor: pointer;\n font-size: var(--text-xs);\n }\n .toggle:hover { background: var(--color-primary-light); }\n footer {\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid var(--color-border-muted);\n color: var(--color-text-secondary);\n font-size: var(--text-sm);\n text-align: center;\n }\n footer a {\n color: var(--color-text-link);\n }\n</style>\n</head>\n<body>\n<h1>Seaworthy Report</h1>\n<div class=\"meta\">${escapeHtml(targetDir)} · ${escapeHtml(tier)} tier · ${new Date().toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })}</div>\n\n<div class=\"summary\">\n <div class=\"summary-card\">\n <div class=\"count\">${findings.length}</div>\n <div class=\"label\">Total</div>\n </div>\n ${['critical', 'high', 'medium', 'low', 'info']\n .map(\n (sev) => `\n <div class=\"summary-card\">\n <div class=\"count\" style=\"color: var(--color-${sev === 'critical' || sev === 'high' ? 'danger' : sev === 'medium' ? 'warning' : sev === 'low' ? 'primary' : 'text-secondary'})\">${bySeverity[sev as Severity]}</div>\n <div class=\"label\">${sev}</div>\n </div>\n `\n )\n .join('')}\n</div>\n\n<div class=\"filters\">\n <label>Category:\n <select id=\"filter-category\">\n <option value=\"\">All</option>\n ${[...new Set(findings.map((f) => f.category))]\n .sort()\n .map((c) => `<option value=\"${escapeHtml(c)}\">${escapeHtml(c)}</option>`)\n .join('')}\n </select>\n </label>\n <label>Severity:\n <select id=\"filter-severity\">\n <option value=\"\">All</option>\n <option value=\"critical\">Critical</option>\n <option value=\"high\">High</option>\n <option value=\"medium\">Medium</option>\n <option value=\"low\">Low</option>\n <option value=\"info\">Info</option>\n </select>\n </label>\n</div>\n\n<table>\n <thead>\n <tr>\n <th scope=\"col\" data-sort=\"severity\">Severity</th>\n <th scope=\"col\" data-sort=\"category\">Category</th>\n <th scope=\"col\" data-sort=\"checkId\">Check</th>\n <th scope=\"col\" data-sort=\"message\">Message</th>\n <th scope=\"col\" data-sort=\"file\">File</th>\n <th scope=\"col\"></th>\n </tr>\n </thead>\n <tbody>\n ${rows}\n </tbody>\n</table>\n\n<footer>Licensed to ${escapeHtml(licensedTo)} — ${escapeHtml(tier)} tier · <a href=\"${escapeHtml(SITE_URL)}\">Learn more at seaworthycode.com</a></footer>\n\n<script>\n(function() {\n const severityOrder = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };\n let currentSort = { col: 'severity', dir: 'asc' };\n\n function getCell(row, col) {\n const map = { severity: 0, category: 1, checkId: 2, message: 3, file: 4 };\n return row.children[map[col]].textContent.trim();\n }\n\n function sortRows(col) {\n const tbody = document.querySelector('tbody');\n const dataRows = Array.from(tbody.querySelectorAll('tr:not(.detail)'));\n const detailMap = new Map();\n Array.from(tbody.querySelectorAll('tr.detail')).forEach((d, i) => {\n detailMap.set(dataRows[i], d);\n });\n const dir = currentSort.col === col && currentSort.dir === 'asc' ? 'desc' : 'asc';\n currentSort = { col, dir };\n dataRows.sort((a, b) => {\n let av = getCell(a, col);\n let bv = getCell(b, col);\n if (col === 'severity') {\n av = severityOrder[av.toLowerCase()] ?? 99;\n bv = severityOrder[bv.toLowerCase()] ?? 99;\n }\n if (av < bv) return dir === 'asc' ? -1 : 1;\n if (av > bv) return dir === 'asc' ? 1 : -1;\n return 0;\n });\n tbody.innerHTML = '';\n dataRows.forEach((r) => {\n tbody.appendChild(r);\n const detail = detailMap.get(r);\n if (detail) tbody.appendChild(detail);\n });\n }\n\n function filterRows() {\n const cat = document.getElementById('filter-category').value;\n const sev = document.getElementById('filter-severity').value;\n const dataRows = document.querySelectorAll('tbody tr:not(.detail)');\n dataRows.forEach((row) => {\n const showCat = !cat || row.dataset.category === cat;\n const showSev = !sev || row.dataset.severity === sev;\n row.style.display = showCat && showSev ? '' : 'none';\n });\n }\n\n document.querySelectorAll('th[data-sort]').forEach((th) => {\n th.addEventListener('click', () => sortRows(th.dataset.sort));\n });\n\n document.getElementById('filter-category').addEventListener('change', filterRows);\n document.getElementById('filter-severity').addEventListener('change', filterRows);\n\n document.querySelectorAll('.toggle').forEach((btn) => {\n btn.addEventListener('click', () => {\n const idx = btn.dataset.index;\n const detail = document.getElementById('detail-' + idx);\n detail.classList.toggle('open');\n btn.textContent = detail.classList.contains('open') ? 'Hide' : 'Details';\n });\n });\n})();\n</script>\n</body>\n</html>`\n }\n}\n\nfunction isValidAnalysisType(value: unknown): value is 'pattern' | 'semantic' {\n return value === 'pattern' || value === 'semantic'\n}\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/\\u0026/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n","import { createHash } from 'crypto'\nimport { isAbsolute, relative } from 'path'\nimport { pathToFileURL } from 'url'\nimport type { Finding, Severity } from '../types/finding.js'\nimport type { ReportInput } from './types.js'\nimport type {\n SarifDocument,\n SarifInvocation,\n SarifLevel,\n SarifLocation,\n SarifResult,\n SarifRule,\n} from './sarif-types.js'\nimport { SITE_URL } from '../config/urls.js'\nimport { registry } from '../registry/index.js'\nimport type { CopyKey } from '../copy/index.js'\nimport { getCopy } from '../copy/index.js'\nimport { dedupeDegradedFindings } from './dedupe-degraded.js'\nimport pkg from '../../package.json' with { type: 'json' }\n\nconst SARIF_SCHEMA_URL = 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Documents/CommitteeSpecifications/2.1.0/sarif-schema-2.1.0.json'\n\nconst SEVERITY_TO_LEVEL: Record<Severity, SarifLevel> = {\n critical: 'error',\n high: 'error',\n medium: 'warning',\n low: 'warning',\n info: 'note',\n}\n\nfunction toPascalCase(segment: string): string {\n return segment\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join('')\n}\n\nfunction extractBareName(checkId: string): string {\n const idx = checkId.lastIndexOf('.')\n return idx === -1 ? checkId : checkId.slice(idx + 1)\n}\n\nfunction relativizePath(filePath: string, targetDir: string): string {\n if (!isAbsolute(filePath)) {\n return filePath.replace(/\\\\/g, '/').replace(/^\\.\\//, '')\n }\n return relative(targetDir, filePath).replace(/\\\\/g, '/').replace(/^\\.\\//, '')\n}\n\nfunction computeFingerprint(file: string | undefined, line: number | undefined, checkId: string): string {\n const input = file !== undefined && line !== undefined\n ? `${file}:${line}:${checkId}`\n : checkId\n return createHash('sha1').update(input).digest('hex')\n}\n\nfunction buildLocations(finding: Finding, targetDir: string): SarifLocation[] | undefined {\n if (finding.lockfiles && finding.lockfiles.length > 0) {\n return finding.lockfiles.map((lf) => ({\n physicalLocation: {\n artifactLocation: {\n uri: relativizePath(lf, targetDir),\n uriBaseId: '%SRCROOT%',\n },\n region: { startLine: finding.line ?? 1 },\n },\n }))\n }\n\n if (finding.file) {\n return [\n {\n physicalLocation: {\n artifactLocation: {\n uri: relativizePath(finding.file, targetDir),\n uriBaseId: '%SRCROOT%',\n },\n region: {\n startLine: finding.line ?? 1,\n ...(finding.column !== undefined ? { startColumn: finding.column } : {}),\n },\n },\n },\n ]\n }\n\n return undefined\n}\n\nfunction buildRuleEntry(\n checkId: string,\n highestSeverity: Severity,\n category: string,\n tier: string,\n): SarifRule {\n const bareName = extractBareName(checkId)\n\n return {\n id: checkId,\n name: toPascalCase(bareName),\n shortDescription: { text: getCopy(`checks.${bareName}.name` as CopyKey) },\n fullDescription: { text: getCopy(`checks.${bareName}.description` as CopyKey) },\n helpUri: `${SITE_URL}/checks/${checkId}`,\n defaultConfiguration: { level: SEVERITY_TO_LEVEL[highestSeverity] },\n properties: { category, tier },\n }\n}\n\nconst SEVERITY_RANK: Record<Severity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n info: 4,\n}\n\nfunction getMinTierForCheckId(checkId: string, fallbackTier: string): string {\n const check = registry.getById(checkId)\n return check?.minTier ?? fallbackTier\n}\n\nfunction buildRules(findings: Finding[], fallbackTier: string): SarifRule[] {\n const seen = new Map<string, { severity: Severity; category: string; tier: string }>()\n\n for (const f of findings) {\n const existing = seen.get(f.checkId)\n if (!existing) {\n seen.set(f.checkId, {\n severity: f.severity,\n category: f.category,\n tier: getMinTierForCheckId(f.checkId, fallbackTier),\n })\n } else {\n if (SEVERITY_RANK[f.severity] < SEVERITY_RANK[existing.severity]) {\n existing.severity = f.severity\n }\n }\n }\n\n return [...seen].map(([checkId, { severity, category, tier }]) =>\n buildRuleEntry(checkId, severity, category, tier),\n )\n}\n\nfunction buildResults(findings: Finding[], targetDir: string): SarifResult[] {\n return findings.map((f) => {\n const result: SarifResult = {\n ruleId: f.checkId,\n level: SEVERITY_TO_LEVEL[f.severity],\n message: { text: f.message },\n partialFingerprints: {\n primaryLocationLineHash: computeFingerprint(f.file, f.line, f.checkId),\n },\n properties: {\n severity: f.severity,\n },\n }\n\n const locations = buildLocations(f, targetDir)\n if (locations !== undefined) {\n result.locations = locations\n }\n\n if (f.baselineState) {\n result.baselineState = f.baselineState === 'existing' ? 'unchanged' : f.baselineState\n }\n\n if (f.confidence !== undefined) {\n result.properties!.confidence = f.confidence\n }\n if (f.remediation !== undefined) {\n result.properties!.remediation = f.remediation\n }\n result.properties!.seaworthyId = f.id\n\n // Propagate taint and analysisType properties\n if (f.properties) {\n if (f.properties.analysisType !== undefined) {\n result.properties!.analysisType = f.properties.analysisType\n }\n if (f.properties.taintSource !== undefined) {\n result.properties!.taintSource = f.properties.taintSource\n }\n if (f.properties.taintSink !== undefined) {\n result.properties!.taintSink = f.properties.taintSink\n }\n if (f.properties.flowPath !== undefined) {\n result.properties!.flowPath = f.properties.flowPath\n }\n }\n\n return result\n })\n}\n\nexport class SarifReporter {\n private readonly now: () => Date\n\n constructor(options?: { now?: () => Date }) {\n this.now = options?.now ?? (() => new Date())\n }\n\n generate(input: ReportInput): string {\n const findings = dedupeDegradedFindings(input.findings)\n const rules = buildRules(findings, input.tier)\n const results = buildResults(findings, input.targetDir)\n\n const doc: SarifDocument = {\n $schema: SARIF_SCHEMA_URL,\n version: '2.1.0',\n runs: [\n {\n tool: {\n driver: {\n name: 'Seaworthy',\n informationUri: SITE_URL,\n version: pkg.version,\n semanticVersion: pkg.version,\n rules,\n },\n },\n invocations: [this.buildInvocation(input)],\n results,\n },\n ],\n }\n return JSON.stringify(doc, null, 2)\n }\n\n private buildInvocation(input: ReportInput): SarifInvocation {\n return {\n executionSuccessful: true,\n endTimeUtc: this.now().toISOString(),\n workingDirectory: { uri: pathToFileURL(input.targetDir).toString() },\n properties: {\n tier: input.tier,\n licensedTo: input.licensedTo,\n scannedFileCount: input.scannedFileCount,\n },\n }\n }\n}\n","{\n \"name\": \"@seaworthy/core\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"lint\": \"eslint src/\",\n \"check-types\": \"tsc --noEmit\",\n \"test\": \"tsc --noEmit && vitest run\",\n \"test:benchmark\": \"vitest run --config vitest.benchmark.config.ts\",\n \"test:recall\": \"vitest run --config vitest.recall.config.ts\",\n \"gen:tsx-golden\": \"tsx scripts/gen-tsx-vuln-golden.ts\"\n },\n \"dependencies\": {\n \"@anthropic-ai/sdk\": \"^0.91.1\",\n \"acorn\": \"^8.16.0\",\n \"acorn-walk\": \"^8.3.5\",\n \"chalk\": \"^5.6.2\",\n \"ignore\": \"^7.0.5\",\n \"jose\": \"^6.0.12\",\n \"openai\": \"^6.37.0\",\n \"tree-sitter-wasms\": \"0.1.13\",\n \"web-tree-sitter\": \"0.25.10\",\n \"yaml\": \"^2.9.0\",\n \"zod\": \"^4.4.3\"\n },\n \"devDependencies\": {\n \"@derekstride/tree-sitter-sql\": \"^0.3.11\",\n \"@types/node\": \"^22.10.5\",\n \"ajv\": \"^8.20.0\",\n \"ajv-formats\": \"^3.0.1\",\n \"eslint\": \"^9.39.4\",\n \"tree-sitter-cli\": \"^0.26.9\",\n \"tree-sitter-sql\": \"^0.1.0\",\n \"tsup\": \"^8.3.6\",\n \"typescript\": \"^5.7.3\",\n \"vitest\": \"^4.1.0\"\n }\n}\n","import { z } from 'zod'\nimport { validateJwt, setJwks, clearJwks, type LicenseClaims } from './validate.js'\nimport { LICENSE_SERVER_URL } from './config.js'\nimport { fail, ok, type Result } from '../types/result.js'\nimport type { JWK } from 'jose'\n\nconst jwksSchema = z.object({\n keys: z.array(z.object({\n kty: z.string(),\n n: z.string(),\n e: z.string(),\n alg: z.string().optional(),\n kid: z.string().optional(),\n use: z.string().optional(),\n })),\n})\n\nconst licenseResponseSchema = z.object({\n token: z.string(),\n tier: z.enum(['free', 'pro']),\n projects: z.number(),\n})\n\nexport type LicenseTier = 'free' | 'pro'\n\nexport interface LicenseClientConfig {\n baseUrl?: string\n timeout?: number\n}\n\nexport interface LicenseValidationResult {\n token: string\n tier: LicenseTier\n projects: number\n licensedTo: string\n}\n\ninterface CachedResult {\n token: string\n tier: LicenseTier\n projects: number\n licensedTo: string\n expiresAt: number\n}\n\nconst CACHE_TTL_MS = 60 * 60 * 1000\nconst REFRESH_WINDOW_MS = 5 * 60 * 1000\n\nexport class LicenseClient {\n private baseUrl: string\n private timeout: number\n private cache: CachedResult | null = null\n private jwksFetched = false\n\n constructor(config: LicenseClientConfig = {}) {\n this.baseUrl = config.baseUrl ?? LICENSE_SERVER_URL\n this.timeout = config.timeout ?? 10_000\n }\n\n private async ensureJwks(): Promise<void> {\n if (this.jwksFetched) return\n\n const response = await fetch(`${this.baseUrl}/.well-known/jwks.json`, {\n signal: AbortSignal.timeout(this.timeout),\n })\n\n if (!response.ok) {\n throw new Error('jwks.fetch_failed')\n }\n\n const data = await response.json()\n const parsed = jwksSchema.safeParse(data)\n if (!parsed.success) {\n throw new Error('jwks.invalid_response')\n }\n\n setJwks(parsed.data as { keys: JWK[] })\n this.jwksFetched = true\n }\n\n async validate(licenseKey: string | undefined): Promise<Result<LicenseValidationResult>> {\n if (this.cache && Date.now() < this.cache.expiresAt && !this.shouldRefresh()) {\n return ok({\n token: this.cache.token,\n tier: this.cache.tier,\n projects: this.cache.projects,\n licensedTo: this.cache.licensedTo,\n })\n }\n\n try {\n await this.ensureJwks()\n\n const response = await fetch(`${this.baseUrl}/validate`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ licenseKey: licenseKey ?? 'free' }),\n signal: AbortSignal.timeout(this.timeout),\n })\n\n if (response.status === 401) {\n return fail('license.invalid')\n }\n\n if (response.status === 429) {\n return fail('license.rate_limited')\n }\n\n if (!response.ok) {\n return fail('license.server_error')\n }\n\n const data = await response.json()\n const parsed = licenseResponseSchema.safeParse(data)\n\n if (!parsed.success) {\n return fail('license.invalid_response')\n }\n\n const claims: LicenseClaims = await validateJwt(parsed.data.token)\n if (claims.expired) {\n return fail('license.expired')\n }\n\n const tier = claims.tier\n const projects = claims.projects\n const licensedTo = claims.email ?? 'free tier'\n\n this.cache = {\n token: parsed.data.token,\n tier,\n projects,\n licensedTo,\n expiresAt: Date.now() + CACHE_TTL_MS,\n }\n\n return ok({\n token: parsed.data.token,\n tier,\n projects,\n licensedTo,\n })\n } catch (err) {\n if (err instanceof DOMException && err.name === 'TimeoutError') {\n return fail('license.server_unreachable')\n }\n if (err instanceof TypeError) {\n return fail('license.server_unreachable')\n }\n return fail('license.server_unreachable')\n }\n }\n\n private shouldRefresh(): boolean {\n if (!this.cache) return false\n return this.cache.expiresAt - Date.now() < REFRESH_WINDOW_MS\n }\n}\n\nexport function resetValidateModule(): void {\n clearJwks()\n}\n","import { jwtVerify, createLocalJWKSet } from 'jose'\nimport type { JWK } from 'jose'\n\nexport interface LicenseClaims {\n tier: 'free' | 'pro'\n projects: number\n email?: string\n expired: boolean\n exp: number | null\n iat: number | null\n}\n\nlet _jwks: ReturnType<typeof createLocalJWKSet> | null = null\n\nexport function setJwks(jwks: { keys: JWK[] }): void {\n _jwks = createLocalJWKSet(jwks)\n}\n\nexport function clearJwks(): void {\n _jwks = null\n}\n\n/**\n * Verify a license JWT's RS256 signature and expiry.\n */\nexport async function validateJwt(token: string): Promise<LicenseClaims> {\n if (!_jwks) {\n return { tier: 'free', projects: 0, expired: true, exp: null, iat: null }\n }\n\n try {\n const { payload } = await jwtVerify(token, _jwks, {\n algorithms: ['RS256'],\n })\n\n const now = Math.floor(Date.now() / 1000)\n const expired = typeof payload.exp === 'number' ? payload.exp < now : false\n\n return {\n tier: (payload.tier as LicenseClaims['tier']) ?? 'free',\n projects: typeof payload.projects === 'number' ? payload.projects : 0,\n email: typeof payload.email === 'string' ? payload.email : undefined,\n expired,\n exp: payload.exp ?? null,\n iat: payload.iat ?? null,\n }\n } catch {\n return { tier: 'free', projects: 0, expired: true, exp: null, iat: null }\n }\n}\n","export const LICENSE_SERVER_URL =\n process.env.SEAWORTHY_LICENSE_URL ?? 'https://api.seaworthycode.com'\n","import type { CredentialProvider } from './credential-provider.js'\n\ntype Credentials = Awaited<ReturnType<CredentialProvider['getCredentials']>>\n\nconst PROVIDER_ENV_KEYS: ReadonlyArray<[string, string]> = [\n ['anthropic', 'ANTHROPIC_API_KEY'],\n ['openai', 'OPENAI_API_KEY'],\n ['kimi', 'KIMI_API_KEY'],\n ['deepseek', 'DEEPSEEK_API_KEY'],\n ['gemini', 'GEMINI_API_KEY'],\n ['openrouter', 'OPENROUTER_API_KEY'],\n ['minimax', 'MINIMAX_API_KEY'],\n]\n\nfunction inferProviderFromEnv(): string | undefined {\n if (process.env.SEAWORTHY_LLM_PROVIDER) {\n return process.env.SEAWORTHY_LLM_PROVIDER\n }\n\n for (const [provider, envKey] of PROVIDER_ENV_KEYS) {\n if (process.env[envKey]) {\n return provider\n }\n }\n\n return undefined\n}\n\nfunction inferApiKeyFromEnv(): string | undefined {\n if (process.env.SEAWORTHY_LLM_API_KEY) {\n return process.env.SEAWORTHY_LLM_API_KEY\n }\n\n for (const [, envKey] of PROVIDER_ENV_KEYS) {\n const value = process.env[envKey]\n if (value) {\n return value\n }\n }\n\n return undefined\n}\n\n/** Merge config-file credentials with environment variables (.env, shell exports). */\nexport function mergeEnvCredentials(credentials: Credentials): Credentials {\n const envApiKey = inferApiKeyFromEnv()\n const envProvider = inferProviderFromEnv()\n\n return {\n ...credentials,\n licenseKey: credentials.licenseKey ?? process.env.SEAWORTHY_LICENSE_KEY,\n llmApiKey: envApiKey ?? credentials.llmApiKey,\n llmProvider: envProvider ?? credentials.llmProvider,\n llmModel: process.env.SEAWORTHY_LLM_MODEL ?? credentials.llmModel,\n llmApiUrl: process.env.SEAWORTHY_LLM_API_URL ?? credentials.llmApiUrl,\n }\n}\n","import { LicenseClient } from '../license/client.js'\nimport type { LicenseTier } from '../license/client.js'\nimport type { CredentialProvider } from './credential-provider.js'\nimport { mergeEnvCredentials } from './merge-env-credentials.js'\nimport { ok, type Result } from '../types/result.js'\n\nexport interface ResolvedAuth {\n tier: LicenseTier\n token: string\n licensedTo: string\n llmApiKey?: string\n llmProvider?: string\n llmModel?: string\n llmApiUrl?: string\n}\n\nexport async function resolveAuth(\n provider: CredentialProvider,\n licenseClient: LicenseClient\n): Promise<Result<ResolvedAuth>> {\n const credentials = mergeEnvCredentials(await provider.getCredentials())\n\n const result = await licenseClient.validate(credentials.licenseKey ?? 'free')\n\n if (!result.ok) {\n return result\n }\n\n return ok({\n tier: result.value.tier,\n token: result.value.token,\n licensedTo: result.value.licensedTo,\n llmApiKey: credentials.llmApiKey,\n llmProvider: credentials.llmProvider,\n llmModel: credentials.llmModel,\n llmApiUrl: credentials.llmApiUrl,\n })\n}\n","import { promises as fs } from 'fs'\nimport { join } from 'path'\nimport { createHash } from 'crypto'\nimport { CACHE_DIR } from '../config/paths.js'\nimport { getCopy } from '../copy/index.js'\n\nexport interface CacheEntry<T> {\n data: T\n createdAt: number\n}\n\nexport function hashKey(parts: string[]): string {\n const h = createHash('sha256')\n for (const part of parts) {\n h.update(part)\n }\n return h.digest('hex').slice(0, 24)\n}\n\nconst PRUNE_INTERVAL_MS = 5 * 60 * 1000\n\nexport abstract class FileCache<T> {\n private cacheDir: string\n private ttlMs: number\n private lastPrune = 0\n\n constructor(subDir: string, ttlMs: number) {\n this.cacheDir = join(CACHE_DIR, subDir)\n this.ttlMs = ttlMs\n }\n\n async get(key: string): Promise<T | undefined> {\n const now = Date.now()\n if (now - this.lastPrune > PRUNE_INTERVAL_MS) {\n await this.prune()\n this.lastPrune = now\n }\n\n try {\n const filePath = join(this.cacheDir, key)\n const raw = await fs.readFile(filePath, 'utf-8')\n const entry: CacheEntry<T> = JSON.parse(raw)\n if (now - entry.createdAt > this.ttlMs) {\n return undefined\n }\n return entry.data\n } catch {\n console.error(getCopy('debug.cache_read_failed', key))\n return undefined\n }\n }\n\n async set(key: string, data: T): Promise<void> {\n try {\n await fs.mkdir(this.cacheDir, { recursive: true })\n const filePath = join(this.cacheDir, key)\n const entry: CacheEntry<T> = { data, createdAt: Date.now() }\n await fs.writeFile(filePath, JSON.stringify(entry), 'utf-8')\n } catch {\n console.error(getCopy('debug.cache_write_failed', key))\n }\n }\n\n async prune(): Promise<void> {\n try {\n const entries = await fs.readdir(this.cacheDir)\n const now = Date.now()\n for (const name of entries) {\n try {\n const filePath = join(this.cacheDir, name)\n const raw = await fs.readFile(filePath, 'utf-8')\n const entry: CacheEntry<T> = JSON.parse(raw)\n if (now - entry.createdAt > this.ttlMs) {\n await fs.unlink(filePath)\n }\n } catch {\n // skip corrupt entries\n }\n }\n } catch {\n // dir may not exist\n }\n }\n}\n","import { FileCache, hashKey } from './file-cache.js'\nimport { createHash } from 'crypto'\n\nconst AST_TTL_MS = 60 * 60 * 1000\n\nexport class AstCache extends FileCache<string> {\n constructor() {\n super('ast', AST_TTL_MS)\n }\n\n makeKey(relativePath: string, content: string): string {\n const contentHash = createHash('sha256').update(content).digest('hex').slice(0, 16)\n return hashKey([relativePath, contentHash])\n }\n\n async getAst(key: string): Promise<string | undefined> {\n return this.get(key)\n }\n\n async setAst(key: string, serializedAst: string): Promise<void> {\n return this.set(key, serializedAst)\n }\n}\n","import { FileCache, hashKey } from './file-cache.js'\nimport { createHash } from 'crypto'\n\nconst DEP_TTL_MS = 24 * 60 * 60 * 1000\n\nexport class DepCache extends FileCache<string> {\n constructor() {\n super('deps', DEP_TTL_MS)\n }\n\n makeKey(relativePath: string, lockfileContent: string): string {\n const contentHash = createHash('sha256').update(lockfileContent).digest('hex').slice(0, 16)\n return hashKey([relativePath, contentHash])\n }\n\n async getAudit(key: string): Promise<string | undefined> {\n return this.get(key)\n }\n\n async setAudit(key: string, auditOutput: string): Promise<void> {\n return this.set(key, auditOutput)\n }\n}\n","import { registry } from '../registry/index.js'\nimport { getCopy } from '../copy/index.js'\nimport type { CopyKey } from '../copy/index.js'\nimport type { Tier, Category } from '../types/check.js'\n\nexport interface CheckManifestEntry {\n /** Full kebab-case check ID, e.g. 'security.dangerous-eval'. Stable public API. */\n id: string\n /** Category the check belongs to. */\n category: Category\n /** Severity of findings emitted by this check. */\n severity: string\n /** Minimum licence tier required to run this check. */\n minTier: Tier\n /** Human-readable name, resolved from copy registry. */\n name: string\n /** Short description, resolved from copy registry. */\n description: string\n /**\n * Why it matters explanation, resolved from copy registry.\n * Null when no why key exists for this check.\n */\n why: string | null\n /**\n * Remediation hint, resolved from copy registry.\n * Null when no remediation key exists for this check (not all checks have one yet).\n */\n remediation: string | null\n}\n\n/**\n * Generate a manifest of all registered checks with copy resolved.\n *\n * Throws if `name` or `description` copy is missing for any check — an\n * undocumented check should not ship. Tolerates a missing `remediation` key\n * (returns null for that field).\n *\n * @attribution CWE-0 (internal tooling — no external rule source)\n */\nexport function generateCheckManifest(): CheckManifestEntry[] {\n // Importing core/src/index.js triggers all check side-effect registrations.\n // Callers are responsible for ensuring checks are registered before calling\n // this function (import '../index.js' or equivalent).\n const checks = registry.all()\n\n return checks.map((check) => {\n const bareId = check.id.includes('.') ? check.id.slice(check.id.indexOf('.') + 1) : check.id\n\n const nameKey = `checks.${bareId}.name` as CopyKey\n const descKey = `checks.${bareId}.description` as CopyKey\n const whyKey = `checks.${bareId}.why` as CopyKey\n const remKey = `remediation.${check.category}.${bareId}` as CopyKey\n\n // name and description are mandatory — getCopy throws on missing key.\n const name = getCopy(nameKey)\n const description = getCopy(descKey)\n\n // Why it matters is optional — attempt resolution, return null on missing key.\n let why: string | null = null\n try {\n why = getCopy(whyKey)\n } catch (error) {\n if (error instanceof Error && /not found/.test(error.message)) {\n why = null\n } else {\n throw error\n }\n }\n\n // Remediation is optional — attempt resolution, return null on missing key.\n let remediation: string | null = null\n try {\n remediation = getCopy(remKey)\n } catch (error) {\n if (error instanceof Error && /not found/.test(error.message)) {\n remediation = null\n } else {\n throw error\n }\n }\n\n return {\n id: check.id,\n category: check.category,\n severity: check.severity,\n minTier: check.minTier,\n name,\n description,\n why,\n remediation,\n }\n })\n}\n","import { getCopy, type CopyKey } from '../copy/index.js'\n\nconst ERROR_CODE_MAP: Record<string, string> = {\n 'license.invalid': 'errors.license.invalid',\n 'license.server_unreachable': 'errors.license.server_unreachable',\n 'license.rate_limited': 'errors.license.rate_limited',\n 'license.invalid_response': 'errors.license.invalid_response',\n 'license.expired': 'errors.license.expired',\n 'license.server_error': 'errors.license.server_error',\n 'config.invalid': 'errors.config.invalid',\n 'network.unreachable': 'errors.network.unreachable',\n 'llm.timeout': 'errors.llm.timeout',\n 'llm.rate_limited': 'errors.llm.rate_limited',\n 'llm.invalid_response': 'errors.llm.invalid_response',\n 'llm.unexpected': 'errors.unexpected',\n 'scan.failed': 'errors.scan.failed',\n 'scan.timed_out': 'errors.scan.timed_out',\n 'scan.findings_found': 'errors.cli.findings_found',\n 'fs.not_a_directory': 'errors.fs.not_a_directory',\n 'fs.not_found': 'errors.fs.not_found',\n 'fs.permission_denied': 'errors.fs.permission_denied',\n 'parse.binary_file': 'errors.parse.binary_file',\n}\n\n/**\n * Map an error code to a user-facing message.\n *\n * Handles both short codes (`license.invalid`) and full copy keys\n * (`errors.license.invalid`). Resolved messages (strings containing spaces)\n * are passed through unchanged. Falls back to `errors.unexpected`.\n */\nexport function resolveErrorMessage(code: string): string {\n // Already a human-readable sentence — pass through\n if (code.includes(' ') && !code.startsWith('errors.')) {\n return code\n }\n\n const mappedKey = ERROR_CODE_MAP[code]\n if (mappedKey) {\n try {\n const message = getCopy(mappedKey as CopyKey)\n if (message) return message\n } catch {\n // ignore\n }\n }\n\n // Try the code itself as a copy key (e.g. \"errors.license.invalid\")\n try {\n const message = getCopy(code as CopyKey)\n if (message) return message\n } catch {\n // ignore\n }\n\n return getCopy('errors.unexpected')\n}\n","import { readFileSync, existsSync } from 'fs'\nimport { join, resolve as pathResolve } from 'path'\nimport {\n Parser,\n Language as TSLanguage,\n Query as TSQuery,\n} from 'web-tree-sitter'\nimport type { SourceFile } from '../types/source-file.js'\nimport { LANGUAGE_WASM_MAP, isLanguageSupported } from './language-map.js'\nimport { runtimeRequire } from '../runtime/paths.js'\n\nconst require = runtimeRequire()\n\ninterface Predicate {\n type: 'match' | 'eq'\n captureName: string\n pattern: string\n}\n\nfunction extractPredicates(queryString: string): Predicate[] {\n const predicates: Predicate[] = []\n // Match (#match? @capture \"pattern\") or (#eq? @capture \"pattern\")\n const predicateRegex = /\\(#(match|eq)\\?\\s+(@[\\w-]+)\\s+\"((?:[^\"\\\\]|\\\\.)*)\"\\s*\\)/g\n let match\n while ((match = predicateRegex.exec(queryString)) !== null) {\n const type = match[1] as 'match' | 'eq'\n const captureName = match[2]!.slice(1) // Remove @ prefix\n const pattern = match[3]!.replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\')\n predicates.push({ type, captureName, pattern })\n }\n return predicates\n}\n\nfunction _applyPredicates(\n matches: { captures: Record<string, string> }[],\n predicates: Predicate[],\n): typeof matches {\n if (predicates.length === 0) return matches\n\n return matches.filter((m) => {\n for (const pred of predicates) {\n const captureValue = m.captures[pred.captureName]\n if (captureValue === undefined) return false\n\n if (pred.type === 'eq') {\n if (captureValue !== pred.pattern) return false\n } else if (pred.type === 'match') {\n try {\n const regex = new RegExp(pred.pattern)\n if (!regex.test(captureValue)) return false\n } catch {\n // Invalid regex, skip this predicate\n }\n }\n }\n return true\n })\n}\n\nexport interface CapturePosition {\n startLine: number\n startColumn: number\n endLine: number\n endColumn: number\n}\n\nexport interface QueryMatch {\n nodeText: string\n startLine: number\n startColumn?: number\n endLine: number\n endColumn?: number\n captures: Record<string, string>\n capturePositions: Record<string, CapturePosition>\n}\n\nexport interface QueryResult {\n matches: QueryMatch[]\n degraded: boolean\n error?: string\n}\n\nlet initPromise: Promise<void> | null = null\n\nexport async function ensureParserInit(): Promise<void> {\n if (initPromise) {\n await initPromise\n return\n }\n initPromise = (async () => {\n const modDir = pathResolve(require.resolve('web-tree-sitter'), '..')\n await Parser.init({\n locateFile: (filename: string) => join(modDir, filename),\n })\n })().catch((err) => {\n initPromise = null\n throw err\n })\n await initPromise\n}\n\nconst languageCache = new Map<string, Promise<TSLanguage>>()\nconst languageVerified = new Map<string, boolean>()\nconst parserCache = new Map<string, Parser>()\nconst compiledQueryCache = new Map<string, TSQuery>()\nconst zshPartialParseWarnings = new Set<string>()\n\nconst EXPECTED_ABI_VERSION = 14\n\nfunction resolveWasmPath(wasmFilename: string): string {\n try {\n const baseDir = import.meta.dirname ?? __dirname\n const localPathSrc = pathResolve(baseDir, '..', '..', 'wasm', wasmFilename)\n if (existsSync(localPathSrc)) {\n return localPathSrc\n }\n const localPathDist = pathResolve(baseDir, '..', 'wasm', wasmFilename)\n if (existsSync(localPathDist)) {\n return localPathDist\n }\n } catch {\n // fallback\n }\n return require.resolve(`tree-sitter-wasms/out/${wasmFilename}`)\n}\n\nfunction warnOnZshPartialParse(file: SourceFile, tree: import('web-tree-sitter').Tree): void {\n if (file.language !== 'bash' || !file.relativePath.endsWith('.zsh')) return\n const rootNode = tree.rootNode as unknown as { hasError?: boolean }\n if (!rootNode.hasError) return\n\n const warningKey = file.relativePath\n if (zshPartialParseWarnings.has(warningKey)) return\n zshPartialParseWarnings.add(warningKey)\n console.warn(`[seaworthy] ZSH_PARTIAL_PARSE: ${file.relativePath} parsed with Bash grammar; zsh-only syntax may be incomplete.`)\n}\n\nexport async function loadLanguage(langKey: string): Promise<TSLanguage> {\n const existing = languageCache.get(langKey)\n if (existing) return existing\n\n const promise = (async (): Promise<TSLanguage> => {\n const wasmFilename = LANGUAGE_WASM_MAP[langKey]\n if (!wasmFilename) {\n throw new Error(`No WASM mapping for language: ${langKey}`)\n }\n\n const wasmPath = resolveWasmPath(wasmFilename)\n const wasmBuf = readFileSync(wasmPath)\n const lang = await TSLanguage.load(wasmBuf)\n\n if (!languageVerified.has(langKey)) {\n const abi = lang.abiVersion\n if (abi !== EXPECTED_ABI_VERSION) {\n console.error(\n `[seaworthy] ABI version mismatch for ${langKey}: expected ${EXPECTED_ABI_VERSION}, got ${abi}`\n )\n languageVerified.set(langKey, false)\n throw new Error(\n `ABI version mismatch: expected ${EXPECTED_ABI_VERSION}, got ${abi}`\n )\n }\n\n const smokeParser = new Parser()\n smokeParser.setLanguage(lang)\n const smokeTree = smokeParser.parse('1 + 1')\n if (\n !smokeTree ||\n !smokeTree.rootNode ||\n smokeTree.rootNode.childCount === 0\n ) {\n smokeTree?.delete()\n smokeParser.delete()\n console.error(`[seaworthy] Smoke test failed for ${langKey}`)\n languageVerified.set(langKey, false)\n throw new Error(`Smoke test failed for language: ${langKey}`)\n }\n smokeTree.delete()\n smokeParser.delete()\n languageVerified.set(langKey, true)\n }\n\n return lang\n })().catch((err) => {\n languageCache.delete(langKey)\n throw err\n })\n\n languageCache.set(langKey, promise)\n return promise\n}\n\nexport function getOrCreateParser(lang: TSLanguage, langKey: string): Parser {\n // tree-sitter-bash crashes on case statements when reusing parser instances\n // (state corruption in WASM). Only skip caching for bash.\n if (langKey === 'bash') {\n const parser = new Parser()\n parser.setLanguage(lang)\n return parser\n }\n let parser = parserCache.get(langKey)\n if (!parser) {\n parser = new Parser()\n parser.setLanguage(lang)\n parserCache.set(langKey, parser)\n }\n return parser\n}\n\nexport async function queryFile(\n file: SourceFile,\n queryString: string,\n astCache?: Map<string, Promise<{ tree: import('web-tree-sitter').Tree; source: string }>>,\n): Promise<QueryResult> {\n if (!isLanguageSupported(file.language)) {\n return { matches: [], degraded: true }\n }\n\n const wasmFilename = LANGUAGE_WASM_MAP[file.language]\n if (!wasmFilename) {\n return { matches: [], degraded: true }\n }\n\n try {\n await ensureParserInit()\n } catch (err) {\n console.error('[seaworthy] Parser.init() failed:', err)\n return { matches: [], degraded: true, error: `Parser.init failed: ${(err as Error).stack || (err as Error).message}` }\n }\n\n let lang: TSLanguage\n try {\n lang = await loadLanguage(file.language)\n } catch (err) {\n console.error(\n `[seaworthy] Failed to load grammar for ${file.language}:`,\n (err as Error).message\n )\n return { matches: [], degraded: true, error: `loadLanguage failed: ${(err as Error).stack || (err as Error).message}` }\n }\n\n if (languageVerified.get(file.language) === false) {\n return { matches: [], degraded: true, error: `languageVerified is false for ${file.language}` }\n }\n\n let source: string\n let tree: import('web-tree-sitter').Tree\n\n if (astCache) {\n const cacheKey = `${file.path}::${file.language}`\n let parsePromise = astCache.get(cacheKey)\n if (!parsePromise) {\n parsePromise = (async () => {\n let s: string\n try {\n s = await file.content()\n } catch {\n throw new Error('read_failed')\n }\n if (s.length === 0) {\n return { tree: null as unknown as import('web-tree-sitter').Tree, source: s }\n }\n const parser = getOrCreateParser(lang, file.language)\n const parsed = parser.parse(s)\n if (!parsed) {\n throw new Error('parse_failed')\n }\n return { tree: parsed, source: s }\n })()\n astCache.set(cacheKey, parsePromise)\n }\n\n let parsed: { tree: import('web-tree-sitter').Tree; source: string }\n try {\n parsed = await parsePromise\n } catch {\n return { matches: [], degraded: true }\n }\n\n if (parsed.source.length === 0) {\n return { matches: [], degraded: false }\n }\n\n source = parsed.source\n tree = parsed.tree\n } else {\n try {\n source = await file.content()\n } catch {\n return { matches: [], degraded: true }\n }\n\n if (source.length === 0) {\n return { matches: [], degraded: false }\n }\n\n try {\n const parser = getOrCreateParser(lang, file.language)\n const parsed = parser.parse(source)\n if (!parsed) {\n return { matches: [], degraded: true }\n }\n tree = parsed\n } catch {\n return { matches: [], degraded: true }\n }\n }\n\n warnOnZshPartialParse(file, tree)\n\n const queryCacheKey = `${file.language}::${queryString}`\n let query = compiledQueryCache.get(queryCacheKey)\n if (!query) {\n try {\n query = new TSQuery(lang, queryString)\n compiledQueryCache.set(queryCacheKey, query)\n } catch (err) {\n tree.delete()\n console.error(\n `[seaworthy] Invalid query for ${file.language}:`,\n (err as Error).message\n )\n return { matches: [], degraded: true }\n }\n }\n\n const rawMatches = query.matches(tree.rootNode)\n\n // Rust, CSS, and HTML grammars in web-tree-sitter do not reliably apply\n // #match? / #eq? predicates natively for all node types (e.g. comments,\n // text nodes), so we filter post-match for those languages.\n const needsManualPredicates = file.language === 'rust' || file.language === 'css' || file.language === 'html'\n const predicates = needsManualPredicates ? extractPredicates(queryString) : []\n\n const matches: QueryMatch[] = rawMatches.map((m) => {\n const captures: Record<string, string> = {}\n const capturePositions: Record<string, CapturePosition> = {}\n for (const cap of m.captures) {\n captures[cap.name] = cap.node.text\n capturePositions[cap.name] = {\n startLine: cap.node.startPosition.row + 1,\n startColumn: cap.node.startPosition.column + 1,\n endLine: cap.node.endPosition.row + 1,\n endColumn: cap.node.endPosition.column + 1,\n }\n }\n\n const firstNode = m.captures[0]?.node ?? tree.rootNode\n\n return {\n nodeText: firstNode.text,\n startLine: firstNode.startPosition.row + 1,\n startColumn: firstNode.startPosition.column + 1,\n endLine: firstNode.endPosition.row + 1,\n endColumn: firstNode.endPosition.column + 1,\n captures,\n capturePositions,\n }\n }).filter((m) => {\n for (const pred of predicates) {\n const captureValue = m.captures[pred.captureName]\n // Skip predicates for captures not present in this match (the match may\n // have come from a different pattern in the same query).\n if (captureValue === undefined) continue\n\n if (pred.type === 'eq') {\n if (captureValue !== pred.pattern) return false\n } else if (pred.type === 'match') {\n try {\n const regex = new RegExp(pred.pattern)\n if (!regex.test(captureValue)) return false\n } catch {\n return false\n }\n }\n }\n return true\n })\n\n if (!astCache) {\n tree.delete()\n }\n return { matches, degraded: false }\n}\n\nexport function _resetCache(): void {\n initPromise = null\n languageCache.clear()\n languageVerified.clear()\n for (const parser of parserCache.values()) {\n parser.delete()\n }\n parserCache.clear()\n for (const query of compiledQueryCache.values()) {\n query.delete()\n }\n compiledQueryCache.clear()\n zshPartialParseWarnings.clear()\n}\n","import type { Language } from '../types/source-file.js'\n\nexport const LANGUAGE_WASM_MAP: Record<string, string> = {\n javascript: 'tree-sitter-javascript.wasm',\n typescript: 'tree-sitter-typescript.wasm',\n tsx: 'tree-sitter-tsx.wasm',\n html: 'tree-sitter-html.wasm',\n css: 'tree-sitter-css.wasm',\n python: 'tree-sitter-python.wasm',\n go: 'tree-sitter-go.wasm',\n ruby: 'tree-sitter-ruby.wasm',\n java: 'tree-sitter-java.wasm',\n rust: 'tree-sitter-rust.wasm',\n bash: 'tree-sitter-bash.wasm',\n php: 'tree-sitter-php.wasm',\n sql: 'tree-sitter-sql.wasm',\n}\n\nexport const TAINTLESS_LANGUAGES = new Set<string>(['json', 'yaml', 'plaintext', 'html', 'css'])\n\nexport function isLanguageSupported(language: Language): boolean {\n return language in LANGUAGE_WASM_MAP\n}\n","import { createRequire } from 'module'\nimport { dirname, resolve as pathResolve } from 'path'\nimport { fileURLToPath, pathToFileURL } from 'url'\n\ndeclare const __dirname: string | undefined\ndeclare const __filename: string | undefined\n\nfunction normaliseStackPath(rawPath: string): string {\n return rawPath.startsWith('file://') ? fileURLToPath(rawPath) : rawPath\n}\n\nfunction filenameFromStack(): string {\n const stack = new Error().stack ?? ''\n const frame = stack\n .split('\\n')\n .map((line) => line.match(/\\(?((?:file:\\/\\/)?(?:\\/)?(?:[A-Za-z]:)?[\\\\/].+?):\\d+:\\d+\\)?$/)?.[1])\n .find((match): match is string => Boolean(match))\n\n if (!frame) {\n return pathResolve(process.cwd(), 'package.json')\n }\n\n return normaliseStackPath(frame)\n}\n\nexport function runtimeModuleDir(): string {\n if (typeof __dirname === 'string') return __dirname\n if (typeof __filename === 'string') return dirname(__filename)\n return dirname(filenameFromStack())\n}\n\nexport function runtimeRequire() {\n return createRequire(pathToFileURL(pathResolve(runtimeModuleDir(), 'index.js')))\n}\n","import type { Finding } from '../../types/finding.js'\n\nexport type AnalysisType = 'pattern' | 'semantic'\n\n/**\n * Build a finding with the given analysisType set in properties.\n * Legacy findings default to 'pattern' when no analysisType is specified.\n */\nexport function buildFinding(\n base: Omit<Finding, 'properties'> & { properties?: Record<string, unknown> },\n analysisType: AnalysisType = 'pattern',\n): Finding {\n return {\n ...base,\n properties: {\n ...base.properties,\n analysisType,\n },\n }\n}\n\n/**\n * Set analysisType on an existing finding object (mutates in place).\n * Used by create-tree-sitter-check to avoid object spread overhead.\n */\nexport function setAnalysisType(finding: Finding, analysisType: AnalysisType = 'pattern'): void {\n if (!finding.properties) {\n finding.properties = {}\n }\n finding.properties.analysisType = analysisType\n}\n","import type { Check, ScanContext, Category, Tier } from '../types/check.js'\nimport type { Severity } from '../types/finding.js'\nimport type { Finding, Confidence } from '../types/finding.js'\nimport type { Language, SourceFile } from '../types/source-file.js'\nimport { queryFile } from '../ast/query.js'\nimport type { CapturePosition } from '../ast/query.js'\nimport { getCopy } from '../copy/index.js'\nimport { setAnalysisType } from './helpers/finding-builder.js'\nimport { runWithConcurrencyCollect } from '../runner/scan-runner.js'\nimport { isMechanicalCheckExcludedPath } from '../config/path-exclusions.js'\n\nexport interface CreateTreeSitterCheckOptions {\n id: string\n nameKey: string\n descriptionKey: string\n category: Category\n severity: Severity\n minTier: Tier\n queries: Partial<Record<Language, string>>\n messageKey: string\n degradedMessageKey: string\n remediationKey: string\n confidence?: Confidence\n\n /**\n * Optional custom function to produce the finding message from a query\n * match. Receives the full captures map. If omitted, the default\n * behaviour is `getCopy(messageKey, match.nodeText)`.\n *\n * Checks import `getCopy` directly — do not pass it as a parameter.\n */\n messageFactory?: (captures: Record<string, string>) => string\n\n /**\n * Optional predicate to filter matches before emitting a finding.\n * Return `true` to emit the finding, `false` to skip it.\n * Receives the full captures map. If omitted, all matches produce findings.\n */\n matchFilter?: (captures: Record<string, string>) => boolean\n\n /**\n * Optional factory for per-match confidence. When omitted, the check-level\n * `confidence` option is used for every finding.\n */\n confidenceFactory?: (captures: Record<string, string>) => Confidence\n\n /**\n * Optional predicate to skip entire files before querying.\n * Return `false` to skip the file (no findings emitted for it).\n * Receives the SourceFile. If omitted, all matching-language files are scanned.\n */\n fileFilter?: (file: SourceFile) => boolean\n\n /**\n * Optional factory to produce a fix payload for a finding.\n * Receives the full captures map and capture positions.\n * Must return undefined if the fix capture is absent — the finding will\n * emit without a fix in that case.\n */\n fixFactory?: (\n captures: Record<string, string>,\n capturePositions: Record<string, CapturePosition>,\n ) => { range: { startLine: number; startColumn: number; endLine: number; endColumn: number }; replacement: string } | undefined\n}\n\n// Cast getCopy to a looser signature so dynamic keys (passed as\n// runtime parameters) can be resolved without fighting the strongly\n// typed CopyKey union.\nconst resolveCopy = getCopy as (key: string, ...args: string[]) => string\n\nexport function createTreeSitterCheck(options: CreateTreeSitterCheckOptions): Check {\n const {\n id,\n nameKey,\n descriptionKey,\n category,\n severity,\n minTier,\n queries,\n messageKey,\n degradedMessageKey,\n remediationKey,\n messageFactory,\n matchFilter,\n fileFilter,\n fixFactory,\n confidenceFactory,\n confidence = 'high',\n } = options\n\n const name = resolveCopy(nameKey)\n const description = resolveCopy(descriptionKey)\n const remediation = resolveCopy(remediationKey)\n\n return {\n id,\n name,\n description,\n category,\n severity,\n minTier,\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n const degradedLanguages = new Set<string>()\n\n const eligibleFiles = ctx.files.filter((file) => {\n const query = queries[file.language]\n if (!query) return false\n if (isMechanicalCheckExcludedPath(file.relativePath)) return false\n if (fileFilter && !fileFilter(file)) return false\n return true\n })\n\n const fileFindings = await runWithConcurrencyCollect(\n eligibleFiles,\n async (file) => {\n const query = queries[file.language]!\n try {\n const result = await queryFile(file, query, ctx.astCache)\n\n if (result.degraded) {\n if (!degradedLanguages.has(file.language)) {\n degradedLanguages.add(file.language)\n return [{\n id: `${id}:${file.relativePath}:degraded:${file.language}`,\n checkId: id,\n category,\n severity: 'info' as Severity,\n message: resolveCopy(degradedMessageKey, file.relativePath, file.language),\n file: file.relativePath,\n confidence,\n remediation,\n }]\n }\n return []\n }\n\n const fileResults: Finding[] = []\n for (let i = 0; i < result.matches.length; i++) {\n const match = result.matches[i]!\n\n if (matchFilter && !matchFilter(match.captures)) {\n continue\n }\n\n const message = messageFactory\n ? messageFactory(match.captures)\n : resolveCopy(messageKey, match.nodeText)\n\n const fix = fixFactory\n ? fixFactory(match.captures, match.capturePositions)\n : undefined\n\n fileResults.push({\n id: `${id}:${file.relativePath}:${match.startLine}:${match.startColumn ?? 0}:${i}`,\n checkId: id,\n category,\n severity,\n message,\n file: file.relativePath,\n line: match.startLine,\n column: match.startColumn,\n confidence: confidenceFactory ? confidenceFactory(match.captures) : confidence,\n remediation,\n fix,\n })\n }\n return fileResults\n } catch {\n return [{\n id: `${id}:${file.relativePath}:degraded:error`,\n checkId: id,\n category,\n severity: 'info' as Severity,\n message: resolveCopy(degradedMessageKey, file.relativePath, file.language),\n file: file.relativePath,\n confidence,\n remediation,\n }]\n }\n },\n 4,\n )\n\n for (const ff of fileFindings) {\n findings.push(...ff)\n }\n\n for (const finding of findings) {\n setAnalysisType(finding, 'pattern')\n }\n return findings\n },\n }\n}\n","import type { Finding } from '../types/finding.js'\n\nfunction findingKey(f: Finding): string {\n return `${f.checkId}:${f.file}:${f.line}:${f.column ?? 0}`\n}\n\n/**\n * Merge two sets of findings from different analysis strategies for the same\n * check ID. When both strategies flag the same location, the tree-sitter\n * finding wins because AST matches are higher-confidence.\n */\nexport function mergeFindings(tsFindings: Finding[], otherFindings: Finding[]): Finding[] {\n const map = new Map<string, Finding>()\n\n for (const f of otherFindings) {\n map.set(findingKey(f), f)\n }\n\n // Tree-sitter findings overwrite other findings on collision.\n for (const f of tsFindings) {\n map.set(findingKey(f), f)\n }\n\n return Array.from(map.values())\n}\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\nimport { mergeFindings } from '../merge-findings.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.hardcoded-secrets'\n\nconst SECRET_PATTERNS = [\n { regex: /AWS_SECRET_ACCESS_KEY\\s*=\\s*['\"]([A-Za-z0-9/+=]{40})['\"]/gi, name: 'AWS secret access key', minLength: 40, method: 'known-format' as const },\n { regex: /private_key\\s*[:=]\\s*['\"]([^'\"]{20,})['\"]/gi, name: 'private key', minLength: 20, method: 'regex' as const },\n { regex: /api_key\\s*[:=]\\s*['\"]([^'\"]{8,})['\"]/gi, name: 'API key', minLength: 8, method: 'regex' as const },\n { regex: /token\\s*[:=]\\s*['\"]([^'\"]{8,})['\"]/gi, name: 'token', minLength: 8, method: 'regex' as const },\n { regex: /connection_string\\s*[:=]\\s*['\"]([^'\"]{10,})['\"]/gi, name: 'connection string', minLength: 10, method: 'regex' as const },\n { regex: /(sk_live_|sk_test_|rk_live_|rk_test_)[A-Za-z0-9]{16,}/g, name: 'Stripe secret key', minLength: 24, method: 'known-format' as const },\n { regex: /whsec_[A-Za-z0-9+/=]{16,}/g, name: 'Stripe webhook signing secret', minLength: 20, method: 'known-format' as const },\n]\n\nfunction isExcluded(path: string): boolean {\n return isMechanicalCheckExcludedPath(path)\n}\n\nconst REMEDIATION = getCopy('remediation.security.hardcoded-secrets')\n\n// ---------------------------------------------------------------------------\n// Regex strategy (retained for plaintext and as a fallback)\n// ---------------------------------------------------------------------------\n\nconst regexCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.hardcoded-secrets.name'),\n description: getCopy('checks.hardcoded-secrets.description'),\n category: 'security',\n severity: 'critical',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n for (const file of ctx.files) {\n if (file.language !== 'javascript' && file.language !== 'typescript' && file.language !== 'plaintext' && file.language !== 'sql' && file.language !== 'bash' && file.language !== 'html' && file.language !== 'css') continue\n if (isExcluded(file.relativePath)) continue\n\n const content = await file.content()\n const lines = content.split('\\n')\n\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\n const line = lines[lineNum]!\n for (let patternIdx = 0; patternIdx < SECRET_PATTERNS.length; patternIdx++) {\n const pattern = SECRET_PATTERNS[patternIdx]!\n const matches = Array.from(line.matchAll(pattern.regex))\n for (let matchIdx = 0; matchIdx < matches.length; matchIdx++) {\n const match = matches[matchIdx]!\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:${matchIdx}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'critical',\n message: getCopy('checks.hardcoded-secrets.message', pattern.name),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: mechanicalConfidence(\n pattern.method,\n file.relativePath,\n match[1] ?? match[0],\n ),\n remediation: REMEDIATION,\n })\n }\n }\n }\n }\n return findings\n },\n}\n\n// ---------------------------------------------------------------------------\n// Tree-sitter strategy (JS / TS / TSX / Python / Ruby / Java / Go / PHP / Rust)\n// ---------------------------------------------------------------------------\n\nconst TS_QUERIES: Record<string, string> = {\n javascript: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (property_identifier) @name\n value: (string) @value) @match\n`,\n typescript: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (property_identifier) @name\n value: (string) @value) @match\n`,\n tsx: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (property_identifier) @name\n value: (string) @value) @match\n`,\n python: `\n(assignment\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (identifier) @name\n value: (string) @value) @match\n`,\n ruby: `\n(assignment left: (identifier) @name right: (string) @value) @match\n\n(pair key: (_) @name value: (string) @value) @match\n`,\n java: `\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name\n value: (string_literal) @value)) @match\n\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name\n value: (string_literal) @value)) @match\n`,\n go: `\n(var_declaration\n (var_spec\n name: (identifier) @name\n value: (_) @value)) @match\n\n(short_var_declaration\n left: (expression_list (identifier) @name)\n right: (expression_list (_) @value)) @match\n`,\n php: `\n(assignment_expression\n left: (_) @name\n right: (_) @value) @match\n`,\n rust: `\n(let_declaration\n pattern: (identifier) @name\n value: (string_literal) @value) @match\n`,\n bash: `\n(variable_assignment\n name: (variable_name) @name\n value: (string) @value) @match\n`,\n}\n\nconst NAME_RULES = [\n { regex: /^AWS_SECRET_ACCESS_KEY$/, name: 'AWS secret access key', minLength: 40, method: 'known-format' as const },\n { regex: /^private_key$/, name: 'private key', minLength: 20, method: 'regex' as const },\n { regex: /^api_key$/, name: 'API key', minLength: 8, method: 'regex' as const },\n { regex: /^token$/, name: 'token', minLength: 8, method: 'regex' as const },\n { regex: /^connection_string$/, name: 'connection string', minLength: 10, method: 'regex' as const },\n]\n\nconst VALUE_PREFIX_RULES = [\n { regex: /^(sk_live_|sk_test_|rk_live_|rk_test_)[A-Za-z0-9]{16,}$/, name: 'Stripe secret key' },\n { regex: /^whsec_[A-Za-z0-9+/=]{16,}$/, name: 'Stripe webhook signing secret' },\n]\n\nfunction matchesValuePrefix(cleanValue: string): { name: string } | undefined {\n for (const rule of VALUE_PREFIX_RULES) {\n if (rule.regex.test(cleanValue)) {\n return { name: rule.name }\n }\n }\n return undefined\n}\n\nconst tsCheck = createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.hardcoded-secrets.name',\n descriptionKey: 'checks.hardcoded-secrets.description',\n category: 'security',\n severity: 'critical',\n minTier: 'free',\n queries: TS_QUERIES,\n messageKey: 'checks.hardcoded-secrets.message',\n degradedMessageKey: 'checks.hardcoded-secrets.degraded',\n remediationKey: 'remediation.security.hardcoded-secrets',\n fileFilter: (file) => !isExcluded(file.relativePath),\n matchFilter: (captures) => {\n let name = captures.name\n const value = captures.value\n if (!name || !value) return false\n\n if (name.startsWith('$')) name = name.slice(1)\n\n const trimmedValue = value.trim()\n if (!/^['\"`].*['\"`]$/.test(trimmedValue)) return false\n const cleanValue = trimmedValue.replace(/^['\"`]|['\"`]$/g, '')\n for (const rule of NAME_RULES) {\n if (rule.regex.test(name) && cleanValue.length >= rule.minLength) {\n return true\n }\n }\n return matchesValuePrefix(cleanValue) !== undefined\n },\n messageFactory: (captures) => {\n let name = captures.name ?? ''\n const value = captures.value ?? ''\n if (name.startsWith('$')) name = name.slice(1)\n const cleanValue = value.replace(/^['\"`]|['\"`]$/g, '')\n for (const rule of NAME_RULES) {\n if (rule.regex.test(name) && cleanValue.length >= rule.minLength) {\n return getCopy('checks.hardcoded-secrets.message', rule.name)\n }\n }\n const valuePrefix = matchesValuePrefix(cleanValue)\n if (valuePrefix) {\n return getCopy('checks.hardcoded-secrets.message', valuePrefix.name)\n }\n return getCopy('checks.hardcoded-secrets.message', name)\n },\n confidenceFactory: (captures) => {\n let name = captures.name ?? ''\n const value = captures.value ?? ''\n if (name.startsWith('$')) name = name.slice(1)\n const cleanValue = value.replace(/^['\"`]|['\"`]$/g, '')\n\n for (const rule of NAME_RULES) {\n if (rule.regex.test(name) && cleanValue.length >= rule.minLength) {\n return mechanicalConfidence(rule.method, undefined, cleanValue)\n }\n }\n const valuePrefix = matchesValuePrefix(cleanValue)\n if (valuePrefix) {\n return mechanicalConfidence('known-format', undefined, cleanValue)\n }\n return mechanicalConfidence('ast', undefined, cleanValue)\n },\n})\n\n// ---------------------------------------------------------------------------\n// Hybrid check\n// ---------------------------------------------------------------------------\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.hardcoded-secrets.name'),\n description: getCopy('checks.hardcoded-secrets.description'),\n category: 'security',\n severity: 'critical',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [regexFindings, tsFindings] = await Promise.all([\n regexCheck.run(ctx),\n tsCheck.run(ctx),\n ])\n return mergeFindings(tsFindings, regexFindings)\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { hasFileInGitHistory } from '../../git.js'\nimport { getCopy } from '../../copy/index.js'\nimport { promises as fs } from 'fs'\nimport { join, relative } from 'path'\nimport { lineMatch, scanBashLines } from '../helpers/bash-patterns.js'\n\n/**\n * Surfaces committed environment files and settings.py files containing hardcoded credentials.\n *\n * @attribution CWE-798\n */\n\nconst SETTINGS_SECRET_REGEX = /(?:SECRET_KEY|DATABASE_URL|API_KEY|AUTH_TOKEN|MAIL_PASSWORD)\\s*=\\s*['\"][^'\"]{8,}['\"]/i\n\nconst JAVA_PROPERTIES_SECRET_REGEX =\n /(?:password|secret|api[_-]?key|auth[_-]?token)\\s*[:=]\\s*['\"]?[^\\s#'\"]{8,}/i\n\nasync function findSettingsFiles(dir: string): Promise<string[]> {\n const results: string[] = []\n let entries\n try {\n entries = await fs.readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {\n results.push(...await findSettingsFiles(join(dir, entry.name)))\n } else if (entry.isFile() && entry.name === 'settings.py') {\n results.push(join(dir, entry.name))\n }\n }\n return results\n}\n\nasync function findJavaConfigFiles(dir: string): Promise<string[]> {\n const names = new Set(['application.properties', 'application.yml', 'application.yaml'])\n const results: string[] = []\n let entries\n try {\n entries = await fs.readdir(dir, { withFileTypes: true })\n } catch {\n return []\n }\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {\n results.push(...(await findJavaConfigFiles(join(dir, entry.name))))\n } else if (entry.isFile() && names.has(entry.name)) {\n results.push(join(dir, entry.name))\n }\n }\n return results\n}\n\nasync function hasCommittedJavaConfigWithSecrets(targetDir: string): Promise<boolean> {\n const configFiles = await findJavaConfigFiles(targetDir)\n for (const configPath of configFiles) {\n try {\n const content = await fs.readFile(configPath, 'utf-8')\n if (!JAVA_PROPERTIES_SECRET_REGEX.test(content)) continue\n const relPath = relative(targetDir, configPath).replace(/\\\\/g, '/')\n const escapedRelPath = relPath.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n if (hasFileInGitHistory(targetDir, new RegExp(`(?:^|/)${escapedRelPath}$`))) return true\n } catch {\n continue\n }\n }\n return false\n}\n\nasync function hasCommittedSettingsWithSecrets(targetDir: string): Promise<boolean> {\n const settingsFiles = await findSettingsFiles(targetDir)\n for (const settingsPath of settingsFiles) {\n try {\n const content = await fs.readFile(settingsPath, 'utf-8')\n if (!SETTINGS_SECRET_REGEX.test(content)) continue\n const relPath = relative(targetDir, settingsPath).replace(/\\\\/g, '/')\n const escapedRelPath = relPath.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n if (hasFileInGitHistory(targetDir, new RegExp(`(?:^|/)${escapedRelPath}$`))) return true\n } catch {\n continue\n }\n }\n return false\n}\n\nregistry.register({\n id: 'security.committed-env',\n name: 'Committed .env files',\n description: '.env files committed to git',\n category: 'security',\n severity: 'high',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const hasEnv = hasFileInGitHistory(\n ctx.targetDir,\n /(?:^|\\/)\\.env(?:$|\\.(?!example$).+)/\n )\n\n const hasSettings = await hasCommittedSettingsWithSecrets(ctx.targetDir)\n const hasJavaConfig = await hasCommittedJavaConfigWithSecrets(ctx.targetDir)\n\n if (!hasEnv && !hasSettings && !hasJavaConfig) return []\n\n const findings: Finding[] = []\n if (hasEnv) {\n findings.push({\n id: 'committed-env-1',\n checkId: 'security.committed-env',\n category: 'security',\n severity: 'high',\n message: 'A .env file (other than .env.example) is tracked in git history. Environment files should never be committed.',\n confidence: 'high',\n remediation: getCopy('remediation.security.committed-env'),\n })\n }\n if (hasSettings) {\n findings.push({\n id: 'committed-env-2',\n checkId: 'security.committed-env',\n category: 'security',\n severity: 'high',\n message: 'A settings.py file containing secrets is tracked in git history. Move secrets to environment variables or a secrets manager.',\n confidence: 'high',\n remediation: getCopy('remediation.security.committed-env'),\n })\n }\n if (hasJavaConfig) {\n findings.push({\n id: 'committed-env-3',\n checkId: 'security.committed-env',\n category: 'security',\n severity: 'high',\n message:\n 'A Spring application.properties or application.yml file containing secrets is tracked in git history. Use environment variables or a secrets manager.',\n confidence: 'high',\n remediation: getCopy('remediation.security.committed-env'),\n })\n }\n if (hasEnv) {\n const sourceFindings = await scanBashLines(ctx, {\n checkId: 'security.committed-env',\n category: 'security',\n severity: 'high',\n message: () => 'Shell script sources a tracked .env file.',\n remediation: getCopy('remediation.security.committed-env'),\n }, (line, _content, index) => lineMatch(line, index, /^\\s*(?:source|\\.)\\s+\\.?\\.env(?:\\s|$)/))\n findings.push(...sourceFindings)\n }\n return findings\n },\n})\n","import type { Category, ScanContext } from '../../types/check.js'\nimport type { Finding, Severity } from '../../types/finding.js'\n\nexport const SENSITIVE_NAME_REGEX =\n /(?:password|passwd|pwd|secret|api[_-]?key|access[_-]?key|private[_-]?key|token|credential|aws[_-]?access[_-]?key[_-]?id|aws[_-]?secret[_-]?access[_-]?key)/i\n\nexport const EXTERNAL_COMMAND_REGEX = /\\b(?:curl|wget|rsync|scp|ssh|psql|mysql|sqlite3)\\b/\n\nexport interface BashFindingConfig {\n checkId: string\n category: Category\n severity: Severity\n message: (match: string) => string\n remediation: string\n}\n\nexport interface BashLineMatch {\n line: number\n column: number\n text: string\n}\n\nexport function isBashFile(language: string | undefined): boolean {\n return language === 'bash'\n}\n\nexport function makeBashFinding(\n config: BashFindingConfig,\n file: string,\n match: BashLineMatch,\n index: number,\n): Finding {\n return {\n id: `${config.checkId}:${file}:${match.line}:${match.column}:${index}`,\n checkId: config.checkId,\n category: config.category,\n severity: config.severity,\n message: config.message(match.text),\n file,\n line: match.line,\n column: match.column,\n confidence: 'high',\n remediation: config.remediation,\n }\n}\n\nexport async function scanBashLines(\n ctx: ScanContext,\n config: BashFindingConfig,\n detector: (line: string, content: string, lineIndex: number) => BashLineMatch | null,\n): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (!isBashFile(file.language)) continue\n const content = await file.content()\n const lines = content.split('\\n')\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index]!\n const match = detector(line, content, index)\n if (!match) continue\n findings.push(makeBashFinding(config, file.relativePath, match, findings.length))\n }\n }\n\n return findings\n}\n\nexport function lineMatch(line: string, lineIndex: number, pattern: RegExp): BashLineMatch | null {\n const match = pattern.exec(line)\n if (!match) return null\n return {\n line: lineIndex + 1,\n column: (match.index ?? 0) + 1,\n text: match[0],\n }\n}\n\nexport function hasShellValidation(content: string): boolean {\n return /\\[\\[\\s*\"?\\$\\d+\"?\\s*=~\\s*\\^/.test(content) ||\n /\\bcase\\s+(?:\"?\\$\\d+\"?|\"?\\$\\{[1-9][0-9]*(?::-[^}]*)?\\}\"?)\\s+in\\b/.test(content) ||\n /\\[\\[\\s+-[nz]\\s+\"?\\$\\d+\"?\\s*\\]\\]/.test(content)\n}\n\nexport function isShellCommentOrBlank(line: string): boolean {\n const trimmed = line.trim()\n return trimmed === '' || trimmed.startsWith('#')\n}\n\nexport function shellLineHasTimeout(line: string): boolean {\n return /^\\s*timeout\\s+\\S+/.test(line) ||\n /(?:^|\\s)(?:--max-time|--connect-timeout|--timeout|-m)(?:\\s|=|$)/.test(line)\n}\n\nexport function shellContentHasRetry(content: string): boolean {\n return /\\b(?:--retry|retry|retries|attempts?)\\b/i.test(content) ||\n /\\bfor\\s+\\w+\\s+in\\s+\\{?1\\.\\.[2-9]/.test(content) ||\n /\\bwhile\\b[\\s\\S]{0,120}\\b(?:attempt|retry|count)\\b/i.test(content)\n}\n\nexport function shellContentHasTrap(content: string): boolean {\n return /^\\s*trap\\b.*\\b(?:EXIT|INT|TERM|SIGINT|SIGTERM)\\b/m.test(content)\n}\n\nexport function shellContentHasLogging(content: string): boolean {\n return /^\\s*(?:echo|printf|logger)\\b/m.test(content) ||\n /(?:^|\\s)>&2(?:\\s|$)/m.test(content)\n}\n","/**\n * @attribution CWE-489\n */\nimport { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\nimport { mergeFindings } from '../merge-findings.js'\n\nconst CHECK_ID = 'ops.debug-mode-enabled'\n\nconst CONFIG_PATTERNS = [\n /\\bDEBUG\\s*=\\s*true\\b/i,\n /\\bLOG_LEVEL\\s*=\\s*['\"]?debug['\"]?\\b/i,\n /[\"']?verbose[\"']?\\s*:\\s*true\\b/i,\n /\\bNODE_ENV\\s*=\\s*['\"]?development['\"]?\\b/i,\n]\n\nconst PYTHON_DEBUG_PATTERNS = [\n /\\bapp\\.run\\s*\\([^)]*debug\\s*=\\s*true\\b/i,\n /\\bDEBUG\\s*=\\s*true\\b/i,\n /\\bapp\\.debug\\s*=\\s*true\\b/i,\n]\n\nconst RUBY_DEBUG_PATTERNS = [\n /\\bconfig\\.consider_all_requests_local\\s*=\\s*true\\b/i,\n /\\bRails\\.application\\.config\\.consider_all_requests_local\\s*=\\s*true\\b/i,\n]\n\nconst HTML_DEBUG_PATTERNS = [\n /<meta\\b[^>]*\\bname\\s*=\\s*[\"']debug[\"'][^>]*\\bcontent\\s*=\\s*[\"']true[\"']/i,\n /<meta\\b[^>]*\\bcontent\\s*=\\s*[\"']true[\"'][^>]*\\bname\\s*=\\s*[\"']debug[\"']/i,\n]\n\nconst CONFIG_FILES = [\n /\\.config\\./,\n /\\.env/,\n /docker-compose/i,\n /Dockerfile/i,\n /settings\\.py$/,\n /settings\\/.*\\.py$/,\n]\n\nfunction isConfigFile(path: string): boolean {\n return CONFIG_FILES.some((p) => p.test(path))\n}\n\nconst REMEDIATION = getCopy('remediation.ops.debug-mode-enabled')\n\n// ---------------------------------------------------------------------------\n// Regex strategy for config files\n// ---------------------------------------------------------------------------\n\nconst regexCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.debug-mode-enabled.name'),\n description: getCopy('checks.debug-mode-enabled.description'),\n category: 'ops',\n severity: 'low',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n for (const file of ctx.files) {\n if (\n !isConfigFile(file.relativePath) &&\n file.language !== 'python' &&\n file.language !== 'html' &&\n file.language !== 'ruby'\n ) {\n continue\n }\n\n const content = await file.content()\n const lines = content.split('\\n')\n\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\n const line = lines[lineNum]!\n\n if (isConfigFile(file.relativePath)) {\n for (let patternIdx = 0; patternIdx < CONFIG_PATTERNS.length; patternIdx++) {\n const pattern = CONFIG_PATTERNS[patternIdx]!\n const match = line.match(pattern)\n if (match) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:c${patternIdx}`,\n checkId: CHECK_ID,\n category: 'ops',\n severity: 'low',\n message: getCopy('checks.debug-mode-enabled.message', match[0] ?? ''),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n if (file.language === 'python') {\n for (let patternIdx = 0; patternIdx < PYTHON_DEBUG_PATTERNS.length; patternIdx++) {\n const pattern = PYTHON_DEBUG_PATTERNS[patternIdx]!\n const match = line.match(pattern)\n if (match) {\n const dedup = findings.some(\n (f) => f.file === file.relativePath && f.line === lineNum + 1,\n )\n if (!dedup) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:p${patternIdx}`,\n checkId: CHECK_ID,\n category: 'ops',\n severity: 'low',\n message: getCopy('checks.debug-mode-enabled.message', match[0] ?? ''),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n }\n }\n\n if (file.language === 'ruby') {\n for (let patternIdx = 0; patternIdx < RUBY_DEBUG_PATTERNS.length; patternIdx++) {\n const pattern = RUBY_DEBUG_PATTERNS[patternIdx]!\n const match = line.match(pattern)\n if (match) {\n const dedup = findings.some(\n (f) => f.file === file.relativePath && f.line === lineNum + 1,\n )\n if (!dedup) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:r${patternIdx}`,\n checkId: CHECK_ID,\n category: 'ops',\n severity: 'low',\n message: getCopy('checks.debug-mode-enabled.message', match[0] ?? ''),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n }\n }\n\n if (file.language === 'html') {\n // Accumulate multi-line <meta> tags\n let currentLine = line\n if (currentLine.includes('<meta') && !currentLine.includes('>')) {\n let j = lineNum + 1\n while (j < lines.length && !lines[j]!.includes('>')) {\n currentLine += ' ' + lines[j]!.trim()\n j++\n }\n if (j < lines.length) {\n currentLine += ' ' + lines[j]!.trim()\n }\n }\n\n for (let patternIdx = 0; patternIdx < HTML_DEBUG_PATTERNS.length; patternIdx++) {\n const pattern = HTML_DEBUG_PATTERNS[patternIdx]!\n const match = currentLine.match(pattern)\n if (match) {\n const dedup = findings.some(\n (f) => f.file === file.relativePath && f.line === lineNum + 1,\n )\n if (!dedup) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:h${patternIdx}`,\n checkId: CHECK_ID,\n category: 'ops',\n severity: 'low',\n message: getCopy('checks.debug-mode-enabled.message', match[0] ?? ''),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n }\n }\n }\n }\n return findings\n },\n}\n\n// ---------------------------------------------------------------------------\n// Tree-sitter strategy for code files\n// ---------------------------------------------------------------------------\n\nconst TS_QUERIES: Record<string, string> = {\n javascript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"console\")\n (#match? @prop \"^(log|debug|trace)$\"))) @match\n`,\n typescript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"console\")\n (#match? @prop \"^(log|debug|trace)$\"))) @match\n`,\n tsx: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"console\")\n (#match? @prop \"^(log|debug|trace)$\"))) @match\n`,\n python: `\n(call\n function: (identifier) @func\n (#match? @func \"^(print|debug)$\")) @match\n`,\n go: `\n(call_expression\n function: (selector_expression\n operand: (identifier) @pkg\n field: (field_identifier) @func\n (#eq? @pkg \"fmt\")\n (#match? @func \"^(Print|Println|Printf)$\"))) @match\n`,\n ruby: `\n(call method: (identifier) @func\n (#match? @func \"^(puts|print|p|debug)$\")) @match\n`,\n java: `\n(expression_statement\n (method_invocation\n object: (field_access\n object: (identifier) @sys\n field: (identifier) @out\n (#eq? @sys \"System\")\n (#eq? @out \"out\"))\n name: (identifier) @func\n (#match? @func \"^(println|printf|print)$\"))) @match\n`,\n rust: `\n(macro_invocation\n macro: (identifier) @name\n (#match? @name \"^(println|print|eprintln|eprint|dbg)$\")) @match\n`,\n php: `\n(function_call_expression\n function: (name) @func\n (#match? @func \"^(var_dump|print_r|echo|dd|dump)$\")) @match\n`,\n bash: `\n(command\n name: (command_name (word) @cmd)\n argument: (word) @arg\n (#eq? @cmd \"set\")\n (#match? @arg \"^-x$\")) @match\n\n(command\n name: (command_name (word) @cmd)\n argument: (word) @opt\n argument: (word) @arg\n (#eq? @cmd \"set\")\n (#eq? @opt \"-o\")\n (#eq? @arg \"xtrace\")) @match\n`,\n html: `\n(script_element\n (raw_text) @match\n (#match? @match \"console\\\\\\\\.(log|debug|trace)\\\\\\\\s*\\\\\\\\(\"))\n`,\n}\n\nconst tsCheck = createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.debug-mode-enabled.name',\n descriptionKey: 'checks.debug-mode-enabled.description',\n category: 'ops',\n severity: 'low',\n minTier: 'pro',\n queries: TS_QUERIES,\n messageKey: 'checks.debug-mode-enabled.code-message',\n degradedMessageKey: 'checks.debug-mode-enabled.degraded',\n remediationKey: 'remediation.ops.debug-mode-enabled',\n})\n\n// ---------------------------------------------------------------------------\n// Hybrid check\n// ---------------------------------------------------------------------------\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.debug-mode-enabled.name'),\n description: getCopy('checks.debug-mode-enabled.description'),\n category: 'ops',\n severity: 'low',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [regexFindings, tsFindings] = await Promise.all([\n regexCheck.run(ctx),\n tsCheck.run(ctx),\n ])\n return mergeFindings(tsFindings, regexFindings)\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { isInsideGitRepo } from '../../git.js'\nimport { getCopy } from '../../copy/index.js'\n\nregistry.register({\n id: 'ops.no-version-control',\n name: 'No version control',\n description: 'Project is not under version control',\n category: 'ops',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n if (isInsideGitRepo(ctx.targetDir)) return []\n\n return [\n {\n id: 'no-version-control-1',\n checkId: 'ops.no-version-control',\n category: 'ops',\n severity: 'medium',\n message:\n 'No version control system detected. Using Git (or another VCS) is essential for collaboration, history, and recovery.',\n confidence: 'high',\n remediation: getCopy('remediation.ops.no-version-control'),\n },\n ]\n },\n})\n","/**\n * @attribution CWE-778\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst LOCALHOST_PATTERN = /\\blocalhost\\b(?::\\d+)?/gi\nconst LOOPBACK_PATTERNS = [\n /\\b127\\.0\\.0\\.1\\b(?::\\d+)?/g,\n /\\b0\\.0\\.0\\.0\\b(?::\\d+)?/g,\n]\n\nconst PYTHON_DEV_PORT_PATTERN = /\\bapp\\.run\\s*\\([^)]*host\\s*=\\s*['\"]?(?:localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0)['\"]?/g\n\nconst URL_CONTEXT = /(?:https?:\\/\\/|fetch\\s*\\(|axios\\b|`[^`]*https?:\\/\\/|requests\\.(get|post|put|delete|patch)|urllib|http\\.client|aiohttp|postgres:\\/\\/|psql:\\/\\/|mysql:\\/\\/|mongodb:\\/\\/)/\n\nconst APPLICATION_LANGUAGES = new Set([\n 'javascript',\n 'typescript',\n 'tsx',\n 'python',\n 'ruby',\n 'java',\n 'sql',\n 'bash',\n 'html',\n 'css',\n])\n\nconst REMEDIATION = getCopy('remediation.ops.hardcoded-localhost')\n\nfunction hasUrlContext(line: string): boolean {\n return URL_CONTEXT.test(line)\n}\n\nfunction isEligibleFile(language: string, relativePath: string): boolean {\n return APPLICATION_LANGUAGES.has(language) && !isMechanicalCheckExcludedPath(relativePath)\n}\n\nregistry.register({\n id: 'ops.hardcoded-localhost',\n name: 'Hardcoded localhost',\n description: 'Hardcoded localhost / 127.0.0.1 / dev URLs in source',\n category: 'ops',\n severity: 'low',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n for (const file of ctx.files) {\n if (!isEligibleFile(file.language, file.relativePath)) continue\n\n const content = await file.content()\n const lines = content.split('\\n')\n\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\n const line = lines[lineNum]!\n\n for (const match of line.matchAll(LOCALHOST_PATTERN)) {\n if (!hasUrlContext(line)) continue\n findings.push(makeFinding(file.relativePath, lineNum, match.index ?? 0, findings.length))\n }\n\n for (const pattern of LOOPBACK_PATTERNS) {\n for (const match of line.matchAll(pattern)) {\n findings.push(makeFinding(file.relativePath, lineNum, match.index ?? 0, findings.length))\n }\n }\n\n if (file.language === 'python') {\n for (const match of line.matchAll(PYTHON_DEV_PORT_PATTERN)) {\n findings.push(makeFinding(file.relativePath, lineNum, match.index ?? 0, findings.length))\n }\n }\n }\n }\n return findings\n },\n})\n\nfunction makeFinding(\n relativePath: string,\n lineNum: number,\n column: number,\n findingIndex: number,\n): Finding {\n return {\n id: `localhost-${findingIndex + 1}`,\n checkId: 'ops.hardcoded-localhost',\n category: 'ops',\n severity: 'low',\n message: 'Hardcoded localhost or loopback address detected',\n file: relativePath,\n line: lineNum + 1,\n column: column + 1,\n confidence: mechanicalConfidence('regex', relativePath),\n remediation: REMEDIATION,\n }\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { promises as fs } from 'fs'\nimport { getCopy } from '../../copy/index.js'\nimport { lineMatch, scanBashLines } from '../helpers/bash-patterns.js'\n\nconst NPM_LOCKFILES = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', 'bun.lockb'] as const\n\ninterface EcosystemRequirement {\n manifest: string\n lockfiles: readonly string[]\n}\n\nfunction detectEcosystems(entries: string[], isMonorepo: boolean): EcosystemRequirement[] {\n const requirements: EcosystemRequirement[] = []\n\n if (entries.includes('composer.json')) {\n requirements.push({ manifest: 'composer.json', lockfiles: ['composer.lock'] })\n }\n if (entries.includes('go.mod')) {\n requirements.push({ manifest: 'go.mod', lockfiles: ['go.sum'] })\n }\n if (entries.includes('Gemfile')) {\n requirements.push({ manifest: 'Gemfile', lockfiles: ['Gemfile.lock'] })\n }\n if (entries.includes('pom.xml')) {\n requirements.push({\n manifest: 'pom.xml',\n lockfiles: [],\n })\n }\n if (entries.includes('build.gradle') || entries.includes('build.gradle.kts')) {\n requirements.push({\n manifest: entries.includes('build.gradle') ? 'build.gradle' : 'build.gradle.kts',\n lockfiles: ['gradle.lockfile'],\n })\n }\n if (entries.includes('package.json') || isMonorepo) {\n requirements.push({ manifest: 'package.json', lockfiles: NPM_LOCKFILES })\n }\n\n return requirements\n}\n\nfunction hasAnyLockfile(entries: string[], lockfiles: readonly string[]): boolean {\n return lockfiles.some((lf) => entries.includes(lf))\n}\n\nexport function missingLockfileEcosystems(\n entries: string[],\n isMonorepo: boolean,\n): EcosystemRequirement[] {\n return detectEcosystems(entries, isMonorepo).filter(\n (req) => req.lockfiles.length > 0 && !hasAnyLockfile(entries, req.lockfiles),\n )\n}\n\nregistry.register({\n id: 'dependencies.missing-lockfile',\n name: 'Missing lockfile',\n description: 'Missing lockfile',\n category: 'dependencies',\n severity: 'high',\n minTier: 'free',\n async run(ctx: ScanContext) {\n const entries: string[] = await fs.readdir(ctx.targetDir).catch(() => [])\n const missing = missingLockfileEcosystems(entries, ctx.meta.isMonorepo)\n const findings: Finding[] = []\n\n if (missing.length > 0) {\n findings.push({\n id: 'deps-001',\n checkId: 'dependencies.missing-lockfile',\n category: 'dependencies',\n severity: 'high',\n message: 'No lockfile found. Unpinned dependencies are a reproducibility and supply-chain risk.',\n confidence: 'high' as const,\n remediation: getCopy('remediation.dependencies.missing-lockfile'),\n })\n }\n\n if (!hasAnyLockfile(entries, NPM_LOCKFILES)) {\n const bashFindings = await scanBashLines(ctx, {\n checkId: 'dependencies.missing-lockfile',\n category: 'dependencies',\n severity: 'high',\n message: () => 'Shell script uses package install command but no lockfile is present for reproducible installs.',\n remediation: getCopy('remediation.dependencies.missing-lockfile'),\n }, (line, _content, index) => lineMatch(line, index, /(?:^|\\s)(?:npm|yarn|pnpm)\\s+(?:install|add)\\b/))\n findings.push(...bashFindings.slice(0, 1))\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { execSync } from 'child_process'\nimport { promises as fs } from 'fs'\nimport { dirname, join, relative } from 'path'\nimport { getCopy } from '../../copy/index.js'\n\nconst MAX_DEPS = 500\n\ninterface AuditAdvisory {\n severity: string\n module_name: string\n title: string\n url?: string\n}\n\ninterface NpmAuditOutput {\n advisories?: Record<string, AuditAdvisory>\n vulnerabilities?: Record<string, { severity: string; via: Array<{ title: string; url?: string } | string> }>\n metadata?: { vulnerabilities: { total: number } }\n}\n\nasync function countDepsFromPackageLock(targetDir: string): Promise<number> {\n try {\n const raw = await fs.readFile(join(targetDir, 'package-lock.json'), 'utf-8')\n const lockfile = JSON.parse(raw)\n if (lockfile.packages) {\n // lockfileVersion 3\n return Object.keys(lockfile.packages).filter((k: string) => k !== '').length\n }\n if (lockfile.dependencies) {\n // lockfileVersion 1 or 2\n return Object.keys(lockfile.dependencies).length\n }\n } catch {\n // ignore missing or unreadable lockfile\n }\n return 0\n}\n\nconst REMEDIATION = getCopy('remediation.dependencies.known-cves')\n\nfunction parseNpmAudit(output: string, lockfilePath: string): Finding[] {\n const data: NpmAuditOutput = JSON.parse(output)\n const findings: Finding[] = []\n\n if (data.advisories) {\n for (const [id, adv] of Object.entries(data.advisories)) {\n if (!isSevereEnough(adv.severity)) continue\n findings.push({\n id: `cve-${id}`,\n checkId: 'dependencies.known-cves',\n category: 'dependencies',\n severity: mapSeverity(adv.severity),\n message: `Known CVE in ${adv.module_name}: ${adv.title}`,\n lockfiles: lockfilePath ? [lockfilePath] : undefined,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n\n if (data.vulnerabilities) {\n let idx = 0\n for (const [moduleName, vuln] of Object.entries(data.vulnerabilities)) {\n if (!isSevereEnough(vuln.severity)) continue\n const viaObj = Array.isArray(vuln.via)\n ? vuln.via.find((v): v is { title: string; url?: string } => typeof v === 'object' && v !== null && 'title' in v)\n : null\n const viaStr = !viaObj && Array.isArray(vuln.via)\n ? vuln.via.find((v): v is string => typeof v === 'string')\n : null\n findings.push({\n id: `cve-${idx++}`,\n checkId: 'dependencies.known-cves',\n category: 'dependencies',\n severity: mapSeverity(vuln.severity),\n message: `Known CVE in ${moduleName}: ${viaObj?.title ?? viaStr ?? 'Unspecified vulnerability'}`,\n lockfiles: lockfilePath ? [lockfilePath] : undefined,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n}\n\nfunction isSevereEnough(sev: string): boolean {\n const order = ['info', 'low', 'moderate', 'high', 'critical']\n return order.indexOf(sev.toLowerCase()) >= order.indexOf('moderate')\n}\n\nfunction mapSeverity(sev: string): Finding['severity'] {\n switch (sev.toLowerCase()) {\n case 'critical':\n return 'critical'\n case 'high':\n return 'high'\n case 'moderate':\n return 'medium'\n default:\n return 'low'\n }\n}\n\nconst auditUnavailable = (): Finding[] => [{\n id: 'known-cves-audit-unavailable',\n checkId: 'dependencies.known-cves',\n category: 'dependencies',\n severity: 'medium',\n message: 'Could not execute or parse npm audit output; CVE scan may be incomplete.',\n confidence: 'high',\n remediation: REMEDIATION,\n}]\n\nfunction dedupeCveFindings(findings: Finding[]): Finding[] {\n const map = new Map<string, Finding>()\n for (const f of findings) {\n const key = `${f.checkId}::${f.message}`\n const existing = map.get(key)\n if (existing) {\n const mergedLockfiles = [...new Set([\n ...(existing.lockfiles ?? []),\n ...(f.lockfiles ?? []),\n ])]\n existing.lockfiles = mergedLockfiles.length > 0 ? mergedLockfiles : undefined\n } else {\n map.set(key, { ...f, lockfiles: f.lockfiles ? [...f.lockfiles] : undefined })\n }\n }\n return Array.from(map.values())\n}\n\nasync function findLockfiles(targetDir: string, scanRoot: string): Promise<string[]> {\n const lockfileNames = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml']\n const results: string[] = []\n for (const name of lockfileNames) {\n const lockfilePath = join(targetDir, name)\n try {\n await fs.access(lockfilePath)\n results.push(relative(scanRoot, lockfilePath).split('\\\\').join('/'))\n } catch {\n // not found\n }\n }\n return results\n}\n\nasync function findWorkspacePackageDirs(rootDir: string): Promise<string[]> {\n const workspaceFile = join(rootDir, 'pnpm-workspace.yaml')\n const dirs: string[] = []\n let content: string\n try {\n content = await fs.readFile(workspaceFile, 'utf-8')\n } catch {\n return dirs\n }\n // parse packages globs like - 'packages/*'\n for (const line of content.split('\\n')) {\n const match = line.match(/-\\s+['\"]?([^'\"]+?)['\"]?\\s*(?:#.*)?$/)\n if (match && match[1]) {\n const glob = match[1]\n const base = glob.endsWith('/*') ? glob.slice(0, -2) : glob\n const basePath = join(rootDir, base)\n try {\n const entries = await fs.readdir(basePath, { withFileTypes: true })\n for (const entry of entries) {\n if (entry.isDirectory()) {\n dirs.push(join(basePath, entry.name))\n }\n }\n } catch {\n // dir doesn't exist\n }\n }\n }\n return dirs\n}\n\nasync function collectLockfiles(ctx: ScanContext): Promise<string[]> {\n const lockfiles = await findLockfiles(ctx.targetDir, ctx.targetDir)\n if (ctx.meta.isMonorepo) {\n const wsDirs = await findWorkspacePackageDirs(ctx.targetDir)\n for (const wsDir of wsDirs) {\n lockfiles.push(...(await findLockfiles(wsDir, ctx.targetDir)))\n }\n }\n return lockfiles\n}\n\nregistry.register({\n id: 'dependencies.known-cves',\n name: 'Known CVEs',\n description: 'Known CVEs in dependencies (npm audit equivalent)',\n category: 'dependencies',\n severity: 'high',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const allFindings: Finding[] = []\n const lockfiles = await collectLockfiles(ctx)\n\n // Warn once per scan if dependency tree exceeds 500 packages\n const depCount = await countDepsFromPackageLock(ctx.targetDir)\n if (depCount > MAX_DEPS) {\n console.error(getCopy('warnings.deps.tree_exceeded'))\n }\n\n if (lockfiles.length === 0) {\n try {\n const output = execSync('npm audit --json', {\n cwd: ctx.targetDir,\n stdio: 'pipe',\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n timeout: 10_000,\n })\n return parseNpmAudit(output, '')\n } catch (err) {\n const output = (err as { stdout?: string }).stdout\n if (output) {\n try {\n return parseNpmAudit(output, '')\n } catch {\n return auditUnavailable()\n }\n }\n return auditUnavailable()\n }\n }\n\n for (const lockfile of lockfiles) {\n const lockfileDir = join(ctx.targetDir, dirname(lockfile))\n try {\n const output = execSync('npm audit --json', {\n cwd: lockfileDir,\n stdio: 'pipe',\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n timeout: 10_000,\n })\n allFindings.push(...parseNpmAudit(output, lockfile))\n } catch (err) {\n const output = (err as { stdout?: string }).stdout\n if (output) {\n try {\n allFindings.push(...parseNpmAudit(output, lockfile))\n } catch {\n // skip this lockfile's audit\n }\n }\n }\n }\n\n return dedupeCveFindings(allFindings)\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { promises as fs } from 'fs'\nimport { join } from 'path'\nimport { getCopy } from '../../copy/index.js'\n\nconst DEV_ONLY_PACKAGES = [\n 'jest',\n 'vitest',\n 'mocha',\n 'chai',\n 'eslint',\n 'prettier',\n '@types',\n 'typescript',\n 'ts-node',\n 'nodemon',\n 'webpack',\n 'vite',\n 'rollup',\n 'parcel',\n 'babel',\n '@babel',\n 'cypress',\n 'playwright',\n 'storybook',\n '@storybook',\n 'husky',\n 'lint-staged',\n 'commitlint',\n '@commitlint',\n]\n\nfunction isDevOnly(name: string): boolean {\n return DEV_ONLY_PACKAGES.some((dev) =>\n name === dev || name.startsWith(`${dev}/`) || name.startsWith(`${dev}-`)\n )\n}\n\nconst REMEDIATION = getCopy('remediation.dependencies.dev-deps-in-prod')\n\nregistry.register({\n id: 'dependencies.dev-deps-in-prod',\n name: 'Dev dependencies in production',\n description: 'Dev dependencies bundled into production bundle',\n category: 'dependencies',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const pkgPath = join(ctx.targetDir, 'package.json')\n let pkg: { dependencies?: Record<string, string> }\n try {\n const raw = await fs.readFile(pkgPath, 'utf-8')\n pkg = JSON.parse(raw)\n } catch {\n return []\n }\n\n const deps = pkg.dependencies ?? {}\n const findings: Finding[] = []\n for (const [name] of Object.entries(deps)) {\n if (isDevOnly(name)) {\n findings.push({\n id: `dev-in-prod-${findings.length + 1}`,\n checkId: 'dependencies.dev-deps-in-prod',\n category: 'dependencies',\n severity: 'medium',\n message: `Dev dependency \"${name}\" is listed in dependencies. Move it to devDependencies.`,\n file: 'package.json',\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { promises as fs } from 'fs'\nimport { join, relative } from 'path'\nimport { getCopy } from '../../copy/index.js'\n\nfunction isUnpinned(version: string): boolean {\n const trimmed = version.trim()\n if (trimmed === '*' || trimmed === 'latest') return true\n if (trimmed.startsWith('^') || trimmed.startsWith('~')) return true\n return false\n}\n\nconst REMEDIATION = getCopy('remediation.dependencies.unpinned-versions')\n\nfunction shellInstallFinding(line: string): { packageName: string; version: string } | null {\n const trimmed = line.trim()\n const installMatch = trimmed.match(/^(?:sudo\\s+)?(?:(apt-get|apt|pip3?|npm)\\s+install)\\b(.*)$/)\n if (!installMatch) return null\n\n const manager = installMatch[1]!\n const rest = installMatch[2]!.trim()\n const args = rest.split(/\\s+/).filter(Boolean)\n const packages = args.filter((arg) => !arg.startsWith('-'))\n if (packages.length === 0) return null\n\n for (const pkg of packages) {\n if (manager === 'apt' || manager === 'apt-get') {\n if (!pkg.includes('=')) return { packageName: pkg, version: 'unversioned apt package' }\n } else if (manager.startsWith('pip')) {\n if (!pkg.includes('==')) return { packageName: pkg, version: 'unversioned pip package' }\n } else if (manager === 'npm') {\n const nameHasVersion = pkg.startsWith('@')\n ? pkg.slice(1).includes('@')\n : pkg.includes('@')\n if (!nameHasVersion) return { packageName: pkg, version: 'unversioned npm package' }\n }\n }\n\n return null\n}\n\nregistry.register({\n id: 'dependencies.unpinned-versions',\n name: 'Unpinned dependency versions',\n description: 'Floating * or latest in dependency manifests',\n category: 'dependencies',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const pkgPath = join(ctx.targetDir, 'package.json')\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }\n try {\n const raw = await fs.readFile(pkgPath, 'utf-8')\n pkg = JSON.parse(raw)\n } catch {\n pkg = {}\n }\n\n const findings: Finding[] = []\n for (const depGroup of [pkg.dependencies ?? {}, pkg.devDependencies ?? {}]) {\n for (const [name, version] of Object.entries(depGroup)) {\n if (isUnpinned(version)) {\n findings.push({\n id: `unpinned-${findings.length + 1}`,\n checkId: 'dependencies.unpinned-versions',\n category: 'dependencies',\n severity: 'medium',\n message: `Dependency \"${name}\" uses an unpinned version \"${version}\". Pin to an exact version for reproducible builds.`,\n file: 'package.json',\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n const pomPath = join(ctx.targetDir, 'pom.xml')\n try {\n const pomRaw = await fs.readFile(pomPath, 'utf-8')\n const versionTags = pomRaw.matchAll(/<version>\\s*([^<]+?)\\s*<\\/version>/gi)\n for (const match of versionTags) {\n const version = match[1]!.trim()\n if (\n version.includes('+') ||\n version.startsWith('${')\n ) {\n continue\n }\n if (\n version === 'LATEST' ||\n version === 'RELEASE' ||\n isUnpinned(version) ||\n /\\[.*,.*\\)/.test(version)\n ) {\n findings.push({\n id: `unpinned-pom-${findings.length + 1}`,\n checkId: 'dependencies.unpinned-versions',\n category: 'dependencies',\n severity: 'medium',\n message: `Maven dependency uses an unpinned version \"${version}\". Pin to an exact version for reproducible builds.`,\n file: 'pom.xml',\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n } catch {\n // no pom.xml\n }\n\n const gradlePath = join(ctx.targetDir, 'build.gradle')\n const gradleKtsPath = join(ctx.targetDir, 'build.gradle.kts')\n for (const gradleFile of [gradlePath, gradleKtsPath]) {\n try {\n const gradleRaw = await fs.readFile(gradleFile, 'utf-8')\n if (/['\"][\\w.-]+:[\\w.-]+:\\+['\"]/.test(gradleRaw) || /version\\s*=\\s*['\"]\\+['\"]/.test(gradleRaw)) {\n findings.push({\n id: `unpinned-gradle-${findings.length + 1}`,\n checkId: 'dependencies.unpinned-versions',\n category: 'dependencies',\n severity: 'medium',\n message: 'Gradle dependency uses a dynamic \"+\" version. Pin to an exact version for reproducible builds.',\n file: relative(ctx.targetDir, gradleFile).split('\\\\').join('/'),\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n } catch {\n // no gradle file\n }\n }\n\n for (const file of ctx.files) {\n if (file.language !== 'bash') continue\n const content = await file.content()\n const lines = content.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const match = shellInstallFinding(lines[i]!)\n if (!match) continue\n findings.push({\n id: `unpinned-shell-${file.relativePath}:${i + 1}`,\n checkId: 'dependencies.unpinned-versions',\n category: 'dependencies',\n severity: 'medium',\n message: `Dependency \"${match.packageName}\" uses an ${match.version}. Pin to an exact version for reproducible builds.`,\n file: file.relativePath,\n line: i + 1,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n return findings\n },\n})\n","export const SUPPORTED_CDN_HOSTS = new Set([\n 'cdn.jsdelivr.net',\n 'jsdelivr.net',\n 'cdnjs.cloudflare.com',\n 'unpkg.com',\n 'ajax.googleapis.com',\n 'fonts.googleapis.com',\n 'cdn.skypack.dev',\n 'esm.sh',\n])\n\nexport interface HtmlCdnAsset {\n host: string\n packageName: string | null\n version: string | null\n}\n\nfunction normalizePackageName(pkg: string): string {\n return pkg.replace(/^npm\\//, '').replace(/^\\//, '').replace(/\\/$/, '')\n}\n\nfunction parsePackageSegment(segment: string): { packageName: string; version: string | null } | null {\n const trimmed = decodeURIComponent(segment.trim())\n if (!trimmed) return null\n const versionSep = trimmed.lastIndexOf('@')\n if (versionSep <= 0) {\n return { packageName: normalizePackageName(trimmed), version: null }\n }\n return {\n packageName: normalizePackageName(trimmed.slice(0, versionSep)),\n version: trimmed.slice(versionSep + 1) || null,\n }\n}\n\nfunction extractFromPath(host: string, pathname: string): HtmlCdnAsset | null {\n const parts = pathname.split('/').filter(Boolean)\n if (parts.length === 0) return null\n\n if (host.includes('cdnjs.cloudflare.com') || host.includes('ajax.googleapis.com')) {\n if (parts.length >= 4 && parts[0] === 'ajax' && parts[1] === 'libs') {\n return {\n host,\n packageName: parts[2] ?? null,\n version: parts[3] ?? null,\n }\n }\n return null\n }\n\n if (host.includes('esm.sh')) {\n const parsed = parsePackageSegment(parts[0] ?? '')\n return parsed ? { host, ...parsed } : null\n }\n\n const first = parts[0] === 'npm' ? parts[1] ?? '' : parts[0] ?? ''\n const parsed = parsePackageSegment(first)\n return parsed ? { host, ...parsed } : null\n}\n\nexport function parseHtmlCdnAsset(rawUrl: string): HtmlCdnAsset | null {\n try {\n const url = new URL(rawUrl)\n const host = url.hostname.toLowerCase()\n if (!SUPPORTED_CDN_HOSTS.has(host)) return null\n return extractFromPath(host, url.pathname)\n } catch {\n return null\n }\n}\n\nexport function isExactVersion(version: string): boolean {\n const trimmed = version.trim()\n if (!trimmed) return false\n if (trimmed === 'latest' || trimmed === '*' || trimmed.startsWith('^') || trimmed.startsWith('~')) return false\n if (/^\\d+\\.x$/.test(trimmed) || /^\\d+\\.\\d+\\.x$/.test(trimmed) || /^\\d+\\.\\d+\\.\\d+\\.\\*$/.test(trimmed)) return false\n // Only accept valid semver-like patterns as exact\n return /^[0-9]+(?:\\.[0-9]+){0,2}(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/.test(trimmed)\n}\n\nexport function isFloatingVersion(version: string): boolean {\n const trimmed = version.trim().toLowerCase()\n if (!trimmed) return true\n if (trimmed === 'latest' || trimmed === '*' || trimmed === 'next') return true\n if (trimmed.startsWith('^') || trimmed.startsWith('~')) return true\n if (/^\\d+\\.x$/.test(trimmed) || /^\\d+\\.\\d+\\.x$/.test(trimmed) || /^\\d+\\.\\d+\\.\\d+\\.\\*$/.test(trimmed)) return true\n return false\n}\n","{\n \"jquery\": [\"1.12.4\"],\n \"angular\": [\"1.8.0\"],\n \"lodash\": [\"4.17.15\"]\n}\n","/**\n * @attribution CWE-1104\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { parseHtmlCdnAsset } from '../helpers/html-cdn.js'\nimport vulnData from './known-cdn-vulns.json'\nconst KNOWN_VULNS: Record<string, Set<string>> = Object.fromEntries(\n Object.entries(vulnData).map(([k, v]) => [k, new Set(v)]),\n)\n\nconst CHECK_ID = 'dependencies.html-cdn-vulnerable-versions'\nconst REMEDIATION = getCopy('remediation.dependencies.html-cdn-vulnerable-versions')\n\nconst SCRIPT_OR_LINK_PATTERN = /<(script|link)\\b[^>]*?(src|href)\\s*=\\s*[\"']([^\"']+)[\"'][^>]*?>/gi\n\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-cdn-vulnerable-versions.name'),\n description: getCopy('checks.html-cdn-vulnerable-versions.description'),\n category: 'dependencies',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n for (const match of content.matchAll(SCRIPT_OR_LINK_PATTERN)) {\n const url = match[3] ?? ''\n const asset = parseHtmlCdnAsset(url)\n if (!asset?.packageName || !asset.version) continue\n const vulnerableVersions = KNOWN_VULNS[asset.packageName.toLowerCase()]\n if (!vulnerableVersions?.has(asset.version)) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'dependencies',\n severity: 'high',\n message: getCopy('checks.html-cdn-vulnerable-versions.message', `${asset.packageName}@${asset.version}`),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-1104\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { isFloatingVersion, parseHtmlCdnAsset } from '../helpers/html-cdn.js'\n\nconst CHECK_ID = 'dependencies.html-cdn-unpinned-versions'\nconst REMEDIATION = getCopy('remediation.dependencies.html-cdn-unpinned-versions')\n\nconst SCRIPT_OR_LINK_PATTERN = /<(script|link)\\b[^>]*?(src|href)\\s*=\\s*[\"']([^\"']+)[\"'][^>]*?>/gi\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-cdn-unpinned-versions.name'),\n description: getCopy('checks.html-cdn-unpinned-versions.description'),\n category: 'dependencies',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n for (const match of content.matchAll(SCRIPT_OR_LINK_PATTERN)) {\n const url = match[3] ?? ''\n const asset = parseHtmlCdnAsset(url)\n if (!asset?.packageName) continue\n if (!asset.version || isFloatingVersion(asset.version)) {\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'dependencies',\n severity: 'medium',\n message: getCopy('checks.html-cdn-unpinned-versions.message', asset.version ? `${asset.packageName}@${asset.version}` : asset.packageName),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\nimport { mergeFindings } from '../merge-findings.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'configuration.secrets-in-source'\n\nconst COMPOUND_SECRET_NAME_REGEX =\n /(?:secret|api[_-]?key|access[_-]?key|private[_-]?key|auth[_-]?token|bearer[_-]?token|refresh[_-]?token|apiKey|accessKey|privateKey|authToken|bearerToken|refreshToken)/i\n\nconst UI_PROP_NAMES = new Set(['key', 'title', 'label', 'id', 'name', 'type', 'variant'])\n\nconst MIN_VALUE_LENGTH = 8\n\nconst SECRET_ASSIGNMENT_PATTERNS = [\n /(?:const|let|var)\\s+(\\w*(?:secret|api[_-]?key|access[_-]?key|private[_-]?key|auth[_-]?token|bearer[_-]?token|refresh[_-]?token|apiKey|accessKey|privateKey|authToken|bearerToken|refreshToken)\\w*)\\s*=\\s*['\"]([^'\"]{8,})['\"]/i,\n /(\\w*(?:secret|api[_-]?key|access[_-]?key|private[_-]?key|auth[_-]?token|bearer[_-]?token|refresh[_-]?token|apiKey|accessKey|privateKey|authToken|bearerToken|refreshToken)\\w*)\\s*:\\s*['\"]([^'\"]{8,})['\"]/i,\n /(?:<!--|\\/\\*)[^]*?(\\w*(?:secret|api[_-]?key|access[_-]?key|private[_-]?key|auth[_-]?token|bearer[_-]?token|refresh[_-]?token|apiKey|accessKey|privateKey|authToken|bearerToken|refreshToken)\\w*)\\s*[:=]\\s*['\"]([^'\"]{8,})['\"]/i,\n]\n\nconst REMEDIATION = getCopy('remediation.configuration.secrets-in-source')\n\nfunction stripQuotes(value: string): string {\n return value.replace(/^['\"`]|['\"`]$/g, '')\n}\n\nfunction isCompoundSecretName(name: string): boolean {\n if (UI_PROP_NAMES.has(name)) return false\n return COMPOUND_SECRET_NAME_REGEX.test(name)\n}\n\n// ---------------------------------------------------------------------------\n// Regex strategy (retained for plaintext and as a fallback)\n// ---------------------------------------------------------------------------\n\nconst regexCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.secrets-in-source.name'),\n description: getCopy('checks.secrets-in-source.description'),\n category: 'configuration',\n severity: 'high',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n for (const file of ctx.files) {\n if (file.language !== 'javascript' && file.language !== 'typescript' && file.language !== 'plaintext' && file.language !== 'sql' && file.language !== 'bash' && file.language !== 'html' && file.language !== 'css') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n // Handle block-oriented comment patterns against full content first\n const blockPattern = new RegExp(SECRET_ASSIGNMENT_PATTERNS[2]!.source, 'ig')\n const blockMatches = Array.from(content.matchAll(blockPattern))\n for (let matchIdx = 0; matchIdx < blockMatches.length; matchIdx++) {\n const match = blockMatches[matchIdx]!\n const name = match[1] ?? ''\n const value = match[2] ?? ''\n if (!isCompoundSecretName(name)) continue\n if (stripQuotes(value).length < MIN_VALUE_LENGTH) continue\n const before = content.slice(0, match.index ?? 0)\n const line = before.split('\\n').length\n const col = (before.split('\\n').at(-1) ?? '').length + 1\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${col}:${matchIdx}`,\n checkId: CHECK_ID,\n category: 'configuration',\n severity: 'high',\n message: getCopy('checks.secrets-in-source.message', match[0] ?? ''),\n file: file.relativePath,\n line,\n column: col,\n confidence: mechanicalConfidence('regex', file.relativePath, value),\n remediation: REMEDIATION,\n })\n }\n\n const lines = content.split('\\n')\n\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\n const line = lines[lineNum]!\n\n for (let patternIdx = 0; patternIdx < 2; patternIdx++) {\n const pattern = SECRET_ASSIGNMENT_PATTERNS[patternIdx]!\n const regex = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : pattern.flags + 'g')\n const matches = Array.from(line.matchAll(regex))\n for (let matchIdx = 0; matchIdx < matches.length; matchIdx++) {\n const match = matches[matchIdx]!\n const name = match[1] ?? ''\n const value = match[2] ?? ''\n if (!isCompoundSecretName(name)) continue\n if (stripQuotes(value).length < MIN_VALUE_LENGTH) continue\n\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:${matchIdx}`,\n checkId: CHECK_ID,\n category: 'configuration',\n severity: 'high',\n message: getCopy('checks.secrets-in-source.message', match[0] ?? ''),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: mechanicalConfidence('regex', file.relativePath, value),\n remediation: REMEDIATION,\n })\n }\n }\n }\n }\n return findings\n },\n}\n\n// ---------------------------------------------------------------------------\n// Tree-sitter strategy (JS / TS / TSX / Python / Ruby / Java / Go / PHP / Rust)\n// ---------------------------------------------------------------------------\n\nconst TS_QUERIES: Record<string, string> = {\n javascript: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (property_identifier) @name\n value: (string) @value) @match\n`,\n typescript: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (property_identifier) @name\n value: (string) @value) @match\n`,\n tsx: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (property_identifier) @name\n value: (string) @value) @match\n`,\n python: `\n(assignment\n left: (identifier) @name\n right: (string) @value) @match\n\n(pair\n key: (identifier) @name\n value: (string) @value) @match\n`,\n ruby: `\n(assignment left: (identifier) @name right: (string) @value) @match\n\n(pair key: (_) @name value: (string) @value) @match\n`,\n java: `\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name\n value: (string_literal) @value)) @match\n\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name\n value: (string_literal) @value)) @match\n`,\n go: `\n(var_declaration\n (var_spec\n name: (identifier) @name\n value: (_) @value)) @match\n\n(short_var_declaration\n left: (expression_list (identifier) @name)\n right: (expression_list (_) @value)) @match\n`,\n php: `\n(assignment_expression\n left: (_) @name\n right: (_) @value) @match\n`,\n rust: `\n(let_declaration\n pattern: (identifier) @name\n value: (string_literal) @value) @match\n`,\n bash: `\n(variable_assignment\n name: (variable_name) @name\n value: (string) @value) @match\n\n(declaration_command\n (variable_assignment\n name: (variable_name) @name\n value: (string) @value)) @match\n`,\n}\n\nconst tsCheck = createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.secrets-in-source.name',\n descriptionKey: 'checks.secrets-in-source.description',\n category: 'configuration',\n severity: 'high',\n minTier: 'free',\n queries: TS_QUERIES,\n messageKey: 'checks.secrets-in-source.message',\n degradedMessageKey: 'checks.secrets-in-source.degraded',\n remediationKey: 'remediation.configuration.secrets-in-source',\n fileFilter: (file) => !isMechanicalCheckExcludedPath(file.relativePath),\n matchFilter: (captures) => {\n const name = captures.name\n const value = captures.value\n if (!name || !value) return false\n if (!isCompoundSecretName(name)) return false\n return stripQuotes(value).length >= MIN_VALUE_LENGTH\n },\n confidenceFactory: (captures) =>\n mechanicalConfidence('ast', undefined, captures.value ?? ''),\n})\n\n// ---------------------------------------------------------------------------\n// Hybrid check\n// ---------------------------------------------------------------------------\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.secrets-in-source.name'),\n description: getCopy('checks.secrets-in-source.description'),\n category: 'configuration',\n severity: 'high',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [regexFindings, tsFindings] = await Promise.all([\n regexCheck.run(ctx),\n tsCheck.run(ctx),\n ])\n return mergeFindings(tsFindings, regexFindings)\n },\n})\n","import type { Finding, Severity } from '../types/finding.js'\n\n/** Normalize paths returned by the LLM for comparison with crawled relative paths. */\nexport function normalizeFindingPath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/^\\.\\/+/, '')\n}\n\n/** Drop LLM findings whose file path was not in the prompt's eligible file set. */\nexport function filterFindingsToAllowedFiles(\n findings: Finding[],\n allowedFiles: ReadonlySet<string>,\n): Finding[] {\n const normalizedAllowed = new Set([...allowedFiles].map(normalizeFindingPath))\n return findings.filter(\n (f) => f.file && normalizedAllowed.has(normalizeFindingPath(f.file)),\n )\n}\n\nexport class LLMResponseError extends Error {\n code: string\n constructor(code: string) {\n super(code)\n this.name = 'LLMResponseError'\n this.code = code\n }\n}\n\nconst SEVERITY_MAP: Record<string, Severity> = {\n critical: 'critical',\n high: 'high',\n medium: 'medium',\n low: 'low',\n info: 'info',\n}\n\n/** Remove model reasoning blocks (e.g. MiniMax) before JSON extraction. */\nfunction stripModelReasoning(raw: string): string {\n const thinkingBlock = new RegExp('<think>[\\\\s\\\\S]*?</think>', 'gi')\n const legacyThinkingBlock = new RegExp('<thinking>[\\\\s\\\\S]*?</thinking>', 'gi')\n return raw.replace(thinkingBlock, '').replace(legacyThinkingBlock, '').trim()\n}\n\nexport function parseLLMResponse(\n raw: string,\n checkId: string,\n defaultSeverity: Severity,\n): Finding[] {\n let json = stripModelReasoning(raw.trim())\n\n const fenceMatch = json.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?\\s*```/)\n if (fenceMatch) {\n json = fenceMatch[1]!.trim()\n } else {\n const arrayStart = json.indexOf('[')\n const arrayEnd = json.lastIndexOf(']')\n if (arrayStart !== -1 && arrayEnd !== -1 && arrayEnd > arrayStart) {\n json = json.slice(arrayStart, arrayEnd + 1)\n }\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(json)\n } catch {\n throw new LLMResponseError('llm.invalid_response')\n }\n\n if (!Array.isArray(parsed)) {\n throw new LLMResponseError('llm.invalid_response')\n }\n\n const seen = new Set<string>()\n const findings: Finding[] = []\n\n for (let i = 0; i < parsed.length; i++) {\n const item = parsed[i]\n if (typeof item !== 'object' || item === null) continue\n\n const file = typeof (item as Record<string, unknown>).file === 'string'\n ? (item as Record<string, unknown>).file as string\n : undefined\n\n const line = typeof (item as Record<string, unknown>).line === 'number'\n ? (item as Record<string, unknown>).line as number\n : undefined\n\n // Discard findings that lack file or line\n if (!file || line === undefined) continue\n\n const message = typeof (item as Record<string, unknown>).message === 'string'\n ? (item as Record<string, unknown>).message as string\n : undefined\n\n const rawSeverity = typeof (item as Record<string, unknown>).severity === 'string'\n ? (item as Record<string, unknown>).severity as string\n : undefined\n\n const severity = rawSeverity\n ? (SEVERITY_MAP[rawSeverity.toLowerCase()] ?? defaultSeverity)\n : defaultSeverity\n\n const key = `${checkId}|${file ?? ''}|${line ?? ''}`\n if (seen.has(key)) continue\n seen.add(key)\n\n findings.push({\n id: `${checkId}-${i + 1}`,\n checkId,\n category: checkId.split('.')[0]!,\n severity,\n message: message ?? 'Issue detected',\n file,\n line,\n })\n }\n\n return findings\n}\n","import { createHash, randomBytes } from 'crypto'\nimport * as fs from 'fs'\nimport { join } from 'path'\nimport type { Finding } from '../types/finding.js'\nimport { LLM_CACHE_DIR } from '../config/paths.js'\nimport pkg from '../../package.json' with { type: 'json' }\n\nconst CURRENT_SCHEMA_VERSION = 1\n\nexport interface CacheEntry {\n schemaVersion: number\n createdAt: number\n expiresAt: number\n payload: Finding[]\n}\n\nfunction defaultTtlHours(): number {\n const env = process.env.SEAWORTHY_LLM_CACHE_TTL_HOURS\n if (env !== undefined) {\n const parsed = parseInt(env, 10)\n if (!isNaN(parsed) && parsed > 0) {\n return parsed\n }\n }\n return 168\n}\n\nfunction ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true })\n }\n}\n\nfunction sha256(input: string): string {\n return createHash('sha256').update(input).digest('hex')\n}\n\nexport interface CacheKeyInputs {\n fileContent: string\n checkId: string\n promptVersion: string\n tokenBudget?: number | null\n providerId: string\n modelId: string\n}\n\nexport function computeCacheKey(inputs: CacheKeyInputs): string {\n const seaworthyVersion = pkg.version\n const raw = [\n inputs.fileContent,\n inputs.checkId,\n inputs.promptVersion,\n String(inputs.tokenBudget ?? 'null'),\n inputs.providerId,\n inputs.modelId,\n seaworthyVersion,\n ].join('\\0')\n return sha256(raw)\n}\n\nfunction assertValidCacheKey(key: string): void {\n // Keep this permissive for tests while blocking traversal/absolute-path tricks.\n if (!/^[A-Za-z0-9_-]+$/.test(key)) {\n throw new Error('Invalid cache key')\n }\n}\n\nfunction cacheFilePath(key: string): string {\n assertValidCacheKey(key)\n ensureDir(LLM_CACHE_DIR)\n return join(LLM_CACHE_DIR, `${key}.json`)\n}\n\nfunction isExpired(entry: CacheEntry): boolean {\n return Date.now() > entry.expiresAt\n}\n\nfunction isValidFinding(item: unknown): boolean {\n if (typeof item !== 'object' || item === null) return false\n const f = item as Record<string, unknown>\n return (\n typeof f.checkId === 'string' &&\n typeof f.category === 'string' &&\n typeof f.severity === 'string' &&\n typeof f.message === 'string'\n )\n}\n\nfunction parseEntry(raw: string): CacheEntry | null {\n try {\n const parsed = JSON.parse(raw) as CacheEntry\n if (\n typeof parsed.schemaVersion !== 'number' ||\n typeof parsed.createdAt !== 'number' ||\n typeof parsed.expiresAt !== 'number' ||\n !Array.isArray(parsed.payload)\n ) {\n return null\n }\n if (parsed.schemaVersion !== CURRENT_SCHEMA_VERSION) {\n return null\n }\n if (isExpired(parsed)) {\n return null\n }\n if (!parsed.payload.every(isValidFinding)) {\n return null\n }\n return parsed\n } catch {\n return null\n }\n}\n\ninterface FsLike {\n existsSync: typeof fs.existsSync\n readFileSync: typeof fs.readFileSync\n writeFileSync: typeof fs.writeFileSync\n renameSync: typeof fs.renameSync\n unlinkSync: typeof fs.unlinkSync\n}\n\nexport function readCache(key: string, fsImpl: FsLike = fs): Finding[] | null {\n const path = cacheFilePath(key)\n if (!fsImpl.existsSync(path)) {\n return null\n }\n try {\n const raw = fsImpl.readFileSync(path, 'utf-8')\n const entry = parseEntry(raw)\n if (entry === null) {\n return null\n }\n return entry.payload\n } catch {\n return null\n }\n}\n\nexport function writeCache(key: string, findings: Finding[], fsImpl: FsLike = fs): void {\n const ttlMs = defaultTtlHours() * 60 * 60 * 1000\n const now = Date.now()\n const entry: CacheEntry = {\n schemaVersion: CURRENT_SCHEMA_VERSION,\n createdAt: now,\n expiresAt: now + ttlMs,\n payload: findings,\n }\n\n const finalPath = cacheFilePath(key)\n const tempPath = `${finalPath}.tmp.${randomBytes(4).toString('hex')}`\n\n try {\n fsImpl.writeFileSync(tempPath, JSON.stringify(entry), 'utf-8')\n fsImpl.renameSync(tempPath, finalPath)\n } catch (err) {\n try {\n fsImpl.unlinkSync(tempPath)\n } catch {\n // Ignore cleanup failure\n }\n throw err\n }\n}\n\nexport function clearCache(): void {\n // Primarily for tests\n ensureDir(LLM_CACHE_DIR)\n // No-op for production; tests can use temp dirs\n}\n","import type { ScanContext } from '../types/check.js'\nimport type { Finding, Confidence, Severity } from '../types/finding.js'\nimport type { PromptTemplate } from '../prompts/types.js'\nimport type { SourceFile } from '../types/source-file.js'\nimport { filterFindingsToAllowedFiles, LLMResponseError } from '../prompts/parse-response.js'\nimport { getCopy, type CopyKey } from '../copy/index.js'\nimport { isDocumentationPath, isNonProductionPath } from '../config/path-exclusions.js'\nimport { setAnalysisType } from './helpers/finding-builder.js'\nimport {\n llmCorroboratedConfidence,\n llmOnlyConfidence,\n mechanicalConfidence,\n} from './helpers/confidence.js'\nimport { computeCacheKey, readCache, writeCache } from '../cache/llm-cache.js'\nimport { runWithConcurrencyCollect } from '../runner/scan-runner.js'\n\nconst PRO_CHECK_SOURCE_LANGUAGES = new Set([\n 'javascript',\n 'typescript',\n 'tsx',\n 'python',\n 'go',\n 'php',\n 'ruby',\n 'java',\n 'rust',\n 'html',\n 'css',\n])\n\nconst ENTRYPOINT_PATTERNS = [\n /(?:^|[\\\\/])index\\.(tsx?|jsx?|mjs|cjs)$/i,\n /(?:^|[\\\\/])main\\.(tsx?|jsx?|mjs|cjs)$/i,\n /(?:^|[\\\\/])server\\.(tsx?|jsx?|mjs|cjs)$/i,\n /(?:^|[\\\\/])app\\.(tsx?|jsx?|mjs|cjs)$/i,\n /(?:^|[\\\\/])app[\\\\/]page\\.tsx$/i,\n /(?:^|[\\\\/])app[\\\\/][^\\\\/]+[\\\\/]page\\.tsx$/i,\n /(?:^|[\\\\/])Main\\.java$/i,\n /(?:^|[\\\\/]).*Application\\.java$/i,\n /(?:^|[\\\\/])Servlet\\.java$/i,\n /(?:^|[\\\\/])config\\.ru$/i,\n /(?:^|[\\\\/])bin[\\\\/]rails$/i,\n /(?:^|[\\\\/])application_controller\\.rb$/i,\n]\n\nexport function isProCheckEligible(file: SourceFile, template?: PromptTemplate): boolean {\n if (template?.checkId === 'security.sql-missing-rls') {\n return (\n file.language === 'sql' &&\n !isDocumentationPath(file.relativePath) &&\n !isNonProductionPath(file.relativePath)\n )\n }\n return (\n PRO_CHECK_SOURCE_LANGUAGES.has(file.language) &&\n !isDocumentationPath(file.relativePath) &&\n !isNonProductionPath(file.relativePath)\n )\n}\n\nexport function pickProjectAnchorFile(files: SourceFile[]): string {\n if (files.length === 0) {\n throw new Error('Cannot pick project anchor from empty file list')\n }\n for (const pattern of ENTRYPOINT_PATTERNS) {\n const match = files.find((f) => pattern.test(f.relativePath))\n if (match) return match.relativePath\n }\n const sorted = [...files].sort((a, b) => a.relativePath.localeCompare(b.relativePath))\n return sorted[0]!.relativePath\n}\n\n/** Bump when shared preamble text changes — invalidates LLM result cache. */\nexport const PROMPT_PREAMBLE_VERSION = '1.0.0'\n\nconst PROMPT_PREAMBLE = `You are a security auditor analysing application source code for a specific check described below.\n\nScope and precision:\n- Only flag paths explicitly shown below. Do not invent file paths or line numbers.\n- Flag actionable issues in production application code only — not documentation, config templates, seed data, or test fixtures unless clearly wired into production.\n- Prefer one project-level finding when a pattern is absent repo-wide; do not emit one finding per file for the same missing control.\n- Reserve critical/high for exploitable or clearly harmful issues; use medium/low for missing best practices.\n- When evidence is weak or ambiguous, return [] rather than guess.\n\nOutput format:\nReturn ONLY a JSON array of findings. Each finding MUST include: \"file\" (relative path), \"line\" (number), \"severity\" (\"critical\"|\"high\"|\"medium\"|\"low\"|\"info\"), and \"message\" (string).\nFindings without both \"file\" and \"line\" will be discarded.\nIf no issues found, return [].`\n\nfunction classifyError(err: unknown): string {\n if (err instanceof LLMResponseError) return err.code\n if (err instanceof Error && err.name === 'TimeoutError') return 'llm.timeout'\n if (err instanceof DOMException && (err.name === 'TimeoutError' || err.name === 'AbortError')) return 'llm.timeout'\n if (err instanceof Error && /rate|429|too many/i.test(err.message)) return 'llm.rate_limited'\n return 'llm.unexpected'\n}\n\nasync function callLLMWithRetry(\n llm: NonNullable<ScanContext['llm']>,\n prompt: string,\n checkId: string,\n): Promise<string> {\n let lastError: unknown\n const delays = [0, 2000]\n\n for (let attempt = 0; attempt < delays.length; attempt++) {\n try {\n if (attempt > 0) await new Promise((r) => setTimeout(r, delays[attempt]))\n return await llm.complete(prompt)\n } catch (err) {\n lastError = err\n if (err instanceof LLMResponseError) break\n if (err instanceof Error && /rate|429/i.test(err.message)) break\n }\n }\n\n const code = classifyError(lastError)\n console.error(`Check \"${checkId}\" LLM failed: ${code}`)\n throw lastError\n}\n\nconst SEVERITY_ORDER: Severity[] = ['critical', 'high', 'medium', 'low', 'info']\n\nfunction downgradeSeverity(severity: Severity): Severity {\n const idx = SEVERITY_ORDER.indexOf(severity)\n if (idx < 0 || idx >= SEVERITY_ORDER.length - 1) return severity\n return SEVERITY_ORDER[idx + 1]!\n}\n\n/** Rough token estimate: ~4 characters per token. */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n\n/** Filter files that exceed the per-check token budget. */\nasync function filterFilesByBudget(\n files: ScanContext['files'],\n budget: number | undefined,\n): Promise<ScanContext['files']> {\n if (budget === undefined || budget === Infinity) {\n return files\n }\n const result: ScanContext['files'] = []\n for (const file of files) {\n const content = await file.content()\n if (estimateTokens(content) <= budget) {\n result.push(file)\n }\n }\n return result\n}\n\n/** Build a cache key from eligible file contents + template + provider metadata. */\nasync function buildCacheKey(\n ctx: ScanContext,\n template: PromptTemplate,\n files: SourceFile[],\n): Promise<string | undefined> {\n if (!ctx.llm) return undefined\n const parts: string[] = []\n for (const file of files) {\n parts.push(file.relativePath)\n parts.push(await file.content())\n }\n const fileContent = parts.join('\\0')\n return computeCacheKey({\n fileContent,\n checkId: template.checkId,\n promptVersion: `${template.promptVersion ?? '0.0.0'}:${PROMPT_PREAMBLE_VERSION}`,\n tokenBudget: template.tokenBudget ?? null,\n providerId: ctx.llm.providerId ?? 'unknown',\n modelId: ctx.llm.modelId ?? 'unknown',\n })\n}\n\nfunction makeMechanicalFinding(\n template: PromptTemplate,\n pattern: PromptTemplate['fallbackPatterns'][number],\n file: string,\n line: number,\n): Finding {\n return {\n id: '',\n checkId: template.checkId,\n category: template.checkId.split('.')[0]!,\n severity: pattern.severity,\n message: pattern.message,\n file,\n line,\n confidence: mechanicalConfidence('regex', file),\n remediation: getCopy(`remediation.${template.checkId}` as CopyKey),\n }\n}\n\nconst SEVERITY_ORDER_FOR_CAP: Severity[] = ['critical', 'high', 'medium', 'low', 'info']\n\nfunction capProjectScopedFindings(findings: Finding[]): Finding[] {\n if (findings.length <= 1) return findings\n\n const corroborated = findings.filter((f) => f.confidence === 'high')\n if (corroborated.length > 0) {\n const byFile = new Map<string, Finding>()\n for (const f of corroborated) {\n const key = f.file ?? ''\n if (!byFile.has(key)) byFile.set(key, f)\n }\n return [...byFile.values()]\n }\n\n const sorted = [...findings].sort(\n (a, b) => SEVERITY_ORDER_FOR_CAP.indexOf(a.severity) - SEVERITY_ORDER_FOR_CAP.indexOf(b.severity),\n )\n return [sorted[0]!]\n}\n\nasync function runProjectScopedMechanical(\n eligibleFiles: SourceFile[],\n template: PromptTemplate,\n): Promise<Finding[]> {\n if (eligibleFiles.length === 0) return []\n\n const contents = await Promise.all(eligibleFiles.map((f) => f.content()))\n const combined = contents.join('\\n')\n let shouldFlag = false\n const pattern = template.fallbackPatterns[0]\n\n if (template.checkId === 'resilience.no-rate-limiting') {\n const hasRoute = /\\.(?:get|post|put|delete|patch)\\s*\\(/i.test(combined)\n const hasMitigation = /rateLimit|express-rate-limit|throttle|slowDown|rate-limit/i.test(combined)\n shouldFlag = hasRoute && !hasMitigation\n } else if (template.checkId === 'security.auth-missing-endpoints') {\n const hasRoute = /\\.(?:get|post|put|delete|patch)\\s*\\(\\s*['\"`]/i.test(combined)\n const hasMitigation =\n /requireAuth|authenticate|passport|verifyToken|isAuthenticated|authMiddleware|\\bjwt\\b/i.test(combined)\n shouldFlag = hasRoute && !hasMitigation\n }\n\n if (!shouldFlag || !pattern) return []\n\n const anchorFile = pickProjectAnchorFile(eligibleFiles)\n return [\n {\n ...makeMechanicalFinding(template, pattern, anchorFile, 1),\n id: `${template.checkId}-mech-1`,\n },\n ]\n}\n\nasync function runProjectAbsenceChecks(\n eligibleFiles: SourceFile[],\n template: PromptTemplate,\n): Promise<Finding[]> {\n const absencePatterns = template.fallbackPatterns.filter((p) => p.absenceBased)\n if (absencePatterns.length === 0 || eligibleFiles.length === 0) {\n return []\n }\n\n const contents = await Promise.all(eligibleFiles.map((f) => f.content()))\n const anchorFile = pickProjectAnchorFile(eligibleFiles)\n const results: Finding[] = []\n\n for (const pattern of absencePatterns) {\n const foundAnywhere = contents.some((content) => pattern.regex.test(content))\n if (!foundAnywhere) {\n results.push(makeMechanicalFinding(template, pattern, anchorFile, 1))\n }\n }\n\n return results\n}\n\nexport async function runMechanicalCheck(\n ctx: ScanContext,\n template: PromptTemplate,\n): Promise<Finding[]> {\n const eligibleFiles = ctx.files.filter((f) => isProCheckEligible(f, template))\n\n if (template.projectScoped) {\n return runProjectScopedMechanical(eligibleFiles, template)\n }\n\n const perFilePatterns = template.fallbackPatterns.filter((p) => !p.absenceBased)\n\n const projectResults = await runProjectAbsenceChecks(eligibleFiles, template)\n\n const fileResults =\n perFilePatterns.length === 0\n ? []\n : await runWithConcurrencyCollect(\n eligibleFiles,\n async (file) => {\n const content = await file.content()\n const lines = content.split('\\n')\n const results: Finding[] = []\n\n for (const pattern of perFilePatterns) {\n if (pattern.multiline) {\n if (pattern.regex.test(content)) {\n results.push(makeMechanicalFinding(template, pattern, file.relativePath, 1))\n }\n continue\n }\n\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\n const line = lines[lineNum]!\n if (pattern.regex.test(line)) {\n results.push(\n makeMechanicalFinding(template, pattern, file.relativePath, lineNum + 1),\n )\n }\n }\n }\n\n return results\n },\n 4,\n )\n\n const allResults: Finding[] = [...projectResults]\n for (const fr of fileResults) {\n allResults.push(...fr)\n }\n\n for (let i = 0; i < allResults.length; i++) {\n allResults[i]!.id = `${template.checkId}-mech-${i + 1}`\n }\n\n return allResults\n}\n\ninterface ClassifiedFinding extends Finding {\n confidence: Confidence\n}\n\nfunction injectRemediation(findings: Finding[], checkId: string): Finding[] {\n try {\n const remediation = getCopy(`remediation.${checkId}` as CopyKey)\n return findings.map((f) => ({ ...f, remediation }))\n } catch {\n return findings\n }\n}\n\nfunction classifyConfidence(\n llmFindings: Finding[],\n mechFindings: Finding[],\n): ClassifiedFinding[] {\n const mechIndex = new Map<string, Finding>()\n for (const mf of mechFindings) {\n const key = `${mf.file ?? ''}:${mf.line ?? 0}`\n mechIndex.set(key, mf)\n }\n\n const usedMechKeys = new Set<string>()\n const classified: ClassifiedFinding[] = []\n\n for (const lf of llmFindings) {\n const key = `${lf.file ?? ''}:${lf.line ?? 0}`\n const mechMatch = mechIndex.get(key)\n\n if (mechMatch) {\n usedMechKeys.add(key)\n classified.push({\n ...lf,\n confidence: llmCorroboratedConfidence(lf.file),\n })\n } else {\n classified.push({\n ...lf,\n confidence: llmOnlyConfidence(lf.file),\n rawSeverity: lf.severity,\n severity: downgradeSeverity(lf.severity),\n })\n }\n }\n\n for (const mf of mechFindings) {\n const key = `${mf.file ?? ''}:${mf.line ?? 0}`\n if (usedMechKeys.has(key)) continue\n classified.push({ ...mf, confidence: mechanicalConfidence('regex', mf.file) })\n }\n\n return classified\n}\n\nexport async function runLLMCheck(\n ctx: ScanContext,\n template: PromptTemplate,\n): Promise<Finding[]> {\n if (!ctx.llm) {\n return []\n }\n\n const proEligibleFiles = ctx.files.filter((f) => isProCheckEligible(f, template))\n\n // Check cache first\n const cacheKey = await buildCacheKey(ctx, template, proEligibleFiles)\n if (cacheKey) {\n const cached = readCache(cacheKey)\n if (cached !== null) {\n return cached\n }\n }\n\n // Token-budget skip: exclude files whose estimated tokens exceed the budget\n const eligibleFiles = await filterFilesByBudget(proEligibleFiles, template.tokenBudget)\n if (eligibleFiles.length === 0) {\n // No files under budget — return mechanical findings only (zero LLM calls)\n let mechFindings = await runMechanicalCheck(ctx, template)\n if (template.projectScoped) {\n mechFindings = capProjectScopedFindings(mechFindings)\n }\n const withRemediation = injectRemediation(mechFindings, template.checkId)\n withRemediation.forEach((f) => setAnalysisType(f, 'pattern'))\n if (cacheKey) {\n try {\n writeCache(cacheKey, withRemediation)\n } catch {\n // Cache write failures are best-effort — don't fail the check\n }\n }\n return withRemediation\n }\n\n const prompt = `${PROMPT_PREAMBLE}\\n\\n${await template.buildPrompt(eligibleFiles)}`\n const allowedFilePaths = new Set(eligibleFiles.map((f) => f.relativePath))\n\n try {\n const response = await callLLMWithRetry(ctx.llm, prompt, template.checkId)\n const llmFindings = filterFindingsToAllowedFiles(\n template.parseResponse(response, template.checkId),\n allowedFilePaths,\n )\n const mechFindings = await runMechanicalCheck(ctx, template)\n let classified: ClassifiedFinding[] = classifyConfidence(llmFindings, mechFindings)\n if (template.projectScoped) {\n classified = capProjectScopedFindings(classified) as ClassifiedFinding[]\n }\n const withRemediation = injectRemediation(classified, template.checkId)\n withRemediation.forEach((f) => setAnalysisType(f, 'semantic'))\n if (cacheKey) {\n try {\n writeCache(cacheKey, withRemediation)\n } catch {\n // Cache write failures are best-effort — don't fail the check\n }\n }\n return withRemediation\n } catch (err) {\n console.error(`Check \"${template.checkId}\" failed: ${classifyError(err)}`)\n let fallback = await runFallback(ctx, template)\n if (template.projectScoped) {\n fallback = capProjectScopedFindings(fallback)\n }\n const withRemediation = injectRemediation(fallback, template.checkId)\n withRemediation.forEach((f) => setAnalysisType(f, 'pattern'))\n if (cacheKey) {\n try {\n writeCache(cacheKey, withRemediation)\n } catch {\n // Cache write failures are best-effort — don't fail the check\n }\n }\n return withRemediation\n }\n}\n\nasync function runFallback(\n ctx: ScanContext,\n template: PromptTemplate,\n): Promise<Finding[]> {\n const results = await runMechanicalCheck(ctx, template)\n return results\n}\n\nexport const _SEVERITY_ORDER = SEVERITY_ORDER\nexport const _downgradeSeverity = downgradeSeverity\nexport const _classifyConfidence = classifyConfidence\nexport const _estimateTokens = estimateTokens\nexport const _filterFilesByBudget = filterFilesByBudget\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.3.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\.(?:get|post|put|delete|patch)\\s*\\(\\s*['\"`][^'\"`]+['\"`]/i,\n message: 'Route defined without visible authentication middleware',\n severity: 'critical',\n },\n {\n regex: /@(?:app|blueprint)\\.(?:route|get|post|put|delete|patch)\\s*\\(/i,\n message: 'Python route decorator found — verify @login_required or auth middleware is present',\n severity: 'critical',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const entry =\n sourceFiles.find((f) => /(?:^|[\\\\/])(?:index|main|server|app)\\.(tsx?|jsx?|mjs|cjs)$/i.test(f.relativePath)) ??\n sourceFiles[0]\n const routeFiles: SourceFile[] = []\n for (const f of sourceFiles) {\n const content = await f.content()\n if (/\\.(?:get|post|put|patch|delete)\\s*\\(\\s*['\"`]/i.test(content)) routeFiles.push(f)\n }\n const parts: string[] = [\n 'Report at most ONE project-level finding if authentication middleware is missing repo-wide.',\n 'Do not emit one finding per route file unless that file clearly lacks auth while others have it.',\n `Route files (${routeFiles.length}): ${routeFiles.map((f) => f.relativePath).join(', ') || 'none listed'}`,\n 'Look for Express/Fastify routes without auth preHandler/hooks, NestJS @Controller handlers missing @UseGuards(AuthGuard) or global guards, Flask @login_required, Django @login_required/@permission_required, FastAPI Depends(get_current_user), or middleware-based auth.',\n ]\n if (entry) {\n const content = await entry.content()\n parts.push(`--- entrypoint ${entry.relativePath} ---\\n${content.slice(0, 6000)}`)\n }\n for (const file of routeFiles.slice(0, 5)) {\n if (file === entry) continue\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 1500)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'critical')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'security.auth-missing-endpoints',\n promptVersion: PROMPT_VERSION,\n projectScoped: true,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/security.auth-missing-endpoints.js'\n\nregistry.register({\n id: 'security.auth-missing-endpoints',\n name: 'Missing authentication on endpoints',\n description: 'Unprotected routes or missing auth on endpoints',\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /Access-Control-Allow-Origin\\s*:\\s*\\*/i,\n message: 'CORS configured with wildcard Allow-Origin',\n severity: 'high',\n },\n {\n regex: /CORS\\s*\\(\\s*app\\s*\\)|CORS\\s*\\(\\s*\\)|flask_cors\\.CORS/i,\n message: 'Flask-CORS installed — verify origins are whitelisted, not wildcard',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check for overly permissive CORS configurations. Flag Access-Control-Allow-Origin: * on non-public APIs. Look at CORS middleware, headers, and configuration.',\n 'In TypeScript/Node, check Express cors({ origin: true }) or cors() with no origin whitelist, @fastify/cors with origin: true or origin: \"*\", and manual res.setHeader(\"Access-Control-Allow-Origin\", \"*\").',\n 'In Python, check Flask-CORS CORS(app)/CORS() without origins whitelist, Django CORS_ALLOW_ALL_ORIGINS = True, and FastAPI CORSMiddleware with allow_origins=[\"*\"].',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'security.cors-too-permissive',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/security.cors-too-permissive.js'\n\n/**\n * Surfaces CORS configurations that allow arbitrary origins on non-public APIs.\n *\n * @attribution CWE-942\n */\n\nregistry.register({\n id: 'security.cors-too-permissive',\n name: 'Overly permissive CORS',\n description: 'Access-Control-Allow-Origin: * on non-public APIs',\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /['\"`]\\s*(?:SELECT|INSERT|UPDATE|DELETE)\\s+.*\\$\\{/i,\n message: 'SQL query appears to use string interpolation',\n severity: 'critical',\n },\n {\n regex: /\\.(?:query|raw|execute)\\s*\\(\\s*['\"`].*\\$\\{/i,\n message: 'Raw SQL with string interpolation detected',\n severity: 'critical',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check for SQL injection vulnerabilities. Look for raw string concatenation or template literals used to build SQL queries. Flag any use of string interpolation in .query(), .raw(), .execute(), or raw SQL strings.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'critical')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'security.sql-injection-surface',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\nimport { mergeFindings } from '../merge-findings.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/security.sql-injection-surface.js'\n\nconst CHECK_ID = 'security.sql-injection-surface'\n\n// ---------------------------------------------------------------------------\n// Tree-sitter strategy (mechanical pre-filter)\n// ---------------------------------------------------------------------------\n\nconst tsCheck = createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.sql-injection-surface.name',\n descriptionKey: 'checks.sql-injection-surface.description',\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n queries: {\n javascript: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(query|raw|execute)$\"))\n arguments: (arguments\n (template_string\n (template_substitution) @interp))) @match\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(query|raw|execute)$\"))\n arguments: (arguments\n (binary_expression\n operator: \"+\"))) @match\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#eq? @method \"find\"))\n arguments: (arguments (object (pair\n key: (property_identifier) @key\n (#eq? @key \"$where\")\n value: [\n (identifier) @arg\n (call_expression) @arg\n (member_expression) @arg\n ])))) @match\n`,\n typescript: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(query|raw|execute)$\"))\n arguments: (arguments\n (template_string\n (template_substitution) @interp))) @match\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(query|raw|execute)$\"))\n arguments: (arguments\n (binary_expression\n operator: \"+\"))) @match\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#eq? @method \"find\"))\n arguments: (arguments (object (pair\n key: (property_identifier) @key\n (#eq? @key \"$where\")\n value: [\n (identifier) @arg\n (call_expression) @arg\n (member_expression) @arg\n ])))) @match\n`,\n tsx: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(query|raw|execute)$\"))\n arguments: (arguments\n (template_string\n (template_substitution) @interp))) @match\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(query|raw|execute)$\"))\n arguments: (arguments\n (binary_expression\n operator: \"+\"))) @match\n\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#eq? @method \"find\"))\n arguments: (arguments (object (pair\n key: (property_identifier) @key\n (#eq? @key \"$where\")\n value: [\n (identifier) @arg\n (call_expression) @arg\n (member_expression) @arg\n ])))) @match\n`,\n python: `\n(call\n function: (attribute\n attribute: (identifier) @method\n (#match? @method \"^(query|execute|raw)$\"))\n arguments: (argument_list\n (string\n (interpolation) @interp))) @match\n\n(call\n function: (attribute\n attribute: (identifier) @method\n (#match? @method \"^(query|execute|raw)$\"))\n arguments: (argument_list\n (binary_operator\n operator: \"+\"))) @match\n\n(call\n function: (attribute\n attribute: (identifier) @method\n (#eq? @method \"execute\"))\n arguments: (argument_list\n (call\n function: (identifier) @func\n (#eq? @func \"text\")\n arguments: (argument_list\n (string\n (interpolation)))))) @match\n\n(call\n function: (attribute\n attribute: (identifier) @method\n (#eq? @method \"execute\"))\n arguments: (argument_list\n (string\n (interpolation) @interp))) @match\n`,\n go: `\n(call_expression\n function: (selector_expression\n field: (field_identifier) @method\n (#match? @method \"^(Query|Exec|QueryRow)$\"))\n arguments: (argument_list\n (binary_expression\n operator: \"+\"))) @match\n\n(call_expression\n function: (selector_expression\n field: (field_identifier) @method\n (#match? @method \"^(Query|Exec|QueryRow)$\"))\n arguments: (argument_list\n (call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"fmt\")\n (#eq? @field \"Sprintf\"))))) @match\n`,\n php: `\n(function_call_expression\n (name) @func\n (#match? @func \"^(mysqli_query|mysqli_multi_query|mysql_query)$\")\n (arguments\n (_) @arg)) @match\n`,\n bash: `\n(command\n name: (command_name (word) @cmd)\n argument: (word) @flag\n argument: [\n (string (simple_expansion) @arg)\n (simple_expansion) @arg\n (concatenation (simple_expansion) @arg)\n ]\n (#match? @cmd \"^(psql|mysql)$\")\n (#match? @flag \"^(-c|-e)$\")) @match\n\n(command\n name: (command_name (word) @cmd)\n argument: (_) @db\n argument: [\n (string (simple_expansion) @arg)\n (simple_expansion) @arg\n (concatenation (simple_expansion) @arg)\n ]\n (#eq? @cmd \"sqlite3\")) @match\n`,\n java: `\n(method_invocation\n name: (identifier) @method\n (#match? @method \"^execute.*$\")\n arguments: (argument_list\n (binary_expression\n operator: \"+\"))) @match\n\n(method_invocation\n name: (identifier) @method\n (#eq? @method \"prepareStatement\")\n arguments: (argument_list\n (binary_expression\n operator: \"+\"))) @match\n\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#eq? @obj \"jdbcTemplate\")\n (#match? @method \"^(query|update)$\")\n arguments: (argument_list\n (binary_expression\n operator: \"+\"))) @match\n`,\n ruby: `\n(call\n method: (identifier) @method\n (#match? @method \"^(find_by_sql|exec_query)$\")\n arguments: (argument_list\n (string\n (interpolation)))) @match\n\n(call\n method: (identifier) @method\n (#eq? @method \"where\")\n arguments: (argument_list\n (string\n (interpolation)))) @match\n`,\n },\n messageKey: 'checks.sql-injection-surface.message',\n degradedMessageKey: 'checks.sql-injection-surface.degraded',\n remediationKey: 'remediation.security.sql-injection-surface',\n messageFactory: (captures) => {\n return getCopy('checks.sql-injection-surface.message', captures.method ?? '?')\n },\n})\n\n// ---------------------------------------------------------------------------\n// LLM strategy (existing)\n// ---------------------------------------------------------------------------\n\nconst llmCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.sql-injection-surface.name'),\n description: getCopy('checks.sql-injection-surface.description'),\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n}\n\n// ---------------------------------------------------------------------------\n// Hybrid check (tree-sitter + LLM)\n// ---------------------------------------------------------------------------\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.sql-injection-surface.name'),\n description: getCopy('checks.sql-injection-surface.description'),\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [tsResult, llmResult] = await Promise.allSettled([\n tsCheck.run(ctx),\n llmCheck.run(ctx),\n ])\n const tsFindings = tsResult.status === 'fulfilled' ? tsResult.value : []\n const llmFindings = llmResult.status === 'fulfilled' ? llmResult.value : []\n return mergeFindings(tsFindings, llmFindings)\n },\n})\n","/**\n * LLM prompt and regex fallbacks for detecting sensitive values sent to logs.\n *\n * @attribution CWE-532\n */\nimport type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex:\n /(?:console\\.(?:log|info|warn|error|debug)|logger\\.\\w+|logging\\.(?:info|debug|warning|error|critical))\\s*\\(.*\\b(?:req\\.body|req\\.params|req\\.query|req\\.headers|request\\.(?:args|form|json|data|headers|body)|authorization|cookie|set-cookie|token|password|secret|api[_-]?key|email)\\b|\\bprint\\s*\\(.*\\b(?:req\\.body|req\\.params|req\\.query|req\\.headers|request\\.(?:args|form|json|data|headers|body)|authorization|cookie|set-cookie|token|password|secret|api[_-]?key|email)\\b/i,\n message: 'Sensitive data potentially logged to console',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check for sensitive data being written to log output. Look for console.log, logger.info, logger.error, logging.info, logging.debug, or similar calls that may log request bodies, query strings, headers (including Authorization or Cookie), tokens, passwords, API keys, emails, session identifiers, or other PII.',\n 'In TypeScript/Node, flag pino/winston structured logs that include req.body, req.headers.authorization, or full request objects (e.g. logger.info({ req }, \"request\")).',\n 'In Python, flag logging.info(request_data), print(user_data), or logger.debug with request objects.',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'security.sensitive-data-in-logs',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/security.sensitive-data-in-logs.js'\nimport { getCopy } from '../../copy/index.js'\nimport { lineMatch, scanBashLines, SENSITIVE_NAME_REGEX } from '../helpers/bash-patterns.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst JAVA_SENSITIVE_LOG =\n /^\\s*.*\\b(?:log|logger)\\s*\\.\\s*(?:info|debug|warn|error|trace)\\s*\\([^)]*(?:password|passwd|secret|token|api[_-]?key|credential)/i\n\nconst RUBY_SENSITIVE_LOG =\n /^\\s*.*\\b(?:Rails\\.)?logger\\s*\\.\\s*(?:info|debug|warn|error)\\s*\\([^)]*\\bparams\\b/i\n\n/**\n * Surfaces logging calls that include potentially sensitive user or authentication data.\n *\n * @attribution CWE-532\n */\n\nregistry.register({\n id: 'security.sensitive-data-in-logs',\n name: 'Sensitive data in logs',\n description: 'Sensitive data written to log output',\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const mechanicalFindings: Finding[] = []\n for (const file of ctx.files) {\n if (file.language === 'ruby') {\n const content = await file.content()\n const lines = content.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n if (!RUBY_SENSITIVE_LOG.test(line)) continue\n mechanicalFindings.push({\n id: `sensitive-log-ruby-${file.relativePath}:${i + 1}`,\n checkId: 'security.sensitive-data-in-logs',\n category: 'security',\n severity: 'high',\n message: 'Logging call may include sensitive request parameters.',\n file: file.relativePath,\n line: i + 1,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: getCopy('remediation.security.sensitive-data-in-logs'),\n })\n }\n continue\n }\n if (file.language !== 'java') continue\n const content = await file.content()\n const lines = content.split('\\n')\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n if (!JAVA_SENSITIVE_LOG.test(line) && !(/logger\\./i.test(line) && SENSITIVE_NAME_REGEX.test(line))) {\n continue\n }\n mechanicalFindings.push({\n id: `sensitive-log-java-${file.relativePath}:${i + 1}`,\n checkId: 'security.sensitive-data-in-logs',\n category: 'security',\n severity: 'high',\n message: 'Logging call may include sensitive data.',\n file: file.relativePath,\n line: i + 1,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: getCopy('remediation.security.sensitive-data-in-logs'),\n })\n }\n }\n\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'security.sensitive-data-in-logs',\n category: 'security',\n severity: 'high',\n message: () => 'Shell logging can expose sensitive variables.',\n remediation: getCopy('remediation.security.sensitive-data-in-logs'),\n }, (line, _content, index) => {\n if (/^\\s*(?:set\\s+-x|set\\s+-o\\s+xtrace)\\b/.test(line)) return lineMatch(line, index, /\\bset\\s+(?:-x|-o\\s+xtrace)\\b/)\n if (!/^\\s*(?:echo|printf|logger)\\b/.test(line) || !SENSITIVE_NAME_REGEX.test(line)) return null\n return lineMatch(line, index, /^\\s*(?:echo|printf|logger)\\b.*\\$(?:\\{)?[A-Z0-9_]*(?:PASSWORD|PASSWD|SECRET|TOKEN|API_KEY|ACCESS_KEY|PRIVATE_KEY|CREDENTIAL)[A-Z0-9_]*(?:\\})?/i)\n }),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...mechanicalFindings, ...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.2.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\.(?:get|post|put|delete|patch)\\s*\\(/i,\n message: 'Route found — verify rate limiting middleware is present',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const entry =\n sourceFiles.find((f) => /(?:^|[\\\\/])(?:index|main|server|app)\\.(tsx?|jsx?|mjs|cjs)$/i.test(f.relativePath)) ??\n sourceFiles[0]\n const routeFiles: SourceFile[] = []\n for (const f of sourceFiles) {\n const content = await f.content()\n if (/\\.(?:get|post|put|patch|delete)\\s*\\(/i.test(content)) routeFiles.push(f)\n }\n const parts: string[] = [\n 'Report at most ONE project-level finding if rate limiting is missing repo-wide.',\n 'Do not emit one finding per route file. Flag only when no rateLimit, throttle, express-rate-limit, Flask-Limiter, django-ratelimit, or similar middleware appears anywhere.',\n 'In TypeScript/Node, look for @fastify/rate-limit, express-rate-limit, or Nest ThrottlerModule — not only bare app.get/post routes.',\n 'In Python, look for Flask-Limiter @limiter.limit, Django ratelimit decorators, or ASGI middleware-based rate limiting.',\n `Route files (${routeFiles.length}): ${routeFiles.map((f) => f.relativePath).join(', ') || 'none listed'}`,\n ]\n if (entry) {\n const content = await entry.content()\n parts.push(`--- entrypoint ${entry.relativePath} ---\\n${content.slice(0, 6000)}`)\n }\n for (const file of routeFiles.slice(0, 5)) {\n if (file === entry) continue\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 1500)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.no-rate-limiting',\n promptVersion: PROMPT_VERSION,\n projectScoped: true,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.no-rate-limiting.js'\n\nregistry.register({\n id: 'resilience.no-rate-limiting',\n name: 'Missing rate limiting',\n description: 'No rate limiting on public endpoints',\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /req\\.(?:body|params|query)\\b(?!.*\\b(?:validate|schema|zod|joi|yup)\\b)/i,\n message: 'Request input used without visible validation',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check for route handlers that accept user input without validation. Look for req.body, req.params, req.query usage without corresponding schema validation (zod, joi, yup) or size limits. In Python, check Flask request.args, request.form, request.json, Django request.GET, request.POST, and FastAPI path/query/body params — flag when used without Pydantic models, marshmallow schemas, or manual type/length validation.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.no-input-validation',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.no-input-validation.js'\nimport { getCopy } from '../../copy/index.js'\nimport { hasShellValidation, lineMatch, scanBashLines } from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-20\n */\nasync function scanBashNoInputValidation(ctx: ScanContext): Promise<Finding[]> {\n return scanBashLines(ctx, {\n checkId: 'resilience.no-input-validation',\n category: 'resilience',\n severity: 'high',\n message: () => 'Shell script uses positional input without visible validation.',\n remediation: getCopy('remediation.resilience.no-input-validation'),\n }, (line, content, index) => {\n if (hasShellValidation(content)) return null\n return lineMatch(line, index, /\\$\\d\\b|\\$\\{[1-9][0-9]*\\}/)\n }).then((findings) => findings.slice(0, 1))\n}\n\nregistry.register({\n id: 'resilience.no-input-validation',\n name: 'Missing input validation',\n description: 'No input validation or request size limits',\n category: 'resilience',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashNoInputValidation(ctx),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /catch\\s*\\{\\s*\\}/,\n message: 'Empty catch block swallows errors',\n severity: 'high',\n },\n {\n regex: /\\.then\\s*\\([^)]*\\)\\s*(?!.*\\.catch\\b)/,\n message: 'Promise .then() without .catch() handler',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check for unhandled promise rejections and swallowed exceptions. Look for empty catch blocks, .then() chains without .catch(), try/catch with empty catch bodies, async functions that may throw without being handled, Python try/except without meaningful error handling (except: pass, except Exception: pass), and async def functions without try/except for I/O operations.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.missing-error-handling',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.missing-error-handling.js'\nimport { getCopy } from '../../copy/index.js'\nimport { scanBashLines, lineMatch } from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-248\n */\nasync function scanBashMissingErrorHandling(ctx: ScanContext): Promise<Finding[]> {\n return scanBashLines(\n ctx,\n {\n checkId: 'resilience.missing-error-handling',\n category: 'resilience',\n severity: 'high',\n message: () => 'Shell script does not enable errexit. Add set -e or set -o errexit near the top of the script.',\n remediation: getCopy('remediation.resilience.missing-error-handling'),\n },\n (_line, content, _lineIndex) => {\n if (/^\\s*set\\s+(?:-[A-Za-z]*e[A-Za-z]*|-o\\s+errexit)\\b/m.test(content)) return null\n const lines = content.split('\\n')\n const firstExecutableIndex = lines.findIndex((l) => !/^\\s*(?:#|$)/.test(l))\n if (firstExecutableIndex === -1) return null\n return lineMatch(lines[firstExecutableIndex]!, firstExecutableIndex, /./)\n },\n ).then((findings) => findings.slice(0, 1))\n}\n\nregistry.register({\n id: 'resilience.missing-error-handling',\n name: 'Missing error handling',\n description: 'Unhandled promise rejections, swallowed exceptions',\n category: 'resilience',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashMissingErrorHandling(ctx),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /SELECT\\s+\\*\\s+FROM\\b(?!.*\\bLIMIT\\b)/i,\n message: 'SELECT * without LIMIT clause — unbounded query',\n severity: 'medium',\n },\n {\n regex: /\\.(?:find|findAll|findMany)\\s*\\(\\s*\\)(?!.*\\.(?:limit|take|skip)\\b)/i,\n message: 'ORM find without pagination limits',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check for unbounded full-table queries on list endpoints. Look for database queries that may return all rows without pagination: missing LIMIT, OFFSET, .limit(), .take(), or .skip() calls. In Python ORMs, flag Django .all() querysets used in list views without slicing, SQLAlchemy .all() without .limit(), and raw SQL without LIMIT clauses.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.no-pagination',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.no-pagination.js'\n\nregistry.register({\n id: 'resilience.no-pagination',\n name: 'Missing pagination',\n description: 'Unbounded full-table queries on list endpoints',\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.2.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /(?:fetch|axios\\.(?:get|post|put|delete|patch|request)|requests\\.(?:get|post|put|patch|delete|head)|aiohttp\\.\\w*[Ss]ession|httpx\\.(?:get|post|put|patch|delete|Client))\\s*\\(/i,\n message: 'Outbound HTTP call found — verify timeout is configured',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check for outbound HTTP calls that lack timeout configuration.',\n 'In TypeScript/Node, flag fetch() without AbortSignal.timeout() or signal, and axios.get/post without a timeout option in async/await handlers.',\n 'In Python, flag requests.get/post without timeout=, aiohttp calls without timeout, and httpx clients without timeout. Flag any external HTTP that could hang indefinitely.',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.missing-timeout',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.missing-timeout.js'\nimport { getCopy } from '../../copy/index.js'\nimport {\n EXTERNAL_COMMAND_REGEX,\n lineMatch,\n scanBashLines,\n shellLineHasTimeout,\n} from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-400\n */\nfunction bashMissingTimeoutPattern(line: string): RegExp | null {\n if (!EXTERNAL_COMMAND_REGEX.test(line)) return null\n if (shellLineHasTimeout(line)) return null\n return EXTERNAL_COMMAND_REGEX\n}\n\nregistry.register({\n id: 'resilience.missing-timeout',\n name: 'Missing timeout',\n description: 'No timeout on outbound HTTP calls',\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'resilience.missing-timeout',\n category: 'resilience',\n severity: 'medium',\n message: () => 'External shell command runs without an explicit timeout.',\n remediation: getCopy('remediation.resilience.missing-timeout'),\n }, (line, _content, index) => {\n const pattern = bashMissingTimeoutPattern(line)\n return pattern ? lineMatch(line, index, pattern) : null\n }),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /(?:fetch|axios|request|got|superagent|node-fetch|requests\\.(?:get|post|put|patch|delete))\\b/i,\n message: 'External service call found — verify retry logic is present',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check if critical external service calls lack retry logic. Look for fetch, axios, or other HTTP clients used for external API calls that are not wrapped with retry mechanisms (retry, p-retry, async-retry, tenacity in Python, urllib3.Retry, or manual retry loops).']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.no-retry-logic',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.no-retry-logic.js'\nimport { getCopy } from '../../copy/index.js'\nimport {\n EXTERNAL_COMMAND_REGEX,\n lineMatch,\n scanBashLines,\n shellContentHasRetry,\n} from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-703\n */\nasync function scanBashNoRetry(ctx: ScanContext): Promise<Finding[]> {\n return scanBashLines(ctx, {\n checkId: 'resilience.no-retry-logic',\n category: 'resilience',\n severity: 'medium',\n message: () => 'External shell command has no visible retry path for transient failures.',\n remediation: getCopy('remediation.resilience.no-retry-logic'),\n }, (line, content, index) => {\n if (shellContentHasRetry(content)) return null\n return lineMatch(line, index, EXTERNAL_COMMAND_REGEX)\n }).then((findings) => findings.slice(0, 1))\n}\n\nregistry.register({\n id: 'resilience.no-retry-logic',\n name: 'Missing retry logic',\n description: 'No retry logic on critical external calls',\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashNoRetry(ctx),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = []\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const webhookFiles: SourceFile[] = []\n\n for (const f of sourceFiles) {\n const content = await f.content()\n if (\n /(?:webhook|paddle|stripe|checkout|billing)/i.test(f.relativePath) ||\n /(?:webhook|paddle-signature|stripe-signature|payment)/i.test(content)\n ) {\n webhookFiles.push(f)\n }\n }\n\n const parts: string[] = [\n 'Analyze the codebase for webhook handlers and payment subscription integrations (Paddle, Stripe, etc.).',\n 'Specifically, interrogate the code and flag the following resilience or security defects:',\n '1. Webhook Signature Validation Bypass: Webhook endpoints that process payloads without verifying signature headers (e.g., checking paddle-signature or stripe-signature).',\n '2. Missing Idempotency Check: Failing to log and check webhook event IDs (e.g., event_id or evt_id) to prevent duplicate transaction processing.',\n '3. Missing Out-of-Order Mitigation: Updating subscription statuses without checking payment event timestamps (e.g., occurred_at or event_created) to prevent stale events from overwriting newer state.',\n '4. Lack of Passive/Active Sync Fallbacks: Relying solely on asynchronous webhooks for subscription lifecycles without a cron fallback or a check-on-access validation flow to sync state from the provider.',\n ]\n\n for (const file of webhookFiles.slice(0, 10)) {\n const content = await file.content()\n parts.push(`--- File: ${file.relativePath} ---\\n${content.slice(0, 4000)}`)\n }\n\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.webhook-processing-defects',\n promptVersion: PROMPT_VERSION,\n projectScoped: true,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.webhook-processing-defects.js'\nimport { getCopy } from '../../copy/index.js'\n\n/**\n * @attribution CWE-347\n */\nregistry.register({\n id: 'resilience.webhook-processing-defects',\n name: getCopy('checks.webhook-processing-defects.name'),\n description: getCopy('checks.webhook-processing-defects.description'),\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","/**\n * @attribution CWE-754\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'resilience.html-inline-resilience'\nconst REMEDIATION = getCopy('remediation.resilience.html-inline-resilience')\n\nconst SCRIPT_BLOCK_PATTERN = /<script\\b(?![^>]*\\btype\\s*=\\s*[\"']application\\/json[\"'])[^>]*>([\\s\\S]*?)<\\/script>/gi\nconst FETCH_OR_XHR_PATTERN = /\\b(?:fetch|XMLHttpRequest)\\s*\\(/i\nconst ABORT_TIMEOUT_PATTERN = /\\b(?:AbortController|AbortSignal|signal)\\b|AbortController\\.timeout\\s*\\(/i\nconst RETRY_PATTERN = /\\b(?:retry|retries|backoff|jitter)\\b/i\nconst RETRY_LOOP_PATTERN = /\\bfor\\s*\\([^)]*\\battempt\\b[^)]*\\)/i\nconst BACKOFF_JITTER_PATTERN = /\\b(?:backoff|jitter|Math\\.random|random\\s*\\()/i\nconst EMPTY_CATCH_PATTERN = /catch\\s*\\(\\s*[^)]*\\s*\\)\\s*\\{\\s*\\}/i\nconst TRY_CATCH_PATTERN = /\\btry\\s*\\{/i\nconst _NO_CATCH_PATTERN = /(?:fetch\\s*\\(|new\\s+XMLHttpRequest\\s*\\()/i\nconst INFINITE_RETRY_PATTERN = /\\bwhile\\s*\\(\\s*(?:true|1)\\s*\\)\\s*\\{[\\s\\S]*?\\b(?:fetch|XMLHttpRequest)\\s*\\(/i\nconst RECURSIVE_RETRY_PATTERN = /function\\s+([A-Za-z_$][\\w$]*)\\s*\\([\\s\\S]*?\\)\\s*\\{[\\s\\S]*?\\b(?:fetch|XMLHttpRequest)\\s*\\([\\s\\S]*?\\b\\1\\s*\\(/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nfunction pushFinding(\n findings: Finding[],\n filePath: string,\n content: string,\n index: number,\n matchText: string,\n issue: string,\n severity: Finding['severity'],\n): void {\n const { line, column } = lineAndColumn(content, index)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}:${issue}`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity,\n message: getCopy('checks.html-inline-resilience.message', `${issue}: ${matchText}`),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath),\n remediation: REMEDIATION,\n })\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-inline-resilience.name'),\n description: getCopy('checks.html-inline-resilience.description'),\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(SCRIPT_BLOCK_PATTERN)) {\n const script = match[1] ?? ''\n const index = match.index ?? 0\n\n if (!FETCH_OR_XHR_PATTERN.test(script)) continue\n\n if (EMPTY_CATCH_PATTERN.test(script)) {\n pushFinding(findings, file.relativePath, content, index, 'empty catch block', 'swallowed-catch', 'high')\n }\n\n if (!ABORT_TIMEOUT_PATTERN.test(script)) {\n pushFinding(findings, file.relativePath, content, index, 'fetch/xhr without timeout', 'missing-timeout', 'medium')\n }\n\n if (!TRY_CATCH_PATTERN.test(script) && !RETRY_PATTERN.test(script) && !RETRY_LOOP_PATTERN.test(script)) {\n pushFinding(findings, file.relativePath, content, index, 'fetch/xhr without retry logic', 'no-retry-logic', 'medium')\n }\n\n if ((RETRY_PATTERN.test(script) || RETRY_LOOP_PATTERN.test(script)) && !BACKOFF_JITTER_PATTERN.test(script)) {\n pushFinding(findings, file.relativePath, content, index, 'retry logic without backoff or jitter', 'no-backoff-jitter', 'medium')\n }\n\n if (INFINITE_RETRY_PATTERN.test(script) || RECURSIVE_RETRY_PATTERN.test(script)) {\n pushFinding(findings, file.relativePath, content, index, 'infinite retry loop', 'infinite-retry', 'medium')\n }\n\n if ((FETCH_OR_XHR_PATTERN.test(script) || /\\basync\\b/i.test(script)) && !TRY_CATCH_PATTERN.test(script)) {\n pushFinding(findings, file.relativePath, content, index, 'missing try/catch or catch handler', 'missing-error-handling', 'high')\n }\n }\n }\n\n return findings\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\/healthz?\\b/i,\n message: 'No health check route found',\n severity: 'low',\n absenceBased: true,\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check if a health check endpoint exists. Look for route definitions matching /health or /healthz.',\n 'In TypeScript/Node, check Express app.get(\"/health\"), Fastify fastify.get(\"/health\"), and Nest @Get(\"health\") controllers.',\n 'In Python, check Flask @app.route(\"/health\"), Django health patterns, or FastAPI @app.get(\"/health\"). Flag projects with no health endpoint.',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'low')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'ops.no-health-check',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/ops.no-health-check.js'\n\nregistry.register({\n id: 'ops.no-health-check',\n name: 'Missing health check',\n description: 'No health check endpoint',\n category: 'ops',\n severity: 'low',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /console\\.(?:log|error|warn)\\b/i,\n message: 'Console logging used — structured logging recommended',\n severity: 'low',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check if error logging is structured and machine-readable. Look for console.log/console.error in route handlers or middleware instead of structured loggers (pino, winston with JSON format).',\n 'In TypeScript/Node, flag console.log in Express/Fastify/Nest handlers where pino/winston with JSON transport is absent repo-wide.',\n 'In Python, flag logging.basicConfig without JSONFormatter, structlog without JSONRenderer, or print() instead of a structured logger.',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'low')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'ops.missing-structured-logging',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/ops.missing-structured-logging.js'\n\nregistry.register({\n id: 'ops.missing-structured-logging',\n name: 'Missing structured logging',\n description: 'Errors not machine-readable',\n category: 'ops',\n severity: 'low',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /process\\.on\\s*\\(\\s*['\"`]SIG(?:TERM|INT)['\"`]|signal\\.signal\\(signal\\.SIG(?:TERM|INT),/,\n message: 'No graceful shutdown handler found',\n severity: 'medium',\n absenceBased: true,\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check for graceful shutdown handling. Look for SIGTERM and SIGINT signal handlers that gracefully close server connections, drain requests, and clean up resources.',\n 'In TypeScript/Node, flag Fastify/Express/Nest apps that call listen() without process.on(\"SIGTERM\") / process.on(\"SIGINT\") handlers to close the server and drain in-flight work.',\n 'In Python, look for signal.signal(signal.SIGTERM, handler), atexit.register, or asyncio shutdown handlers. Flag app.run(), uvicorn.run(), or gunicorn configs without shutdown hooks.',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'ops.no-graceful-shutdown',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/ops.no-graceful-shutdown.js'\nimport { getCopy } from '../../copy/index.js'\nimport {\n EXTERNAL_COMMAND_REGEX,\n lineMatch,\n scanBashLines,\n shellContentHasTrap,\n} from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-705\n */\nasync function scanBashNoGracefulShutdown(ctx: ScanContext): Promise<Finding[]> {\n return scanBashLines(ctx, {\n checkId: 'ops.no-graceful-shutdown',\n category: 'ops',\n severity: 'medium',\n message: () => 'Shell script runs operational work without an EXIT, SIGINT, or SIGTERM trap.',\n remediation: getCopy('remediation.ops.no-graceful-shutdown'),\n }, (line, content, index) => {\n if (shellContentHasTrap(content)) return null\n return lineMatch(line, index, EXTERNAL_COMMAND_REGEX)\n }).then((findings) => findings.slice(0, 1))\n}\n\nregistry.register({\n id: 'ops.no-graceful-shutdown',\n name: 'Missing graceful shutdown',\n description: 'No graceful shutdown handling',\n category: 'ops',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashNoGracefulShutdown(ctx),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /NODE_ENV|DJANGO_SETTINGS_MODULE|FLASK_ENV|ENVIRONMENT/,\n message: 'No environment separation detected in config file',\n severity: 'medium',\n absenceBased: true,\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check if dev, staging, and production environments share a single configuration without overrides. Look for config files that do not differentiate between environments, missing NODE_ENV/DJANGO_SETTINGS_MODULE/FLASK_ENV checks, or hardcoded values that should vary by environment. In Python, flag settings.py files without environment-specific overrides, single config.py serving all envs, or Django settings using hardcoded DEBUG=True without environment checks.',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'configuration.no-env-separation',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/configuration.no-env-separation.js'\n\nregistry.register({\n id: 'configuration.no-env-separation',\n name: 'No environment separation',\n description: 'No separation of dev/staging/prod config',\n category: 'configuration',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /(?:admin:admin|password\\s*[:=]\\s*['\"`]password|changeme|default)/i,\n message: 'Default credentials possibly in use',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check if default credentials are unchanged. Look for default usernames/passwords (admin/admin, root/root, guest/guest), placeholder credentials (changeme, password), or default connection strings that have not been customised.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'configuration.default-credentials',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","/**\n * AST extraction helper functions for SQL scanning.\n */\n\n/**\n * Strips quotes/brackets from SQL identifiers and converts to lowercase.\n * Example: `public` -> `public`, `\"public\"` -> `public`, `` `public` `` -> `public`, `[public]` -> `public`\n */\nexport function normalizeIdentifier(name: string): string {\n if (!name) return ''\n let cleaned = name.trim()\n if (\n (cleaned.startsWith('\"') && cleaned.endsWith('\"')) ||\n (cleaned.startsWith(\"'\") && cleaned.endsWith(\"'\")) ||\n (cleaned.startsWith('`') && cleaned.endsWith('`'))\n ) {\n cleaned = cleaned.slice(1, -1)\n } else if (cleaned.startsWith('[') && cleaned.endsWith(']')) {\n cleaned = cleaned.slice(1, -1)\n }\n return cleaned.toLowerCase()\n}\n\n/**\n * Returns normalized string literal content by stripping quotes.\n * Example: `'admin'` -> `admin`\n */\nexport function unquoteString(value: string): string {\n if (!value) return ''\n const trimmed = value.trim()\n if (\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\")) ||\n (trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n ) {\n return trimmed.slice(1, -1)\n }\n return trimmed\n}\n\n/**\n * Splits and normalizes schema-qualified table/object names.\n * Example: `public.users` -> { schema: 'public', name: 'users', fullName: 'public.users' }\n * Example: `\"Users\"` -> { schema: undefined, name: 'users', fullName: 'users' }\n */\nexport interface SchemaQualifiedName {\n schema?: string\n name: string\n fullName: string\n}\n\nexport function parseSchemaQualifiedName(name: string): SchemaQualifiedName {\n const parts = name.split('.')\n if (parts.length === 2) {\n const schema = normalizeIdentifier(parts[0]!)\n const tableName = normalizeIdentifier(parts[1]!)\n return {\n schema,\n name: tableName,\n fullName: `${schema}.${tableName}`,\n }\n }\n const tableName = normalizeIdentifier(name)\n return {\n name: tableName,\n fullName: tableName,\n }\n}\n\n/**\n * Checks if a string literal password matches a default pattern.\n */\nexport function isDefaultCredential(password: string): boolean {\n const normalized = unquoteString(password).toLowerCase()\n const defaults = new Set([\n 'admin',\n 'password',\n '123456',\n 'changeme',\n 'letmein',\n 'secret',\n 'test',\n 'postgres',\n 'root',\n ])\n return defaults.has(normalized)\n}\n\n/**\n * Checks if a policy expression is restrictive or a tautology.\n * Example: `true`, `1 = 1`, `true = true`\n */\nexport function isTautologyExpression(exprText: string): boolean {\n const normalized = exprText.replace(/\\s+/g, '').toLowerCase()\n const tautologies = new Set([\n 'true',\n '1=1',\n 'true=true',\n \"'1'='1'\",\n '\\'t\\'=\\'t\\'',\n '1::boolean',\n 'true::boolean',\n ])\n return tautologies.has(normalized)\n}\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/configuration.default-credentials.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { isDefaultCredential, unquoteString } from '../helpers/sql-ast.js'\nimport { lineMatch, scanBashLines } from '../helpers/bash-patterns.js'\n\n/**\n * Detects literal default credentials in SQL seed/migration scripts.\n *\n * @attribution CWE-798\n */\nconst CHECK_ID = 'configuration.default-credentials'\nconst REMEDIATION = getCopy('remediation.configuration.default-credentials')\n\nconst SENSITIVE_TABLES = new Set([\n 'users',\n 'user',\n 'accounts',\n 'account',\n 'auth',\n 'admins',\n 'admin',\n 'customers',\n 'customer',\n 'employees',\n 'employee',\n])\n\nconst HASH_PREFIXES = ['$2a$', '$2b$', '$2y$', '$argon2', '$scrypt']\n\nfunction looksLikeHash(value: string): boolean {\n const trimmed = value.trim()\n return (\n HASH_PREFIXES.some((p) => trimmed.startsWith(p)) ||\n /^[a-f0-9]{32,}$/i.test(trimmed) ||\n /^[A-Za-z0-9+/]{40,}={0,2}$/.test(trimmed)\n )\n}\n\n/**\n * Scans SQL files for INSERT statements that place default/weak\n * passwords into sensitive tables, and CREATE ROLE ... PASSWORD\n * statements with weak credentials.\n */\nasync function scanSqlDefaultCredentials(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n // Pattern 1: INSERT INTO sensitive_table ... VALUES (... 'password' ...)\n const insertRegex =\n /\\binsert\\s+into\\s+(?:only\\s+)?(?:public\\.)?(\\w+|\"\\w+\"|`\\w+`|\\[\\w+\\])\\b[\\s\\S]*?\\bvalues\\s*\\(/gi\n\n let insertMatch = insertRegex.exec(content)\n while (insertMatch) {\n const tableName = insertMatch[1]!.replace(/[\"`[\\]]/g, '').toLowerCase()\n if (!SENSITIVE_TABLES.has(tableName)) {\n insertMatch = insertRegex.exec(content)\n continue\n }\n\n // Extract the VALUES clause content between the first ( and matching )\n const valuesStart = insertMatch.index + insertMatch[0].length\n let parenDepth = 1\n let valuesEnd = valuesStart\n while (parenDepth > 0 && valuesEnd < content.length) {\n const ch = content[valuesEnd]!\n if (ch === '(') parenDepth++\n else if (ch === ')') parenDepth--\n valuesEnd++\n }\n const valuesClause = content.slice(valuesStart, valuesEnd)\n\n // Look for string literals in the VALUES clause\n const stringLiteralRegex = /'([^']*)'/g\n let strMatch = stringLiteralRegex.exec(valuesClause)\n while (strMatch) {\n const value = strMatch[1]!\n if (!looksLikeHash(value) && isDefaultCredential(value)) {\n // Find line number\n const beforeMatch = content.slice(0, insertMatch.index)\n const lineNum = beforeMatch.split('\\n').length\n\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:1:sql-insert`,\n checkId: CHECK_ID,\n category: 'configuration',\n severity: 'high',\n message: getCopy(\n 'checks.default-credentials.message',\n `INSERT INTO \"${tableName}\" contains a default/weak password`\n ),\n file: file.relativePath,\n line: lineNum,\n column: 1,\n remediation: REMEDIATION,\n })\n }\n strMatch = stringLiteralRegex.exec(valuesClause)\n }\n\n insertMatch = insertRegex.exec(content)\n }\n insertRegex.lastIndex = 0\n\n // Pattern 2: CREATE ROLE ... PASSWORD '...'\n const createRoleRegex =\n /\\bcreate\\s+(?:role|user)\\s+(?:if\\s+not\\s+exists\\s+)?(\\w+|\"\\w+\"|`\\w+`|\\[\\w+\\])\\b[\\s\\S]*?\\bpassword\\s+['\"]([^'\"]{1,64})['\"]/gi\n\n let roleMatch = createRoleRegex.exec(content)\n while (roleMatch) {\n const roleName = roleMatch[1]!.replace(/[\"`[\\]]/g, '')\n const password = roleMatch[2]!\n\n if (!looksLikeHash(password) && isDefaultCredential(password)) {\n const beforeMatch = content.slice(0, roleMatch.index)\n const lineNum = beforeMatch.split('\\n').length\n\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:1:sql-role`,\n checkId: CHECK_ID,\n category: 'configuration',\n severity: 'high',\n message: getCopy(\n 'checks.default-credentials.message',\n `CREATE ROLE \"${roleName}\" uses a default/weak password`\n ),\n file: file.relativePath,\n line: lineNum,\n column: 1,\n remediation: REMEDIATION,\n })\n }\n\n roleMatch = createRoleRegex.exec(content)\n }\n createRoleRegex.lastIndex = 0\n }\n\n return findings\n}\n\nasync function scanBashDefaultCredentials(ctx: ScanContext): Promise<Finding[]> {\n return scanBashLines(ctx, {\n checkId: CHECK_ID,\n category: 'configuration',\n severity: 'high',\n message: (match) => getCopy('checks.default-credentials.message', match),\n remediation: REMEDIATION,\n }, (line, _content, index) => {\n const assignment = /(?:^|\\s)(?:export\\s+)?[A-Z0-9_]*(?:PASS|PASSWORD|PWD|SECRET|TOKEN)[A-Z0-9_]*=([\"'])([^\"']{1,64})\\1/i.exec(line)\n if (!assignment) return null\n const value = unquoteString(assignment[2]!)\n if (!isDefaultCredential(value) || looksLikeHash(value)) return null\n return lineMatch(line, index, /(?:^|\\s)(?:export\\s+)?[A-Z0-9_]*(?:PASS|PASSWORD|PWD|SECRET|TOKEN)[A-Z0-9_]*=([\"'])([^\"']{1,64})\\1/i)\n })\n}\n\nconst sqlCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.default-credentials.name'),\n description: getCopy('checks.default-credentials.description'),\n category: 'configuration',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [sqlFindings, bashFindings, llmFindings] = await Promise.all([\n scanSqlDefaultCredentials(ctx),\n scanBashDefaultCredentials(ctx),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...sqlFindings, ...bashFindings, ...llmFindings]\n },\n}\n\nregistry.register(sqlCheck)\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /(?:err|error)\\.stack\\b/,\n message: 'Stack trace potentially returned in error response',\n severity: 'high',\n },\n {\n regex: /stack\\s*:\\s*(?:err|error)\\.(?:stack|message)/,\n message: 'Error details exposed in response body',\n severity: 'high',\n },\n {\n regex: /traceback\\.format_exc\\(\\)|traceback\\.print_exc\\(\\)/,\n message: 'Python traceback potentially returned to client',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check if stack traces or internal paths are returned to API clients. Look for error handling middleware that exposes err.stack, process.cwd(), __dirname, or internal file paths in HTTP responses. In Python, flag traceback.format_exc() or traceback.print_exc() in response builders, DEBUG=True in production, or exception details returned in JSON error responses.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'data-exposure.verbose-errors',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/data-exposure.verbose-errors.js'\nimport { getCopy } from '../../copy/index.js'\nimport { lineMatch, scanBashLines } from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-209\n */\n\nregistry.register({\n id: 'data-exposure.verbose-errors',\n name: 'Verbose error messages',\n description: 'Stack traces or internal paths in client responses',\n category: 'data-exposure',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'data-exposure.verbose-errors',\n category: 'data-exposure',\n severity: 'high',\n message: () => 'Shell xtrace is enabled and can expose commands, paths, and secrets in logs.',\n remediation: getCopy('remediation.data-exposure.verbose-errors'),\n }, (line, _content, index) => lineMatch(line, index, /^\\s*(?:set\\s+-x|set\\s+-o\\s+xtrace|BASH_XTRACEFD=)/)),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\b(?:ssn|social_security|date_of_birth|dob|passport|national_id)\\b/i,\n message: 'Potentially sensitive field name found — verify it is not exposed in API responses',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check if PII or sensitive fields are included in API responses. Look for response serialization that may include SSN, date of birth, passport numbers, or other personally identifiable information that should be filtered. In Python, flag Django REST Framework serializers or FastAPI response models that include PII fields without exclude/exclude_unset configuration.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'data-exposure.pii-in-responses',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/data-exposure.pii-in-responses.js'\n\nregistry.register({\n id: 'data-exposure.pii-in-responses',\n name: 'PII in API responses',\n description: 'PII or sensitive fields in API responses',\n category: 'data-exposure',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /SELECT\\s+\\*\\s+FROM\\b(?!.*\\b(?:LIMIT|select|Select)\\b)/i,\n message: 'SELECT * without field filtering — full rows may be exposed',\n severity: 'high',\n },\n {\n regex: /\\.(?:find|findAll)\\s*\\(\\s*\\)/i,\n message: 'ORM query without field selection — all columns returned',\n severity: 'high',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check if API list endpoints expose full database rows without field filtering. Look for SELECT * queries or ORM find() calls where the full result is returned to the client without field selection or response filtering. In Python, flag Django .all() querysets returned directly, SQLAlchemy .all() without .with_entities() field selection, or raw SQL SELECT * patterns.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'data-exposure.no-response-filtering',\n promptVersion: PROMPT_VERSION,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/data-exposure.no-response-filtering.js'\n\nregistry.register({\n id: 'data-exposure.no-response-filtering',\n name: 'No response filtering',\n description: 'Full DB rows returned on list endpoints',\n category: 'data-exposure',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","/**\n * @attribution CWE-200\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'data-exposure.html-form-pii-exposure'\nconst REMEDIATION = getCopy('remediation.data-exposure.html-form-pii-exposure')\n\nconst INPUT_PATTERN = /<input\\b[^>]*?>/gi\nconst AUTOCOMPLETE_PATTERN = /\\bautocomplete\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst TYPE_PATTERN = /\\btype\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst VALUE_PATTERN = /\\bvalue\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst NAME_PATTERN = /\\bname\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst PII_VALUE_PATTERNS = [\n /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/i,\n /\\b\\d{3}-\\d{2}-\\d{4}\\b/,\n /\\b(?:\\+?\\d[\\d\\s().-]{7,}\\d)\\b/,\n /\\b\\d{13,19}\\b/,\n]\nconst SENSITIVE_AUTOCOMPLETE = /^(?:on|name|email|tel|address|cc-number|cc-exp)$/i\nconst SENSITIVE_TYPES = /^(?:email|tel|password|number|search|text)$/i\nconst SENSITIVE_NAME = /(?:email|e-mail|phone|tel|mobile|address|ssn|social|credit|card|cc)/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nfunction pushFinding(\n findings: Finding[],\n filePath: string,\n content: string,\n index: number,\n matchText: string,\n): void {\n const { line, column } = lineAndColumn(content, index)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'data-exposure',\n severity: 'medium',\n message: getCopy('checks.html-form-pii-exposure.message', matchText),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath),\n remediation: REMEDIATION,\n })\n}\n\nfunction hasPiiValue(tagText: string): boolean {\n const value = tagText.match(VALUE_PATTERN)?.[1] ?? ''\n if (!value) return false\n return PII_VALUE_PATTERNS.some((pattern) => pattern.test(value))\n}\n\nfunction hasSensitiveAutocomplete(tagText: string): boolean {\n const autocomplete = tagText.match(AUTOCOMPLETE_PATTERN)?.[1] ?? ''\n return autocomplete !== '' && SENSITIVE_AUTOCOMPLETE.test(autocomplete.trim())\n}\n\nfunction hasSensitiveField(tagText: string): boolean {\n const type = tagText.match(TYPE_PATTERN)?.[1] ?? ''\n const name = tagText.match(NAME_PATTERN)?.[1] ?? ''\n return SENSITIVE_TYPES.test(type.trim()) || SENSITIVE_NAME.test(name)\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-form-pii-exposure.name'),\n description: getCopy('checks.html-form-pii-exposure.description'),\n category: 'data-exposure',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n for (const match of content.matchAll(INPUT_PATTERN)) {\n const tagText = match[0] ?? ''\n const index = match.index ?? 0\n const type = tagText.match(TYPE_PATTERN)?.[1] ?? ''\n const autocomplete = tagText.match(AUTOCOMPLETE_PATTERN)?.[1] ?? ''\n\n if ((type.trim().toLowerCase() === 'hidden' && hasPiiValue(tagText)) || hasSensitiveAutocomplete(tagText)) {\n pushFinding(findings, file.relativePath, content, index, tagText)\n continue\n }\n\n if (hasSensitiveField(tagText) && autocomplete.trim().toLowerCase() !== 'off') {\n pushFinding(findings, file.relativePath, content, index, tagText)\n }\n }\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\nconst CHECK_ID = 'security.xss-surface'\n\nconst QUERIES = {\n javascript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"document\")\n (#eq? @prop \"write\"))) @match\n\n(assignment_expression\n left: (member_expression\n property: (property_identifier) @prop\n (#eq? @prop \"innerHTML\"))\n right: (_) @value) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"res\")\n (#match? @prop \"^(send|write|json)$\"))\n arguments: (arguments . [\n (identifier) @arg\n (call_expression) @arg\n (member_expression) @arg\n (binary_expression) @arg\n (template_string) @arg\n ])) @match\n `,\n typescript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"document\")\n (#eq? @prop \"write\"))) @match\n\n(assignment_expression\n left: (member_expression\n property: (property_identifier) @prop\n (#eq? @prop \"innerHTML\"))\n right: (_) @value) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"res\")\n (#match? @prop \"^(send|write|json)$\"))\n arguments: (arguments . [\n (identifier) @arg\n (call_expression) @arg\n (member_expression) @arg\n (binary_expression) @arg\n (template_string) @arg\n ])) @match\n `,\n tsx: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"document\")\n (#eq? @prop \"write\"))) @match\n\n(assignment_expression\n left: (member_expression\n property: (property_identifier) @prop\n (#eq? @prop \"innerHTML\"))\n right: (_) @value) @match\n\n(jsx_attribute\n (property_identifier) @prop\n (#eq? @prop \"dangerouslySetInnerHTML\")) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"res\")\n (#match? @prop \"^(send|write|json)$\"))\n arguments: (arguments . [\n (identifier) @arg\n (call_expression) @arg\n (member_expression) @arg\n (binary_expression) @arg\n (template_string) @arg\n ])) @match\n `,\n dockerfile: '((identifier) @name) @match',\n php: `\n(echo_statement\n (subscript_expression\n (variable_name\n (name) @sg)\n (#match? @sg \"^_(GET|POST|REQUEST|COOKIE)$\"))) @match\n\n(echo_statement\n (binary_expression\n (subscript_expression\n (variable_name\n (name) @sg)\n (#match? @sg \"^_(GET|POST|REQUEST|COOKIE)$\")))) @match\n\n(echo_statement\n (variable_name\n (name) @vn\n (#match? @vn \"(html|Html|HTML|output|Output|message|Message|content|Content|buffer|Buffer|text|Text)\"))) @match\n\n(print_intrinsic\n (variable_name\n (name) @vn\n (#match? @vn \"(html|Html|HTML|output|Output|message|Message|content|Content|buffer|Buffer|text|Text)\"))) @match\n\n(function_call_expression\n (name) @func\n (#eq? @func \"printf\")\n arguments: (arguments\n (argument\n (subscript_expression\n (variable_name\n (name) @sg)\n (#match? @sg \"^_(GET|POST|REQUEST|COOKIE)$\"))))) @match\n `,\n python: `\n(call\n function: (attribute\n object: (identifier) @obj\n attribute: (identifier) @attr\n (#eq? @obj \"flask\")\n (#match? @attr \"^(render_template_string|Markup)$\"))\n arguments: (argument_list\n (_) @arg\n (#match? @arg \"request\"))) @match\n\n(call\n function: (attribute\n object: (identifier) @obj\n attribute: (identifier) @attr\n (#eq? @obj \"flask\")\n (#match? @attr \"^(render_template_string|Markup)$\"))\n arguments: (argument_list\n (string\n (interpolation)))) @match\n\n(call\n function: (identifier) @func\n (#eq? @func \"HttpResponse\")\n arguments: (argument_list\n (_) @arg\n (#match? @arg \"request\"))) @match\n\n(call\n function: (identifier) @func\n (#match? @func \"^(HTMLResponse|Response)$\")\n arguments: (argument_list\n (string\n (interpolation)))) @match\n `,\n go: `\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"fmt\")\n (#eq? @field \"Fprintf\"))\n arguments: (argument_list\n (_)\n [\n (identifier) @arg\n (call_expression) @arg\n (selector_expression) @arg\n (index_expression) @arg\n (binary_expression) @arg\n ])) @match\n\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"io\")\n (#eq? @field \"WriteString\"))\n arguments: (argument_list\n (_)\n [\n (identifier) @arg\n (call_expression) @arg\n (selector_expression) @arg\n (index_expression) @arg\n (binary_expression) @arg\n ])) @match\n\n(call_expression\n function: (selector_expression\n operand: (identifier) @recv\n field: (field_identifier) @field\n (#match? @recv \"^c$\")\n (#match? @field \"^(String|HTML)$\"))\n arguments: (argument_list\n (_)\n (_)\n [\n (identifier) @arg\n (call_expression) @arg\n (selector_expression) @arg\n (index_expression) @arg\n (binary_expression) @arg\n ])) @match\n\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"template\")\n (#eq? @field \"HTML\"))\n arguments: (argument_list\n (_)\n [\n (identifier) @arg\n (call_expression) @arg\n (selector_expression) @arg\n (index_expression) @arg\n (binary_expression) @arg\n ])) @match\n `,\n bash: `\n(command\n name: (command_name (word) @cmd)\n argument: [\n (string (simple_expansion) @arg)\n (simple_expansion) @arg\n ]\n (#match? @cmd \"^(echo|printf)$\")) @match\n `,\n java: `\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#match? @obj \"^(out|response|writer|pw|jspWriter)$\")\n (#match? @method \"^(print|println|printf|write|append)$\")\n arguments: (argument_list\n [\n (identifier) @arg\n (binary_expression) @arg\n (field_access) @arg\n ])) @match\n `,\n ruby: `\n(call\n method: (identifier) @method\n (#eq? @method \"raw\")\n arguments: (argument_list\n [\n (identifier) @arg\n (call) @arg\n (element_reference) @arg\n ])) @match\n\n(call\n receiver: (_) @recv\n method: (identifier) @method\n (#eq? @method \"html_safe\")) @match\n\n(call\n method: (identifier) @method\n (#eq? @method \"render\")\n arguments: (argument_list\n (pair\n key: (hash_key_symbol) @k (#match? @k \"^(html|inline)$\")\n value: (_) @arg))) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.xss-surface.name',\n descriptionKey: 'checks.xss-surface.description',\n category: 'security',\n severity: 'high',\n minTier: 'free',\n queries: QUERIES,\n messageKey: 'checks.xss-surface.message',\n degradedMessageKey: 'checks.xss-surface.degraded',\n remediationKey: 'remediation.security.xss-surface',\n })\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Surfaces OS command execution sinks (child_process, bare exec helpers, etc.).\n *\n * @attribution CWE-78\n */\n\nconst CHECK_ID = 'security.os-command-injection'\n\n/** Skip findings when the first argument is a static string or static template literal (reduces noise vs dynamic argv). */\nfunction isStaticShellLikeLiteral(text: string): boolean {\n const t = text.trim()\n if (t.length < 2) return false\n if ((t.startsWith('\"') && t.endsWith('\"')) || (t.startsWith(\"'\") && t.endsWith(\"'\"))) return true\n if (t.startsWith('`') && t.endsWith('`') && !/(?<!\\\\)\\${/.test(t)) return true\n return false\n}\n\nconst QUERIES = {\n javascript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"child_process\")\n (#match? @prop \"^(exec|execSync|spawn|execFile)$\"))\n arguments: (arguments . (_) @first .)) @match\n\n(call_expression\n function: (identifier) @func\n (#match? @func \"^(exec|execSync|spawn|execFile)$\")\n arguments: (arguments . (_) @first .)) @match\n `,\n typescript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"child_process\")\n (#match? @prop \"^(exec|execSync|spawn|execFile)$\"))\n arguments: (arguments . (_) @first .)) @match\n\n(call_expression\n function: (identifier) @func\n (#match? @func \"^(exec|execSync|spawn|execFile)$\")\n arguments: (arguments . (_) @first .)) @match\n `,\n tsx: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"child_process\")\n (#match? @prop \"^(exec|execSync|spawn|execFile)$\"))\n arguments: (arguments . (_) @first .)) @match\n\n(call_expression\n function: (identifier) @func\n (#match? @func \"^(exec|execSync|spawn|execFile)$\")\n arguments: (arguments . (_) @first .)) @match\n `,\n python: `\n(call\n function: (attribute\n object: (identifier) @mod\n attribute: (identifier) @func\n (#match? @mod \"^(os|subprocess)$\")\n (#match? @func \"^(system|popen|call|run|check_output|Popen)$\"))\n arguments: (argument_list . (_) @first .)) @match\n `,\n go: `\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"exec\")\n (#match? @field \"^(Command|CommandContext)$\"))\n arguments: (argument_list\n (_)\n (_)\n [\n (identifier) @first\n (call_expression) @first\n (selector_expression) @first\n (index_expression) @first\n (binary_expression) @first\n ])) @match\n `,\n ruby: `\n(call method: (identifier) @func\n (#match? @func \"^(system|exec|spawn|open)$\")\n arguments: (argument_list . (_) @first .)) @match\n\n(call\n receiver: (constant) @recv (#eq? @recv \"IO\")\n method: (identifier) @func\n (#eq? @func \"popen\")\n arguments: (argument_list . (_) @first .)) @match\n `,\n php: `\n(function_call_expression\n function: (name) @func\n (#match? @func \"^(system|exec|passthru|shell_exec|popen|proc_open)$\")\n arguments: (arguments . (_) @first .)) @match\n `,\n dockerfile: '((identifier) @name) @match',\n bash: `\n(command\n name: (command_name) @cmd\n (#match? @cmd \"^(eval|bash|sh)$\")) @match\n `,\n java: `\n(method_invocation\n object: (method_invocation\n object: (identifier) @rt\n name: (identifier) @gr\n (#eq? @rt \"Runtime\")\n (#eq? @gr \"getRuntime\"))\n name: (identifier) @method\n (#eq? @method \"exec\")\n arguments: (argument_list . (_) @first)) @match\n\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#eq? @obj \"ProcessBuilder\")\n (#eq? @method \"command\")\n arguments: (argument_list . (_) @first)) @match\n\n(object_creation_expression\n type: [\n (type_identifier) @t\n (scoped_type_identifier) @t\n ]\n (#match? @t \"ProcessBuilder$\")\n arguments: (argument_list . (_) @first)) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.os-command-injection.name',\n descriptionKey: 'checks.os-command-injection.description',\n category: 'security',\n severity: 'critical',\n minTier: 'free',\n queries: QUERIES,\n messageKey: 'checks.os-command-injection.message',\n degradedMessageKey: 'checks.os-command-injection.degraded',\n remediationKey: 'remediation.security.os-command-injection',\n matchFilter: (captures) => {\n const first = captures.first\n if (first === undefined) return true\n return !isStaticShellLikeLiteral(first)\n },\n })\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Detects shell evaluation commands that execute unquoted dynamic input.\n *\n * @attribution CWE-78\n */\n\nconst CHECK_ID = 'security.shell-arbitrary-evaluation'\n\nconst QUERY = `\n(command\n name: (command_name (word) @cmd)\n argument: (simple_expansion) @arg\n (#match? @cmd \"^(eval|source|\\\\.)$\")) @match\n\n(command\n name: (command_name (word) @cmd)\n argument: (concatenation (simple_expansion) @arg)\n (#match? @cmd \"^(eval|source|\\\\.)$\")) @match\n`\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.shell-arbitrary-evaluation.name',\n descriptionKey: 'checks.shell-arbitrary-evaluation.description',\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n queries: { bash: QUERY },\n messageKey: 'checks.shell-arbitrary-evaluation.message',\n degradedMessageKey: 'checks.shell-arbitrary-evaluation.degraded',\n remediationKey: 'remediation.security.shell-arbitrary-evaluation',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Detects destructive shell deletions that use unquoted variable paths.\n *\n * @attribution CWE-73\n */\n\nconst CHECK_ID = 'security.shell-unescaped-path-deletion'\n\nconst QUERY = `\n(command\n name: (command_name (word) @cmd)\n argument: (word) @flag\n argument: (simple_expansion) @path\n (#eq? @cmd \"rm\")\n (#match? @flag \"^-.*[rf].*$\")) @match\n\n(command\n name: (command_name (word) @cmd)\n argument: (word) @flag\n argument: (concatenation (simple_expansion) @path)\n (#eq? @cmd \"rm\")\n (#match? @flag \"^-.*[rf].*$\")) @match\n\n(command\n name: (command_name (word) @cmd)\n .\n argument: (simple_expansion) @path\n (#eq? @cmd \"rm\")) @match\n\n(command\n name: (command_name (word) @cmd)\n .\n argument: (concatenation (simple_expansion) @path)\n (#eq? @cmd \"rm\")) @match\n`\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.shell-unescaped-path-deletion.name',\n descriptionKey: 'checks.shell-unescaped-path-deletion.description',\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n queries: { bash: QUERY },\n messageKey: 'checks.shell-unescaped-path-deletion.message',\n degradedMessageKey: 'checks.shell-unescaped-path-deletion.degraded',\n remediationKey: 'remediation.security.shell-unescaped-path-deletion',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Surfaces dynamic PHP file inclusion (include/require with non-literal paths).\n *\n * @attribution CWE-98\n */\n\nconst CHECK_ID = 'security.file-inclusion'\n\nconst QUERIES = {\n php: `\n(include_expression\n (parenthesized_expression\n (subscript_expression))) @match\n\n(include_expression\n (parenthesized_expression\n (variable_name))) @match\n\n(require_expression\n (parenthesized_expression\n (subscript_expression))) @match\n\n(require_expression\n (parenthesized_expression\n (variable_name))) @match\n\n(include_once_expression\n (parenthesized_expression\n (subscript_expression))) @match\n\n(require_once_expression\n (parenthesized_expression\n (variable_name))) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.file-inclusion.name',\n descriptionKey: 'checks.file-inclusion.description',\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.file-inclusion.message',\n degradedMessageKey: 'checks.file-inclusion.degraded',\n remediationKey: 'remediation.security.file-inclusion',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Surfaces open redirect via user-controlled Location headers in PHP.\n *\n * @attribution CWE-601\n */\n\nconst CHECK_ID = 'security.open-redirect'\n\nconst QUERIES = {\n php: `\n(function_call_expression\n (name) @func\n (#eq? @func \"header\")\n (arguments\n (argument\n (binary_expression)))) @match\n `,\n python: `\n(call\n function: (attribute\n object: (identifier) @obj\n attribute: (identifier) @attr\n (#eq? @obj \"flask\")\n (#eq? @attr \"redirect\"))\n arguments: (argument_list\n (_) @url)) @match\n\n(call\n function: (identifier) @func\n (#eq? @func \"HttpResponseRedirect\")\n arguments: (argument_list\n (_) @url)) @match\n\n(call\n function: (identifier) @func\n (#eq? @func \"RedirectResponse\")\n arguments: (argument_list\n (_) @url)) @match\n `,\n javascript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"res\")\n (#eq? @prop \"redirect\"))\n arguments: (arguments\n [\n (identifier) @url\n (member_expression) @url\n (subscript_expression) @url\n (binary_expression) @url\n ])) @match\n `,\n typescript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"res\")\n (#eq? @prop \"redirect\"))\n arguments: (arguments\n [\n (identifier) @url\n (member_expression) @url\n (subscript_expression) @url\n (binary_expression) @url\n ])) @match\n `,\n tsx: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"res\")\n (#eq? @prop \"redirect\"))\n arguments: (arguments\n [\n (identifier) @url\n (member_expression) @url\n (subscript_expression) @url\n (binary_expression) @url\n ])) @match\n\n(call_expression\n function: (identifier) @func\n (#eq? @func \"redirect\")\n arguments: (arguments\n [\n (identifier) @url\n (member_expression) @url\n (subscript_expression) @url\n (binary_expression) @url\n ])) @match\n `,\n go: `\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"http\")\n (#eq? @field \"Redirect\"))\n arguments: (argument_list\n (_)\n (_)\n [\n (identifier) @url\n (call_expression) @url\n (selector_expression) @url\n (index_expression) @url\n (binary_expression) @url\n ])) @match\n\n(call_expression\n function: (selector_expression\n operand: (identifier) @recv\n field: (field_identifier) @field\n (#match? @recv \"^c$\")\n (#eq? @field \"Redirect\"))\n arguments: (argument_list\n (_)\n [\n (identifier) @url\n (call_expression) @url\n (selector_expression) @url\n (index_expression) @url\n (binary_expression) @url\n ])) @match\n `,\n java: `\n(method_invocation\n name: (identifier) @method\n (#eq? @method \"sendRedirect\")\n arguments: (argument_list\n [\n (identifier) @url\n (method_invocation) @url\n (field_access) @url\n (binary_expression) @url\n ])) @match\n\n(method_invocation\n name: (identifier) @method\n (#eq? @method \"setHeader\")\n arguments: (argument_list\n (string_literal (string_fragment) @h)\n (#eq? @h \"Location\")\n [\n (identifier) @url\n (method_invocation) @url\n (binary_expression) @url\n ])) @match\n `,\n ruby: `\n(call\n method: (identifier) @method\n (#eq? @method \"redirect_to\")\n arguments: (argument_list\n [\n (identifier) @url\n (call) @url\n (element_reference) @url\n ])) @match\n\n(call\n method: (identifier) @method\n (#eq? @method \"redirect_to\")\n arguments: (argument_list\n (_)*\n (pair\n key: [(hash_key_symbol) (simple_symbol)] @k\n (#eq? @k \"allow_other_host\")\n value: (true)))) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.open-redirect.name',\n descriptionKey: 'checks.open-redirect.description',\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.open-redirect.message',\n degradedMessageKey: 'checks.open-redirect.degraded',\n remediationKey: 'remediation.security.open-redirect',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Surfaces unrestricted file upload when destination paths use user-controlled names.\n *\n * @attribution CWE-434\n */\n\nconst CHECK_ID = 'security.unsafe-file-upload'\n\nconst QUERIES = {\n javascript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"fs\")\n (#match? @prop \"^(writeFile|writeFileSync|createWriteStream|appendFile)$\"))\n arguments: (arguments\n (member_expression\n object: (member_expression\n object: (identifier) @req\n property: (property_identifier) @fileProp\n (#eq? @req \"req\")\n (#eq? @fileProp \"file\"))\n property: (property_identifier) @nameProp\n (#match? @nameProp \"^(path|filename|originalname)$\")) @dest)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"path\")\n (#eq? @prop \"join\"))\n arguments: (arguments\n (member_expression\n object: (member_expression\n object: (identifier) @req\n property: (property_identifier) @fileProp\n (#eq? @req \"req\")\n (#eq? @fileProp \"file\"))\n property: (property_identifier) @nameProp\n (#match? @nameProp \"^(path|filename|originalname)$\")) @dest)) @match\n `,\n typescript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"fs\")\n (#match? @prop \"^(writeFile|writeFileSync|createWriteStream|appendFile)$\"))\n arguments: (arguments\n (member_expression\n object: (member_expression\n object: (identifier) @req\n property: (property_identifier) @fileProp\n (#eq? @req \"req\")\n (#eq? @fileProp \"file\"))\n property: (property_identifier) @nameProp\n (#match? @nameProp \"^(path|filename|originalname)$\")) @dest)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"path\")\n (#eq? @prop \"join\"))\n arguments: (arguments\n (member_expression\n object: (member_expression\n object: (identifier) @req\n property: (property_identifier) @fileProp\n (#eq? @req \"req\")\n (#eq? @fileProp \"file\"))\n property: (property_identifier) @nameProp\n (#match? @nameProp \"^(path|filename|originalname)$\")) @dest)) @match\n `,\n tsx: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"fs\")\n (#match? @prop \"^(writeFile|writeFileSync|createWriteStream|appendFile)$\"))\n arguments: (arguments\n (member_expression\n object: (member_expression\n object: (identifier) @req\n property: (property_identifier) @fileProp\n (#eq? @req \"req\")\n (#eq? @fileProp \"file\"))\n property: (property_identifier) @nameProp\n (#match? @nameProp \"^(path|filename|originalname)$\")) @dest)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"path\")\n (#eq? @prop \"join\"))\n arguments: (arguments\n (member_expression\n object: (member_expression\n object: (identifier) @req\n property: (property_identifier) @fileProp\n (#eq? @req \"req\")\n (#eq? @fileProp \"file\"))\n property: (property_identifier) @nameProp\n (#match? @nameProp \"^(path|filename|originalname)$\")) @dest)) @match\n `,\n php: `\n(function_call_expression\n (name) @func\n (#eq? @func \"move_uploaded_file\")\n arguments: (arguments\n (_) @dest)) @match\n `,\n python: `\n(call\n function: (identifier) @func\n (#eq? @func \"open\")\n arguments: (argument_list\n (_) @dest)) @match\n `,\n ruby: `\n(call\n receiver: (constant) @recv (#eq? @recv \"File\")\n method: (identifier) @method (#match? @method \"^(open|write)$\")\n arguments: (argument_list\n (string\n (interpolation)))) @match\n\n(call\n method: (identifier) @method (#eq? @method \"attach\")\n arguments: (argument_list\n (_) @dest)) @match\n `,\n go: `\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"os\")\n (#match? @field \"^(Create|OpenFile)$\"))\n arguments: (argument_list\n [\n (identifier) @dest\n (selector_expression) @dest\n (call_expression) @dest\n (binary_expression) @dest\n ])) @match\n `,\n java: `\n(object_creation_expression\n type: [\n (type_identifier) @t\n (scoped_type_identifier) @t\n ]\n (#match? @t \"File$\")\n arguments: (argument_list\n [\n (identifier) @dest\n (method_invocation) @dest\n (binary_expression) @dest\n ])) @match\n\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#eq? @obj \"Files\")\n (#match? @method \"^(copy|move|write)$\")\n arguments: (argument_list\n [\n (identifier) @dest\n (method_invocation) @dest\n (binary_expression) @dest\n ])) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.unsafe-file-upload.name',\n descriptionKey: 'checks.unsafe-file-upload.description',\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.unsafe-file-upload.message',\n degradedMessageKey: 'checks.unsafe-file-upload.degraded',\n remediationKey: 'remediation.security.unsafe-file-upload',\n matchFilter: (captures) => {\n const dest = captures.dest ?? ''\n return (\n dest.includes('_FILES') ||\n dest.includes('upload_file') ||\n dest.includes('.filename') ||\n dest.includes('Filename') ||\n dest.includes('FormFile') ||\n dest.includes('req.file') ||\n dest.includes('originalname') ||\n dest.includes('params[:file]') ||\n dest.includes('original_filename') ||\n dest.includes('getParameter') ||\n dest.includes('MultipartFile') ||\n dest.includes('getOriginalFilename') ||\n (dest.includes('+') && /\\b(name|filename|path|file)\\b/i.test(dest))\n )\n },\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Surfaces unsafe deserialization of untrusted data (pickle, yaml.load, marshal, node-serialize).\n *\n * @attribution CWE-502\n */\n\nconst CHECK_ID = 'security.unsafe-deserialization'\n\nconst QUERIES = {\n javascript: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @prop\n (#eq? @prop \"unserialize\"))\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (identifier) @func\n (#eq? @func \"unserialize\")\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"serialize\")\n (#eq? @prop \"unserialize\"))\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"yaml\")\n (#eq? @prop \"load\"))\n arguments: (arguments (_) @data)) @match\n `,\n typescript: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @prop\n (#eq? @prop \"unserialize\"))\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (identifier) @func\n (#eq? @func \"unserialize\")\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"serialize\")\n (#eq? @prop \"unserialize\"))\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"yaml\")\n (#eq? @prop \"load\"))\n arguments: (arguments (_) @data)) @match\n `,\n tsx: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @prop\n (#eq? @prop \"unserialize\"))\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (identifier) @func\n (#eq? @func \"unserialize\")\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"serialize\")\n (#eq? @prop \"unserialize\"))\n arguments: (arguments (_) @data)) @match\n\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"yaml\")\n (#eq? @prop \"load\"))\n arguments: (arguments (_) @data)) @match\n `,\n python: `\n(call\n function: (attribute\n object: (identifier) @obj\n attribute: (identifier) @attr\n (#eq? @obj \"pickle\")\n (#match? @attr \"^(load|loads)$\"))\n arguments: (argument_list\n (_) @data)) @match\n\n(call\n function: (attribute\n object: (identifier) @obj\n attribute: (identifier) @attr\n (#eq? @obj \"marshal\")\n (#match? @attr \"^(load|loads)$\"))\n arguments: (argument_list\n (_) @data)) @match\n\n(call\n function: (attribute\n object: (identifier) @obj\n attribute: (identifier) @attr\n (#eq? @obj \"yaml\")\n (#eq? @attr \"load\"))\n arguments: (argument_list\n (_) @data)) @match\n `,\n ruby: `\n(call\n receiver: (constant) @recv (#match? @recv \"^(Marshal|YAML|Oj)$\")\n method: (identifier) @method (#eq? @method \"load\")\n arguments: (argument_list\n (_) @data)) @match\n `,\n go: `\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"json\")\n (#eq? @field \"Unmarshal\"))\n arguments: (argument_list\n [\n (identifier) @data\n (call_expression) @data\n (selector_expression) @data\n (index_expression) @data\n (binary_expression) @data\n ]\n (_))) @match\n\n(call_expression\n function: (selector_expression\n field: (field_identifier) @field\n (#eq? @field \"Decode\"))\n arguments: (argument_list\n [\n (identifier) @data\n (call_expression) @data\n (selector_expression) @data\n (index_expression) @data\n (binary_expression) @data\n ])) @match\n\n(call_expression\n function: (selector_expression\n operand: (identifier) @obj\n field: (field_identifier) @field\n (#eq? @obj \"xml\")\n (#eq? @field \"Unmarshal\"))\n arguments: (argument_list\n [\n (identifier) @data\n (call_expression) @data\n (selector_expression) @data\n (index_expression) @data\n (binary_expression) @data\n ]\n (_))) @match\n `,\n java: `\n(method_invocation\n name: (identifier) @method\n (#eq? @method \"readObject\")\n arguments: (argument_list\n (_) @data)) @match\n\n(object_creation_expression\n type: (type_identifier) @t\n (#eq? @t \"ObjectInputStream\")\n arguments: (argument_list\n (_) @data)) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.unsafe-deserialization.name',\n descriptionKey: 'checks.unsafe-deserialization.description',\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.unsafe-deserialization.message',\n degradedMessageKey: 'checks.unsafe-deserialization.degraded',\n remediationKey: 'remediation.security.unsafe-deserialization',\n matchFilter: (captures) => {\n const data = captures.data?.trim() ?? ''\n if (/^(b)?[\"']/.test(data)) return false\n if (/^\\[\\]byte\\s*\\(\\s*[\"']/.test(data)) return false\n return true\n },\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { getCopy } from '../../copy/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.hardcoded-passwords'\n\nconst PASSWORD_NAME_REGEX = /^(\\$)?(password|pwd|passwd|secret|pass)$/i\n\nconst REMEDIATION = getCopy('remediation.security.hardcoded-passwords')\n\nconst HTML_CSS_PASSWORD_PATTERNS = [\n /(?:<!--|\\/\\*)[^]*?(\\w*(?:password|pwd|passwd|secret|pass)\\w*)\\s*[:=]\\s*['\"]([^'\"]{1,64})['\"]/i,\n /<input[^>]*type\\s*=\\s*[\"']password[\"'][^>]*value\\s*=\\s*[\"']([^\"']{1,64})[\"']/i,\n]\n\nconst QUERIES = {\n javascript: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n right: (string) @value) @match\n `,\n typescript: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n right: (string) @value) @match\n `,\n tsx: `\n(lexical_declaration\n (variable_declarator\n name: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n value: (string) @value)) @match\n\n(assignment_expression\n left: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n right: (string) @value) @match\n `,\n python: `\n(assignment\n left: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n right: (string) @value) @match\n `,\n ruby: `\n(assignment left: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n right: (string) @value) @match\n `,\n go: `\n(short_var_declaration\n left: (expression_list (identifier) @name)\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n right: (expression_list (interpreted_string_literal) @value)) @match\n `,\n java: `\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name\n (#match? @name \"^(password|pwd|passwd|secret|pass)$\")\n value: (string_literal) @value)) @match\n `,\n php: `\n(assignment_expression\n left: (_) @name\n right: (_) @value) @match\n `,\n bash: `\n(variable_assignment\n name: (variable_name) @name\n value: (string) @value) @match\n `,\n dockerfile: '((identifier) @name) @match',\n}\n\nconst regexCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.hardcoded-passwords.name'),\n description: getCopy('checks.hardcoded-passwords.description'),\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n for (const file of ctx.files) {\n if (file.language !== 'html' && file.language !== 'css') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n const lines = content.split('\\n')\n\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\n const line = lines[lineNum]!\n for (let patternIdx = 0; patternIdx < HTML_CSS_PASSWORD_PATTERNS.length; patternIdx++) {\n const pattern = HTML_CSS_PASSWORD_PATTERNS[patternIdx]!\n const regex = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : pattern.flags + 'g')\n const matches = Array.from(line.matchAll(regex))\n for (let matchIdx = 0; matchIdx < matches.length; matchIdx++) {\n const match = matches[matchIdx]!\n const name = match[1] ?? 'password'\n const value = match[2] ?? match[1] ?? ''\n if (match[2] === undefined && line.toLowerCase().includes('type=\"password\"')) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:${matchIdx}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'critical',\n message: getCopy('checks.hardcoded-passwords.message', 'password'),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: mechanicalConfidence('regex', file.relativePath, value || line),\n remediation: REMEDIATION,\n })\n continue\n }\n if (!PASSWORD_NAME_REGEX.test(name)) continue\n if ((value ?? '').trim().length === 0) continue\n\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(match.index ?? 0) + 1}:${matchIdx}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'critical',\n message: getCopy('checks.hardcoded-passwords.message', name),\n file: file.relativePath,\n line: lineNum + 1,\n column: (match.index ?? 0) + 1,\n confidence: mechanicalConfidence('regex', file.relativePath, value),\n remediation: REMEDIATION,\n })\n }\n }\n }\n }\n return findings\n },\n}\n\nconst treeSitterCheck = createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.hardcoded-passwords.name',\n descriptionKey: 'checks.hardcoded-passwords.description',\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.hardcoded-passwords.message',\n degradedMessageKey: 'checks.hardcoded-passwords.degraded',\n remediationKey: 'remediation.security.hardcoded-passwords',\n matchFilter: (captures) => {\n let name = captures.name ?? ''\n const value = captures.value ?? ''\n if (name.startsWith('$')) name = name.slice(1)\n if (!PASSWORD_NAME_REGEX.test(name)) return false\n const trimmedValue = value.trim()\n if (!/^['\"`].*['\"`]$/.test(trimmedValue)) return false\n const cleanValue = trimmedValue.replace(/^['\"`]|['\"`]$/g, '')\n return cleanValue.length > 0\n },\n messageFactory: (captures) => {\n let name = captures.name ?? ''\n if (name.startsWith('$')) name = name.slice(1)\n return getCopy('checks.hardcoded-passwords.message', name)\n },\n })\n\nregistry.register({\n ...treeSitterCheck,\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [regexFindings, treeSitterFindings] = await Promise.all([\n regexCheck.run(ctx),\n treeSitterCheck.run(ctx),\n ])\n return [...regexFindings, ...treeSitterFindings]\n },\n})\n","import type { SourceFile } from '../../types/source-file.js'\n\nexport interface StaticHostSecurityState {\n hasAnyHostConfig: boolean\n hasCsp: boolean\n hasReferrerPolicy: boolean\n hasXContentTypeOptions: boolean\n hasFrameProtection: boolean\n hasPermissionsPolicy: boolean\n hostConfigFiles: string[]\n}\n\nconst HOST_CONFIG_NAMES = new Set([\n '_headers',\n 'vercel.json',\n 'netlify.toml',\n 'firebase.json',\n 'cloudflare-pages.json',\n 'wrangler.toml',\n])\n\nconst WEAK_CSP_PATTERNS = [\n /\\bdefault-src\\s+\\*/i,\n /\\bscript-src\\b[^;]*'unsafe-inline'/i,\n /\\bscript-src\\b[^;]*'unsafe-eval'/i,\n /\\bstyle-src\\b[^;]*'unsafe-inline'/i,\n]\n\nfunction isHostConfigPath(relativePath: string): boolean {\n const normalized = relativePath.replace(/\\\\/g, '/')\n const fileName = normalized.slice(normalized.lastIndexOf('/') + 1)\n return HOST_CONFIG_NAMES.has(fileName)\n}\n\nfunction isWeakCsp(value: string): boolean {\n return WEAK_CSP_PATTERNS.some((pattern) => pattern.test(value))\n}\n\nfunction scanHeaderText(\n state: StaticHostSecurityState,\n headerName: string,\n value: string,\n): void {\n const lower = headerName.toLowerCase()\n const normalized = value.trim().replace(/^[\"']|[\"']$/g, '')\n\n if (lower === 'content-security-policy') {\n if (normalized && !isWeakCsp(normalized)) state.hasCsp = true\n if (/frame-ancestors\\b/i.test(normalized) && !/\\bframe-ancestors\\s+\\*/i.test(normalized)) {\n state.hasFrameProtection = true\n }\n return\n }\n\n if (lower === 'referrer-policy' && normalized) {\n state.hasReferrerPolicy = true\n return\n }\n\n if (lower === 'x-content-type-options' && /nosniff/i.test(normalized)) {\n state.hasXContentTypeOptions = true\n return\n }\n\n if (lower === 'x-frame-options' && /^(deny|sameorigin)$/i.test(normalized)) {\n state.hasFrameProtection = true\n return\n }\n\n if (lower === 'permissions-policy' && normalized) {\n state.hasPermissionsPolicy = true\n }\n}\n\nfunction scanHeaderLines(state: StaticHostSecurityState, content: string): void {\n for (const line of content.split('\\n')) {\n const headerMatch = line.match(/^\\s*([^:#=]+)\\s*[:=]\\s*(.+?)\\s*$/)\n if (!headerMatch) continue\n scanHeaderText(state, headerMatch[1]!, headerMatch[2]!)\n }\n}\n\nfunction scanJsonForHeaders(state: StaticHostSecurityState, value: unknown, depth = 0): void {\n if (depth > 100) return // Prevent stack overflow\n if (!value || typeof value !== 'object') return\n\n if (Array.isArray(value)) {\n for (const item of value) scanJsonForHeaders(state, item, depth + 1)\n return\n }\n\n const record = value as Record<string, unknown>\n const key = typeof record.key === 'string' ? record.key : undefined\n const headerValue = typeof record.value === 'string' ? record.value : undefined\n if (key && headerValue) scanHeaderText(state, key, headerValue)\n\n for (const nested of Object.values(record)) {\n scanJsonForHeaders(state, nested, depth + 1)\n }\n}\n\nfunction scanTomlForHeaders(state: StaticHostSecurityState, content: string): void {\n for (const line of content.split('\\n')) {\n const match = line.match(/^\\s*([A-Za-z0-9-]+)\\s*=\\s*[\"']([^\"']+)[\"']\\s*$/)\n if (!match) continue\n scanHeaderText(state, match[1]!, match[2]!)\n }\n}\n\nexport async function scanStaticHostSecurity(files: SourceFile[]): Promise<StaticHostSecurityState> {\n const state: StaticHostSecurityState = {\n hasAnyHostConfig: false,\n hasCsp: false,\n hasReferrerPolicy: false,\n hasXContentTypeOptions: false,\n hasFrameProtection: false,\n hasPermissionsPolicy: false,\n hostConfigFiles: [],\n }\n\n for (const file of files) {\n if (!isHostConfigPath(file.relativePath)) continue\n state.hasAnyHostConfig = true\n state.hostConfigFiles.push(file.relativePath)\n\n const content = await file.content()\n\n if (file.relativePath.endsWith('.json')) {\n try {\n scanJsonForHeaders(state, JSON.parse(content))\n } catch {\n scanHeaderLines(state, content)\n }\n continue\n }\n\n if (file.relativePath.endsWith('.toml')) {\n scanTomlForHeaders(state, content)\n continue\n }\n\n scanHeaderLines(state, content)\n }\n\n return state\n}\n\nexport function hasHostConfig(file: SourceFile): boolean {\n return isHostConfigPath(file.relativePath)\n}\n","/**\n * @attribution AST helper utilities for HTML and CSS static analysis.\n * Extracts attributes, inline content, CSS URLs, and CDN metadata while\n * preserving original source locations.\n */\n\nexport interface SourceLocation {\n line: number\n column: number\n}\n\nexport interface HtmlAttribute {\n name: string\n value: string\n raw: string\n index: number\n}\n\nexport interface InlineBlock {\n tagName: 'script' | 'style'\n content: string\n attributes: HtmlAttribute[]\n index: number\n}\n\nexport interface CssUrlRef {\n url: string\n property?: string\n index: number\n}\n\nexport function lineAndColumn(content: string, index: number): SourceLocation {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\n/**\n * Extract all attributes from an HTML tag string.\n * Handles mixed-case, unquoted, and multi-line attributes.\n */\nexport function extractHtmlAttributes(tagOpen: string): HtmlAttribute[] {\n const attrs: HtmlAttribute[] = []\n const pattern = /\\b([A-Za-z][A-Za-z0-9-]*)\\s*(?:=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?/g\n let m: RegExpExecArray | null\n while ((m = pattern.exec(tagOpen)) !== null) {\n const name = m[1]!.toLowerCase()\n const value = m[2] ?? m[3] ?? m[4] ?? ''\n attrs.push({\n name,\n value,\n raw: m[0]!,\n index: m.index,\n })\n }\n return attrs\n}\n\n/**\n * Find the value of a specific attribute by name (case-insensitive).\n */\nexport function getAttributeValue(attrs: HtmlAttribute[], name: string): string | undefined {\n return attrs.find((a) => a.name === name.toLowerCase())?.value\n}\n\n/**\n * Extract inline <script> and <style> blocks from HTML content.\n * Skips script blocks with type=\"application/json\" or type=\"importmap\".\n */\nexport function extractInlineBlocks(content: string): InlineBlock[] {\n const blocks: InlineBlock[] = []\n const tagPattern = /<(script|style)\\b([^>]*)>([\\s\\S]*?)<\\/\\1>/gi\n let m: RegExpExecArray | null\n while ((m = tagPattern.exec(content)) !== null) {\n const tagName = m[1]!.toLowerCase() as 'script' | 'style'\n const attributes = extractHtmlAttributes(m[2] ?? '')\n const type = getAttributeValue(attributes, 'type')\n if (tagName === 'script' && (type === 'application/json' || type === 'importmap')) {\n continue\n }\n blocks.push({\n tagName,\n content: m[3] ?? '',\n attributes,\n index: m.index,\n })\n }\n return blocks\n}\n\n/**\n * Extract CSS url(...) references from a CSS string.\n * Optionally filter by property name (e.g. 'background-image').\n */\nexport function extractCssUrls(cssContent: string, propertyFilter?: string): CssUrlRef[] {\n const refs: CssUrlRef[] = []\n const urlPattern = /url\\(\\s*([\"']?)([^\"')\\s]+)\\1\\s*\\)/gi\n const declarationPattern = /([A-Za-z-]+)\\s*:\\s*([^;]+);/gi\n\n let decl: RegExpExecArray | null\n while ((decl = declarationPattern.exec(cssContent)) !== null) {\n const prop = decl[1]!\n const value = decl[2]!\n if (propertyFilter && prop.toLowerCase() !== propertyFilter.toLowerCase()) {\n continue\n }\n let urlMatch: RegExpExecArray | null\n while ((urlMatch = urlPattern.exec(value)) !== null) {\n refs.push({\n url: urlMatch[2]!,\n property: prop,\n index: decl.index + urlMatch.index,\n })\n }\n }\n\n // Also match @import url(...)\n const importPattern = /@import\\s+(?:url\\(\\s*[\"']?([^\"')\\s]+)[\"']?\\s*\\)|[\"']([^\"';\\s]+)[\"']);/gi\n let imp: RegExpExecArray | null\n while ((imp = importPattern.exec(cssContent)) !== null) {\n refs.push({\n url: imp[1] ?? imp[2] ?? '',\n property: '@import',\n index: imp.index,\n })\n }\n\n return refs\n}\n\n/**\n * Extract @font-face declarations from CSS content.\n */\nexport interface FontFaceDeclaration {\n srcUrl: string | null\n family: string | null\n index: number\n}\n\nexport function extractFontFaces(cssContent: string): FontFaceDeclaration[] {\n const faces: FontFaceDeclaration[] = []\n const facePattern = /@font-face\\s*\\{([^}]*)\\}/gi\n let m: RegExpExecArray | null\n while ((m = facePattern.exec(cssContent)) !== null) {\n const block = m[1] ?? ''\n const srcMatch = block.match(/src\\s*:\\s*[^;]*/i)\n const familyMatch = block.match(/font-family\\s*:\\s*[\"']?([^\"';\\s]+)[\"']?/i)\n let srcUrl: string | null = null\n if (srcMatch) {\n const urlMatch = srcMatch[0].match(/url\\(\\s*[\"']?([^\"')\\s]+)[\"']?\\s*\\)/)\n srcUrl = urlMatch?.[1] ?? null\n }\n faces.push({\n srcUrl,\n family: familyMatch?.[1] ?? null,\n index: m.index,\n })\n }\n return faces\n}\n\n/**\n * Extract style=\"...\" attributes from HTML content.\n */\nexport function extractInlineStyles(htmlContent: string): Array<{ value: string; index: number }> {\n const results: Array<{ value: string; index: number }> = []\n const pattern = /\\bstyle\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/gi\n let m: RegExpExecArray | null\n while ((m = pattern.exec(htmlContent)) !== null) {\n results.push({ value: m[1] ?? m[2] ?? '', index: m.index })\n }\n return results\n}\n\n/**\n * Extract <script src=\"...\"> and <link rel=\"stylesheet\" href=\"...\"> CDN URLs.\n */\nexport function extractExternalAssetUrls(content: string): Array<{\n tag: string\n url: string\n attributes: HtmlAttribute[]\n index: number\n}> {\n const results: Array<{ tag: string; url: string; attributes: HtmlAttribute[]; index: number }> = []\n const tagPattern = /<(script|link)\\b([^>]*)>/gi\n let m: RegExpExecArray | null\n while ((m = tagPattern.exec(content)) !== null) {\n const tag = m[1]!\n const attrs = extractHtmlAttributes(m[2] ?? '')\n const url = getAttributeValue(attrs, tag === 'script' ? 'src' : 'href') ?? ''\n if (url) {\n results.push({ tag, url, attributes: attrs, index: m.index })\n }\n }\n return results\n}\n\n/**\n * Parse <script type=\"importmap\"> JSON content and extract module → URL mappings.\n */\nexport function parseImportMap(content: string): Array<{\n specifier: string\n url: string\n index: number\n}> {\n const results: Array<{ specifier: string; url: string; index: number }> = []\n const pattern = /<script\\b[^>]*type\\s*=\\s*[\"']importmap[\"'][^>]*>([\\s\\S]*?)<\\/script>/gi\n let m: RegExpExecArray | null\n while ((m = pattern.exec(content)) !== null) {\n try {\n const json = JSON.parse(m[1]!)\n const imports = json.imports as Record<string, string> | undefined\n if (imports) {\n for (const [specifier, url] of Object.entries(imports)) {\n if (typeof url === 'string') {\n results.push({ specifier, url, index: m.index })\n }\n }\n }\n } catch {\n // Ignore malformed importmap JSON\n }\n }\n return results\n}\n\n/**\n * Extract HTML comment contents.\n */\nexport function extractHtmlComments(content: string): Array<{ text: string; index: number }> {\n const results: Array<{ text: string; index: number }> = []\n const pattern = /<!--([\\s\\S]*?)-->/g\n let m: RegExpExecArray | null\n while ((m = pattern.exec(content)) !== null) {\n results.push({ text: m[1]!, index: m.index })\n }\n return results\n}\n\n/**\n * Extract CSS comment contents.\n */\nexport function extractCssComments(content: string): Array<{ text: string; index: number }> {\n const results: Array<{ text: string; index: number }> = []\n const pattern = /\\/\\*([\\s\\S]*?)\\*\\//g\n let m: RegExpExecArray | null\n while ((m = pattern.exec(content)) !== null) {\n results.push({ text: m[1]!, index: m.index })\n }\n return results\n}\n\n/**\n * Extract <meta> tags with a specific http-equiv value.\n */\nexport function extractMetaTags(\n content: string,\n httpEquiv?: string,\n): Array<{ content: string; index: number }> {\n const results: Array<{ content: string; index: number }> = []\n const pattern = /<meta\\b([^>]*)>/gi\n let m: RegExpExecArray | null\n while ((m = pattern.exec(content)) !== null) {\n const attrs = extractHtmlAttributes(m[1] ?? '')\n if (httpEquiv) {\n const he = getAttributeValue(attrs, 'http-equiv')\n if (he?.toLowerCase() !== httpEquiv.toLowerCase()) continue\n }\n const contentAttr = getAttributeValue(attrs, 'content')\n if (contentAttr) {\n results.push({ content: contentAttr, index: m.index })\n }\n }\n return results\n}\n\n/**\n * Extract <base> tag attributes.\n */\nexport function extractBaseTag(content: string): { href?: string; target?: string; index: number } | null {\n const pattern = /<base\\b([^>]*)>/gi\n const m = pattern.exec(content)\n if (!m) return null\n const attrs = extractHtmlAttributes(m[1] ?? '')\n return {\n href: getAttributeValue(attrs, 'href'),\n target: getAttributeValue(attrs, 'target'),\n index: m.index,\n }\n}\n\n/**\n * Extract <a> and <form> tags with target=\"_blank\".\n */\nexport function extractOpenBlankTargets(content: string): Array<{\n tag: 'a' | 'form'\n text: string\n hasRel: boolean\n index: number\n}> {\n const results: Array<{ tag: 'a' | 'form'; text: string; hasRel: boolean; index: number }> = []\n const pattern = /<(a|form)\\b([^>]*)>/gi\n let m: RegExpExecArray | null\n while ((m = pattern.exec(content)) !== null) {\n const attrs = extractHtmlAttributes(m[2] ?? '')\n const target = getAttributeValue(attrs, 'target')\n if (target === '_blank') {\n const rel = getAttributeValue(attrs, 'rel') ?? ''\n results.push({\n tag: m[1] as 'a' | 'form',\n text: m[0]!,\n hasRel: /noopener|noreferrer/.test(rel),\n index: m.index,\n })\n }\n }\n return results\n}\n\n/**\n * Check if content looks like a full HTML document (has doctype or <html>).\n */\nexport function isFullHtmlDocument(content: string): boolean {\n return /<!doctype\\s+html|<html\\b/i.test(content)\n}\n\n/**\n * Check if content contains a <head> element.\n */\nexport function hasHeadElement(content: string): boolean {\n return /<head\\b/i.test(content)\n}\n","/**\n * @attribution CWE-693\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { scanStaticHostSecurity } from '../helpers/html-static-host.js'\nimport { lineAndColumn, isFullHtmlDocument, hasHeadElement } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-missing-csp'\nconst REMEDIATION = getCopy('remediation.security.html-missing-csp')\n\nconst META_CSP_PATTERN = /<meta\\b[^>]*\\bhttp-equiv\\s*=\\s*[\"']content-security-policy[\"'][^>]*>/gi\nconst CSP_CONTENT_PATTERN = /\\bcontent\\s*=\\s*([\"'])([\\s\\S]*?)\\1/i\n\nfunction firstHtmlAnchor(files: ScanContext['files']): string | undefined {\n return files\n .filter((file) => file.language === 'html' && !isMechanicalCheckExcludedPath(file.relativePath))\n .map((file) => file.relativePath)\n .sort()[0]\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-missing-csp.name'),\n description: getCopy('checks.html-missing-csp.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n const hostSecurity = await scanStaticHostSecurity(ctx.files)\n\n if (hostSecurity.hasAnyHostConfig) {\n return findings\n }\n\n const anchor = firstHtmlAnchor(ctx.files)\n if (!anchor) return findings\n\n let sawFullHtmlDoc = false\n let sawValidMetaCsp = false\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n if (!isFullHtmlDocument(content) || !hasHeadElement(content)) continue\n sawFullHtmlDoc = true\n\n for (const match of content.matchAll(META_CSP_PATTERN)) {\n const meta = match[0] ?? ''\n const contentMatch = meta.match(CSP_CONTENT_PATTERN)\n const cspValue = contentMatch?.[2] ?? ''\n if (!cspValue) continue\n if (/default-src\\s+\\*|unsafe-inline|unsafe-eval/i.test(cspValue)) {\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-missing-csp.message', 'weak Content Security Policy'),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n } else {\n sawValidMetaCsp = true\n }\n }\n }\n\n if (findings.length === 0 && sawFullHtmlDoc && !sawValidMetaCsp) {\n findings.push({\n id: `${CHECK_ID}:${anchor}:1:1`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-missing-csp.message', 'no Content Security Policy found'),\n file: anchor,\n line: 1,\n column: 1,\n confidence: mechanicalConfidence('regex', anchor),\n remediation: REMEDIATION,\n })\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-693\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { scanStaticHostSecurity } from '../helpers/html-static-host.js'\n\nconst CHECK_ID = 'security.html-static-host-headers'\nconst REMEDIATION = getCopy('remediation.security.html-static-host-headers')\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-static-host-headers.name'),\n description: getCopy('checks.html-static-host-headers.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const state = await scanStaticHostSecurity(ctx.files)\n if (!state.hasAnyHostConfig) return []\n\n const missing: string[] = []\n if (!state.hasCsp) missing.push('Content-Security-Policy')\n if (!state.hasReferrerPolicy) missing.push('Referrer-Policy')\n if (!state.hasXContentTypeOptions) missing.push('X-Content-Type-Options')\n if (!state.hasFrameProtection) missing.push('frame protection')\n if (!state.hasPermissionsPolicy) missing.push('Permissions-Policy')\n\n if (missing.length === 0) return []\n\n const anchor =\n state.hostConfigFiles\n .filter((path) => !isMechanicalCheckExcludedPath(path))\n .sort()[0] ??\n ctx.files\n .filter((file) => file.language === 'html' && !isMechanicalCheckExcludedPath(file.relativePath))\n .map((file) => file.relativePath)\n .sort()[0]\n\n if (!anchor) return []\n\n return [\n {\n id: `${CHECK_ID}:${anchor}:1:1`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-static-host-headers.message', missing.join(', ')),\n file: anchor,\n line: 1,\n column: 1,\n confidence: mechanicalConfidence('regex', anchor),\n remediation: REMEDIATION,\n },\n ]\n },\n})\n","/**\n * @attribution CWE-79\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.html-inline-unsafe-script'\nconst REMEDIATION = getCopy('remediation.security.html-inline-unsafe-script')\n\nconst SCRIPT_BLOCK_PATTERN = /<script\\b([^>]*)>([\\s\\S]*?)<\\/script>/gi\nconst EVENT_HANDLER_PATTERN = /\\son[a-z]+\\s*=\\s*[\"']([^\"']+)[\"']/gi\nconst DANGEROUS_PATTERNS = [\n { regex: /\\bdocument\\.write(?:ln)?\\s*\\(/i, label: 'document.write' },\n { regex: /\\b(?:innerHTML|outerHTML)\\s*=/i, label: 'innerHTML assignment' },\n { regex: /\\beval\\s*\\(/i, label: 'eval' },\n { regex: /\\bnew\\s+Function\\s*\\(/i, label: 'new Function' },\n { regex: /\\bset(?:Timeout|Interval)\\s*\\(\\s*[\"'`]/i, label: 'string timer' },\n { regex: /\\blocalStorage\\.setItem\\s*\\(/i, label: 'localStorage' },\n { regex: /\\blocation\\.(?:hash|search|href)\\b|\\bdocument\\.referrer\\b/i, label: 'window input' },\n]\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nfunction findScriptMatches(content: string): Array<{ index: number; text: string }> {\n const matches: Array<{ index: number; text: string }> = []\n for (const match of content.matchAll(SCRIPT_BLOCK_PATTERN)) {\n const attrs = match[1] ?? ''\n if (/\\bsrc\\s*=/i.test(attrs)) continue\n const body = match[2] ?? ''\n const bodyIndex = (match.index ?? 0) + (match[0]?.indexOf(body) ?? 0)\n for (const pattern of DANGEROUS_PATTERNS) {\n const danger = body.match(pattern.regex)\n if (!danger) continue\n matches.push({\n index: bodyIndex + (danger.index ?? 0),\n text: danger[0] ?? pattern.label,\n })\n break\n }\n }\n return matches\n}\n\nfunction findEventHandlerMatches(content: string): Array<{ index: number; text: string }> {\n const results: Array<{ index: number; text: string }> = []\n for (const match of content.matchAll(EVENT_HANDLER_PATTERN)) {\n const handler = match[1] ?? ''\n for (const pattern of DANGEROUS_PATTERNS) {\n const danger = handler.match(pattern.regex)\n if (!danger) continue\n results.push({\n index: (match.index ?? 0) + (danger.index ?? 0),\n text: danger[0] ?? pattern.label,\n })\n break\n }\n }\n return results\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-inline-unsafe-script.name'),\n description: getCopy('checks.html-inline-unsafe-script.description'),\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of findScriptMatches(content)) {\n const { line, column } = lineAndColumn(content, match.index)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.html-inline-unsafe-script.message', match.text),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n\n for (const match of findEventHandlerMatches(content)) {\n const { line, column } = lineAndColumn(content, match.index)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}:event`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.html-inline-unsafe-script.message', match.text),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-1021\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn, extractOpenBlankTargets } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-referrer-leak'\nconst REMEDIATION = getCopy('remediation.security.html-referrer-leak')\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-referrer-leak.name'),\n description: getCopy('checks.html-referrer-leak.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n for (const target of extractOpenBlankTargets(content)) {\n if (target.hasRel) continue\n\n const { line, column } = lineAndColumn(content, target.index)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-referrer-leak.message', target.text),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-798\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-css-comments-secrets'\nconst REMEDIATION = getCopy('remediation.security.html-css-comments-secrets')\n\nconst SECRET_MARKER = /(?:api[_-]?key|firebase[_-]?config|google[_-]?api|token|secret|password|private[_-]?key|access[_-]?key)/i\nconst SECRET_VALUE = /(?:[:=]\\s*|[\"'`])([A-Za-z0-9+/=_-]{8,}|sk_[A-Za-z0-9/+=_-]{8,})/i\nconst HTML_COMMENT = /<!--([\\s\\S]*?)-->/g\nconst CSS_COMMENT = /\\/\\*([\\s\\S]*?)\\*\\//g\nconst JSON_SCRIPT = /<script\\b[^>]*type\\s*=\\s*[\"']application\\/json[\"'][^>]*>([\\s\\S]*?)<\\/script>/gi\n\nfunction scanPattern(\n content: string,\n filePath: string,\n checkPrefix: string,\n pattern: RegExp,\n messageText: string,\n findings: Finding[],\n): void {\n for (const match of content.matchAll(pattern)) {\n const text = match[1] ?? match[0] ?? ''\n if (!SECRET_MARKER.test(text)) continue\n const valueMatch = text.match(SECRET_VALUE)\n const value = valueMatch?.[1] ?? text\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}:${checkPrefix}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'critical',\n message: getCopy('checks.html-css-comments-secrets.message', messageText),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath, value),\n remediation: REMEDIATION,\n })\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-css-comments-secrets.name'),\n description: getCopy('checks.html-css-comments-secrets.description'),\n category: 'security',\n severity: 'critical',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n for (const file of ctx.files) {\n if (file.language !== 'html' && file.language !== 'css') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n scanPattern(content, file.relativePath, 'html-comment', HTML_COMMENT, 'HTML comment', findings)\n scanPattern(content, file.relativePath, 'css-comment', CSS_COMMENT, 'CSS comment', findings)\n scanPattern(content, file.relativePath, 'json-script', JSON_SCRIPT, 'application/json script', findings)\n }\n return findings\n },\n})\n","/**\n * @attribution CWE-319\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.css-insecure-import'\nconst REMEDIATION = getCopy('remediation.security.css-insecure-import')\n\nconst HTTP_URL_PATTERN = /^http:\\/\\//i\nconst IMPORT_PATTERN = /@import\\s+(?:url\\(\\s*)?([\"']?)([^\"')\\s;]+)\\1\\s*\\)?\\s*;/gi\nconst URL_PROPERTY_PATTERN = /url\\(\\s*([\"']?)(https?:\\/\\/[^\"')]+)\\1\\s*\\)/gi\n\nfunction lineText(content: string, index: number): string {\n const start = content.lastIndexOf('\\n', index - 1) + 1\n const end = content.indexOf('\\n', index)\n return content.slice(start, end === -1 ? content.length : end)\n}\n\nfunction pushFinding(\n findings: Finding[],\n filePath: string,\n content: string,\n matchText: string,\n index: number,\n): void {\n const { line, column } = lineAndColumn(content, index)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.css-insecure-import.message', matchText),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath, matchText),\n remediation: REMEDIATION,\n })\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.css-insecure-import.name'),\n description: getCopy('checks.css-insecure-import.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n for (const file of ctx.files) {\n if (file.language !== 'css') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(IMPORT_PATTERN)) {\n const url = match[2] ?? ''\n if (!HTTP_URL_PATTERN.test(url)) continue\n pushFinding(findings, file.relativePath, content, match[0] ?? url, match.index ?? 0)\n }\n\n for (const match of content.matchAll(URL_PROPERTY_PATTERN)) {\n const url = match[2] ?? ''\n if (!url.startsWith('http://')) continue\n if (lineText(content, match.index ?? 0).includes('@import')) continue\n pushFinding(findings, file.relativePath, content, match[0] ?? url, match.index ?? 0)\n }\n }\n return findings\n },\n})\n","/**\n * @attribution CWE-319\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-mixed-content'\nconst REMEDIATION = getCopy('remediation.security.html-mixed-content')\n\nconst TAG_RESOURCE_PATTERN =\n /<(script|link|iframe|img|form|object|embed)\\b[^>]*?\\b(src|href|action|data)\\s*=\\s*[\"'](http:\\/\\/[^\"']+)[\"'][^>]*?>/gi\nconst STYLE_ATTR_PATTERN = /\\bstyle\\s*=\\s*[\"']([\\s\\S]*?http:\\/\\/[\\s\\S]*?)[\"']/gi\nconst STYLE_BLOCK_PATTERN = /<style\\b[^>]*>([\\s\\S]*?)<\\/style>/gi\nconst CSS_URL_PATTERN = /url\\(\\s*([\"']?)(http:\\/\\/[^\"')]+)\\1\\s*\\)/gi\n\nfunction pushFinding(\n findings: Finding[],\n filePath: string,\n content: string,\n index: number,\n matchText: string,\n): void {\n const { line, column } = lineAndColumn(content, index)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-mixed-content.message', matchText),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath, matchText),\n remediation: REMEDIATION,\n })\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-mixed-content.name'),\n description: getCopy('checks.html-mixed-content.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(TAG_RESOURCE_PATTERN)) {\n const url = match[3] ?? ''\n pushFinding(findings, file.relativePath, content, match.index ?? 0, match[0] ?? url)\n }\n\n for (const match of content.matchAll(STYLE_ATTR_PATTERN)) {\n const styleValue = match[1] ?? ''\n if (!styleValue.includes('http://')) continue\n pushFinding(findings, file.relativePath, content, match.index ?? 0, match[0] ?? styleValue)\n }\n\n for (const block of content.matchAll(STYLE_BLOCK_PATTERN)) {\n const blockText = block[1] ?? ''\n for (const match of blockText.matchAll(CSS_URL_PATTERN)) {\n const url = match[2] ?? ''\n pushFinding(\n findings,\n file.relativePath,\n content,\n (block.index ?? 0) + (match.index ?? 0),\n match[0] ?? url,\n )\n }\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-829\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-external-asset-integrity'\nconst REMEDIATION = getCopy('remediation.security.html-external-asset-integrity')\n\nconst SCRIPT_PATTERN = /<script\\b[^>]*?\\bsrc\\s*=\\s*[\"'](https:\\/\\/[^\"']+)[\"'][^>]*?>/gi\nconst STYLESHEET_PATTERN =\n /<link\\b(?=[^>]*\\brel\\s*=\\s*[\"'][^\"']*\\bstylesheet\\b[^\"']*[\"'])[^>]*?\\bhref\\s*=\\s*[\"'](https:\\/\\/[^\"']+)[\"'][^>]*?>/gi\nconst INTEGRITY_PATTERN = /\\bintegrity\\s*=\\s*[\"'][^\"']+[\"']/i\nconst CROSSORIGIN_PATTERN = /\\bcrossorigin\\s*=\\s*[\"'][^\"']+[\"']/i\n\nfunction isLocalDevelopmentUrl(rawUrl: string): boolean {\n try {\n const url = new URL(rawUrl)\n return (\n url.hostname === 'localhost' ||\n url.hostname === '127.0.0.1' ||\n url.hostname === '::1' ||\n url.hostname === '[::1]'\n )\n } catch {\n return false\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-external-asset-integrity.name'),\n description: getCopy('checks.html-external-asset-integrity.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n for (const match of content.matchAll(SCRIPT_PATTERN)) {\n const tagText = match[0] ?? ''\n const url = match[1] ?? ''\n if (isLocalDevelopmentUrl(url)) continue\n\n const hasIntegrity = INTEGRITY_PATTERN.test(tagText)\n const hasCrossorigin = CROSSORIGIN_PATTERN.test(tagText)\n if (hasIntegrity && hasCrossorigin) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-external-asset-integrity.message', tagText),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n\n for (const match of content.matchAll(STYLESHEET_PATTERN)) {\n const tagText = match[0] ?? ''\n const url = match[1] ?? ''\n if (isLocalDevelopmentUrl(url)) continue\n\n const hasIntegrity = INTEGRITY_PATTERN.test(tagText)\n const hasCrossorigin = CROSSORIGIN_PATTERN.test(tagText)\n if (hasIntegrity && hasCrossorigin) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-external-asset-integrity.message', tagText),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-319\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.html-insecure-form-action'\nconst REMEDIATION = getCopy('remediation.security.html-insecure-form-action')\n\nconst FORM_ACTION_PATTERN = /<form\\b[^>]*?\\baction\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))[^>]*?>/gi\nconst LOCAL_DEV_URL_PATTERN = /^(?:https?:)?\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\]|::1)(?::\\d+)?(?:\\/|$)/i\nconst INSECURE_ACTION_PATTERN = /^(?:http:\\/\\/|\\/\\/)/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-insecure-form-action.name'),\n description: getCopy('checks.html-insecure-form-action.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(FORM_ACTION_PATTERN)) {\n const action = match[1] ?? match[2] ?? match[3] ?? ''\n if (!INSECURE_ACTION_PATTERN.test(action)) continue\n if (LOCAL_DEV_URL_PATTERN.test(action)) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-insecure-form-action.message', match[0] ?? action),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-693\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-iframe-sandbox'\nconst REMEDIATION = getCopy('remediation.security.html-iframe-sandbox')\n\nconst IFRAME_PATTERN = /<iframe\\b[^>]*?>/gi\nconst SRC_PATTERN = /\\bsrc\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst SANDBOX_ATTR_PATTERN = /\\bsandbox(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+)))?/i\nconst LOCAL_DEV_URL_PATTERN = /^(?:https?:)?\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\]|::1)(?::\\d+)?(?:\\/|$)/i\nconst EXTERNAL_URL_PATTERN = /^https?:\\/\\//i\nconst BROAD_SANDBOX_PATTERN = /\\ballow-scripts\\b/i\nconst SAME_ORIGIN_PATTERN = /\\ballow-same-origin\\b/i\n\nfunction hasSandboxAttribute(tagText: string): { present: boolean; value: string } {\n const match = tagText.match(SANDBOX_ATTR_PATTERN)\n if (!match) return { present: false, value: '' }\n // Bare sandbox attribute or sandbox=\"\" both count as present\n return { present: true, value: match[1] ?? match[2] ?? match[3] ?? '' }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-iframe-sandbox.name'),\n description: getCopy('checks.html-iframe-sandbox.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(IFRAME_PATTERN)) {\n const tagText = match[0] ?? ''\n const srcMatch = tagText.match(SRC_PATTERN)\n const src = srcMatch?.[1] ?? ''\n if (!EXTERNAL_URL_PATTERN.test(src)) continue\n if (LOCAL_DEV_URL_PATTERN.test(src)) continue\n\n const sandbox = hasSandboxAttribute(tagText)\n const hasBroadEscape = BROAD_SANDBOX_PATTERN.test(sandbox.value) && SAME_ORIGIN_PATTERN.test(sandbox.value)\n\n if (sandbox.present && !hasBroadEscape) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-iframe-sandbox.message', tagText),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-693\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.html-unsafe-embed'\nconst REMEDIATION = getCopy('remediation.security.html-unsafe-embed')\n\nconst OBJECT_PATTERN = /<object\\b[^>]*?\\bdata\\s*=\\s*[\"'](https:\\/\\/[^\"']+)[\"'][^>]*?>/gi\nconst EMBED_PATTERN = /<embed\\b[^>]*?\\bsrc\\s*=\\s*[\"'](https:\\/\\/[^\"']+)[\"'][^>]*?>/gi\nconst TYPE_PATTERN = /\\btype\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst LOCAL_DEV_URL_PATTERN = /^(?:https?:)?\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\]|::1)(?::\\d+)?(?:\\/|$)/i\nconst ACTIVE_TYPE_PATTERN = /(shockwave|java|silverlight|octet-stream|plugin|x-shockwave-flash|x-java|x-silverlight)/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nfunction getTypeValue(tagText: string): string {\n return tagText.match(TYPE_PATTERN)?.[1] ?? ''\n}\n\nfunction pushFindings(\n findings: Finding[],\n filePath: string,\n content: string,\n index: number,\n tagText: string,\n): void {\n const { line, column } = lineAndColumn(content, index)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-unsafe-embed.message', tagText),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath),\n remediation: REMEDIATION,\n })\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-unsafe-embed.name'),\n description: getCopy('checks.html-unsafe-embed.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(OBJECT_PATTERN)) {\n const tagText = match[0] ?? ''\n const url = match[1] ?? ''\n if (LOCAL_DEV_URL_PATTERN.test(url)) continue\n const typeValue = getTypeValue(tagText)\n if (typeValue && !ACTIVE_TYPE_PATTERN.test(typeValue)) continue\n pushFindings(findings, file.relativePath, content, match.index ?? 0, tagText)\n }\n\n for (const match of content.matchAll(EMBED_PATTERN)) {\n const tagText = match[0] ?? ''\n const url = match[1] ?? ''\n if (LOCAL_DEV_URL_PATTERN.test(url)) continue\n const typeValue = getTypeValue(tagText)\n if (typeValue && !ACTIVE_TYPE_PATTERN.test(typeValue)) continue\n pushFindings(findings, file.relativePath, content, match.index ?? 0, tagText)\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-601\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-meta-redirect'\nconst REMEDIATION = getCopy('remediation.security.html-meta-redirect')\n\nconst META_REFRESH_PATTERN = /<meta\\b[^>]*\\bhttp-equiv\\s*=\\s*[\"']refresh[\"'][^>]*>/gi\nconst CONTENT_PATTERN = /\\bcontent\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst LOCAL_DEV_URL_PATTERN = /^(?:https?:)?\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\]|::1)(?::\\d+)?(?:\\/|$)/i\n\nfunction parseRefreshContent(value: string): { delay: number; url: string | null } | null {\n const match = value.match(/^\\s*(\\d+(?:\\.\\d+)?)\\s*;\\s*url\\s*=\\s*(.+?)\\s*$/i)\n if (!match) return null\n const delay = Number.parseFloat(match[1]!)\n if (!Number.isFinite(delay)) return null\n const rawUrl = match[2]!.trim().replace(/^[\"']|[\"']$/g, '')\n return {\n delay,\n url: rawUrl,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-meta-redirect.name'),\n description: getCopy('checks.html-meta-redirect.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(META_REFRESH_PATTERN)) {\n const tagText = match[0] ?? ''\n const contentAttr = tagText.match(CONTENT_PATTERN)?.[1] ?? ''\n const parsed = parseRefreshContent(contentAttr)\n if (!parsed) continue\n if (parsed.delay > 2) continue\n if (!parsed.url) continue\n if (parsed.url.startsWith('#')) continue\n if (LOCAL_DEV_URL_PATTERN.test(parsed.url)) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-meta-redirect.message', tagText),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-693\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-base-tag-hijack'\nconst REMEDIATION = getCopy('remediation.security.html-base-tag-hijack')\n\nconst BASE_PATTERN = /<base\\b[^>]*?>/gi\nconst HREF_PATTERN = /\\bhref\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst TARGET_PATTERN = /\\btarget\\s*=\\s*[\"']([^\"']+)[\"']/i\nconst LOCAL_DEV_URL_PATTERN = /^(?:https?:)?\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\]|::1)(?::\\d+)?(?:\\/|$)/i\nconst EXTERNAL_URL_PATTERN = /^(?:https?:)?\\/\\//i\n\nfunction isOutsideHead(content: string, index: number): boolean {\n const headStart = content.search(/<head\\b[^>]*>/i)\n if (headStart === -1) return true\n const headCloseIndex = content.search(/<\\/head>/i)\n if (index < headStart) return true\n if (headCloseIndex !== -1 && index > headCloseIndex) return true\n return false\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-base-tag-hijack.name'),\n description: getCopy('checks.html-base-tag-hijack.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(BASE_PATTERN)) {\n const tagText = match[0] ?? ''\n const href = tagText.match(HREF_PATTERN)?.[1] ?? ''\n const target = tagText.match(TARGET_PATTERN)?.[1] ?? ''\n const externalHref = EXTERNAL_URL_PATTERN.test(href) && !LOCAL_DEV_URL_PATTERN.test(href)\n const targetBlank = target.toLowerCase() === '_blank'\n const outsideHead = isOutsideHead(content, match.index ?? 0)\n\n if (!externalHref && !targetBlank && !outsideHead) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-base-tag-hijack.message', tagText),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-79\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\nimport { lineAndColumn } from '../helpers/html-css-ast.js'\n\nconst CHECK_ID = 'security.html-javascript-uri'\nconst REMEDIATION = getCopy('remediation.security.html-javascript-uri')\n\nconst TAG_PATTERN = /<(a|form|iframe|object|embed)\\b[^>]*?\\b(href|action|src|data)\\s*=\\s*[\"'](javascript:[^\"']+)[\"'][^>]*?>/gi\nconst VOID_PATTERN = /^javascript:\\s*(?:void\\s*\\(?\\s*0\\s*\\)?)(?:\\s*;)?\\s*$/i\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-javascript-uri.name'),\n description: getCopy('checks.html-javascript-uri.description'),\n category: 'security',\n severity: 'low',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(TAG_PATTERN)) {\n const tagText = match[0] ?? ''\n const jsUrl = match[3] ?? ''\n if (VOID_PATTERN.test(jsUrl)) continue\n\n const { line, column } = lineAndColumn(content, match.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'low',\n message: getCopy('checks.html-javascript-uri.message', tagText),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-829\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.html-import-map-integrity'\nconst REMEDIATION = getCopy('remediation.security.html-import-map-integrity')\n\nconst IMPORTMAP_SCRIPT_PATTERN = /<script\\b[^>]*\\btype\\s*=\\s*[\"']importmap[\"'][^>]*>([\\s\\S]*?)<\\/script>/gi\nconst IMPORTMAP_SRC_PATTERN = /<script\\b[^>]*\\btype\\s*=\\s*[\"']importmap[\"'][^>]*\\bsrc\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi\nconst INTEGRITY_PATTERN = /\\bintegrity\\s*=\\s*[\"'][^\"']+[\"']/i\nconst EXTERNAL_URL_PATTERN = /^(?:https?:)?\\/\\//i\nconst LOCAL_DEV_URL_PATTERN = /^(?:https?:)?\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\]|::1)(?::\\d+)?(?:\\/|$)/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nfunction isExternalUrl(value: string): boolean {\n return EXTERNAL_URL_PATTERN.test(value) && !LOCAL_DEV_URL_PATTERN.test(value)\n}\n\nfunction pushFinding(\n findings: Finding[],\n filePath: string,\n content: string,\n index: number,\n matchText: string,\n): void {\n const { line, column } = lineAndColumn(content, index)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.html-import-map-integrity.message', matchText),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath),\n remediation: REMEDIATION,\n })\n}\n\nfunction scanImportMapValue(\n findings: Finding[],\n filePath: string,\n content: string,\n value: unknown,\n contextLabel: string,\n index: number,\n): void {\n if (typeof value === 'string') {\n if (isExternalUrl(value)) {\n pushFinding(findings, filePath, content, index, `${contextLabel}: ${value}`)\n }\n return\n }\n\n if (!value || typeof value !== 'object') return\n\n for (const [key, nested] of Object.entries(value as Record<string, unknown>)) {\n const nestedLabel = key === '*' ? `${contextLabel} wildcard` : `${contextLabel} ${key}`\n scanImportMapValue(findings, filePath, content, nested, nestedLabel, index)\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.html-import-map-integrity.name'),\n description: getCopy('checks.html-import-map-integrity.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(IMPORTMAP_SRC_PATTERN)) {\n const src = match[1] ?? ''\n if (!isExternalUrl(src)) continue\n const tagText = match[0] ?? ''\n if (INTEGRITY_PATTERN.test(tagText)) continue\n pushFinding(findings, file.relativePath, content, match.index ?? 0, `importmap src ${src}`)\n }\n\n for (const match of content.matchAll(IMPORTMAP_SCRIPT_PATTERN)) {\n const jsonText = match[1] ?? ''\n let parsed: unknown\n try {\n parsed = JSON.parse(jsonText)\n } catch {\n continue\n }\n scanImportMapValue(findings, file.relativePath, content, parsed, 'importmap', match.index ?? 0)\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-200\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.css-data-exfiltration'\nconst REMEDIATION = getCopy('remediation.security.css-data-exfiltration')\n\nconst ATTR_SELECTOR_PATTERN =\n /\\[[^\\]]*(?:value|type|name|email|tel|address|cc-number|cc-exp)[^\\]]*(?:\\^=|\\$=|\\*=|~=|\\|=)[^\\]]*\\]/i\nconst EXTERNAL_HTTP_URL_PATTERN = /url\\(\\s*([\"']?)http:\\/\\/[^\"')]+\\1\\s*\\)/i\nconst STYLE_BLOCK_PATTERN = /<style\\b[^>]*>([\\s\\S]*?)<\\/style>/gi\nconst STYLE_ATTR_PATTERN = /\\bstyle\\s*=\\s*([\"'])([\\s\\S]*?)\\1/gi\nconst BRACE_RULE_PATTERN = /[^{}]+\\{[^}]*?url\\(\\s*([\"']?)http:\\/\\/[^\"')]+\\1\\s*\\)[^}]*?\\}/gi\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nfunction pushFinding(\n findings: Finding[],\n filePath: string,\n content: string,\n index: number,\n matchText: string,\n): void {\n const { line, column } = lineAndColumn(content, index)\n findings.push({\n id: `${CHECK_ID}:${filePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.css-data-exfiltration.message', matchText),\n file: filePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', filePath),\n remediation: REMEDIATION,\n })\n}\n\nfunction scanCss(findings: Finding[], filePath: string, scanContent: string, originalContent: string, offset = 0): void {\n for (const match of scanContent.matchAll(BRACE_RULE_PATTERN)) {\n const text = match[0] ?? ''\n if (!ATTR_SELECTOR_PATTERN.test(text)) continue\n if (!EXTERNAL_HTTP_URL_PATTERN.test(text)) continue\n const leadingWhitespace = text.match(/^\\s*/)?.[0] ?? ''\n pushFinding(findings, filePath, originalContent, (match.index ?? 0) + offset + leadingWhitespace.length, text)\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.css-data-exfiltration.name'),\n description: getCopy('checks.css-data-exfiltration.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'css' && file.language !== 'html') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n if (file.language === 'css') {\n scanCss(findings, file.relativePath, content, content)\n continue\n }\n\n for (const block of content.matchAll(STYLE_BLOCK_PATTERN)) {\n const blockContent = block[1] ?? ''\n const leadingWhitespace = blockContent.match(/^\\s*/)?.[0] ?? ''\n const blockOffset = (block.index ?? 0) + (block[0]?.indexOf(blockContent) ?? 0) + leadingWhitespace.length\n scanCss(findings, file.relativePath, blockContent, content, blockOffset)\n }\n\n for (const attr of content.matchAll(STYLE_ATTR_PATTERN)) {\n const value = attr[2] ?? ''\n if (!value.includes('http://')) continue\n if (!ATTR_SELECTOR_PATTERN.test(value)) continue\n pushFinding(findings, file.relativePath, content, attr.index ?? 0, value)\n }\n }\n\n return findings\n },\n})\n","/**\n * @attribution CWE-829\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.css-external-font-integrity'\nconst REMEDIATION = getCopy('remediation.security.css-external-font-integrity')\n\nconst FONT_FACE_PATTERN = /@font-face\\b[\\s\\S]*?\\}/gi\nconst URL_PATTERN = /url\\(\\s*([\"']?)([^\"')]+)\\1\\s*\\)/gi\nconst LOCAL_REF_PATTERN = /^(?:data:|local\\(|\\/|\\.\\/|\\.\\.\\/)/i\nconst KNOWN_CDN_HOSTS = new Set([\n 'jsdelivr.net',\n 'cdn.jsdelivr.net',\n 'cdnjs.cloudflare.com',\n 'unpkg.com',\n 'fonts.googleapis.com',\n 'fonts.gstatic.com',\n 'cdn.skypack.dev',\n 'esm.sh',\n])\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nfunction isPublicCdnFont(url: string): boolean {\n try {\n const parsed = new URL(url)\n return KNOWN_CDN_HOSTS.has(parsed.hostname.toLowerCase())\n } catch {\n return false\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.css-external-font-integrity.name'),\n description: getCopy('checks.css-external-font-integrity.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'css') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const face of content.matchAll(FONT_FACE_PATTERN)) {\n const block = face[0] ?? ''\n for (const match of block.matchAll(URL_PATTERN)) {\n const url = match[2] ?? ''\n if (LOCAL_REF_PATTERN.test(url)) continue\n if (!url.startsWith('https://')) continue\n if (!isPublicCdnFont(url)) continue\n\n const { line, column } = lineAndColumn(content, face.index ?? 0)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.css-external-font-integrity.message', match[0] ?? url),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Surfaces use of cryptographically weak random number generators (Math.random, Python random module, etc.).\n *\n * @attribution CWE-338\n */\n\nconst CHECK_ID = 'security.insecure-random'\n\nconst QUERIES = {\n javascript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"Math\")\n (#eq? @prop \"random\"))) @match\n `,\n typescript: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"Math\")\n (#eq? @prop \"random\"))) @match\n `,\n tsx: `\n(call_expression\n function: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"Math\")\n (#eq? @prop \"random\"))) @match\n `,\n python: `\n(call\n function: (attribute\n object: (identifier) @mod\n attribute: (identifier) @func\n (#eq? @mod \"random\")\n (#match? @func \"^(random|randint|uniform|choice|shuffle|sample)$\"))) @match\n\n(call\n function: (identifier) @func\n (#match? @func \"^(random|randint|uniform|choice|shuffle|sample)$\")) @match\n `,\n ruby: `\n(call method: (identifier) @func\n (#match? @func \"^(rand|srand)$\")) @match\n `,\n go: `\n(call_expression\n function: (selector_expression\n operand: (identifier) @pkg\n field: (field_identifier) @func\n (#eq? @pkg \"rand\")\n (#match? @func \"^(Int|Intn|Float32|Float64|Perm|Read|Shuffle)$\"))) @match\n `,\n java: `\n(object_creation_expression\n type: (type_identifier) @cls\n (#eq? @cls \"Random\")) @match\n `,\n bash: `\n(simple_expansion\n (variable_name) @name\n (#eq? @name \"RANDOM\")) @match\n `,\n dockerfile: '((identifier) @name) @match',\n html: `\n(script_element\n (raw_text) @match\n (#match? @match \"Math\\\\\\\\.random\\\\\\\\s*\\\\\\\\(\"))\n`,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.insecure-random.name',\n descriptionKey: 'checks.insecure-random.description',\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.insecure-random.message',\n degradedMessageKey: 'checks.insecure-random.degraded',\n remediationKey: 'remediation.security.insecure-random',\n })\n)\n","/**\n * @attribution CWE-326\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.weak-key-entropy'\nconst REMEDIATION = getCopy('remediation.security.weak-key-entropy')\n\nconst RANDOM_BYTES_PATTERN = /randomBytes\\s*\\(\\s*(\\d+)\\s*\\)/g\nconst WEAK_KEY_CONTEXT = /(?:key|token|secret|id|license|password|session|csrf|nonce|salt|iv)/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.weak-key-entropy.name'),\n description: getCopy('checks.weak-key-entropy.description'),\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'typescript' && file.language !== 'javascript' && file.language !== 'tsx') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(RANDOM_BYTES_PATTERN)) {\n const byteCount = parseInt(match[1]!, 10)\n if (byteCount >= 16) continue\n\n const matchIndex = match.index ?? 0\n const startOfLine = content.lastIndexOf('\\n', matchIndex) + 1\n const endOfLine = content.indexOf('\\n', matchIndex)\n const lineContent = content.slice(startOfLine, endOfLine === -1 ? content.length : endOfLine)\n\n if (!WEAK_KEY_CONTEXT.test(lineContent) && !WEAK_KEY_CONTEXT.test(content.slice(Math.max(0, matchIndex - 200), matchIndex))) continue\n\n const { line, column } = lineAndColumn(content, matchIndex)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.weak-key-entropy.message', match[0], String(byteCount)),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})","/**\n * @attribution CWE-319\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.insecure-api-url-default'\nconst REMEDIATION = getCopy('remediation.security.insecure-api-url-default')\n\nconst HTTP_URL_DEFAULT_PATTERN = /(?:['\"`])(https?:\\/\\/[^\\s'\"`]+)(?:['\"`])/g\nconst API_CONTEXT = /(?:api[_-]?url|base[_-]?url|endpoint|server|host|webhook|resend|paddle|stripe|sendgrid|mailgun|postmark)/i\nconst ONLY_HTTP = /^http:\\/\\//i\nconst LOCALHOST_PATTERN = /\\/\\/(?:localhost|127\\.0\\.0\\.1|\\[::1\\]|::1)(?::\\d+)?(?:\\/|$)/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.insecure-api-url-default.name'),\n description: getCopy('checks.insecure-api-url-default.description'),\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'typescript' && file.language !== 'javascript' && file.language !== 'tsx' && file.language !== 'python' && file.language !== 'ruby' && file.language !== 'go') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n for (const match of content.matchAll(HTTP_URL_DEFAULT_PATTERN)) {\n const url = match[1]!\n if (!ONLY_HTTP.test(url)) continue\n\n if (LOCALHOST_PATTERN.test(url)) continue\n\n const matchIndex = match.index ?? 0\n const surroundingLine = content.slice(Math.max(0, matchIndex - 150), matchIndex + 150)\n const matchLine = content.slice(content.lastIndexOf('\\n', matchIndex) + 1, content.indexOf('\\n', matchIndex) === -1 ? content.length : content.indexOf('\\n', matchIndex))\n\n const isConfigContext = API_CONTEXT.test(matchLine) || API_CONTEXT.test(surroundingLine)\n if (!isConfigContext) continue\n\n const isEnvDefault = /[?:]\\s*$|process\\.env|process\\.ENV|ENV\\[|os\\.environ|os\\.getenv|ENV\\.fetch/i.test(matchLine)\n if (!isEnvDefault && !API_CONTEXT.test(matchLine)) continue\n\n const { line, column } = lineAndColumn(content, matchIndex)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${line}:${column}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.insecure-api-url-default.message', url),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})","/**\n * @attribution CWE-89\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.dynamic-sql-columns'\nconst REMEDIATION = getCopy('remediation.security.dynamic-sql-columns')\n\nconst SQL_SET_INTERPOLATION = /\\bSET\\s+.*\\$\\{[^}]*\\}/gis\nconst SQL_SET_TEMPLATE = /\\bSET\\s+.*`[^`]*\\$\\{[^}]*\\}[^`]*`/gis\nconst FIELDS_JOIN_IN_SQL = /(?:fields|columns)\\s*(?:\\.\\s*join|\\.map)\\s*\\(.+\\)\\s*[`'\"].*\\b(?:SET|INSERT|UPDATE|DELETE)\\b/gis\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.dynamic-sql-columns.name'),\n description: getCopy('checks.dynamic-sql-columns.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'typescript' && file.language !== 'javascript' && file.language !== 'tsx') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n const patterns = [\n { regex: SQL_SET_INTERPOLATION, label: 'SQL SET with interpolation' },\n { regex: SQL_SET_TEMPLATE, label: 'SQL SET with template literal' },\n { regex: FIELDS_JOIN_IN_SQL, label: 'fields.join in SQL' },\n ]\n\n for (const { regex, label } of patterns) {\n for (const match of content.matchAll(regex)) {\n const matchIndex = match.index ?? 0\n const { line, column } = lineAndColumn(content, matchIndex)\n\n const dedupKey = `${CHECK_ID}:${file.relativePath}:${line}`\n if (findings.some((f) => f.id === dedupKey)) continue\n\n findings.push({\n id: dedupKey,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.dynamic-sql-columns.message', label),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n return findings\n },\n})","/**\n * @attribution CWE-20\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.weak-email-validation'\nconst REMEDIATION = getCopy('remediation.security.weak-email-validation')\n\nconst WEAK_EMAIL_REGEX_LINE = /\\/\\^[^\\/]*@[^\\/]*\\\\\\.[^\\/]{0,4}\\$\\/[gimsuy]*/g\nconst LOOSE_REGEX_CLASS = /\\[\\^?\\\\?s@\\]\\+@\\[\\^?\\\\?s@\\]\\+\\\\\\.\\[\\^?\\\\?s@\\]\\+/g\nconst EMAIL_CONTEXT = /email|e-?mail|validateEmail|isEmail|checkEmail|verifyEmail|deliverable/is\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.weak-email-validation.name'),\n description: getCopy('checks.weak-email-validation.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'typescript' && file.language !== 'javascript' && file.language !== 'tsx' && file.language !== 'python' && file.language !== 'ruby') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n if (!EMAIL_CONTEXT.test(content)) continue\n\n const patterns = [\n { regex: WEAK_EMAIL_REGEX_LINE, label: 'short-TLD email regex' },\n { regex: LOOSE_REGEX_CLASS, label: 'overly-permissive email regex' },\n ]\n\n for (const { regex, label } of patterns) {\n for (const match of content.matchAll(regex)) {\n const matchIndex = match.index ?? 0\n const { line, column } = lineAndColumn(content, matchIndex)\n\n const dedupKey = `${CHECK_ID}:${file.relativePath}:${line}`\n if (findings.some((f) => f.id === dedupKey)) continue\n\n findings.push({\n id: dedupKey,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.weak-email-validation.message', `${match[0]} (${label})`),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n return findings\n },\n})","/**\n * @attribution CWE-200\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'security.idempotency-key-leak'\nconst REMEDIATION = getCopy('remediation.security.idempotency-key-leak')\n\nconst IDEMPOTENCY_CONTEXT = /idempotency[_-]?key|idempotency[_-]?token/i\nconst TEMPLATE_LITERAL_INTERPOLATION = /\\`[^`]*\\$\\{[^}]+\\}[^`]*\\`/g\nconst STRUCTURED_ID_PATTERN = /(?:lic(?:ense|ence)|sub(?:scription)?|order|cust(?:omer)?|user|tx|pay(?:ment)?|inv(?:oice)?)[-/]/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.idempotency-key-leak.name'),\n description: getCopy('checks.idempotency-key-leak.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'typescript' && file.language !== 'javascript' && file.language !== 'tsx') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n if (!IDEMPOTENCY_CONTEXT.test(content)) continue\n\n for (const match of content.matchAll(TEMPLATE_LITERAL_INTERPOLATION)) {\n const templateStr = match[0]\n if (!templateStr.includes('${')) continue\n\n if (!STRUCTURED_ID_PATTERN.test(templateStr)) continue\n\n const matchIndex = match.index ?? 0\n const { line, column } = lineAndColumn(content, matchIndex)\n\n const dedupKey = `${CHECK_ID}:${file.relativePath}:${line}`\n if (findings.some((f) => f.id === dedupKey)) continue\n\n findings.push({\n id: dedupKey,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.idempotency-key-leak.message', templateStr.slice(0, 80)),\n file: file.relativePath,\n line,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})","/**\n * @attribution CWE-319\n */\nimport { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { mechanicalConfidence } from '../helpers/confidence.js'\n\nconst CHECK_ID = 'data-exposure.plaintext-secret-in-email'\nconst REMEDIATION = getCopy('remediation.data-exposure.plaintext-secret-in-email')\n\nconst EMAIL_FILE_PATTERN = /email|mail|notify|notification/i\nconst SECRET_IN_TEXT_PATTERN = /(?:license[_-]?key|api[_-]?key|secret[_-]?key|token|password|auth[_-]?code|verification[_-]?code)\\b/i\nconst WARNING_PATTERN = /(?:encrypt|plain[_-]?text|unencrypted|not.*encrypt|transit.*encrypt|security.*warning|do.*not.*share|keep.*private)/i\n\nfunction lineAndColumn(content: string, index: number): { line: number; column: number } {\n const prefix = content.slice(0, index)\n const lines = prefix.split('\\n')\n return {\n line: lines.length,\n column: lines[lines.length - 1]!.length + 1,\n }\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.plaintext-secret-in-email.name'),\n description: getCopy('checks.plaintext-secret-in-email.description'),\n category: 'data-exposure',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'typescript' && file.language !== 'javascript' && file.language !== 'tsx') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n if (!EMAIL_FILE_PATTERN.test(file.relativePath)) continue\n\n const content = await file.content()\n\n const hasWarning = WARNING_PATTERN.test(content)\n\n for (const line of content.matchAll(/.*/g)) {\n const lineText = line[0]\n const lineIndex = line.index ?? 0\n\n if (!SECRET_IN_TEXT_PATTERN.test(lineText)) continue\n\n if (hasWarning) continue\n\n const { line: lineNum, column } = lineAndColumn(content, lineIndex)\n const secretMatch = SECRET_IN_TEXT_PATTERN.exec(lineText)\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:${column}`,\n checkId: CHECK_ID,\n category: 'data-exposure',\n severity: 'medium',\n message: getCopy('checks.plaintext-secret-in-email.message', secretMatch?.[0] ?? 'secret'),\n file: file.relativePath,\n line: lineNum,\n column,\n confidence: mechanicalConfidence('regex', file.relativePath),\n remediation: REMEDIATION,\n })\n\n break\n }\n }\n\n return findings\n },\n})","import { createHash } from 'crypto'\nimport type { Node as TSNode, Tree as TSTree, Language as TSLanguage } from 'web-tree-sitter'\nimport { Query as TSQuery } from 'web-tree-sitter'\nimport { ensureParserInit, loadLanguage, getOrCreateParser } from '../ast/query.js'\nimport { isLanguageSupported, TAINTLESS_LANGUAGES } from '../ast/language-map.js'\nimport type { SourceFile } from '../types/source-file.js'\nimport type {\n TaintTable,\n TaggedNode,\n TaintFlow,\n SinkClass,\n TaintTagKind,\n} from './types.js'\n\nexport interface AnalyseContext {\n taintCache?: Map<string, Promise<AnalyseResult>>\n astCache?: Map<string, Promise<{ tree: import('web-tree-sitter').Tree; source: string }>>\n}\n\nexport interface AnalyseResult {\n flows: TaintFlow[]\n degraded: boolean\n}\n\n// Module-level query cache: key = `${lang.name}::${entry.query}` -> TSQuery\nconst queryCache = new Map<string, TSQuery>()\n\nconst SCOPE_TYPES = new Set([\n 'function_declaration',\n 'function_expression',\n 'arrow_function',\n 'method_definition',\n 'function_definition',\n 'method_declaration',\n 'anonymous_function',\n 'program',\n 'module',\n 'class_definition',\n 'source_file',\n 'function_item',\n 'closure_expression',\n])\n\nconst LOOP_TYPES = new Set([\n 'for_statement',\n 'for_in_statement',\n 'while_statement',\n 'do_statement',\n 'foreach_statement',\n 'do_while_statement',\n 'loop_expression',\n 'while_expression',\n 'for_expression',\n])\n\nconst CALL_EXPRESSION_TYPES = new Set([\n 'call_expression',\n 'function_call_expression',\n 'call',\n 'method_invocation',\n])\nconst OBJECT_CREATION_TYPES = new Set(['object_creation_expression'])\n\nconst ASSIGNMENT_TYPES = new Set(['assignment_expression', 'assignment', 'assignment_statement'])\nconst AUGMENTED_ASSIGNMENT_TYPES = new Set(['augmented_assignment_expression', 'augmented_assignment'])\nconst BINARY_EXPR_TYPES = new Set(['binary_expression', 'binary_operator'])\nconst MEMBER_ACCESS_TYPES = new Set(['member_expression', 'attribute', 'selector_expression', 'call', 'field_expression'])\nconst SUBSCRIPT_TYPES = new Set(['subscript_expression', 'subscript', 'index_expression', 'element_reference'])\nconst ARGS_CONTAINER_TYPES = new Set(['arguments', 'argument_list'])\n\nfunction getMemberContainer(n: TSNode, depth = 0): TSNode | null {\n if (depth > 10) return null\n if (n.type === 'generic_function') {\n const inner = field(n, 'function')\n if (inner) return getMemberContainer(inner, depth + 1)\n }\n return field(n, 'object') ?? field(n, 'operand') ?? field(n, 'receiver') ?? (n.type === 'field_expression' ? field(n, 'value') : null) ?? (n.type === 'call' ? n.namedChild(0) : null)\n}\n\nfunction getMemberField(n: TSNode, depth = 0): TSNode | null {\n if (depth > 10) return null\n if (n.type === 'generic_function') {\n const inner = field(n, 'function')\n if (inner) return getMemberField(inner, depth + 1)\n }\n return field(n, 'property') ?? field(n, 'attribute') ?? field(n, 'field') ?? field(n, 'method')\n}\n\nfunction applyTaintToExpressionList(\n list: TSNode,\n scopeRoot: TSNode,\n s: State,\n cleanseFromId?: number,\n): void {\n for (let i = 0; i < list.namedChildCount; i++) {\n const child = list.namedChild(i)!\n if (isVarBinding(child)) {\n applyTaintToBinding(child, scopeRoot, s, cleanseFromId)\n } else if (child.type === 'object_pattern') {\n applyTaintToObjectPattern(child, scopeRoot, s, cleanseFromId)\n }\n }\n}\n\nfunction applyTaintToRustPattern(\n pattern: TSNode,\n scopeRoot: TSNode,\n s: State,\n cleanseFromId?: number,\n): void {\n if (isVarBinding(pattern)) {\n applyTaintToBinding(pattern, scopeRoot, s, cleanseFromId)\n } else if (pattern.type === 'tuple_pattern') {\n for (let i = 0; i < pattern.namedChildCount; i++) {\n applyTaintToRustPattern(pattern.namedChild(i)!, scopeRoot, s, cleanseFromId)\n }\n } else if (pattern.type === 'struct_pattern') {\n for (let i = 0; i < pattern.namedChildCount; i++) {\n const child = pattern.namedChild(i)!\n if (child.type === 'field_pattern') {\n const fieldPat = field(child, 'pattern') ?? child.namedChild(0)\n if (fieldPat) {\n applyTaintToRustPattern(fieldPat, scopeRoot, s, cleanseFromId)\n }\n } else if (isVarBinding(child)) {\n applyTaintToBinding(child, scopeRoot, s, cleanseFromId)\n }\n }\n } else if (pattern.type === 'tuple_struct_pattern') {\n for (let i = 1; i < pattern.namedChildCount; i++) {\n applyTaintToRustPattern(pattern.namedChild(i)!, scopeRoot, s, cleanseFromId)\n }\n } else if (pattern.type === 'ref_pattern' || pattern.type === 'mut_pattern') {\n const inner = pattern.namedChild(0)\n if (inner) {\n applyTaintToRustPattern(inner, scopeRoot, s, cleanseFromId)\n }\n }\n}\n\nfunction applyTaintToObjectPattern(\n pattern: TSNode,\n scopeRoot: TSNode,\n s: State,\n cleanseFromId?: number,\n): void {\n for (let i = 0; i < pattern.namedChildCount; i++) {\n const child = pattern.namedChild(i)!\n if (child.type === 'shorthand_property_identifier_pattern') {\n applyTaintToBinding(child, scopeRoot, s, cleanseFromId)\n } else if (child.type === 'pair_pattern') {\n const value = field(child, 'value')\n if (value && isVarBinding(value)) {\n applyTaintToBinding(value, scopeRoot, s, cleanseFromId)\n }\n }\n }\n}\n\nfunction expressionListContainsNodeId(list: TSNode, nodeId: number): boolean {\n for (let i = 0; i < list.namedChildCount; i++) {\n if (subtreeContainsNodeId(list.namedChild(i)!, nodeId)) return true\n }\n return false\n}\n\nfunction isCallNode(n: TSNode): boolean {\n return CALL_EXPRESSION_TYPES.has(n.type) || n.type === 'macro_invocation'\n}\n\nfunction getSubscriptContainer(n: TSNode): TSNode | null {\n return field(n, 'object') ?? field(n, 'operand') ?? (n.type === 'index_expression' || n.type === 'element_reference' ? n.namedChild(0) : null)\n}\n\nfunction getCallArgsNode(callNode: TSNode): TSNode | null {\n return field(callNode, 'arguments') ?? field(callNode, 'argument_list')\n}\n\nfunction getCallCallee(callNode: TSNode): TSNode | null {\n return field(callNode, 'function') ?? field(callNode, 'name') ?? field(callNode, 'macro') ?? field(callNode, 'method')\n}\n\nfunction mergeCleanse(s: State, fromId: number, toId: number): void {\n const nc = s.C.get(fromId)\n if (!nc || nc.size === 0) return\n const target = s.C.get(toId) ?? new Set<SinkClass>()\n nc.forEach((c) => target.add(c))\n s.C.set(toId, target)\n}\n\nfunction markTaintWithCleanse(s: State, toId: number, fromId: number): void {\n markTaint(s, toId)\n mergeCleanse(s, fromId, toId)\n}\n\nfunction commandNameText(command: TSNode): string | null {\n const name = field(command, 'name')\n if (!name) return null\n return name.namedChild(0)?.text ?? name.text\n}\n\nfunction applyTaintToBashReadTarget(\n command: TSNode,\n scopeRoot: TSNode,\n s: State,\n cleanseFromId?: number,\n): void {\n if (commandNameText(command) !== 'read') return\n for (let i = 0; i < command.namedChildCount; i++) {\n const child = command.namedChild(i)!\n if (child.type !== 'word') continue\n const text = child.text\n if (text === 'read' || text.startsWith('-')) continue\n markTaint(s, child.id)\n if (cleanseFromId !== undefined) mergeCleanse(s, cleanseFromId, child.id)\n taintVarUses(text, scopeRoot, s)\n }\n}\n\ninterface TableEntryForTag {\n id: string\n query: string\n kind: TaintTagKind\n sinkClass?: SinkClass\n sanitises?: SinkClass[]\n}\n\ntype TSNodeFieldResult = TSNode | null\n\nfunction collectEntries(table: TaintTable): TableEntryForTag[] {\n const entries: TableEntryForTag[] = []\n table.sources.forEach((s) => entries.push({ id: s.id, query: s.query, kind: 'source' }))\n table.sinks.forEach((s) =>\n entries.push({ id: s.id, query: s.query, kind: 'sink', sinkClass: s['sink-class'] }),\n )\n table.sanitisers.forEach((s) =>\n entries.push({ id: s.id, query: s.query, kind: 'sanitiser', sanitises: s.sanitises }),\n )\n return entries\n}\n\nfunction captureKind(name: string): TaintTagKind | null {\n if (name === 'source') return 'source'\n if (name === 'sink') return 'sink'\n if (name === 'sanitiser') return 'sanitiser'\n return null\n}\n\nfunction nodeRange(n: TSNode): TaggedNode['range'] {\n return {\n startLine: n.startPosition.row + 1,\n startColumn: n.startPosition.column + 1,\n endLine: n.endPosition.row + 1,\n endColumn: n.endPosition.column + 1,\n }\n}\n\nfunction getEnclosingScope(node: TSNode): TSNode {\n let c: TSNode | null = node\n while (c) {\n if (SCOPE_TYPES.has(c.type)) return c\n c = c.parent\n }\n return node.tree.rootNode\n}\n\n\nfunction findNodeById(root: TSNode, id: number): TSNode | null {\n if (root.id === id) return root\n for (let i = 0; i < root.namedChildCount; i++) {\n const f = findNodeById(root.namedChild(i)!, id)\n if (f) return f\n }\n return null\n}\n\nfunction nl(n: TSNode): number {\n return n.startPosition.row + 1\n}\n\nfunction _isIdent(n: TSNode): boolean {\n return n.type === 'identifier'\n}\n\nfunction isVarBinding(n: TSNode): boolean {\n return (\n n.type === 'identifier'\n || n.type === 'variable_name'\n || n.type === 'shorthand_property_identifier_pattern'\n || n.type === 'instance_variable'\n || n.type === 'class_variable'\n || n.type === 'global_variable'\n || n.type === 'constant'\n )\n}\n\nfunction varBindingName(n: TSNode): string | null {\n if (\n n.type === 'identifier'\n || n.type === 'shorthand_property_identifier_pattern'\n || n.type === 'instance_variable'\n || n.type === 'class_variable'\n || n.type === 'global_variable'\n || n.type === 'constant'\n ) return n.text\n if (n.type === 'variable_name') {\n for (let i = 0; i < n.namedChildCount; i++) {\n const c = n.namedChild(i)!\n if (c.type === 'name') return c.text\n }\n return n.text\n }\n return null\n}\n\nfunction varBindingMatches(n: TSNode, name: string): boolean {\n const binding = varBindingName(n)\n return binding !== null && binding === name\n}\n\nfunction applyTaintToBinding(\n binding: TSNode,\n scopeRoot: TSNode,\n s: State,\n cleanseFromId?: number,\n): void {\n markTaint(s, binding.id)\n let ex: Set<SinkClass> | undefined\n if (cleanseFromId !== undefined) {\n const nc = s.C.get(cleanseFromId)\n if (nc) {\n const target = s.C.get(binding.id) ?? new Set<SinkClass>()\n nc.forEach((c) => target.add(c))\n s.C.set(binding.id, target)\n ex = target\n }\n }\n const name = varBindingName(binding)\n if (name) {\n taintVarUses(name, scopeRoot, s)\n if (ex && ex.size > 0) {\n spreadCleanseToVarUses(name, scopeRoot, s, ex)\n }\n }\n}\n\nfunction field(n: TSNode, f: string): TSNodeFieldResult {\n return n.childForFieldName(f)\n}\n\nfunction isDescendantOf(n: TSNode, ancestor: TSNode, parentMap?: Map<number, TSNode>): boolean {\n if (parentMap) {\n let currId: number | undefined = n.id\n while (currId !== undefined) {\n if (currId === ancestor.id) return true\n const parent = parentMap.get(currId)\n if (!parent) break\n currId = parent.id\n }\n return false\n }\n let curr: TSNode | null = n\n while (curr) {\n if (curr.id === ancestor.id) return true\n curr = curr.parent\n }\n return false\n}\n\ntype TaintSet = Set<number>\ntype CleanseMap = Map<number, Set<SinkClass>>\n\ninterface State {\n T: TaintSet\n C: CleanseMap\n propagated: Set<number>\n visitedFunctions: Set<number>\n /** Set when T gains members or merge leaves unpropagated nodes. */\n propagationDirty: boolean\n}\n\nfunction stateNeedsPropagation(s: State): boolean {\n if (s.propagationDirty) return true\n for (const id of s.T) {\n if (!s.propagated.has(id)) return true\n }\n return false\n}\n\nfunction copy(s: State): State {\n const c = new Map<number, Set<SinkClass>>()\n s.C.forEach((classes, id) => c.set(id, new Set(classes)))\n return {\n T: new Set(s.T),\n C: c,\n propagated: new Set(s.propagated),\n visitedFunctions: new Set(s.visitedFunctions),\n propagationDirty: s.propagationDirty,\n }\n}\n\nfunction mergeOr(a: State, b: State): State {\n const t = new Set([...Array.from(a.T), ...Array.from(b.T)])\n const c = new Map<number, Set<SinkClass>>()\n a.C.forEach((classes, id) => {\n const bc = b.C.get(id)\n if (bc) {\n const inter = new Set<SinkClass>()\n classes.forEach((s) => { if (bc.has(s)) inter.add(s) })\n if (inter.size > 0) c.set(id, inter)\n }\n })\n const propagated = new Set([...Array.from(a.propagated), ...Array.from(b.propagated)])\n const visitedFunctions = new Set([...Array.from(a.visitedFunctions), ...Array.from(b.visitedFunctions)])\n const merged: State = { T: t, C: c, propagated, visitedFunctions, propagationDirty: false }\n for (const id of merged.T) {\n if (!merged.propagated.has(id)) {\n merged.propagationDirty = true\n break\n }\n }\n return merged\n}\n\n/* ---------- inter-function helpers ---------- */\n\nfunction buildFunctionMap(root: TSNode): Map<string, TSNode> {\n const map = new Map<string, TSNode>()\n\n function walk(n: TSNode) {\n if (n.type === 'function_declaration' || n.type === 'function_definition') {\n const name = n.childForFieldName('name')\n if (name && (name.type === 'identifier' || name.type === 'name') && !map.has(name.text)) {\n map.set(name.text, n)\n }\n } else if (n.type === 'variable_declarator') {\n const name = n.childForFieldName('name')\n const value = n.childForFieldName('value')\n if (name && name.type === 'identifier' && value) {\n if (\n (value.type === 'function_expression' || value.type === 'arrow_function') &&\n !map.has(name.text)\n ) {\n map.set(name.text, value)\n }\n }\n } else if (n.type === 'let_declaration') {\n const pattern = n.childForFieldName('pattern')\n const value = n.childForFieldName('value')\n if (pattern && pattern.type === 'identifier' && value && value.type === 'closure_expression') {\n map.set(pattern.text, value)\n }\n }\n\n for (let i = 0; i < n.namedChildCount; i++) {\n const child = n.namedChild(i)!\n walk(child)\n }\n }\n\n walk(root)\n return map\n}\n\nfunction getArgumentIndex(argsNode: TSNode, argNodeId: number): number {\n for (let i = 0; i < argsNode.namedChildCount; i++) {\n const child = argsNode.namedChild(i)!\n if (child.id === argNodeId) return i\n if (child.type === 'argument' && subtreeContainsNodeId(child, argNodeId)) return i\n }\n return -1\n}\n\nfunction subtreeContainsNodeId(root: TSNode, nodeId: number): boolean {\n if (root.id === nodeId) return true\n for (let i = 0; i < root.namedChildCount; i++) {\n if (subtreeContainsNodeId(root.namedChild(i)!, nodeId)) return true\n }\n return false\n}\n\nfunction getParameter(funcNode: TSNode, index: number): TSNode | null {\n const params = funcNode.childForFieldName('parameters')\n if (!params) return null\n if (index < 0 || index >= params.namedChildCount) return null\n const param = params.namedChild(index)\n if (!param) return null\n if (param.type === 'identifier') return param\n if (param.type === 'variable_name') return param\n if (param.type === 'simple_parameter') {\n for (let i = 0; i < param.namedChildCount; i++) {\n const c = param.namedChild(i)!\n if (c.type === 'variable_name' && isVarBinding(c)) return c\n }\n }\n return null\n}\n\nfunction getReturnArgument(ret: TSNode): TSNode | null {\n const arg = ret.childForFieldName('argument')\n if (arg) return arg\n return ret.namedChildCount > 0 ? ret.namedChild(0) : null\n}\n\nfunction findReturnStatements(root: TSNode): TSNode[] {\n const results: TSNode[] = []\n function walk(n: TSNode) {\n if (SCOPE_TYPES.has(n.type) && n.id !== root.id) return\n if (n.type === 'return_statement') {\n results.push(n)\n return\n }\n for (let i = 0; i < n.namedChildCount; i++) {\n walk(n.namedChild(i)!)\n }\n }\n walk(root)\n return results\n}\n\nfunction hasTaint(s: State, id: number): boolean {\n return s.T.has(id)\n}\n\nfunction subtreeHasTaint(s: State, n: TSNode): boolean {\n if (hasTaint(s, n.id)) return true\n for (let i = 0; i < n.namedChildCount; i++) {\n const c = n.namedChild(i)\n if (c && subtreeHasTaint(s, c)) return true\n }\n return false\n}\n\n\nfunction pushTagged(map: Map<number, TaggedNode[]>, nodeId: number, tn: TaggedNode): void {\n const cur = map.get(nodeId) ?? []\n cur.push(tn)\n map.set(nodeId, cur)\n}\n\nfunction isCleansed(s: State, id: number, cls: SinkClass): boolean {\n return s.C.get(id)?.has(cls) ?? false\n}\n\nfunction isTaintCleansedForSink(\n s: State,\n n: TSNode,\n cls: SinkClass,\n parentMap: Map<number, TSNode>,\n): boolean {\n let c: TSNode | null = n\n while (c) {\n if (isCleansed(s, c.id, cls)) return true\n c = parentMap.get(c.id) ?? null\n }\n return false\n}\n\nfunction collectTaintedNodes(root: TSNode, s: State, out: TSNode[]): void {\n if (hasTaint(s, root.id)) {\n let hasTaintedChild = false\n for (let i = 0; i < root.namedChildCount; i++) {\n if (subtreeHasTaint(s, root.namedChild(i)!)) {\n hasTaintedChild = true\n break\n }\n }\n if (!hasTaintedChild) {\n out.push(root)\n return\n }\n }\n for (let i = 0; i < root.namedChildCount; i++) {\n collectTaintedNodes(root.namedChild(i)!, s, out)\n }\n}\n\nfunction sinkHasUncleansedTaint(\n s: State,\n sinkNode: TSNode,\n cls: SinkClass,\n parentMap: Map<number, TSNode>,\n): boolean {\n const tainted: TSNode[] = []\n collectTaintedNodes(sinkNode, s, tainted)\n\n if (tainted.length === 0) return false\n return tainted.some((tn) => !isTaintCleansedForSink(s, tn, cls, parentMap))\n}\n\nfunction markTaint(s: State, id: number): void {\n if (!s.T.has(id) || !s.propagated.has(id)) {\n s.propagationDirty = true\n }\n s.T.add(id)\n}\n\nfunction taintVarUses(\n name: string,\n scopeRoot: TSNode,\n s: State,\n): void {\n function walk(n: TSNode) {\n if (n.id !== scopeRoot.id && SCOPE_TYPES.has(n.type)) return\n if (varBindingMatches(n, name)) {\n markTaint(s, n.id)\n }\n for (let i = 0; i < n.namedChildCount; i++) {\n walk(n.namedChild(i)!)\n }\n }\n walk(scopeRoot)\n}\n\n/** Copy cleanse classes to every in-scope use of `name` (separate AST ids from the binding). */\nfunction spreadCleanseToVarUses(\n name: string,\n scopeRoot: TSNode,\n s: State,\n classes: Set<SinkClass>,\n parentMap?: Map<number, TSNode>,\n): void {\n let added = false\n function walk(n: TSNode) {\n if (n.id !== scopeRoot.id && SCOPE_TYPES.has(n.type)) return\n if (varBindingMatches(n, name)) {\n const existing = s.C.get(n.id)\n if (!existing || Array.from(classes).some((c) => !existing.has(c))) {\n s.C.set(n.id, new Set([...Array.from(existing || []), ...Array.from(classes)]))\n added = true\n }\n const parent = parentMap?.get(n.id)\n if (parent?.type === 'simple_expansion' || parent?.type === 'expansion') {\n const pExisting = s.C.get(parent.id)\n if (!pExisting || Array.from(classes).some((c) => !pExisting.has(c))) {\n s.C.set(parent.id, new Set([...Array.from(pExisting || []), ...Array.from(classes)]))\n added = true\n }\n }\n }\n for (let i = 0; i < n.namedChildCount; i++) {\n walk(n.namedChild(i)!)\n }\n }\n walk(scopeRoot)\n if (added) {\n s.propagated.clear()\n s.propagationDirty = true\n }\n}\n\nfunction propagate(\n nodeId: number,\n scopeRoot: TSNode,\n s: State,\n nodeMap: Map<number, TSNode>,\n parentMap: Map<number, TSNode>,\n): number[] {\n const next: number[] = []\n const node = nodeMap.get(nodeId)\n if (!node) return next\n const p = parentMap.get(nodeId)\n if (!p) return next\n\n // Taint inside call arguments also marks the surrounding call so sinks\n // on the call node (or on the argument subtree) still see taint.\n if (ARGS_CONTAINER_TYPES.has(p.type)) {\n const gp = parentMap.get(p.id)\n if (gp && (isCallNode(gp) || OBJECT_CREATION_TYPES.has(gp.type))) {\n if (isCallNode(gp)) {\n const callee = getCallCallee(gp)\n if (callee?.type === 'member_expression' || callee?.type === 'attribute' || callee?.type === 'field_expression') {\n const prop = getMemberField(callee)\n const isMutator =\n prop &&\n (prop.type === 'property_identifier' || prop.type === 'identifier' || prop.type === 'field_identifier') &&\n ['push', 'concat', 'fill', 'append', 'extend'].includes(prop.text)\n if (isMutator) {\n const arr = getMemberContainer(callee)\n if (arr && isVarBinding(arr)) {\n applyTaintToBinding(arr, scopeRoot, s, nodeId)\n }\n }\n }\n }\n markTaintWithCleanse(s, gp.id, nodeId)\n next.push(gp.id)\n }\n return next\n }\n\n // PHP: argument wrapper around tainted value\n if (p.type === 'argument') {\n const gp = parentMap.get(p.id)\n if (gp && ARGS_CONTAINER_TYPES.has(gp.type)) {\n const callNode = parentMap.get(gp.id)\n if (callNode && isCallNode(callNode)) {\n markTaintWithCleanse(s, callNode.id, nodeId)\n next.push(callNode.id)\n }\n }\n }\n\n // PHP: tainted variable inside double-quoted string\n if (p.type === 'encapsed_string' && isVarBinding(node)) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Python/Ruby: string interpolation\n if (p.type === 'interpolation') {\n const str = parentMap.get(p.id)\n if (str?.type === 'string' || str?.type === 'string_literal' || str?.type === 'subshell') {\n markTaintWithCleanse(s, str.id, nodeId)\n next.push(str.id)\n }\n }\n\n // Bash: expansions, command substitutions, heredocs, redirects, and\n // pipelines carry taint to their enclosing shell syntax node.\n if (\n p.type === 'simple_expansion' ||\n p.type === 'expansion' ||\n p.type === 'command_substitution' ||\n p.type === 'subshell' ||\n p.type === 'string' ||\n p.type === 'concatenation' ||\n p.type === 'heredoc_body' ||\n p.type === 'herestring_redirect' ||\n p.type === 'heredoc_redirect' ||\n p.type === 'redirected_statement' ||\n p.type === 'pipeline'\n ) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n if (p.type === 'command') {\n applyTaintToBashReadTarget(p, scopeRoot, s, nodeId)\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n if (p.type === 'variable_assignment') {\n const value = field(p, 'value')\n const name = field(p, 'name')\n if (name && (!value || value.id === nodeId || subtreeContainsNodeId(value, nodeId))) {\n applyTaintToBinding(name, scopeRoot, s, nodeId)\n }\n }\n\n if (p.type === 'declaration_command') {\n for (let i = 0; i < p.namedChildCount; i++) {\n const child = p.namedChild(i)!\n if (child.type !== 'variable_assignment') continue\n const value = field(child, 'value')\n const name = field(child, 'name')\n if (name && value && (value.id === nodeId || subtreeContainsNodeId(value, nodeId))) {\n applyTaintToBinding(name, scopeRoot, s, nodeId)\n }\n }\n }\n\n // T as U — taint through type assertions (TypeScript / TSX)\n if (p.type === 'as_expression' && field(p, 'expression')?.id === nodeId) {\n markTaint(s, p.id)\n next.push(p.id)\n }\n\n // T satisfies U — taint through satisfies checks (TypeScript 4.9+)\n if (p.type === 'satisfies_expression') {\n const expr =\n field(p, 'expression') ?? field(p, 'value') ?? (p.namedChildCount > 0 ? p.namedChild(0) : null)\n if (expr && (expr.id === nodeId || subtreeContainsNodeId(expr, nodeId))) {\n markTaint(s, p.id)\n next.push(p.id)\n }\n }\n\n // let x = N / const { x } = N (JS/TS destructuring)\n if (p.type === 'variable_declarator' || p.type === 'var_spec') {\n const val = field(p, 'value')\n if (val?.id === nodeId) {\n const nm = field(p, 'name')\n if (nm && isVarBinding(nm)) {\n applyTaintToBinding(nm, scopeRoot, s, nodeId)\n } else if (nm?.type === 'object_pattern') {\n applyTaintToObjectPattern(nm, scopeRoot, s, nodeId)\n }\n }\n }\n\n // Rust: let x = N / let (a, b) = N\n if (p.type === 'let_declaration') {\n const val = field(p, 'value')\n if (val && (val.id === nodeId || subtreeContainsNodeId(val, nodeId))) {\n const pattern = field(p, 'pattern')\n if (pattern) {\n applyTaintToRustPattern(pattern, scopeRoot, s, nodeId)\n }\n }\n }\n\n // Rust: function parameter extractor propagation\n if (node.type === 'parameter') {\n const pattern = field(node, 'pattern') ?? node.namedChild(0)\n if (pattern) {\n applyTaintToRustPattern(pattern, scopeRoot, s, nodeId)\n }\n }\n\n // Rust: macro invocation (format! / println!)\n if (p.type === 'macro_invocation' || p.type === 'token_tree' || p.type === 'macro_arguments') {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: type cast (tainted as i32)\n if (p.type === 'type_cast_expression' && field(p, 'value')?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: borrow reference (&tainted)\n if (p.type === 'reference_expression' && field(p, 'value')?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: dereference (*tainted)\n if (p.type === 'unary_expression' && p.namedChild(0)?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: closure evaluation / return\n const closureBody = field(p, 'body')\n if (p.type === 'closure_expression' && closureBody && (closureBody.id === nodeId || subtreeContainsNodeId(closureBody, nodeId))) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: generic_function (params.id.parse::<i32>)\n if (p.type === 'generic_function' && field(p, 'function')?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: await_expression (expression.await)\n if (p.type === 'await_expression' && p.namedChild(0)?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: let condition (if let pattern = value)\n if (p.type === 'let_condition' && field(p, 'value')?.id === nodeId) {\n const pattern = field(p, 'pattern')\n if (pattern) {\n applyTaintToRustPattern(pattern, scopeRoot, s, nodeId)\n }\n }\n\n // Rust: match expression\n if (p.type === 'match_expression' && field(p, 'value')?.id === nodeId) {\n const body = field(p, 'body')\n if (body) {\n for (let i = 0; i < body.namedChildCount; i++) {\n const arm = body.namedChild(i)!\n if (arm.type === 'match_arm') {\n const pattern = field(arm, 'pattern')\n if (pattern) {\n applyTaintToRustPattern(pattern, scopeRoot, s, nodeId)\n }\n }\n }\n }\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Rust: match arm value to match expression\n if (p.type === 'match_arm' && field(p, 'value')?.id === nodeId) {\n const block = parentMap.get(p.id)\n if (block && block.type === 'match_block') {\n const matchExpr = parentMap.get(block.id)\n if (matchExpr && matchExpr.type === 'match_expression') {\n markTaintWithCleanse(s, matchExpr.id, nodeId)\n next.push(matchExpr.id)\n }\n }\n }\n\n // Rust: for loop (for pattern in value)\n if (p.type === 'for_expression') {\n const val = field(p, 'value')\n if (val && (val.id === nodeId || subtreeContainsNodeId(val, nodeId))) {\n const pattern = field(p, 'pattern')\n if (pattern) {\n applyTaintToRustPattern(pattern, scopeRoot, s, nodeId)\n }\n }\n }\n\n if (p.type === 'short_var_declaration') {\n const right = field(p, 'right')\n if (right && (right.id === nodeId || expressionListContainsNodeId(right, nodeId))) {\n const left = field(p, 'left')\n if (left) {\n applyTaintToExpressionList(left, scopeRoot, s, nodeId)\n }\n }\n }\n\n // Go: id := expr — RHS may sit in expression_list before short_var_declaration\n if (p.type === 'expression_list') {\n const gp = parentMap.get(p.id)\n if (gp?.type === 'short_var_declaration' && field(gp, 'right')?.id === p.id) {\n const left = field(gp, 'left')\n if (left && (p.id === nodeId || expressionListContainsNodeId(p, nodeId))) {\n applyTaintToExpressionList(left, scopeRoot, s, nodeId)\n }\n }\n }\n\n // x = N (JS/TS/PHP/Python/Go)\n if (ASSIGNMENT_TYPES.has(p.type)) {\n const r = field(p, 'right')\n if (r?.id === nodeId) {\n const l = field(p, 'left')\n if (l) {\n if (isVarBinding(l)) {\n applyTaintToBinding(l, scopeRoot, s, nodeId)\n } else if (l.type === 'object_pattern') {\n applyTaintToObjectPattern(l, scopeRoot, s, nodeId)\n } else if (l.type === 'parenthesized_expression') {\n const inner = l.namedChild(0)\n if (inner?.type === 'object_pattern') {\n applyTaintToObjectPattern(inner, scopeRoot, s, nodeId)\n }\n } else if (l.type === 'expression_list') {\n applyTaintToExpressionList(l, scopeRoot, s, nodeId)\n } else if (SUBSCRIPT_TYPES.has(l.type) || MEMBER_ACCESS_TYPES.has(l.type)) {\n const obj = getSubscriptContainer(l) ?? getMemberContainer(l)\n if (obj && isVarBinding(obj)) {\n applyTaintToBinding(obj, scopeRoot, s, nodeId)\n }\n }\n }\n }\n }\n\n // $html .= N / x += N\n if (AUGMENTED_ASSIGNMENT_TYPES.has(p.type)) {\n const r = field(p, 'right')\n if (r?.id === nodeId) {\n const l = field(p, 'left')\n if (l && isVarBinding(l)) {\n applyTaintToBinding(l, scopeRoot, s, nodeId)\n }\n }\n }\n\n // N.foo → taint attribute / member_expression / selector_expression\n if (MEMBER_ACCESS_TYPES.has(p.type) && getMemberContainer(p)?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // N[...] → taint subscript / index_expression\n if (SUBSCRIPT_TYPES.has(p.type) && getSubscriptContainer(p)?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // `${N}` → taint template\n if (p.type === 'template_substitution') {\n const tmpl = parentMap.get(p.id)\n if (tmpl && (tmpl.type === 'template_string' || tmpl.type === 'template_literal')) {\n markTaint(s, tmpl.id)\n next.push(tmpl.id)\n }\n }\n\n // a + N / a . N → taint binary\n if (BINARY_EXPR_TYPES.has(p.type)) {\n const left = field(p, 'left')\n const right = field(p, 'right')\n if ((left?.id === nodeId || right?.id === nodeId) && (hasPlus(p) || hasDot(p) || hasNullishCoalesce(p))) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n }\n\n // ...N → taint container\n if (p.type === 'spread_element') {\n const ctr = parentMap.get(p.id)\n if (ctr) {\n markTaint(s, ctr.id)\n next.push(ctr.id)\n }\n }\n\n // arr.push(N) → taint arr\n if (isCallNode(p)) {\n const callee = getCallCallee(p)\n if (callee && MEMBER_ACCESS_TYPES.has(callee.type)) {\n const prop = getMemberField(callee)\n const isMutator =\n prop &&\n (prop.type === 'property_identifier' || prop.type === 'identifier' || prop.type === 'field_identifier') &&\n ['push', 'concat', 'fill', 'append', 'extend'].includes(prop.text)\n if (isMutator) {\n const arr = getMemberContainer(callee)\n if (arr && isVarBinding(arr)) {\n applyTaintToBinding(arr, scopeRoot, s, nodeId)\n }\n }\n }\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Python: for x in N (comprehension clauses)\n if (p.type === 'for_in_clause') {\n const left = field(p, 'left')\n const right = field(p, 'right')\n if (right && right.id === nodeId && left) {\n applyTaintToBinding(left, scopeRoot, s, nodeId)\n }\n }\n\n // Python: for x in N (for_statement taint from iterable)\n if (p.type === 'for_statement') {\n const right = field(p, 'right')\n const left = field(p, 'left')\n if (right && right.id === nodeId && left) {\n applyTaintToBinding(left, scopeRoot, s, nodeId)\n }\n }\n\n // Python: [x for x in N] (comprehension yield values)\n if (p.type === 'list_comprehension' || p.type === 'set_comprehension' || p.type === 'dictionary_comprehension') {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n // Python: **kwargs / *args (dictionary splat and starred expressions)\n if (p.type === 'dictionary_splat' || p.type === 'starred_expression') {\n const gp = parentMap.get(p.id)\n if (gp) {\n markTaint(s, gp.id)\n next.push(gp.id)\n }\n }\n\n // TSX: taint inside {expr} propagates to jsx_expression and enclosing JSX\n if (p.type === 'jsx_expression') {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n if (p.type === 'pair') {\n const value = field(p, 'value')\n if (value?.id === nodeId) {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n }\n\n if (p.type === 'object' || p.type === 'jsx_fragment') {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n if (p.type === 'jsx_spread_attribute' || p.type === 'spread_element') {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n if (p.type === 'jsx_attribute') {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n if (p.type === 'jsx_element' || p.type === 'jsx_self_closing_element') {\n markTaintWithCleanse(s, p.id, nodeId)\n next.push(p.id)\n }\n\n return next\n}\n\nfunction hasBinaryOperator(n: TSNode, op: string): boolean {\n for (let i = 0; i < n.childCount; i++) {\n const c = n.child(i)\n if (c && c.text === op) return true\n }\n return false\n}\n\nfunction hasPlus(n: TSNode): boolean {\n return hasBinaryOperator(n, '+')\n}\n\nfunction hasDot(n: TSNode): boolean {\n return hasBinaryOperator(n, '.')\n}\n\nfunction hasNullishCoalesce(n: TSNode): boolean {\n return hasBinaryOperator(n, '??')\n}\n\nexport function propagateAll(\n state: State,\n scopeRoot: TSNode,\n nodeMap: Map<number, TSNode>,\n parentMap: Map<number, TSNode>,\n): void {\n const pending = new Set<number>()\n for (const id of state.T) {\n if (!state.propagated.has(id)) pending.add(id)\n }\n\n while (pending.size > 0) {\n const id = pending.values().next().value!\n pending.delete(id)\n if (state.propagated.has(id)) continue\n state.propagated.add(id)\n\n const tBefore = new Set(state.T)\n const next = propagate(id, scopeRoot, state, nodeMap, parentMap)\n for (const nid of next) {\n if (!state.propagated.has(nid) && state.T.has(nid)) pending.add(nid)\n }\n\n // Only enqueue nodes newly tainted during this step (e.g. via taintVarUses).\n // Re-scanning all of state.T each iteration caused catastrophic queue growth.\n for (const tid of state.T) {\n if (!tBefore.has(tid) && !state.propagated.has(tid)) pending.add(tid)\n }\n }\n\n state.propagationDirty = false\n}\n\nfunction propagateAllIfDirty(\n state: State,\n scopeRoot: TSNode,\n nodeMap: Map<number, TSNode>,\n parentMap: Map<number, TSNode>,\n): void {\n if (!stateNeedsPropagation(state)) return\n propagateAll(state, scopeRoot, nodeMap, parentMap)\n}\n\nfunction propagateInternalSourceReturnTaint(\n state: State,\n root: TSNode,\n functionMap: Map<string, TSNode>,\n nodeMap: Map<number, TSNode>,\n parentMap: Map<number, TSNode>,\n): void {\n for (const [funcName, funcDef] of functionMap) {\n const body = funcDef.childForFieldName('body')\n if (!body) continue\n\n const returns = findReturnStatements(funcDef)\n let returnIsTainted = false\n for (const ret of returns) {\n const retArg = getReturnArgument(ret)\n if (retArg && subtreeHasTaint(state, retArg)) {\n returnIsTainted = true\n break\n }\n }\n if (!returnIsTainted) continue\n\n propagateReturnTaintToCallSites(state, root.tree.rootNode, funcName, nodeMap, parentMap, functionMap)\n }\n}\n\nfunction propagateReturnTaintToCallSites(\n state: State,\n root: TSNode,\n funcName: string,\n _nodeMap: Map<number, TSNode>,\n _parentMap: Map<number, TSNode>,\n _functionMap: Map<string, TSNode>,\n): void {\n function markCallSites(n: TSNode) {\n if (n.type === 'function_definition' && n.childForFieldName('name')?.text === funcName) {\n return\n }\n if (isCallNode(n)) {\n const callee = getCallCallee(n)\n if (callee && (callee.type === 'identifier' || callee.type === 'name') && callee.text === funcName) {\n markTaint(state, n.id)\n }\n }\n for (let i = 0; i < n.namedChildCount; i++) {\n markCallSites(n.namedChild(i)!)\n }\n }\n markCallSites(root)\n}\n\nfunction propagateInterFunction(\n state: State,\n scopeRoot: TSNode,\n nodeMap: Map<number, TSNode>,\n parentMap: Map<number, TSNode>,\n tagged: Map<number, TaggedNode[]>,\n filePath: string,\n sourceId: string,\n functionMap: Map<string, TSNode>,\n): TaintFlow[] {\n const flows: TaintFlow[] = []\n\n for (const taintedId of state.T) {\n const node = nodeMap.get(taintedId)\n if (!node) continue\n\n // PHP wraps args in `argument`; Python uses bare argument_list children\n const parent = parentMap.get(taintedId)\n if (!parent) continue\n const argsNode =\n ARGS_CONTAINER_TYPES.has(parent.type)\n ? parent\n : parent.type === 'argument' && parentMap.get(parent.id) && ARGS_CONTAINER_TYPES.has(parentMap.get(parent.id)!.type)\n ? parentMap.get(parent.id)!\n : null\n if (!argsNode) continue\n\n const callNode = parentMap.get(argsNode.id)\n if (!callNode || !isCallNode(callNode)) continue\n\n const callee = getCallCallee(callNode)\n if (!callee || (callee.type !== 'identifier' && callee.type !== 'name')) continue\n\n const funcDef = functionMap.get(callee.text)\n if (!funcDef) {\n continue\n }\n\n // Recursion guard\n if (state.visitedFunctions.has(funcDef.id)) continue\n\n const argNodeId = parent.type === 'argument' ? taintedId : taintedId\n const argIndex = getArgumentIndex(argsNode, argNodeId)\n if (argIndex < 0) continue\n\n const param = getParameter(funcDef, argIndex)\n if (!param) continue\n\n // Mark function as visited for this source\n state.visitedFunctions.add(funcDef.id)\n // Copy state for callee analysis\n const calleeState = copy(state)\n try {\n // Taint the parameter with the same cleanse classes as the argument\n markTaint(calleeState, param.id)\n const cleansedClasses = state.C.get(taintedId)\n if (cleansedClasses) {\n const target = calleeState.C.get(param.id) ?? new Set<SinkClass>()\n cleansedClasses.forEach((c: SinkClass) => target.add(c))\n calleeState.C.set(param.id, target)\n }\n taintVarUses(varBindingName(param) ?? param.text, funcDef, calleeState)\n\n // Analyse callee function body\n const calleeFlows = analyseScope(\n funcDef,\n calleeState,\n funcDef,\n nodeMap,\n parentMap,\n tagged,\n filePath,\n sourceId,\n functionMap,\n )\n flows.push(...calleeFlows)\n } finally {\n state.visitedFunctions.delete(funcDef.id)\n }\n\n // Return propagation: if any return statement has taint, taint the call expression\n const returns = findReturnStatements(funcDef)\n for (const ret of returns) {\n const retArg = getReturnArgument(ret)\n if (retArg && hasTaint(calleeState, retArg.id)) {\n markTaint(state, callNode.id)\n const retCleanse = calleeState.C.get(retArg.id)\n if (retCleanse) {\n const target = state.C.get(callNode.id) ?? new Set<SinkClass>()\n retCleanse.forEach((c: SinkClass) => target.add(c))\n state.C.set(callNode.id, target)\n }\n break\n }\n }\n }\n\n return flows\n}\n\nfunction isDescendantOfId(nodeId: number, ancestorId: number, parentMap: Map<number, TSNode>): boolean {\n let currId = nodeId\n while (currId !== undefined) {\n if (currId === ancestorId) return true\n const parent = parentMap.get(currId)\n if (!parent) break\n currId = parent.id\n }\n return false\n}\n\nfunction isInScopeOptimized(nodeId: number, scopeRootId: number, nodeMap: Map<number, TSNode>, parentMap: Map<number, TSNode>): boolean {\n let currId = nodeId\n while (currId !== undefined) {\n if (currId === scopeRootId) return true\n const currNode = nodeMap.get(currId)\n if (currNode && SCOPE_TYPES.has(currNode.type) && currId !== scopeRootId) return false\n const parent = parentMap.get(currId)\n if (!parent) break\n currId = parent.id\n }\n return false\n}\n\nfunction collectSinks(\n root: TSNode,\n state: State,\n tagged: Map<number, TaggedNode[]>,\n scopeRoot: TSNode,\n filePath: string,\n sourceId: string,\n parentMap: Map<number, TSNode>,\n nodeMap: Map<number, TSNode>,\n): TaintFlow[] {\n const flows: TaintFlow[] = []\n\n const sanitisersToProcess: { node: TSNode; tag: TaggedNode }[] = []\n const sinksToProcess: { node: TSNode; tag: TaggedNode }[] = []\n\n for (const [nodeId, tags] of tagged.entries()) {\n if (isDescendantOfId(nodeId, root.id, parentMap) && isInScopeOptimized(nodeId, scopeRoot.id, nodeMap, parentMap)) {\n const node = nodeMap.get(nodeId)\n if (!node) continue\n for (const t of tags) {\n if (t.kind === 'sanitiser' && t.sanitises) {\n sanitisersToProcess.push({ node, tag: t })\n } else if (t.kind === 'sink' && t.sinkClass) {\n sinksToProcess.push({ node, tag: t })\n }\n }\n }\n }\n\n // 1. Process all sanitisers first\n for (const { node: n, tag: t } of sanitisersToProcess) {\n let added = false\n if (isVarBinding(n)) {\n const existing = state.C.get(n.id) ?? new Set<SinkClass>()\n const beforeSize = existing.size\n t.sanitises!.forEach((c: SinkClass) => existing.add(c))\n if (existing.size > beforeSize) {\n state.C.set(n.id, existing)\n added = true\n const parent = parentMap.get(n.id)\n if (parent?.type === 'simple_expansion' || parent?.type === 'expansion') {\n state.C.set(parent.id, new Set(existing))\n }\n const nm = varBindingName(n)\n if (nm) spreadCleanseToVarUses(nm, scopeRoot, state, existing, parentMap)\n }\n }\n let callNode: TSNode | null = null\n if (isCallNode(n)) {\n callNode = n\n } else if (isVarBinding(n) && parentMap.get(n.id) && isCallNode(parentMap.get(n.id)!)) {\n callNode = parentMap.get(n.id) ?? null\n }\n if (callNode) {\n let cleansedAny = false\n const args = getCallArgsNode(callNode)\n if (args) {\n for (let i = 0; i < args.namedChildCount; i++) {\n const a = args.namedChild(i)\n if (a && subtreeHasTaint(state, a)) {\n t.sanitises!.forEach((c: SinkClass) => {\n const ex = state.C.get(callNode!.id) ?? new Set<SinkClass>()\n const before = ex.size\n ex.add(c)\n if (ex.size > before) {\n state.C.set(callNode!.id, ex)\n state.C.set(a.id, new Set(ex))\n added = true\n }\n })\n cleansedAny = true\n }\n }\n }\n const callee = getCallCallee(callNode)\n let recv = callee ? getMemberContainer(callee) : null\n if (!recv) {\n recv = field(callNode, 'receiver') ?? field(callNode, 'object')\n }\n if (recv && subtreeHasTaint(state, recv)) {\n t.sanitises!.forEach((c: SinkClass) => {\n const ex = state.C.get(callNode!.id) ?? new Set<SinkClass>()\n const before = ex.size\n ex.add(c)\n if (ex.size > before) {\n state.C.set(callNode!.id, ex)\n state.C.set(recv.id, new Set(ex))\n added = true\n }\n })\n cleansedAny = true\n }\n if (cleansedAny) {\n markTaint(state, callNode.id)\n\n // Walk up call/member chain to propagate cleanse to the outer expression!\n let currNode = callNode\n while (currNode) {\n const parent = parentMap.get(currNode.id)\n if (\n parent &&\n (isCallNode(parent) ||\n MEMBER_ACCESS_TYPES.has(parent.type) ||\n parent.type === 'type_cast_expression' ||\n parent.type === 'reference_expression' ||\n parent.type === 'unary_expression' ||\n parent.type === 'generic_function' ||\n parent.type === 'await_expression' ||\n parent.type === 'try_expression' ||\n parent.type === 'assignment' ||\n parent.type === 'let_declaration')\n ) {\n const ex = state.C.get(currNode.id)\n if (ex) {\n const parentEx = state.C.get(parent.id) ?? new Set<SinkClass>()\n const before = parentEx.size\n ex.forEach((c) => parentEx.add(c))\n if (parentEx.size > before) {\n state.C.set(parent.id, parentEx)\n added = true\n }\n }\n currNode = parent\n } else {\n break\n }\n }\n\n let declParent = parentMap.get(currNode.id)\n if (declParent?.type === 'expression_list') {\n declParent = parentMap.get(declParent.id) ?? declParent\n }\n const declNode = declParent?.type === 'expression_list' ? parentMap.get(declParent.id) ?? declParent : declParent\n if (\n declNode &&\n (declNode.type === 'variable_declarator' ||\n declNode.type === 'var_spec' ||\n declNode.type === 'let_declaration' ||\n declNode.type === 'assignment' ||\n declNode.type === 'assignment_expression' ||\n declNode.type === 'assignment_statement')\n ) {\n const val =\n field(declNode, 'value') ?? field(declNode, 'right') ?? field(declNode, 'initializer')\n const nm =\n field(declNode, 'name') ?? field(declNode, 'pattern') ?? field(declNode, 'left')\n if (val && val.id === currNode.id && nm && isVarBinding(nm)) {\n const ex = state.C.get(currNode.id)\n if (ex) {\n state.C.set(nm.id, new Set(ex))\n const nmText = varBindingName(nm)\n if (nmText) spreadCleanseToVarUses(nmText, scopeRoot, state, ex)\n }\n }\n }\n if (declParent?.type === 'let_declaration') {\n const val = field(declParent, 'value')\n const pattern = field(declParent, 'pattern')\n if (val?.id === currNode.id && pattern && isVarBinding(pattern)) {\n const ex = state.C.get(currNode.id)\n if (ex) {\n state.C.set(pattern.id, new Set(ex))\n const nmText = varBindingName(pattern)\n if (nmText) spreadCleanseToVarUses(nmText, scopeRoot, state, ex)\n }\n }\n }\n if (declParent?.type === 'short_var_declaration') {\n const right = field(declParent, 'right')\n const left = field(declParent, 'left')\n if (right && left && expressionListContainsNodeId(right, currNode.id)) {\n const ex = state.C.get(currNode.id)\n if (ex) {\n for (let i = 0; i < left.namedChildCount; i++) {\n const binding = left.namedChild(i)!\n if (isVarBinding(binding)) {\n state.C.set(binding.id, new Set(ex))\n const nmText = varBindingName(binding)\n if (nmText) spreadCleanseToVarUses(nmText, scopeRoot, state, ex)\n }\n }\n }\n }\n }\n if (declParent && ASSIGNMENT_TYPES.has(declParent.type)) {\n const l = field(declParent, 'left')\n const r = field(declParent, 'right')\n if (r?.id === currNode.id && l && isVarBinding(l)) {\n const ex = state.C.get(currNode.id)\n if (ex) {\n state.C.set(l.id, new Set(ex))\n const nmText = varBindingName(l)\n if (nmText) spreadCleanseToVarUses(nmText, scopeRoot, state, ex)\n }\n }\n }\n }\n }\n if (added) {\n state.propagated.clear()\n state.propagationDirty = true\n propagateAllIfDirty(state, scopeRoot, nodeMap, parentMap)\n }\n }\n\n // 2. Process all sinks next\n for (const { node: n, tag: t } of sinksToProcess) {\n let parentCall = parentMap.get(n.id)\n while (parentCall && !isCallNode(parentCall)) {\n if (SCOPE_TYPES.has(parentCall.type)) break\n parentCall = parentMap.get(parentCall.id)\n }\n let callTainted = false\n if (parentCall !== undefined && isCallNode(parentCall) && hasTaint(state, parentCall.id)) {\n const args = getCallArgsNode(parentCall)\n callTainted = !args || !isDescendantOf(n, args, parentMap)\n }\n if (hasTaint(state, n.id) || subtreeHasTaint(state, n) || callTainted) {\n const checkNode = callTainted ? parentCall! : n\n const uncleansed = sinkHasUncleansedTaint(state, checkNode, t.sinkClass!, parentMap)\n if (uncleansed) {\n const parent = parentMap.get(n.id)\n const isSingleArgument =\n parent !== undefined && ARGS_CONTAINER_TYPES.has(parent.type) && parent.namedChildCount === 1\n\n const f = {\n sourceId,\n sinkId: t.id,\n sinkClass: t.sinkClass!,\n flowPath: [{ file: filePath, line: nl(n), column: n.startPosition.column + 1 }],\n cleansedClasses: [],\n sinkArg: {\n range: nodeRange(n),\n nodeType: n.type,\n isSingleArgument: isSingleArgument ?? false,\n text: n.text,\n },\n }\n flows.push(f)\n }\n }\n }\n\n return flows\n}\n\nfunction analyseScope(\n root: TSNode,\n state: State,\n scopeRoot: TSNode,\n nodeMap: Map<number, TSNode>,\n parentMap: Map<number, TSNode>,\n tagged: Map<number, TaggedNode[]>,\n filePath: string,\n sourceId: string,\n functionMap?: Map<string, TSNode>,\n): TaintFlow[] {\n propagateAllIfDirty(state, scopeRoot, nodeMap, parentMap)\n let flows: TaintFlow[] = []\n\n for (let i = 0; i < root.namedChildCount; i++) {\n const c = root.namedChild(i)!\n if (!isInScopeOptimized(c.id, scopeRoot.id, nodeMap, parentMap)) continue\n\n // if / if_expression / if_let_expression\n if (c.type === 'if_statement' || c.type === 'if_expression' || c.type === 'if_let_expression') {\n const conseq = field(c, 'consequence') ?? field(c, 'body')\n const altern = field(c, 'alternative')\n\n const sT = copy(state)\n const sE = copy(state)\n\n if (conseq) flows = flows.concat(analyseScope(conseq, sT, scopeRoot, nodeMap, parentMap, tagged, filePath, sourceId, functionMap))\n if (altern) flows = flows.concat(analyseScope(altern, sE, scopeRoot, nodeMap, parentMap, tagged, filePath, sourceId, functionMap))\n\n Object.assign(state, mergeOr(sT, sE))\n continue\n }\n\n // match_expression (Rust switch-like)\n if (c.type === 'match_expression') {\n const body = field(c, 'body')\n if (body) {\n let merged: State | null = null\n for (let j = 0; j < body.namedChildCount; j++) {\n const sc = body.namedChild(j)\n if (!sc) continue\n if (sc.type === 'match_arm') {\n const cs = copy(state)\n flows = flows.concat(analyseScope(sc, cs, scopeRoot, nodeMap, parentMap, tagged, filePath, sourceId, functionMap))\n merged = merged ? mergeOr(merged, cs) : cs\n }\n }\n if (merged) Object.assign(state, merged)\n }\n continue\n }\n\n // switch\n if (c.type === 'switch_statement') {\n const body = field(c, 'body')\n if (body) {\n let merged: State | null = null\n for (let j = 0; j < body.namedChildCount; j++) {\n const sc = body.namedChild(j)\n if (!sc) continue\n if (sc.type === 'switch_case' || sc.type === 'switch_default') {\n const cs = copy(state)\n flows = flows.concat(analyseScope(sc, cs, scopeRoot, nodeMap, parentMap, tagged, filePath, sourceId, functionMap))\n merged = merged ? mergeOr(merged, cs) : cs\n }\n }\n if (merged) Object.assign(state, merged)\n }\n continue\n }\n\n // loop\n if (LOOP_TYPES.has(c.type)) {\n const body = field(c, 'body')\n if (body) {\n let its = 0\n let changed = true\n while (changed && its < 50) {\n changed = false\n its++\n const pT = state.T.size\n const pC = state.C.size\n flows = flows.concat(analyseScope(body, state, scopeRoot, nodeMap, parentMap, tagged, filePath, sourceId, functionMap))\n if (state.T.size !== pT || state.C.size !== pC) changed = true\n }\n }\n continue\n }\n\n // Collect sinks in this child (propagation already done above)\n flows = flows.concat(collectSinks(c, state, tagged, scopeRoot, filePath, sourceId, parentMap, nodeMap))\n\n // Recurse into this child to process its nested statements\n flows = flows.concat(analyseScope(c, state, scopeRoot, nodeMap, parentMap, tagged, filePath, sourceId, functionMap))\n }\n\n propagateAllIfDirty(state, scopeRoot, nodeMap, parentMap)\n // Inter-function tracing runs once per source (when finishing the enclosing scope root),\n // not on every nested AST child walk.\n if (functionMap && root.id === scopeRoot.id) {\n propagateInternalSourceReturnTaint(\n state, root, functionMap, nodeMap, parentMap,\n )\n propagateAllIfDirty(state, scopeRoot, nodeMap, parentMap)\n flows = flows.concat(\n propagateInterFunction(\n state, scopeRoot, nodeMap, parentMap, tagged, filePath, sourceId, functionMap,\n ),\n )\n const fileRoot = root.tree.rootNode\n flows = flows.concat(collectSinks(fileRoot, state, tagged, fileRoot, filePath, sourceId, parentMap, nodeMap))\n }\n\n return flows\n}\n\nexport function buildMaps(scopeRoot: TSNode): {\n nodeMap: Map<number, TSNode>\n parentMap: Map<number, TSNode>\n} {\n const nodeMap = new Map<number, TSNode>()\n const parentMap = new Map<number, TSNode>()\n\n function walk(n: TSNode) {\n nodeMap.set(n.id, n)\n for (let i = 0; i < n.namedChildCount; i++) {\n const c = n.namedChild(i)\n if (c) {\n parentMap.set(c.id, n)\n walk(c)\n }\n }\n }\n\n walk(scopeRoot)\n return { nodeMap, parentMap }\n}\n\nlet bfsEntryCount = 0\n\nexport function _bfsResetCount(): void {\n bfsEntryCount = 0\n queryCache.clear()\n}\n\nexport function _bfsGetCount(): number {\n return bfsEntryCount\n}\n\nexport function _resetBfsCache(): void {\n bfsEntryCount = 0\n queryCache.clear()\n}\n\nfunction runAnalyse(\n file: SourceFile,\n table: TaintTable,\n fileContent?: string,\n astCache?: Map<string, Promise<{ tree: import('web-tree-sitter').Tree; source: string }>>,\n): Promise<AnalyseResult> {\n return (async (): Promise<AnalyseResult> => {\n if (TAINTLESS_LANGUAGES.has(file.language)) {\n return { flows: [], degraded: false }\n }\n\n if (!isLanguageSupported(file.language)) {\n return { flows: [], degraded: true }\n }\n\n try { await ensureParserInit() } catch { return { flows: [], degraded: true } }\n\n let lang: TSLanguage\n try { lang = await loadLanguage(file.language) } catch { return { flows: [], degraded: true } }\n\n let content: string\n if (fileContent !== undefined) {\n content = fileContent\n } else {\n try { content = await file.content() } catch { return { flows: [], degraded: true } }\n }\n\n if (content.length === 0) return { flows: [], degraded: false }\n\n let tree: TSTree\n let ownTree = false\n const cacheKey = `${file.path}::${file.language}`\n\n if (astCache) {\n let cached = astCache.get(cacheKey)\n if (!cached) {\n cached = (async () => {\n const parser = getOrCreateParser(lang, file.language)\n const parsed = parser.parse(content)\n if (!parsed) throw new Error('parse failed')\n return { tree: parsed, source: content }\n })()\n astCache.set(cacheKey, cached)\n ownTree = false // cache owns it\n }\n try {\n const r = await cached\n tree = r.tree\n } catch {\n return { flows: [], degraded: true }\n }\n } else {\n try {\n const parser = getOrCreateParser(lang, file.language)\n const parsed = parser.parse(content)\n if (!parsed) return { flows: [], degraded: true }\n tree = parsed\n ownTree = true\n } catch { return { flows: [], degraded: true } }\n }\n\n /* tag start */\n const entries = collectEntries(table)\n const taggedByNode = new Map<number, TaggedNode[]>()\n const sourceNodes: TaggedNode[] = []\n\n for (const entry of entries) {\n const cacheKey = `${file.language}::${entry.query}`\n let query = queryCache.get(cacheKey)\n if (!query) {\n try {\n query = new TSQuery(lang, entry.query)\n queryCache.set(cacheKey, query)\n } catch {\n continue\n }\n }\n\n const rawMatches = query.matches(tree.rootNode)\n for (const match of rawMatches) {\n for (const cap of match.captures) {\n const kind = captureKind(cap.name)\n if (!kind) continue\n\n const tn: TaggedNode = {\n id: entry.id,\n kind,\n nodeId: cap.node.id,\n range: nodeRange(cap.node as TSNode),\n ...(entry.sinkClass ? { sinkClass: entry.sinkClass } : {}),\n ...(entry.sanitises ? { sanitises: entry.sanitises } : {}),\n }\n\n pushTagged(taggedByNode, cap.node.id, tn)\n if (kind === 'source') sourceNodes.push(tn)\n }\n }\n }\n /* tag end */\n\n if (sourceNodes.length === 0) {\n if (ownTree) tree.delete()\n return { flows: [], degraded: false }\n }\n\n let allFlows: TaintFlow[] = []\n\n /* Build file-level maps once for inter-function propagation */\n const { nodeMap: fileNodeMap, parentMap: fileParentMap } = buildMaps(tree.rootNode)\n const functionMap = buildFunctionMap(tree.rootNode)\n\n for (const source of sourceNodes) {\n const sourceNode = findNodeById(tree.rootNode, source.nodeId)\n if (!sourceNode) continue\n\n const scopeRoot = getEnclosingScope(sourceNode)\n\n const state: State = {\n T: new Set([source.nodeId]),\n C: new Map(),\n propagated: new Set(),\n visitedFunctions: new Set(),\n propagationDirty: true,\n }\n\n if (isVarBinding(sourceNode)) {\n const name = varBindingName(sourceNode)\n if (name) taintVarUses(name, scopeRoot, state)\n }\n\n const flows = analyseScope(scopeRoot, state, scopeRoot, fileNodeMap, fileParentMap, taggedByNode, file.relativePath, source.id, functionMap)\n allFlows = allFlows.concat(flows)\n }\n\n // Deduplicate\n const seen = new Set<string>()\n const deduped: TaintFlow[] = []\n allFlows.forEach((f) => {\n const sl = f.flowPath.length > 0 ? f.flowPath[f.flowPath.length - 1]!.line : 0\n const k = `${f.sourceId}::${f.sinkId}::${sl}`\n if (!seen.has(k)) { seen.add(k); deduped.push(f) }\n })\n\n // Sort\n deduped.sort((a, b) => {\n const sa = a.flowPath.length > 0 ? a.flowPath[a.flowPath.length - 1]!.line : 0\n const sb = b.flowPath.length > 0 ? b.flowPath[b.flowPath.length - 1]!.line : 0\n if (sa !== sb) return sa - sb\n const la = a.flowPath.length > 0 ? a.flowPath[0]!.line : 0\n const lb = b.flowPath.length > 0 ? b.flowPath[0]!.line : 0\n if (la !== lb) return la - lb\n return a.sourceId.localeCompare(b.sourceId) || a.sinkId.localeCompare(b.sinkId)\n })\n\n if (ownTree) tree.delete()\n bfsEntryCount++\n return { flows: deduped, degraded: false }\n })()\n}\n\nexport async function analyseFile(\n file: SourceFile,\n table: TaintTable,\n ctx: AnalyseContext = {},\n): Promise<AnalyseResult> {\n let contentStr: string\n try {\n contentStr = await file.content()\n } catch (_err) {\n return { flows: [], degraded: true }\n }\n const contentSha256 = createHash('sha256').update(contentStr).digest('hex')\n const key = `${file.path}::${file.language}::${contentSha256}::${table.tableVersion}`\n\n if (ctx.taintCache) {\n const existing = ctx.taintCache.get(key)\n if (existing) return existing\n const promise = runAnalyse(file, table, contentStr, ctx.astCache)\n ctx.taintCache.set(key, promise)\n return promise\n }\n\n return runAnalyse(file, table, contentStr, ctx.astCache)\n}\n","import { readFileSync, readdirSync, existsSync } from 'fs'\nimport { dirname, resolve as pathResolve } from 'path'\nimport { parse as parseYaml } from 'yaml'\nimport { z, ZodError } from 'zod'\nimport { createHash } from 'crypto'\nimport type { Language } from '../types/source-file.js'\nimport type { TaintTable, SinkClass, AutofixSafety } from './types.js'\nimport { LANGUAGE_WASM_MAP } from '../ast/language-map.js'\nimport { ensureParserInit } from '../ast/query.js'\nimport { Language as TSLanguage, Query as TSQuery } from 'web-tree-sitter'\nimport { runtimeModuleDir, runtimeRequire } from '../runtime/paths.js'\n\nconst require = runtimeRequire()\n\nfunction resolveCoreEntryDir(): string | null {\n try {\n return dirname(require.resolve('@seaworthy/core'))\n } catch {\n return null\n }\n}\n\nconst SINK_CLASSES = [\n 'code-execution',\n 'xss',\n 'sql-injection',\n 'command-injection',\n 'path-traversal',\n 'url-injection',\n 'prototype-pollution',\n] as const\n\nconst AUTOFIX_SAFETY_VALUES = ['global', 'requires-import', 'manual'] as const\nconst ATTRIBUTION_PATTERN = /^(CWE-\\d+|OWASP-[A-Z0-9:.-]+|ast-grep:[a-z0-9-]+(\\.[a-z0-9-]+)*)$/\n\nconst sinkClassSchema = z.enum(SINK_CLASSES)\nconst autofixSafetySchema = z.enum(AUTOFIX_SAFETY_VALUES)\n\nconst sourceEntrySchema = z.strictObject({\n id: z.string(),\n query: z.string(),\n class: z.string().optional(),\n})\n\nconst sinkEntrySchema = z.strictObject({\n id: z.string(),\n 'sink-class': sinkClassSchema,\n query: z.string(),\n})\n\nconst sanitiserEntrySchema = z.strictObject({\n id: z.string(),\n sanitises: z.array(sinkClassSchema),\n query: z.string(),\n 'autofix-safety': autofixSafetySchema.optional(),\n})\n\nconst taintFileSchema = z\n .strictObject({\n attribution: z.string().regex(ATTRIBUTION_PATTERN),\n language: z.string(),\n 'applies-to': z.array(z.string()).optional(),\n 'supplement-only': z.boolean().optional(),\n sources: z.array(sourceEntrySchema).default([]),\n sinks: z.array(sinkEntrySchema).default([]),\n sanitisers: z.array(sanitiserEntrySchema).default([]),\n })\n .superRefine((data, ctx) => {\n const total = data.sources.length + data.sinks.length + data.sanitisers.length\n if (total === 0) {\n ctx.addIssue({\n code: 'custom',\n message: 'At least one source, sink, or sanitiser entry is required',\n path: [],\n })\n }\n if (!data['supplement-only']) {\n if (data.sources.length < 1) {\n ctx.addIssue({ code: 'custom', message: 'Required', path: ['sources'] })\n }\n if (data.sinks.length < 1) {\n ctx.addIssue({ code: 'custom', message: 'Required', path: ['sinks'] })\n }\n if (data.sanitisers.length < 1) {\n ctx.addIssue({ code: 'custom', message: 'Required', path: ['sanitisers'] })\n }\n }\n })\n\ninterface LoadError {\n file: string\n pathInYaml: string\n message: string\n}\n\nexport class TaintLoaderError extends Error {\n public readonly errors: LoadError[]\n\n constructor(errors: LoadError[]) {\n super(\n `Failed to load taint rules:\\n${errors\n .map((e) => ` ${e.file}: ${e.pathInYaml ? `${e.pathInYaml}: ` : ''}${e.message}`)\n .join('\\n')}`,\n )\n this.name = 'TaintLoaderError'\n this.errors = errors\n }\n}\n\nfunction globYamlFiles(dir: string): string[] {\n const results: string[] = []\n let entries\n try {\n entries = readdirSync(dir, { withFileTypes: true })\n } catch {\n return []\n }\n\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n if (\n entry.isFile() &&\n entry.name.endsWith('.yaml') &&\n !entry.name.endsWith('.test.yaml')\n ) {\n results.push(entry.name)\n }\n }\n\n return results\n}\n\nfunction resolveTaintRulesRoot(): string {\n const moduleDirCandidates = [\n runtimeModuleDir(),\n resolveCoreEntryDir(),\n ].filter((candidate): candidate is string => Boolean(candidate))\n\n const candidates = [\n ...moduleDirCandidates.flatMap((moduleDir) => [\n pathResolve(moduleDir, '..', 'rules', 'internal', 'taint'),\n pathResolve(moduleDir, '..', '..', 'rules', 'internal', 'taint'),\n pathResolve(moduleDir, 'rules', 'internal', 'taint'),\n ]),\n ]\n for (const candidate of candidates) {\n if (existsSync(pathResolve(candidate, 'javascript.yaml'))) return candidate\n }\n return candidates[candidates.length - 1]!\n}\n\nfunction validateLanguageKey(lang: string): Language | null {\n const validLanguages: Set<string> = new Set(Object.keys(LANGUAGE_WASM_MAP))\n if (validLanguages.has(lang)) {\n return lang as Language\n }\n return null\n}\n\nfunction checkDuplicateIds(\n sources: { id: string }[],\n sinks: { id: string }[],\n sanitisers: { id: string }[],\n filePath: string,\n): LoadError[] {\n const errors: LoadError[] = []\n const seenIds = new Map<string, string>()\n\n const allEntries = [\n ...sources.map((s) => ({ id: s.id, kind: 'sources' })),\n ...sinks.map((s) => ({ id: s.id, kind: 'sinks' })),\n ...sanitisers.map((s) => ({ id: s.id, kind: 'sanitisers' })),\n ]\n\n for (const entry of allEntries) {\n const existing = seenIds.get(entry.id)\n if (existing) {\n errors.push({\n file: filePath,\n pathInYaml: `${entry.kind}[id]`,\n message: `Duplicate id \"${entry.id}\" — already used in ${existing}`,\n })\n } else {\n seenIds.set(entry.id, entry.kind)\n }\n }\n\n return errors\n}\n\nasync function validateQueryAgainstGrammars(\n queryString: string,\n queryId: string,\n languages: Language[],\n filePath: string,\n): Promise<LoadError[]> {\n const errors: LoadError[] = []\n\n try {\n await ensureParserInit()\n } catch {\n return errors\n }\n\n for (const lang of languages) {\n const wasmFilename = LANGUAGE_WASM_MAP[lang]\n if (!wasmFilename) continue\n\n try {\n const wasmPath = require.resolve(`tree-sitter-wasms/out/${wasmFilename}`)\n const wasmBuf = readFileSync(wasmPath)\n const tsLang = await TSLanguage.load(wasmBuf)\n try {\n new TSQuery(tsLang, queryString)\n } catch {\n errors.push({\n file: filePath,\n pathInYaml: queryId,\n message: `Query fails to compile against ${lang} grammar`,\n })\n }\n } catch {\n // Gracefully skip query validation when grammar WASM is unavailable\n // (e.g. in subprocesses with custom loaders or incomplete installs)\n }\n }\n\n return errors\n}\n\nconst loadedTables = new Map<Language, string>()\nconst loadedTableVersions = new Map<Language, string>()\n\nexport function _resetTaintLoader(): void {\n loadedTables.clear()\n loadedTableVersions.clear()\n}\n\nexport async function loadAllTaintRules(\n taintDirOverride?: string,\n): Promise<Map<Language, TaintTable>> {\n const taintDir = taintDirOverride ?? resolveTaintRulesRoot()\n\n let files: string[]\n try {\n files = globYamlFiles(taintDir)\n } catch {\n return new Map()\n }\n\n const tables = new Map<Language, TaintTable>()\n const loadErrors: LoadError[] = []\n\n interface PendingSupplement {\n relativePath: string\n primaryLang: Language\n mapSources: TaintTable['sources']\n mapSinks: TaintTable['sinks']\n mapSanitisers: TaintTable['sanitisers']\n tableVersion: string\n }\n const pendingSupplements: PendingSupplement[] = []\n\n for (const fileName of files) {\n const fullPath = pathResolve(taintDir, fileName)\n const relativePath = `taint/${fileName}`\n\n let raw: string\n try {\n raw = readFileSync(fullPath, 'utf-8')\n } catch {\n loadErrors.push({\n file: relativePath,\n pathInYaml: '',\n message: 'Cannot read file',\n })\n continue\n }\n\n let parsed: unknown\n try {\n parsed = parseYaml(raw, { strict: true })\n if (parsed === null || parsed === undefined) {\n throw new Error('Empty YAML document')\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n loadErrors.push({\n file: relativePath,\n pathInYaml: '',\n message: `Parse error: ${message}`,\n })\n continue\n }\n\n let validated: z.infer<typeof taintFileSchema>\n try {\n validated = taintFileSchema.parse(parsed)\n } catch (err) {\n if (err instanceof ZodError) {\n const issues: LoadError[] = err.issues.map((issue) => ({\n file: relativePath,\n pathInYaml: issue.path.join('.'),\n message: issue.message,\n }))\n loadErrors.push(...issues)\n } else {\n loadErrors.push({\n file: relativePath,\n pathInYaml: '',\n message: String(err),\n })\n }\n continue\n }\n\n const dupErrors = checkDuplicateIds(\n validated.sources,\n validated.sinks,\n validated.sanitisers,\n relativePath,\n )\n if (dupErrors.length > 0) {\n loadErrors.push(...dupErrors)\n continue\n }\n\n const primaryLang = validateLanguageKey(validated.language)\n if (!primaryLang) {\n loadErrors.push({\n file: relativePath,\n pathInYaml: 'language',\n message: `Unknown language: ${validated.language}`,\n })\n continue\n }\n\n const appliesTo: Language[] = validated['applies-to']\n ? validated['applies-to'].flatMap((l) => {\n const validated_ = validateLanguageKey(l)\n if (!validated_) {\n loadErrors.push({\n file: relativePath,\n pathInYaml: 'applies-to',\n message: `Unknown language: ${l}`,\n })\n return []\n }\n return [validated_]\n })\n : []\n\n const supplementOnly = validated['supplement-only'] === true\n const allLanguages = supplementOnly ? [primaryLang] : [primaryLang, ...appliesTo]\n\n let hasQueryErrors = false\n for (const entry of [...validated.sources, ...validated.sinks, ...validated.sanitisers]) {\n const queryErrors = await validateQueryAgainstGrammars(\n entry.query,\n entry.id,\n allLanguages,\n relativePath,\n )\n if (queryErrors.length > 0) {\n loadErrors.push(...queryErrors)\n hasQueryErrors = true\n }\n }\n if (hasQueryErrors) continue\n\n const tableVersion = createHash('sha256').update(raw).digest('hex')\n\n const mapSources = validated.sources.map((s) => ({\n id: s.id,\n query: s.query,\n ...(s.class ? { class: s.class } : {}),\n }))\n const mapSinks = validated.sinks.map((s) => ({\n id: s.id,\n 'sink-class': s['sink-class'] as SinkClass,\n query: s.query,\n }))\n const mapSanitisers = validated.sanitisers.map((s) => ({\n id: s.id,\n sanitises: s.sanitises as SinkClass[],\n query: s.query,\n ...(s['autofix-safety'] ? { 'autofix-safety': s['autofix-safety'] as AutofixSafety } : {}),\n }))\n\n if (supplementOnly) {\n pendingSupplements.push({\n relativePath,\n primaryLang,\n mapSources,\n mapSinks,\n mapSanitisers,\n tableVersion,\n })\n continue\n }\n\n const table: TaintTable = {\n language: primaryLang,\n appliesTo,\n attribution: validated.attribution,\n sources: mapSources,\n sinks: mapSinks,\n sanitisers: mapSanitisers,\n tableVersion,\n }\n\n for (const lang of allLanguages) {\n const existingFile = loadedTables.get(lang)\n if (existingFile) {\n if (existingFile === relativePath) {\n const existingVersion = loadedTableVersions.get(lang)\n if (existingVersion === tableVersion) {\n // Same content — true no-op (idempotent)\n tables.set(lang, table)\n continue\n }\n // Content changed — perform proper update\n loadedTableVersions.set(lang, tableVersion)\n tables.set(lang, table)\n continue\n }\n loadErrors.push({\n file: relativePath,\n pathInYaml: 'language',\n message: `Language \"${lang}\" already registered by ${existingFile}`,\n })\n continue\n }\n loadedTables.set(lang, relativePath)\n loadedTableVersions.set(lang, tableVersion)\n tables.set(lang, table)\n }\n }\n\n for (const pending of pendingSupplements) {\n const existing = tables.get(pending.primaryLang)\n if (!existing) {\n loadErrors.push({\n file: pending.relativePath,\n pathInYaml: 'supplement-only',\n message: `Language \"${pending.primaryLang}\" must be registered before supplement-only rules`,\n })\n continue\n }\n const dupErrors = checkDuplicateIds(\n [...existing.sources, ...pending.mapSources],\n [...existing.sinks, ...pending.mapSinks],\n [...existing.sanitisers, ...pending.mapSanitisers],\n pending.relativePath,\n )\n if (dupErrors.length > 0) {\n loadErrors.push(...dupErrors)\n continue\n }\n const merged: TaintTable = {\n ...existing,\n sources: [...existing.sources, ...pending.mapSources],\n sinks: [...existing.sinks, ...pending.mapSinks],\n sanitisers: [...existing.sanitisers, ...pending.mapSanitisers],\n tableVersion: createHash('sha256')\n .update(existing.tableVersion + pending.tableVersion)\n .digest('hex'),\n }\n tables.set(pending.primaryLang, merged)\n }\n\n if (loadErrors.length > 0) {\n throw new TaintLoaderError(loadErrors)\n }\n\n return tables\n}\n","import type { Severity, Confidence } from '../../types/finding.js'\nimport type { SinkClass } from '../../taint/types.js'\n\n/**\n * Severity mappings for taint-consuming checks.\n * High for command-injection and path-traversal, medium for xss and sql-injection.\n */\nexport function getTaintSeverity(sinkClass: SinkClass): Severity {\n switch (sinkClass) {\n case 'command-injection':\n case 'path-traversal':\n return 'high'\n case 'xss':\n case 'sql-injection':\n return 'medium'\n default:\n return 'medium'\n }\n}\n\n/**\n * Confidence for all taint checks.\n */\nexport const TAINT_CONFIDENCE: Confidence = 'medium'\n","/**\n * Per-language global symbol allow-lists.\n *\n * Identifiers in autofix replacements must either:\n * 1. Already be in scope at the patch site (the original tainted identifier), or\n * 2. Be present in the allow-list for the target language.\n */\n\nexport const JS_GLOBALS = new Set([\n 'Array',\n 'ArrayBuffer',\n 'Boolean',\n 'DataView',\n 'Date',\n 'Error',\n 'EvalError',\n 'Float32Array',\n 'Float64Array',\n 'Function',\n 'Infinity',\n 'Int16Array',\n 'Int32Array',\n 'Int8Array',\n 'JSON',\n 'Map',\n 'Math',\n 'NaN',\n 'Number',\n 'Object',\n 'Promise',\n 'Proxy',\n 'RangeError',\n 'ReferenceError',\n 'RegExp',\n 'Set',\n 'String',\n 'Symbol',\n 'SyntaxError',\n 'TypeError',\n 'URIError',\n 'Uint16Array',\n 'Uint32Array',\n 'Uint8Array',\n 'Uint8ClampedArray',\n 'WeakMap',\n 'WeakSet',\n 'console',\n 'decodeURI',\n 'decodeURIComponent',\n 'encodeURI',\n 'encodeURIComponent',\n 'escape',\n 'eval',\n 'isFinite',\n 'isNaN',\n 'parseFloat',\n 'parseInt',\n 'undefined',\n 'unescape',\n])\n\nexport const GLOBAL_SYMBOLS: Record<string, Set<string>> = {\n javascript: JS_GLOBALS,\n typescript: JS_GLOBALS,\n tsx: JS_GLOBALS,\n}\n\n/**\n * Check whether every identifier in a code snippet is either:\n * 1. Already present in `scopeIdentifiers`, or\n * 2. A documented global for the given language.\n */\nexport function allIdentifiersAreSafe(\n code: string,\n language: string,\n scopeIdentifiers: Set<string>,\n): boolean {\n const globals = GLOBAL_SYMBOLS[language] ?? new Set()\n // Naive extraction: match identifier-like tokens, excluding keywords and literals\n const idPattern = /\\b[a-zA-Z_$][a-zA-Z0-9_$]*\\b/g\n const keywords = new Set([\n 'const',\n 'let',\n 'var',\n 'function',\n 'return',\n 'if',\n 'else',\n 'for',\n 'while',\n 'do',\n 'switch',\n 'case',\n 'break',\n 'continue',\n 'try',\n 'catch',\n 'finally',\n 'throw',\n 'new',\n 'this',\n 'true',\n 'false',\n 'null',\n 'typeof',\n 'instanceof',\n 'in',\n 'of',\n 'await',\n 'async',\n 'yield',\n 'class',\n 'extends',\n 'super',\n 'import',\n 'export',\n 'default',\n 'from',\n 'as',\n 'with',\n 'void',\n 'delete',\n ])\n\n let match: RegExpExecArray | null\n while ((match = idPattern.exec(code)) !== null) {\n const id = match[0]\n if (keywords.has(id)) continue\n if (!scopeIdentifiers.has(id) && !globals.has(id)) {\n return false\n }\n }\n return true\n}\n\n/**\n * Validate that an autofix replacement is safe: every identifier is either\n * in scope at the patch site or a documented global. Property names in\n * member expressions (e.g. `stringify` in `JSON.stringify`) are ignored.\n */\nexport function isAutofixSafe(\n sanitiserId: string,\n argText: string,\n language: string,\n): boolean {\n const globals = GLOBAL_SYMBOLS[language] ?? new Set()\n\n // The base of a member expression must be global (e.g. `JSON` in `JSON.stringify`)\n const baseId = sanitiserId.split('.')[0]!\n if (!globals.has(baseId)) {\n return false\n }\n\n const replacement = `${sanitiserId}(${argText})`\n const idPattern = /\\b[a-zA-Z_$][a-zA-Z0-9_$]*\\b/g\n const keywords = new Set([\n 'const', 'let', 'var', 'function', 'return', 'if', 'else', 'for', 'while',\n 'do', 'switch', 'case', 'break', 'continue', 'try', 'catch', 'finally',\n 'throw', 'new', 'this', 'true', 'false', 'null', 'typeof', 'instanceof',\n 'in', 'of', 'await', 'async', 'yield', 'class', 'extends', 'super',\n 'import', 'export', 'default', 'from', 'as', 'with', 'void', 'delete',\n ])\n\n const sanitiserParts = sanitiserId.split('.')\n\n let match: RegExpExecArray | null\n while ((match = idPattern.exec(replacement)) !== null) {\n const id = match[0]\n if (keywords.has(id)) continue\n if (id === argText) continue // argument is in scope\n if (sanitiserParts.includes(id)) continue // part of the sanitiser id\n if (!globals.has(id)) {\n return false\n }\n }\n return true\n}\n","import type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport type { SinkClass } from '../../taint/types.js'\nimport { analyseFile } from '../../taint/bfs.js'\nimport { loadAllTaintRules } from '../../taint/loader.js'\nimport type { Language } from '../../types/source-file.js'\nimport { getTaintSeverity, TAINT_CONFIDENCE } from './severity-rubric.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isAutofixSafe } from './global-symbols.js'\nimport { runWithConcurrencyCollect } from '../../runner/scan-runner.js'\nimport { TAINTLESS_LANGUAGES } from '../../ast/language-map.js'\n\nlet taintTablesCache: Map<Language, import('../../taint/types.js').TaintTable> | null = null\nlet taintTablesPromise: Promise<Map<Language, import('../../taint/types.js').TaintTable>> | null = null\n\nasync function getTaintTables(): Promise<Map<Language, import('../../taint/types.js').TaintTable>> {\n if (taintTablesCache) return taintTablesCache\n if (taintTablesPromise) return taintTablesPromise\n taintTablesPromise = loadAllTaintRules()\n .then((tables) => {\n taintTablesCache = tables\n return tables\n })\n .catch((error) => {\n taintTablesPromise = null\n throw error\n })\n return taintTablesPromise\n}\n\nexport function _resetTaintTablesCache(): void {\n taintTablesCache = null\n taintTablesPromise = null\n}\n\nexport interface CreateTaintCheckOptions {\n id: string\n nameKey: string\n descriptionKey: string\n category: 'security'\n sinkClass: SinkClass\n minTier: 'free' | 'pro'\n messageKey: string\n degradedMessageKey: string\n remediationKey: string\n attribution: string\n autofix?: boolean\n suggestionKey?: string\n}\n\nconst resolveCopy = getCopy as (key: string, ...args: string[]) => string\n\nexport function decideAutofix(\n flow: import('../../taint/types.js').TaintFlow,\n sinkClass: SinkClass,\n table: import('../../taint/types.js').TaintTable,\n autofix: boolean | undefined,\n suggestionText: string | undefined,\n): { fix?: Finding['fix']; suggestion?: string } {\n if (!autofix || !flow.sinkArg) {\n if (!autofix && suggestionText) {\n return { suggestion: suggestionText }\n }\n return {}\n }\n\n const globalSanitiser = table.sanitisers.find(\n (s) => s.sanitises.includes(sinkClass) && s['autofix-safety'] === 'global',\n )\n\n if (globalSanitiser) {\n if (flow.sinkArg.nodeType === 'identifier' && flow.sinkArg.isSingleArgument) {\n const replacement = `${globalSanitiser.id}(${flow.sinkArg.text})`\n if (isAutofixSafe(globalSanitiser.id, flow.sinkArg.text, table.language)) {\n return {\n fix: {\n range: flow.sinkArg.range,\n replacement,\n },\n }\n }\n }\n // Complex argument (template literal, concat, multi-arg): no fix, no suggestion\n return {}\n }\n\n if (suggestionText) {\n return { suggestion: suggestionText }\n }\n return {}\n}\n\nexport function createTaintCheck(options: CreateTaintCheckOptions): Check {\n const {\n id,\n nameKey,\n descriptionKey,\n category,\n sinkClass,\n minTier,\n messageKey,\n degradedMessageKey,\n remediationKey,\n attribution: _attribution,\n autofix,\n suggestionKey,\n } = options\n\n const name = resolveCopy(nameKey)\n const description = resolveCopy(descriptionKey)\n const remediation = resolveCopy(remediationKey)\n const suggestionText = suggestionKey ? resolveCopy(suggestionKey) : undefined\n\n return {\n id,\n name,\n description,\n category,\n severity: getTaintSeverity(sinkClass),\n minTier,\n async run(ctx: ScanContext): Promise<Finding[]> {\n const tables = await getTaintTables()\n\n const fileFindings = await runWithConcurrencyCollect(\n ctx.files,\n async (file) => {\n const fileFindings: Finding[] = []\n const table = tables.get(file.language)\n if (!table) {\n if (TAINTLESS_LANGUAGES.has(file.language)) {\n return fileFindings\n }\n fileFindings.push({\n id: `${id}:${file.relativePath}:degraded:${file.language}`,\n checkId: id,\n category,\n severity: 'info',\n message: resolveCopy(degradedMessageKey, file.relativePath, file.language),\n file: file.relativePath,\n confidence: TAINT_CONFIDENCE,\n remediation,\n properties: {\n analysisType: 'pattern',\n },\n })\n return fileFindings\n }\n\n // Use a dedicated parse for taint — sharing astCache with concurrent pattern\n // checks can invalidate tree-sitter nodes mid-BFS on large pro-tier scans.\n const result = await analyseFile(file, table, {\n taintCache: ctx.taintCache,\n })\n\n if (result.degraded) {\n fileFindings.push({\n id: `${id}:${file.relativePath}:degraded:${file.language}`,\n checkId: id,\n category,\n severity: 'info',\n message: resolveCopy(degradedMessageKey, file.relativePath, file.language),\n file: file.relativePath,\n confidence: TAINT_CONFIDENCE,\n remediation,\n properties: {\n analysisType: 'pattern',\n },\n })\n return fileFindings\n }\n\n for (const flow of result.flows) {\n if (flow.sinkClass === sinkClass) {\n const { fix, suggestion } = decideAutofix(flow, sinkClass, table, autofix, suggestionText)\n\n const finding: Finding = {\n id: `${id}:${file.relativePath}:${flow.flowPath[0]?.line ?? 0}:${flow.sinkId}:${flow.sourceId}`,\n checkId: id,\n category,\n severity: getTaintSeverity(sinkClass),\n message: resolveCopy(messageKey, flow.sourceId, flow.sinkId),\n file: file.relativePath,\n line: flow.flowPath.length > 0 ? flow.flowPath[flow.flowPath.length - 1]!.line : undefined,\n column: flow.flowPath.length > 0 ? flow.flowPath[flow.flowPath.length - 1]!.column : undefined,\n confidence: TAINT_CONFIDENCE,\n remediation,\n properties: {\n analysisType: 'pattern',\n taintSource: flow.sourceId,\n taintSink: flow.sinkId,\n flowPath: flow.flowPath,\n ...(suggestion ? { suggestion } : {}),\n },\n }\n\n if (fix) {\n finding.fix = fix\n }\n\n fileFindings.push(finding)\n }\n }\n\n return fileFindings\n },\n 4,\n )\n\n return fileFindings.flat()\n },\n }\n}\n","import { registry } from '../../registry/index.js'\nimport { createTaintCheck } from '../helpers/taint-check.js'\n\n/**\n * @attribution CWE-79\n */\nregistry.register(\n createTaintCheck({\n id: 'security.taint-xss',\n nameKey: 'checks.taint-xss.name',\n descriptionKey: 'checks.taint-xss.description',\n category: 'security',\n sinkClass: 'xss',\n minTier: 'pro',\n messageKey: 'checks.taint-xss.message',\n degradedMessageKey: 'checks.taint-xss.degraded',\n remediationKey: 'remediation.security.taint-xss',\n attribution: 'CWE-79',\n autofix: true,\n suggestionKey: 'checks.taint-xss.suggestion',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTaintCheck } from '../helpers/taint-check.js'\n\n/**\n * @attribution CWE-89\n */\nregistry.register(\n createTaintCheck({\n id: 'security.taint-sql-injection',\n nameKey: 'checks.taint-sql-injection.name',\n descriptionKey: 'checks.taint-sql-injection.description',\n category: 'security',\n sinkClass: 'sql-injection',\n minTier: 'pro',\n messageKey: 'checks.taint-sql-injection.message',\n degradedMessageKey: 'checks.taint-sql-injection.degraded',\n remediationKey: 'remediation.security.taint-sql-injection',\n attribution: 'CWE-89',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTaintCheck } from '../helpers/taint-check.js'\n\n/**\n * @attribution CWE-78\n */\nregistry.register(\n createTaintCheck({\n id: 'security.taint-command-injection',\n nameKey: 'checks.taint-command-injection.name',\n descriptionKey: 'checks.taint-command-injection.description',\n category: 'security',\n sinkClass: 'command-injection',\n minTier: 'pro',\n messageKey: 'checks.taint-command-injection.message',\n degradedMessageKey: 'checks.taint-command-injection.degraded',\n remediationKey: 'remediation.security.taint-command-injection',\n attribution: 'CWE-78',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTaintCheck } from '../helpers/taint-check.js'\n\n/**\n * @attribution CWE-22\n */\nregistry.register(\n createTaintCheck({\n id: 'security.taint-path-traversal',\n nameKey: 'checks.taint-path-traversal.name',\n descriptionKey: 'checks.taint-path-traversal.description',\n category: 'security',\n sinkClass: 'path-traversal',\n minTier: 'pro',\n messageKey: 'checks.taint-path-traversal.message',\n degradedMessageKey: 'checks.taint-path-traversal.degraded',\n remediationKey: 'remediation.security.taint-path-traversal',\n attribution: 'CWE-22',\n suggestionKey: 'checks.taint-path-traversal.suggestion',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTaintCheck } from '../helpers/taint-check.js'\n\n/**\n * @attribution CWE-601\n */\nregistry.register(\n createTaintCheck({\n id: 'security.taint-open-redirect',\n nameKey: 'checks.taint-open-redirect.name',\n descriptionKey: 'checks.taint-open-redirect.description',\n category: 'security',\n sinkClass: 'url-injection',\n minTier: 'pro',\n messageKey: 'checks.taint-open-redirect.message',\n degradedMessageKey: 'checks.taint-open-redirect.degraded',\n remediationKey: 'remediation.security.taint-open-redirect',\n attribution: 'CWE-601',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTaintCheck } from '../helpers/taint-check.js'\n\n/**\n * @attribution CWE-1321\n */\nregistry.register(\n createTaintCheck({\n id: 'security.taint-prototype-pollution',\n nameKey: 'checks.taint-prototype-pollution.name',\n descriptionKey: 'checks.taint-prototype-pollution.description',\n category: 'security',\n sinkClass: 'prototype-pollution',\n minTier: 'pro',\n messageKey: 'checks.taint-prototype-pollution.message',\n degradedMessageKey: 'checks.taint-prototype-pollution.degraded',\n remediationKey: 'remediation.security.taint-prototype-pollution',\n attribution: 'CWE-1321',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTaintCheck } from '../helpers/taint-check.js'\n\n/**\n * @attribution CWE-94\n */\nregistry.register(\n createTaintCheck({\n id: 'security.taint-code-execution',\n nameKey: 'checks.taint-code-execution.name',\n descriptionKey: 'checks.taint-code-execution.description',\n category: 'security',\n sinkClass: 'code-execution',\n minTier: 'pro',\n messageKey: 'checks.taint-code-execution.message',\n degradedMessageKey: 'checks.taint-code-execution.degraded',\n remediationKey: 'remediation.security.taint-code-execution',\n attribution: 'CWE-94',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport type { Language, SourceFile } from '../../types/source-file.js'\nimport { queryFile } from '../../ast/query.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { setAnalysisType } from '../helpers/finding-builder.js'\nimport { pickProjectAnchorFile } from '../pro-check-runner.js'\n\n/**\n * Surfaces state-changing handlers without visible CSRF protection at project scope.\n *\n * @attribution CWE-352\n */\n\nconst CHECK_ID = 'security.missing-csrf-protection'\n\nconst CSRF_MARKERS =\n /\\bcsrf\\b|xsrf|csrfmiddlewaretoken|double[\\s-]submit[\\s-]cookie|csurf\\b|cookie-parser.*csrf|protect_from_forgery|verify_authenticity_token/i\n\nconst QUERIES: Partial<Record<Language, string>> = {\n php: `\n(subscript_expression\n (variable_name\n (name) @sg)\n (#eq? @sg \"_POST\")) @match\n `,\n javascript: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(post|put|patch|delete)$\"))\n arguments: (arguments (string) @route)) @match\n `,\n typescript: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(post|put|patch|delete)$\"))\n arguments: (arguments (string) @route)) @match\n `,\n tsx: `\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(post|put|patch|delete)$\"))\n arguments: (arguments (string) @route)) @match\n `,\n python: `\n(decorator\n (call\n function: (attribute\n attribute: (identifier) @route_attr\n (#match? @route_attr \"^(route|post|put|patch|delete)$\"))\n arguments: (argument_list) @route)) @match\n `,\n ruby: `\n(call\n method: (identifier) @method\n (#match? @method \"^(post|put|patch|delete)$\")\n arguments: (argument_list (string) @route)) @match\n `,\n}\n\nconst resolveCopy = getCopy as (key: string, ...args: string[]) => string\n\nfunction isEligibleFile(file: SourceFile): boolean {\n return Boolean(QUERIES[file.language]) && !isMechanicalCheckExcludedPath(file.relativePath)\n}\n\nasync function hasProjectCsrfProtection(files: SourceFile[]): Promise<boolean> {\n for (const file of files) {\n const content = await file.content()\n if (CSRF_MARKERS.test(content)) return true\n }\n return false\n}\n\nconst check: Check = {\n id: CHECK_ID,\n name: resolveCopy('checks.missing-csrf-protection.name'),\n description: resolveCopy('checks.missing-csrf-protection.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const remediation = resolveCopy('remediation.security.missing-csrf-protection')\n const eligible = ctx.files.filter(isEligibleFile)\n if (eligible.length === 0) return []\n\n if (await hasProjectCsrfProtection(eligible)) {\n return []\n }\n\n const degradedLanguages = new Set<string>()\n let handlerCount = 0\n let exampleRoute = ''\n const _exampleLine = 1\n\n for (const file of eligible) {\n const query = QUERIES[file.language]!\n const result = await queryFile(file, query, ctx.astCache)\n\n if (result.degraded) {\n if (!degradedLanguages.has(file.language)) {\n degradedLanguages.add(file.language)\n }\n continue\n }\n\n if (result.matches.length > 0) {\n handlerCount += result.matches.length\n if (!exampleRoute) {\n const match = result.matches[0]!\n exampleRoute = match.captures.route?.trim() ?? 'state-changing handler'\n void match.startLine\n }\n }\n }\n\n const findings: Finding[] = []\n\n for (const lang of degradedLanguages) {\n const sample = eligible.find((f) => f.language === lang)\n if (!sample) continue\n findings.push({\n id: `${CHECK_ID}:${sample.relativePath}:degraded:${lang}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'info',\n message: resolveCopy('checks.missing-csrf-protection.degraded', sample.relativePath, lang),\n file: sample.relativePath,\n confidence: 'medium',\n remediation,\n })\n }\n\n if (handlerCount === 0) {\n return findings\n }\n\n const anchorPath = pickProjectAnchorFile(eligible)\n const anchor = eligible.find((f) => f.relativePath === anchorPath) ?? eligible[0]!\n\n const sameFileMarker = CSRF_MARKERS.test(await anchor.content())\n const confidence = sameFileMarker ? 'high' : 'medium'\n const message = resolveCopy(\n 'checks.missing-csrf-protection.message',\n handlerCount > 1\n ? `${handlerCount} state-changing handlers (e.g. ${exampleRoute})`\n : exampleRoute,\n )\n\n const finding: Finding = {\n id: `${CHECK_ID}:project:${anchor.relativePath}:1`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message,\n file: anchor.relativePath,\n line: 1,\n confidence,\n remediation,\n }\n setAnalysisType(finding, 'pattern')\n findings.push(finding)\n\n return findings\n },\n}\n\nregistry.register(check)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n\n/**\n * Surfaces user-controlled or predictable session identifier assignment.\n *\n * @attribution CWE-330\n */\n\nconst CHECK_ID = 'security.weak-session-id'\n\nconst QUERIES = {\n php: `\n(function_call_expression\n (name) @func\n (#eq? @func \"session_id\")\n arguments: (arguments\n (argument\n [\n (subscript_expression) @arg\n (binary_expression) @arg\n (variable_name) @arg\n ]))) @match\n `,\n javascript: `\n(assignment_expression\n left: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"req\")\n (#eq? @prop \"sessionID\"))\n right: (_) @arg) @match\n `,\n typescript: `\n(assignment_expression\n left: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"req\")\n (#eq? @prop \"sessionID\"))\n right: (_) @arg) @match\n `,\n tsx: `\n(assignment_expression\n left: (member_expression\n object: (identifier) @obj\n property: (property_identifier) @prop\n (#eq? @obj \"req\")\n (#eq? @prop \"sessionID\"))\n right: (_) @arg) @match\n `,\n python: `\n(assignment\n left: (subscript\n value: (identifier) @obj\n subscript: (string\n (string_content) @prop))\n right: (_) @arg\n (#eq? @obj \"session\")\n (#match? @prop \"^(sid|session_id|sessionid|id)$\")) @match\n\n(assignment\n left: (attribute\n object: (identifier) @obj\n attribute: (identifier) @prop)\n right: (_) @arg\n (#eq? @obj \"session\")\n (#match? @prop \"^(sid|session_id|sessionid)$\")) @match\n `,\n ruby: `\n(call\n method: (identifier) @method\n arguments: (argument_list (_) @arg)\n (#eq? @method \"session_id\")) @match\n\n(assignment\n left: (element_reference\n object: (identifier) @obj\n [(simple_symbol) (string)] @key)\n right: (_) @arg\n (#match? @obj \"^(session|cookies|request)$\")\n (#match? @key \"session_id|sessionid|sid|session\")) @match\n\n(assignment\n left: (element_reference\n object: (call\n receiver: (identifier) @obj\n method: (identifier) @method)\n [(simple_symbol) (string)] @key)\n right: (_) @arg\n (#match? @obj \"^(cookies)$\")\n (#match? @method \"^(signed|permanent)$\")\n (#match? @key \"session|id\")) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.weak-session-id.name',\n descriptionKey: 'checks.weak-session-id.description',\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.weak-session-id.message',\n degradedMessageKey: 'checks.weak-session-id.degraded',\n remediationKey: 'remediation.security.weak-session-id',\n matchFilter: (captures) => {\n const arg = captures.arg?.trim() ?? ''\n if (!arg) return false\n if (/^[\"']/.test(arg)) return false\n return true\n },\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Detects Active Record mass assignment using raw params hash.\n *\n * @attribution CWE-915\n */\n\nconst CHECK_ID = 'security.rails-mass-assignment'\n\nconst QUERIES = {\n ruby: `\n(call\n receiver: (constant) @model\n method: (identifier) @method\n (#match? @method \"^(create|update|new|update_attributes|assign_attributes)$\")\n arguments: (argument_list\n (element_reference\n object: (identifier) @source\n (#eq? @source \"params\")) @arg)) @match\n\n(call\n method: (identifier) @method\n (#match? @method \"^(update_attributes|assign_attributes)$\")\n arguments: (argument_list\n (element_reference\n object: (identifier) @source\n (#eq? @source \"params\")) @arg)) @match\n `,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.rails-mass-assignment.name',\n descriptionKey: 'checks.rails-mass-assignment.description',\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.rails-mass-assignment.message',\n degradedMessageKey: 'checks.rails-mass-assignment.degraded',\n remediationKey: 'remediation.security.rails-mass-assignment',\n }),\n)\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\n\n/**\n * Detects missing secure flags on Rails session cookie configuration.\n *\n * @attribution CWE-614\n */\n\nconst CHECK_ID = 'security.rails-insecure-session-config'\nconst REMEDIATION = getCopy('remediation.security.rails-insecure-session-config')\n\nconst SESSION_STORE_PATH = /config\\/initializers\\/session_store\\.rb$/\n\nfunction hasSecureFlag(content: string): boolean {\n return /\\bsecure:\\s*true\\b/.test(content)\n}\n\nfunction hasHttpOnlyFlag(content: string): boolean {\n return /\\bhttponly:\\s*true\\b/.test(content)\n}\n\nfunction hasSameSiteFlag(content: string): boolean {\n return /\\bsame_site:\\s*:(strict|lax)\\b/.test(content)\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.rails-insecure-session-config.name'),\n description: getCopy('checks.rails-insecure-session-config.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'ruby') continue\n if (!SESSION_STORE_PATH.test(file.relativePath)) continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n // Only inspect files that actually configure a session store\n if (!/session_store/.test(content)) continue\n\n const missing: string[] = []\n if (!hasSecureFlag(content)) missing.push('secure: true')\n if (!hasHttpOnlyFlag(content)) missing.push('httponly: true')\n if (!hasSameSiteFlag(content)) missing.push('same_site: :strict or :lax')\n\n if (missing.length > 0) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:1`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy(\n 'checks.rails-insecure-session-config.message',\n missing.join(', '),\n ),\n file: file.relativePath,\n line: 1,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport { createTreeSitterCheck } from '../create-tree-sitter-check.js'\n\n/**\n * Surfaces XML parsers configured with external entity expansion (XXE).\n *\n * @attribution CWE-611\n */\n\nconst CHECK_ID = 'security.xxe-surface'\n\nconst LIBXML_PARSE_QUERY = `\n(call_expression\n function: (member_expression\n property: (property_identifier) @method\n (#match? @method \"^(parseXml|parseXmlString)$\"))\n arguments: (arguments\n (_)\n (object\n (pair\n key: (property_identifier) @opt\n (#eq? @opt \"noent\")\n value: (true))))) @match\n`\n\nconst JAVA_XXE_QUERY = `\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#eq? @obj \"DocumentBuilderFactory\")\n (#eq? @method \"newInstance\")) @match\n\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#eq? @obj \"SAXParserFactory\")\n (#eq? @method \"newInstance\")) @match\n\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#eq? @obj \"XMLInputFactory\")\n (#eq? @method \"newInstance\")) @match\n\n(method_invocation\n object: (identifier) @obj\n name: (identifier) @method\n (#eq? @obj \"TransformerFactory\")\n (#eq? @method \"newInstance\")) @match\n`\n\nconst QUERIES = {\n javascript: LIBXML_PARSE_QUERY,\n typescript: LIBXML_PARSE_QUERY,\n tsx: LIBXML_PARSE_QUERY,\n java: JAVA_XXE_QUERY,\n}\n\nregistry.register(\n createTreeSitterCheck({\n id: CHECK_ID,\n nameKey: 'checks.xxe-surface.name',\n descriptionKey: 'checks.xxe-surface.description',\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n queries: QUERIES,\n messageKey: 'checks.xxe-surface.message',\n degradedMessageKey: 'checks.xxe-surface.degraded',\n remediationKey: 'remediation.security.xxe-surface',\n }),\n)\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /catch\\s*\\{\\s*\\}/,\n message: 'Empty catch block swallows errors',\n severity: 'high',\n },\n {\n regex: /catch\\s*\\(\\s*\\w+\\s*\\)\\s*\\{\\s*\\}/,\n message: 'Catch block with parameter but empty body swallows errors',\n severity: 'high',\n },\n {\n regex: /except\\s*:\\s*\\n\\s*(?:pass|return)\\b/,\n message: 'Bare except with pass/return swallows all errors',\n severity: 'high',\n multiline: true,\n },\n {\n regex: /except\\s+Exception\\s*:\\s*\\n\\s*pass\\b/,\n message: 'except Exception: pass swallows errors',\n severity: 'high',\n multiline: true,\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const header = 'Identify empty catch blocks and places where errors are silently swallowed. Look for catch blocks with empty bodies, catch blocks that only log at debug level, or catch blocks that do nothing with the error. In Python, flag except: pass, except Exception: pass, bare except clauses, or try blocks whose except bodies only contain `pass` or `return` without error handling.'\n const parts: string[] = [header]\n let length = header.length\n const budget = 14000\n\n for (const file of sourceFiles) {\n let content: string\n try {\n content = await file.content()\n } catch (err) {\n console.error(`[debug] Skipping ${file.relativePath}: unable to read content`, err)\n continue\n }\n const chunk = `--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`\n if (length + chunk.length + 2 > budget) {\n parts.push('... (additional files omitted due to token budget)')\n break\n }\n parts.push(chunk)\n length += chunk.length + 2\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.swallowed-catch',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.swallowed-catch.js'\nimport { getCopy } from '../../copy/index.js'\nimport { scanBashLines, lineMatch } from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-392\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'resilience.swallowed-catch',\n name: getCopy('checks.swallowed-catch.name'),\n description: getCopy('checks.swallowed-catch.description'),\n category: 'resilience',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'resilience.swallowed-catch',\n category: 'resilience',\n severity: 'high',\n message: () => 'Shell command suppresses failures with a no-op or discarded stderr.',\n remediation: getCopy('remediation.resilience.swallowed-catch'),\n }, (line, _content, index) => lineMatch(line, index, /\\|\\|\\s*(?:true|:)\\b|2>\\s*\\/dev\\/null/)),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /setTimeout\\s*\\([^)]*,\\s*\\d+\\s*\\)|time\\.sleep\\s*\\(\\s*\\d+\\s*\\)/,\n message: 'Fixed-delay retry found — verify retry logic uses exponential backoff with jitter',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const header = 'Identify retry logic that lacks exponential backoff or jitter. Look for loops or recursive functions that retry failed operations using fixed delays (e.g., setTimeout with a constant number, time.sleep(N) in Python, asyncio.sleep(N) without multiplier). In Python backends, flag tenacity @retry without wait=wait_exponential or similar, or manual retry loops using time.sleep() with static values.'\n const parts: string[] = [header]\n let length = header.length\n const budget = 14000\n\n for (const file of sourceFiles) {\n let content: string\n try {\n content = await file.content()\n } catch {\n continue\n }\n const chunk = `--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`\n if (length + chunk.length + 2 > budget) {\n parts.push('... (additional files omitted due to token budget)')\n break\n }\n parts.push(chunk)\n length += chunk.length + 2\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.no-backoff-jitter',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.no-backoff-jitter.js'\nimport { getCopy } from '../../copy/index.js'\n\n/**\n * @attribution CWE-770\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'resilience.no-backoff-jitter',\n name: getCopy('checks.no-backoff-jitter.name'),\n description: getCopy('checks.no-backoff-jitter.description'),\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\b(fetch|axios\\.|request\\(|http\\.request|requests\\.(?:get|post|put|patch|delete|head|options)\\b|aiohttp\\.\\w*[Ss]ession|httpx\\.(?:get|post|put|patch|delete|Client)\\b|urllib\\.request)\\b/i,\n message: 'External service call found — verify a circuit breaker is present',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const header = 'Identify external service calls that are not protected by a circuit breaker. Look for HTTP requests (fetch, axios, requests.get, aiohttp, httpx), API calls, or database connections that could fail cascadingly without isolation. In Python, look for requests.get/post/put/delete/patch, aiohttp.ClientSession, or httpx calls without circuit breaker wrappers (pybreaker, failsafe, tenacity).'\n const parts: string[] = [header]\n let length = header.length\n const budget = 14000\n\n for (const file of sourceFiles) {\n let content: string\n try {\n content = await file.content()\n } catch {\n continue\n }\n const chunk = `--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`\n if (length + chunk.length + 2 > budget) {\n parts.push('... (additional files omitted due to token budget)')\n break\n }\n parts.push(chunk)\n length += chunk.length + 2\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.no-circuit-breaker',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.no-circuit-breaker.js'\nimport { getCopy } from '../../copy/index.js'\n\n/**\n * @attribution CWE-1088\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'resilience.no-circuit-breaker',\n name: getCopy('checks.no-circuit-breaker.name'),\n description: getCopy('checks.no-circuit-breaker.description'),\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /while\\s*\\(\\s*(?:true|1)\\s*\\)|while\\s+True\\s*:/i,\n message: 'Infinite loop found — verify retry logic has a maximum attempt limit',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const header = 'Identify retry loops that have no maximum attempt limit. Look for while(true), for(;;), while True:, or recursion that retries indefinitely without a counter or termination condition. In Python, flag tenacity @retry without stop=stop_after_attempt or manual while True: loops wrapping external calls.'\n const parts: string[] = [header]\n let length = header.length\n const budget = 14000\n\n for (const file of sourceFiles) {\n let content: string\n try {\n content = await file.content()\n } catch {\n continue\n }\n const chunk = `--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`\n if (length + chunk.length + 2 > budget) {\n parts.push('... (additional files omitted due to token budget)')\n break\n }\n parts.push(chunk)\n length += chunk.length + 2\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'resilience.infinite-retry',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/resilience.infinite-retry.js'\nimport { getCopy } from '../../copy/index.js'\nimport { EXTERNAL_COMMAND_REGEX, lineMatch, scanBashLines } from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-835\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'resilience.infinite-retry',\n name: getCopy('checks.infinite-retry.name'),\n description: getCopy('checks.infinite-retry.description'),\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'resilience.infinite-retry',\n category: 'resilience',\n severity: 'medium',\n message: () => 'Shell retry loop can run forever while calling an external service.',\n remediation: getCopy('remediation.resilience.infinite-retry'),\n }, (line, content, index) => {\n if (!/\\bwhile\\s+(?:true|:)\\s*;?\\s*do\\b/.test(content)) return null\n if (/\\b(?:break|return|exit)\\b/.test(content)) return null\n return lineMatch(line, index, EXTERNAL_COMMAND_REGEX)\n }).then((findings) => findings.slice(0, 1)),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.1.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /console\\.(?:log|error|warn)\\b/,\n message: 'Unstructured logging detected — verify observability hooks are present',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Identify missing observability and monitoring hooks. Look for server startup code, route handlers, or background jobs that lack metrics, tracing, or health telemetry.',\n 'Flag projects that use only console.log or unstructured text logging instead of emitting metrics (Prometheus, DataDog, CloudWatch) or distributed traces.',\n 'In TypeScript/Node, verify OpenTelemetry SDK (@opentelemetry/sdk-node, instrumentation-http) or vendor SDKs are initialized in main.ts/server.ts — not only ad-hoc console logging in handlers.',\n 'In Python, flag services using print() or logging without metrics exporters (prometheus_client, opentelemetry, datadog).',\n ]\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'ops.missing-observability',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/ops.missing-observability.js'\nimport { getCopy } from '../../copy/index.js'\nimport {\n EXTERNAL_COMMAND_REGEX,\n lineMatch,\n scanBashLines,\n shellContentHasLogging,\n} from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-778\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'ops.missing-observability',\n name: getCopy('checks.missing-observability.name'),\n description: getCopy('checks.missing-observability.description'),\n category: 'ops',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'ops.missing-observability',\n category: 'ops',\n severity: 'medium',\n message: () => 'Shell script performs operational work without visible logging.',\n remediation: getCopy('remediation.ops.missing-observability'),\n }, (line, content, index) => {\n if (shellContentHasLogging(content)) return null\n return lineMatch(line, index, EXTERNAL_COMMAND_REGEX)\n }).then((findings) => findings.slice(0, 1)),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /secrets?[_-]?manager|vault|keychain|aws\\.secrets|azure\\.keyvault/i,\n message: 'Secret management integration detected — verify rotation automation',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const header = 'Identify hardcoded secret paths or configurations that impede secret rotation. Look for config files or source code that embed secret values directly, reference fixed file paths for secrets, or lack integration with a secret manager (e.g., AWS Secrets Manager, HashiCorp Vault, Azure Key Vault). In Python, flag settings.py or config.py with hardcoded secret values, os.environ.get(\"SECRET\") without rotation mechanism, or missing boto3/kms integration. Flag patterns where rotating a secret would require a code change or redeploy.'\n const parts: string[] = [header]\n let length = header.length\n const budget = 14000\n\n for (const file of sourceFiles) {\n let content: string\n try {\n content = await file.content()\n } catch {\n continue\n }\n const chunk = `--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`\n if (length + chunk.length + 2 > budget) {\n parts.push('... (additional files omitted due to token budget)')\n break\n }\n parts.push(chunk)\n length += chunk.length + 2\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'ops.secret-rotation-friction',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/ops.secret-rotation-friction.js'\nimport { getCopy } from '../../copy/index.js'\nimport { lineMatch, scanBashLines, SENSITIVE_NAME_REGEX } from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-798\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'ops.secret-rotation-friction',\n name: getCopy('checks.secret-rotation-friction.name'),\n description: getCopy('checks.secret-rotation-friction.description'),\n category: 'ops',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'ops.secret-rotation-friction',\n category: 'ops',\n severity: 'medium',\n message: () => 'Secret value or secret CLI flag is hardcoded in a shell command.',\n remediation: getCopy('remediation.ops.secret-rotation-friction'),\n }, (line, _content, index) => {\n if (!SENSITIVE_NAME_REGEX.test(line)) return null\n return lineMatch(line, index, /--[A-Za-z0-9-]*(?:key|secret|token|password)[A-Za-z0-9-]*(?:=|\\s+)\\S+|(?:^|\\s)[A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD)[A-Z0-9_]*=[\"'][^\"']{8,}[\"']/i)\n }),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /process\\.env\\.[A-Z_]+|os\\.(?:environ|getenv)\\(/,\n message: 'Environment variable usage detected — verify .env.example is kept in sync',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const header = 'Identify drift between .env.example (or equivalent template) and runtime environment variable usage. Look for source files that read process.env or os.environ/os.getenv variables without a matching entry in .env.example, or variables declared in .env.example that are never consumed in code. In Python projects, also check settings.py, config.py, and .env files for drift. Flag configuration drift that could cause deployment failures or expose unused secrets.'\n const parts: string[] = [header]\n let length = header.length\n const budget = 14000 // ~4000 tokens at 1 token ≈ 3.5 chars\n\n for (const file of sourceFiles) {\n let content: string\n try {\n content = await file.content()\n } catch {\n continue\n }\n const chunk = `--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`\n if (length + chunk.length + 2 > budget) {\n parts.push('... (additional files omitted due to token budget)')\n break\n }\n parts.push(chunk)\n length += chunk.length + 2\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'ops.env-drift',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/ops.env-drift.js'\nimport { getCopy } from '../../copy/index.js'\n\n/**\n * @attribution CWE-1188\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'ops.env-drift',\n name: getCopy('checks.env-drift.name'),\n description: getCopy('checks.env-drift.description'),\n category: 'ops',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\b(?:zip|zipcode|postal)\\b[\\s\\S]*?\\b(?:dob|birth|birthday|age)\\b|\\b(?:dob|birth|birthday|age)\\b[\\s\\S]*?\\b(?:zip|zipcode|postal)\\b/i,\n message: 'Composite PII fields (zip + date of birth) may enable re-identification',\n severity: 'medium',\n multiline: true,\n },\n {\n regex: /\\b(?:ssn|social_security|social)\\b[\\s\\S]*?\\b(?:address|street|city)\\b|\\b(?:address|street|city)\\b[\\s\\S]*?\\b(?:ssn|social_security|social)\\b/i,\n message: 'Composite PII fields (SSN + address) may enable re-identification',\n severity: 'medium',\n multiline: true,\n },\n {\n regex: /\\b(?:name|full_name)\\b[\\s\\S]*?\\b(?:email|phone|mobile)\\b[\\s\\S]*?\\b(?:dob|birth|zip|address)\\b/i,\n message: 'Multiple PII fields collected together may enable re-identification',\n severity: 'medium',\n multiline: true,\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check for composite PII fields that together enable re-identification. Look for data structures, API payloads, Django models, SQLAlchemy tables, or database schemas that collect multiple personally identifiable attributes (e.g. zip + date of birth, name + email + address, SSN + address) in one place. In Python, flag Django models or Pydantic schemas exposing multiple PII fields together, or ORM queries selecting multiple PII columns. Individual fields may be harmless; the risk is the combination.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'data-exposure.composite-pii',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/data-exposure.composite-pii.js'\nimport { getCopy } from '../../copy/index.js'\n\n/**\n * @attribution CWE-359\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'data-exposure.composite-pii',\n name: getCopy('checks.composite-pii.name'),\n description: getCopy('checks.composite-pii.description'),\n category: 'data-exposure',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\b(?:fingerprint|deviceId|visitorId|trackingId|correlationId|analyticsId)\\b/i,\n message: 'Derived identifier may link records across sessions or users',\n severity: 'medium',\n },\n {\n regex: /\\bhash\\s*\\(\\s*(?:email|phone|userId|id)\\s*\\)/i,\n message: 'Hashed identifier can still be used to correlate or link records',\n severity: 'medium',\n },\n {\n regex: /\\b(?:combine|merge|join)\\s*\\([^;]{0,200}\\b(?:email|phone|id|userId)\\b[^;]{0,200}\\b(?:email|phone|id|userId)\\b[^;]{0,200}\\)/i,\n message: 'Derived identifier created by combining user attributes may enable record linkage',\n severity: 'medium',\n multiline: true,\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check for derived identifiers that enable record linkage or re-identification. Look for device fingerprints, hashed emails, correlation IDs, tracking tokens, or any synthetic identifier derived from user data that can link records across sessions, devices, or datasets. In Python, flag hashlib.sha256 applied to email/phone, uuid generation from user data, or fingerprint generation in analytics/tracking code.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'data-exposure.derived-identifiers',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/data-exposure.derived-identifiers.js'\nimport { getCopy } from '../../copy/index.js'\n\n/**\n * @attribution CWE-359\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'data-exposure.derived-identifiers',\n name: getCopy('checks.derived-identifiers.name'),\n description: getCopy('checks.derived-identifiers.description'),\n category: 'data-exposure',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /console\\.log\\s*\\([\\s\\S]*?\\b(?:email|phone|ssn|password|token|secret|credit|card)\\b/i,\n message: 'Potentially sensitive data logged without redaction',\n severity: 'medium',\n },\n {\n regex: /logger\\.(?:info|debug|warn|error|log)\\s*\\([\\s\\S]*?\\b(?:email|phone|ssn|password|token|secret|credit|card)\\b/i,\n message: 'Potentially sensitive data logged without redaction',\n severity: 'medium',\n },\n {\n regex: /\\b(?:log|logs|logging)\\s*\\([\\s\\S]*?\\b(?:email|phone|ssn|password|token|secret|credit|card)\\b/i,\n message: 'Potentially sensitive data referenced in logging context without redaction',\n severity: 'medium',\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = ['Check for unredacted PII or sensitive data written to logs. Look for console.log, logger calls, logging.info/error, or logging middleware that include emails, phone numbers, SSNs, passwords, tokens, credit card numbers, or other sensitive identifiers. In Python, flag logging.info(user.email), print(request_data), or structlog calls with request/response bodies. Distinguish between arbitrary string values and actual identifiers — flag only when sensitive data is being logged.']\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 3000)}`)\n }\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'medium')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'data-exposure.unredacted-logs',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 4000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/data-exposure.unredacted-logs.js'\nimport { getCopy } from '../../copy/index.js'\nimport { lineMatch, scanBashLines, SENSITIVE_NAME_REGEX } from '../helpers/bash-patterns.js'\n\n/**\n * @attribution CWE-532\n * @tokenBudget 4000\n */\nregistry.register({\n id: 'data-exposure.unredacted-logs',\n name: getCopy('checks.unredacted-logs.name'),\n description: getCopy('checks.unredacted-logs.description'),\n category: 'data-exposure',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const [bashFindings, llmFindings] = await Promise.all([\n scanBashLines(ctx, {\n checkId: 'data-exposure.unredacted-logs',\n category: 'data-exposure',\n severity: 'medium',\n message: () => 'Shell logging statement writes a sensitive variable without redaction.',\n remediation: getCopy('remediation.data-exposure.unredacted-logs'),\n }, (line, _content, index) => {\n if (!/^\\s*(?:echo|printf|logger)\\b/.test(line)) return null\n if (!SENSITIVE_NAME_REGEX.test(line)) return null\n return lineMatch(line, index, /^\\s*(?:echo|printf|logger)\\b.*\\$(?:\\{)?[A-Z0-9_]*(?:PASSWORD|PASSWD|SECRET|TOKEN|API_KEY|ACCESS_KEY|PRIVATE_KEY|CREDENTIAL)[A-Z0-9_]*(?:\\})?/i)\n }),\n runLLMCheck(ctx, promptTemplate),\n ])\n return [...bashFindings, ...llmFindings]\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\n\n/**\n * Detects overly permissive database grants to PUBLIC or anonymous roles.\n *\n * @attribution CWE-732\n */\nconst CHECK_ID = 'security.permissive-grants'\n\nconst GRANT_PATTERN = /\\bgrant\\s+(?:all|all\\s+privileges|select|insert|update|delete|usage|execute)\\b[\\s\\S]*?\\bto\\s+(?:public|anon|anonymous|guest)\\b/gi\nconst ALTER_DEFAULT_PRIVILEGES_PATTERN = /\\balter\\s+default\\s+privileges\\b[\\s\\S]*?\\bgrant\\s+[\\s\\S]*?\\bto\\s+(?:public|anon|anonymous|guest)\\b/gi\n\nconst REMEDIATION = getCopy('remediation.security.permissive-grants')\n\nexport const permissiveGrantsCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.permissive-grants.name'),\n description: getCopy('checks.permissive-grants.description'),\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n\n let match = GRANT_PATTERN.exec(content)\n while (match) {\n const beforeMatch = content.slice(0, match.index)\n const lineNum = beforeMatch.split('\\n').length\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:1`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.permissive-grants.message', match[0].trim()),\n file: file.relativePath,\n line: lineNum,\n column: 1,\n remediation: REMEDIATION,\n })\n match = GRANT_PATTERN.exec(content)\n }\n GRANT_PATTERN.lastIndex = 0\n\n let altMatch = ALTER_DEFAULT_PRIVILEGES_PATTERN.exec(content)\n while (altMatch) {\n const beforeMatch = content.slice(0, altMatch.index)\n const lineNum = beforeMatch.split('\\n').length\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:1`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.permissive-grants.message', altMatch[0].trim()),\n file: file.relativePath,\n line: lineNum,\n column: 1,\n remediation: REMEDIATION,\n })\n altMatch = ALTER_DEFAULT_PRIVILEGES_PATTERN.exec(content)\n }\n ALTER_DEFAULT_PRIVILEGES_PATTERN.lastIndex = 0\n }\n\n return findings\n },\n}\n\nregistry.register(permissiveGrantsCheck)\n","export type SqlDialect = 'postgres' | 'supabase' | 'mysql' | 'sqlite' | 'unknown'\n\n/**\n * Classifies a SQL file's content deterministically based on keyword and function signals.\n */\nexport function classifySqlDialect(content: string): SqlDialect {\n const lower = content.toLowerCase()\n\n // Supabase is built on top of Postgres, so check Supabase signals first\n const hasSupabase =\n lower.includes('auth.uid()') ||\n lower.includes('auth.jwt()') ||\n lower.includes('storage.objects') ||\n lower.includes('storage.buckets') ||\n lower.includes('service_role') ||\n lower.includes('realtime') ||\n /\\b(anon|authenticated)\\b/.test(lower)\n\n if (hasSupabase) {\n return 'supabase'\n }\n\n // Postgres-specific signals\n const hasPostgres =\n lower.includes('enable row level security') ||\n lower.includes('force row level security') ||\n lower.includes('create policy') ||\n lower.includes('gen_random_uuid()') ||\n lower.includes('jsonb') ||\n lower.includes('current_setting(') ||\n lower.includes('alter default privileges') ||\n /\\b(uuid|varchar|integer|boolean|text|timestamp)\\b/.test(lower) && /\\b(create extension|create trigger|returning)\\b/.test(lower)\n\n if (hasPostgres) {\n return 'postgres'\n }\n\n // MySQL / MariaDB specific signals\n // Check for backticks (e.g. `table_name`) or specific keywords\n const hasMysql =\n /`\\w+`/.test(content) ||\n lower.includes('engine=') ||\n lower.includes('auto_increment') ||\n lower.includes('definer=') ||\n lower.includes('sql security')\n\n if (hasMysql) {\n return 'mysql'\n }\n\n // SQLite specific signals\n const hasSqlite =\n lower.includes('pragma') ||\n lower.includes('autoincrement') ||\n lower.includes('without rowid')\n\n if (hasSqlite) {\n return 'sqlite'\n }\n\n // Check generic PostgreSQL hints that didn't trigger RLS signals\n if (lower.includes('row level security') || lower.includes('create policy') || lower.includes('uuid')) {\n return 'postgres'\n }\n\n return 'unknown'\n}\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { queryFile } from '../../ast/query.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { classifySqlDialect } from '../helpers/sql-dialect.js'\nimport { normalizeIdentifier, isTautologyExpression } from '../helpers/sql-ast.js'\n\n/**\n * Deterministically checks SQL schemas for missing or weak Row-Level Security (RLS).\n *\n * @attribution CWE-284\n */\nconst CHECK_ID = 'security.sql-rls-static'\nconst REMEDIATION = getCopy('remediation.security.sql-rls-static')\n\ninterface SqlTable {\n name: string\n line: number\n columns: string[]\n isTenantTable: boolean\n}\n\nexport const sqlRlsStaticCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.sql-rls-static.name'),\n description: getCopy('checks.sql-rls-static.description'),\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n const dialect = classifySqlDialect(content)\n // Only PostgreSQL/Supabase support RLS checks\n if (dialect !== 'postgres' && dialect !== 'supabase') continue\n\n // Step 1: Query AST for CREATE TABLE statements and column definitions\n const tableQuery = '(create_table (object_reference name: (identifier) @table_name))'\n const tableResult = await queryFile(file, tableQuery, ctx.astCache)\n\n if (tableResult.degraded) continue\n\n const tables: SqlTable[] = []\n\n // For each table match, let's find the table name, line number, and columns.\n // Since tree-sitter will parse column definitions inside each table,\n // we can do a secondary query or simple text-based column scan for that table.\n for (const match of tableResult.matches) {\n const tableNameRaw = match.captures.table_name\n if (!tableNameRaw) continue\n const tableName = normalizeIdentifier(tableNameRaw)\n\n // Find columns for this table\n const columnQuery = `(create_table\n (object_reference name: (identifier) @t_name (#eq? @t_name \"${tableNameRaw}\"))\n (column_definitions (column_definition name: (identifier) @col_name)))`\n const columnResult = await queryFile(file, columnQuery, ctx.astCache)\n\n const columns = columnResult.matches.map(m => normalizeIdentifier(m.captures.col_name ?? ''))\n const tenantColumns = ['tenant_id', 'org_id', 'workspace_id', 'account_id', 'user_id']\n const isTenantTable = columns.some(c => tenantColumns.includes(c))\n\n tables.push({\n name: tableName,\n line: match.startLine,\n columns,\n isTenantTable,\n })\n }\n\n // Step 2: Use regex to find RLS enable/force patterns and policies\n\n // Enable RLS patterns: ALTER TABLE users ENABLE ROW LEVEL SECURITY\n const enableRlsRegex = /alter\\s+table\\s+(?:only\\s+)?(?:public\\.)?(\\w+|\"\\w+\"|`\\w+`|\\[\\w+\\])\\s+enable\\s+row\\s+level\\s+security/gi\n const enabledTables = new Set<string>()\n let rlsMatch = enableRlsRegex.exec(content)\n while (rlsMatch) {\n if (rlsMatch[1]) enabledTables.add(normalizeIdentifier(rlsMatch[1]))\n rlsMatch = enableRlsRegex.exec(content)\n }\n\n // Force RLS patterns: ALTER TABLE users FORCE ROW LEVEL SECURITY\n const forceRlsRegex = /alter\\s+table\\s+(?:only\\s+)?(?:public\\.)?(\\w+|\"\\w+\"|`\\w+`|\\[\\w+\\])\\s+force\\s+row\\s+level\\s+security/gi\n const forcedTables = new Set<string>()\n let forceMatch = forceRlsRegex.exec(content)\n while (forceMatch) {\n if (forceMatch[1]) forcedTables.add(normalizeIdentifier(forceMatch[1]))\n forceMatch = forceRlsRegex.exec(content)\n }\n\n // Step 3: Analyze tables\n for (const table of tables) {\n // We only enforce RLS on tenant/private tables.\n // Static lookup tables (countries, currencies) do not require RLS.\n if (!table.isTenantTable) continue\n\n const isRlsEnabled = enabledTables.has(table.name)\n if (!isRlsEnabled) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${table.line}:1:missing-rls`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.sql-rls-static.message', `Table \"${table.name}\" contains tenant columns but Row-Level Security is not enabled.`),\n file: file.relativePath,\n line: table.line,\n column: 1,\n remediation: REMEDIATION,\n })\n continue\n }\n\n const isRlsForced = forcedTables.has(table.name)\n if (!isRlsForced) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${table.line}:1:missing-force-rls`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.sql-rls-static.message', `Table \"${table.name}\" has Row-Level Security enabled but lacks FORCE ROW LEVEL SECURITY, creating tenant bypass risks for table owners.`),\n file: file.relativePath,\n line: table.line,\n column: 1,\n remediation: REMEDIATION,\n })\n }\n }\n\n // Step 4: Scan for unrestrictive policies using regex\n // Example: CREATE POLICY \"name\" ON table FOR ALL USING (true);\n const policyRegex = /create\\s+policy\\s+(\"?\\w+\"?)\\s+on\\s+(?:public\\.)?(\\w+|\"\\w+\")(?:\\s+for\\s+\\w+)?(?:\\s+to\\s+\\w+)?\\s+(?:using\\s*\\(([^)]+)\\)|with\\s+check\\s*\\(([^)]+)\\))/gi\n\n let policyMatch = policyRegex.exec(content)\n while (policyMatch) {\n const policyName = policyMatch[1] ?? 'unnamed'\n const tableName = normalizeIdentifier(policyMatch[2] ?? '')\n const usingExpr = policyMatch[3]?.trim()\n const checkExpr = policyMatch[4]?.trim()\n\n const isWeakUsing = usingExpr && isTautologyExpression(usingExpr)\n const isWeakCheck = checkExpr && isTautologyExpression(checkExpr)\n\n if (isWeakUsing || isWeakCheck) {\n const beforeMatch = content.slice(0, policyMatch.index)\n const lineNum = beforeMatch.split('\\n').length\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:1:weak-policy`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.sql-rls-static.message', `Policy ${policyName} on table \"${tableName}\" uses an unrestrictive tautology (like true or 1=1).`),\n file: file.relativePath,\n line: lineNum,\n column: 1,\n remediation: REMEDIATION,\n })\n }\n policyMatch = policyRegex.exec(content)\n }\n policyRegex.lastIndex = 0\n }\n\n return findings\n },\n}\n\nregistry.register(sqlRlsStaticCheck)\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { classifySqlDialect } from '../helpers/sql-dialect.js'\n\n/**\n * Detects PostgreSQL SECURITY DEFINER functions missing a locked search_path.\n *\n * @attribution CWE-732\n */\nconst CHECK_ID = 'security.sql-security-definer-search-path'\nconst REMEDIATION = getCopy('remediation.security.sql-security-definer-search-path')\n\nexport const sqlSecurityDefinerSearchPathCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.sql-security-definer-search-path.name'),\n description: getCopy('checks.sql-security-definer-search-path.description'),\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n const dialect = classifySqlDialect(content)\n if (dialect !== 'postgres' && dialect !== 'supabase') continue\n\n // Step 1: Detect CREATE FUNCTION ... SECURITY DEFINER statements\n // We parse the file statement by statement or line by line.\n // Since function definitions can span multiple lines, let's analyze blocks\n // starting with CREATE [OR REPLACE] FUNCTION.\n const functionBlockRegex = /create\\s+(?:or\\s+replace\\s+)?function\\s+(\\w+)\\b[\\s\\S]*?returns\\s+[\\s\\S]*?(?:language\\s+(\\w+))?[\\s\\S]*?(?=create\\s+(?:or\\s+replace\\s+)?function|$)/gi\n\n let match = functionBlockRegex.exec(content)\n while (match) {\n const block = match[0]\n const functionName = match[1] ?? 'unnamed'\n const lowerBlock = block.toLowerCase()\n\n if (lowerBlock.includes('security definer')) {\n const hasSearchPath = lowerBlock.includes('search_path') || lowerBlock.includes('set search_path')\n\n if (!hasSearchPath) {\n // Find the line number of this CREATE FUNCTION statement\n const beforeMatch = content.slice(0, match.index)\n const lineNum = beforeMatch.split('\\n').length\n\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:1`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'high',\n message: getCopy('checks.sql-security-definer-search-path.message', `Function \"${functionName}\" is defined as SECURITY DEFINER but is missing a locked search_path.`),\n file: file.relativePath,\n line: lineNum,\n column: 1,\n remediation: REMEDIATION,\n })\n }\n }\n\n match = functionBlockRegex.exec(content)\n }\n functionBlockRegex.lastIndex = 0\n }\n\n return findings\n },\n}\n\nregistry.register(sqlSecurityDefinerSearchPathCheck)\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\n\n/**\n * Warns if large migration scripts lack transaction guards (BEGIN/COMMIT).\n *\n * @attribution CWE-358\n */\nconst CHECK_ID = 'resilience.missing-transaction-guard'\nconst REMEDIATION = getCopy('remediation.resilience.missing-transaction-guard')\n\nconst MUTATION_KEYWORDS = [\n /\\binsert\\s+into\\b/i,\n /\\bupdate\\b/i,\n /\\bdelete\\s+from\\b/i,\n /\\balter\\s+table\\b/i,\n /\\bdrop\\s+(?:table|column|schema|database|index|policy|function)\\b/i,\n /\\btruncate\\b/i,\n /\\bcreate\\s+index\\b/i,\n /\\bcreate\\s+table\\s+\\w+\\s+as\\b/i,\n]\n\nexport const missingTransactionGuardCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.missing-transaction-guard.name'),\n description: getCopy('checks.missing-transaction-guard.description'),\n category: 'resilience',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n const lower = content.toLowerCase()\n\n // PostgreSQL does not allow CREATE INDEX CONCURRENTLY inside a transaction block.\n // If we see it, we skip warning since it cannot run inside BEGIN/COMMIT.\n if (lower.includes('concurrently')) {\n continue\n }\n\n // Check transaction boundaries\n const hasBegin = /\\b(?:begin|begin\\s+transaction|start\\s+transaction)\\b/i.test(lower)\n const hasCommit = /\\bcommit(?:\\s+transaction)?\\b/i.test(lower)\n\n if (hasBegin && hasCommit) {\n continue\n }\n\n // Count mutating statements\n let mutationCount = 0\n const lines = content.split('\\n')\n for (const line of lines) {\n if (MUTATION_KEYWORDS.some((kw) => kw.test(line))) {\n mutationCount++\n }\n }\n\n if (mutationCount > 5) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:1:1`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'medium',\n message: getCopy('checks.missing-transaction-guard.message'),\n file: file.relativePath,\n line: 1,\n column: 1,\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n },\n}\n\nregistry.register(missingTransactionGuardCheck)\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\n\n/**\n * Warns about risky destructive database migration operations like DROP/TRUNCATE.\n *\n * @attribution CWE-664\n */\nconst CHECK_ID = 'resilience.destructive-sql-migration'\nconst REMEDIATION = getCopy('remediation.resilience.destructive-sql-migration')\n\nexport const destructiveSqlMigrationCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.destructive-sql-migration.name'),\n description: getCopy('checks.destructive-sql-migration.description'),\n category: 'resilience',\n severity: 'high', // base severity\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n const content = await file.content()\n const lines = content.split('\\n')\n\n for (let lineNum = 0; lineNum < lines.length; lineNum++) {\n const line = lines[lineNum]!\n\n // 1. High risk operations: DROP TABLE/SCHEMA/DATABASE, TRUNCATE\n const highRiskRegex = /\\bdrop\\s+(?:table|schema|database)\\b/i\n const truncateRegex = /\\btruncate\\b/i\n\n const highMatch = highRiskRegex.exec(line)\n if (highMatch) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(highMatch.index ?? 0) + 1}:high`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'high',\n message: getCopy('checks.destructive-sql-migration.message', highMatch[0]),\n file: file.relativePath,\n line: lineNum + 1,\n column: (highMatch.index ?? 0) + 1,\n remediation: REMEDIATION,\n })\n }\n\n const truncateMatch = truncateRegex.exec(line)\n if (truncateMatch) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(truncateMatch.index ?? 0) + 1}:high`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'high',\n message: getCopy('checks.destructive-sql-migration.message', truncateMatch[0]),\n file: file.relativePath,\n line: lineNum + 1,\n column: (truncateMatch.index ?? 0) + 1,\n remediation: REMEDIATION,\n })\n }\n\n // 2. Medium risk operations: ALTER TABLE ... DROP COLUMN, DROP POLICY, DROP INDEX\n const dropColumnRegex = /\\balter\\s+table\\s+\\w+\\s+drop\\s+column\\b/i\n const dropPolicyRegex = /\\bdrop\\s+policy\\b/i\n const dropIndexRegex = /\\bdrop\\s+index\\b/i\n\n const colMatch = dropColumnRegex.exec(line)\n if (colMatch) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(colMatch.index ?? 0) + 1}:col`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'medium',\n message: getCopy('checks.destructive-sql-migration.message', colMatch[0]),\n file: file.relativePath,\n line: lineNum + 1,\n column: (colMatch.index ?? 0) + 1,\n remediation: REMEDIATION,\n })\n }\n\n const policyMatch = dropPolicyRegex.exec(line)\n if (policyMatch) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(policyMatch.index ?? 0) + 1}:policy`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'medium',\n message: getCopy('checks.destructive-sql-migration.message', policyMatch[0]),\n file: file.relativePath,\n line: lineNum + 1,\n column: (policyMatch.index ?? 0) + 1,\n remediation: REMEDIATION,\n })\n }\n\n const indexMatch = dropIndexRegex.exec(line)\n if (indexMatch) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum + 1}:${(indexMatch.index ?? 0) + 1}:index`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'medium',\n message: getCopy('checks.destructive-sql-migration.message', indexMatch[0]),\n file: file.relativePath,\n line: lineNum + 1,\n column: (indexMatch.index ?? 0) + 1,\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n return findings\n },\n}\n\nregistry.register(destructiveSqlMigrationCheck)\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { isTautologyExpression } from '../helpers/sql-ast.js'\n\n/**\n * Detects broad UPDATE or DELETE statements missing safe WHERE clauses.\n *\n * @attribution CWE-20\n */\nconst CHECK_ID = 'resilience.sql-broad-mutation'\nconst REMEDIATION = getCopy('remediation.resilience.sql-broad-mutation')\n\n/**\n * Splits SQL content into statements by semicolons,\n * respecting quoted string literals so semicolons inside\n * strings do not act as statement terminators.\n */\nfunction splitSqlStatements(content: string): string[] {\n const statements: string[] = []\n let current = ''\n let inString = false\n let stringChar: string | null = null\n\n for (let i = 0; i < content.length; i++) {\n const ch = content[i]!\n const next = content[i + 1]\n\n if (inString) {\n current += ch\n // SQL escapes quotes by doubling them: '' or \"\"\n if (ch === stringChar && next === stringChar) {\n current += next\n i++ // skip doubled quote\n } else if (ch === stringChar) {\n inString = false\n stringChar = null\n }\n } else {\n if (ch === \"'\" || ch === '\"') {\n inString = true\n stringChar = ch\n current += ch\n } else if (ch === ';') {\n statements.push(current)\n current = ''\n } else {\n current += ch\n }\n }\n }\n\n if (current.trim()) {\n statements.push(current)\n }\n\n return statements\n}\n\nexport const sqlBroadMutationCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.sql-broad-mutation.name'),\n description: getCopy('checks.sql-broad-mutation.description'),\n category: 'resilience',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n // Avoid seed/test files\n const lowerPath = file.relativePath.toLowerCase()\n if (\n lowerPath.includes('seed') ||\n lowerPath.includes('test') ||\n lowerPath.includes('fixture') ||\n lowerPath.includes('disposable')\n ) {\n continue\n }\n\n const content = await file.content()\n // Split the content into statements by semicolon,\n // respecting string literals so semicolons inside quotes\n // do not act as statement terminators.\n const statements = splitSqlStatements(content)\n\n let charOffset = 0\n for (const statement of statements) {\n const stmtTrimmed = statement.trim()\n if (!stmtTrimmed) {\n charOffset += statement.length + 1\n continue\n }\n\n const lowerStmt = stmtTrimmed.toLowerCase()\n const isUpdate = lowerStmt.startsWith('update')\n const isDelete = lowerStmt.startsWith('delete')\n\n if (isUpdate || isDelete) {\n const hasWhere = lowerStmt.includes('where')\n\n let isBroad = false\n let matchedKeyword = isUpdate ? 'UPDATE' : 'DELETE'\n\n if (!hasWhere) {\n isBroad = true\n } else {\n // Extract the where clause expression\n const whereIndex = lowerStmt.indexOf('where')\n const whereExpr = stmtTrimmed.slice(whereIndex + 5).trim()\n if (isTautologyExpression(whereExpr)) {\n isBroad = true\n matchedKeyword = `${matchedKeyword} WHERE ${whereExpr}`\n }\n }\n\n if (isBroad) {\n // Find line number of this statement in the original content\n const leadingWhitespace = statement.length - statement.trimStart().length\n const beforeStatement = content.slice(0, charOffset + leadingWhitespace)\n const lineNum = beforeStatement.split('\\n').length\n\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${lineNum}:1`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'high',\n message: getCopy('checks.sql-broad-mutation.message', matchedKeyword),\n file: file.relativePath,\n line: lineNum,\n column: 1,\n remediation: REMEDIATION,\n })\n }\n }\n\n charOffset += statement.length + 1\n }\n }\n\n return findings\n },\n}\n\nregistry.register(sqlBroadMutationCheck)\n","import { registry } from '../../registry/index.js'\nimport type { Check, ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\nimport { queryFile } from '../../ast/query.js'\nimport { isMechanicalCheckExcludedPath } from '../../config/path-exclusions.js'\nimport { normalizeIdentifier } from '../helpers/sql-ast.js'\n\n/**\n * Detects sensitive columns (SSNs, cards, passwords) stored as plain text.\n *\n * @attribution CWE-312\n */\nconst CHECK_ID = 'data-exposure.unprotected-sensitive-sql-columns'\nconst REMEDIATION = getCopy('remediation.data-exposure.unprotected-sensitive-sql-columns')\n\nconst SENSITIVE_KEYWORDS = [\n 'ssn',\n 'social_security',\n 'tax_id',\n 'national_id',\n 'credit_card',\n 'card_number',\n 'cvv',\n 'cvc',\n 'secret',\n 'api_key',\n 'token',\n 'refresh_token',\n 'password',\n]\n\nconst PLAIN_TEXT_TYPES = [\n 'text',\n 'varchar',\n 'char',\n 'character',\n 'string',\n]\n\nconst PROTECTED_SUFFIXES = [\n '_hash',\n '_digest',\n '_encrypted',\n '_ciphertext',\n '_key_id',\n]\n\nexport const unprotectedSensitiveSqlColumnsCheck: Check = {\n id: CHECK_ID,\n name: getCopy('checks.unprotected-sensitive-sql-columns.name'),\n description: getCopy('checks.unprotected-sensitive-sql-columns.description'),\n category: 'data-exposure',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (file.language !== 'sql') continue\n if (isMechanicalCheckExcludedPath(file.relativePath)) continue\n\n // Step 1: Query AST for column definitions and types\n const query = `(column_definition\n name: (identifier) @col_name\n type: [\n (identifier) @col_type\n (keyword_text) @col_type\n ])`\n\n const result = await queryFile(file, query, ctx.astCache)\n if (result.degraded) continue\n\n for (const match of result.matches) {\n const colNameRaw = match.captures.col_name\n const colTypeRaw = match.captures.col_type\n if (!colNameRaw || !colTypeRaw) continue\n\n const colName = normalizeIdentifier(colNameRaw)\n const colType = normalizeIdentifier(colTypeRaw)\n\n const isSensitive = SENSITIVE_KEYWORDS.some((kw) => colName.includes(kw))\n const isPlainText = PLAIN_TEXT_TYPES.some((pt) => colType.includes(pt))\n const isProtected = PROTECTED_SUFFIXES.some((suf) => colName.endsWith(suf))\n\n if (isSensitive && isPlainText && !isProtected) {\n findings.push({\n id: `${CHECK_ID}:${file.relativePath}:${match.startLine}:${match.startColumn ?? 1}`,\n checkId: CHECK_ID,\n category: 'data-exposure',\n severity: 'high',\n message: getCopy('checks.unprotected-sensitive-sql-columns.message', `Column \"${colNameRaw}\" with type \"${colTypeRaw}\"`),\n file: file.relativePath,\n line: match.startLine,\n column: match.startColumn ?? 1,\n remediation: REMEDIATION,\n })\n }\n }\n }\n\n return findings\n },\n}\n\nregistry.register(unprotectedSensitiveSqlColumnsCheck)\n","import type { SourceFile } from '../types/source-file.js'\nimport type { Finding } from '../types/finding.js'\nimport type { FallbackPattern, PromptTemplate } from './types.js'\nimport { parseLLMResponse } from './parse-response.js'\n\nexport const PROMPT_VERSION = '1.0.0'\n\nconst fallbackPatterns: FallbackPattern[] = [\n {\n regex: /\\bcreate\\s+policy\\s+(\"?\\w+\"?)\\s+on\\s+(?:\\w+|\"\\w+\")\\s+[\\s\\S]*?(?:using\\s*\\((?:true|1\\s*=\\s*1)\\)|with\\s+check\\s*\\((?:true|1\\s*=\\s*1)\\))/i,\n message: 'RLS policy uses an unrestrictive tautology (like true or 1=1)',\n severity: 'high',\n multiline: true,\n },\n {\n regex: /\\balter\\s+table\\s+(?:\\w+|\"\\w+\")\\s+enable\\s+row\\s+level\\s+security\\b/i,\n message: 'Row-Level Security is not enabled on tenant tables.',\n severity: 'high',\n absenceBased: true,\n },\n]\n\nasync function buildPrompt(sourceFiles: SourceFile[]): Promise<string> {\n const parts: string[] = [\n 'Check for missing or weak Row-Level Security (RLS) on PostgreSQL/Supabase tables containing private user or tenant data. ' +\n 'Identify tables representing private tenant resources (look for columns like tenant_id, org_id, workspace_id, account_id, user_id). ' +\n 'For each private table, verify if Row-Level Security is enabled via ALTER TABLE ... ENABLE ROW LEVEL SECURITY, and if RLS is forced ' +\n 'via FORCE ROW LEVEL SECURITY. Also inspect defined policies to ensure they contain restrictive predicates filtering by the tenant/user boundary. ' +\n 'Flag policies using unrestrictive expressions like true, 1=1, or TRUE, or write policies (INSERT, UPDATE, ALL) missing WITH CHECK.',\n ]\n\n for (const file of sourceFiles) {\n const content = await file.content()\n parts.push(`--- ${file.relativePath} ---\\n${content.slice(0, 4000)}`)\n }\n\n return parts.join('\\n\\n')\n}\n\nfunction parseResponse(response: string, checkId: string): Finding[] {\n return parseLLMResponse(response, checkId, 'high')\n}\n\nexport const promptTemplate: PromptTemplate = {\n checkId: 'security.sql-missing-rls',\n promptVersion: PROMPT_VERSION,\n tokenBudget: 5000,\n buildPrompt,\n parseResponse,\n fallbackPatterns,\n}\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { runLLMCheck } from '../pro-check-runner.js'\nimport { promptTemplate } from '../../prompts/security.sql-missing-rls.js'\nimport { getCopy } from '../../copy/index.js'\n\n/**\n * Overly permissive RLS or missing RLS check on PostgreSQL/Supabase tables.\n *\n * @attribution CWE-284\n * @tokenBudget 5000\n */\nregistry.register({\n id: 'security.sql-missing-rls',\n name: getCopy('checks.sql-missing-rls.name'),\n description: getCopy('checks.sql-missing-rls.description'),\n category: 'security',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n return runLLMCheck(ctx, promptTemplate)\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { queryFile } from '../../ast/query.js'\nimport { getCopy } from '../../copy/index.js'\nimport { setAnalysisType } from '../helpers/finding-builder.js'\n\n/**\n * Surfaces usage of unsafe blocks that lack a preceding safety contract comment.\n *\n * @attribution CWE-758\n */\n\nconst CHECK_ID = 'security.rust-unsafe-blocks'\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.rust-unsafe-blocks.name'),\n description: getCopy('checks.rust-unsafe-blocks.description'),\n category: 'security',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const rustFiles = ctx.files.filter((file) => file.language === 'rust')\n if (rustFiles.length === 0) return []\n\n const findings: Finding[] = []\n const remediation = getCopy('remediation.security.rust-unsafe-blocks')\n\n for (const file of rustFiles) {\n let code: string\n try {\n code = await file.content()\n } catch {\n continue\n }\n const lines = code.split('\\n')\n \n const queryResult = await queryFile(file, '(unsafe_block) @unsafe', ctx.astCache)\n if (queryResult.degraded) continue\n\n for (let i = 0; i < queryResult.matches.length; i++) {\n const match = queryResult.matches[i]\n if (!match) continue\n const startRow = match.startLine - 1\n \n let foundSafety = false\n \n // Check 1: Inline comment on the unsafe line itself\n const lineAtStart = lines[startRow]\n if (lineAtStart && /SAFETY\\s*:/i.test(lineAtStart)) {\n foundSafety = true\n }\n \n // Check 2: First line inside block\n if (!foundSafety && startRow + 1 < lines.length) {\n const lineNext = lines[startRow + 1]\n if (lineNext && /SAFETY\\s*:/i.test(lineNext)) {\n foundSafety = true\n }\n }\n \n // Check 3: Preceding comments (allow up to 3 non-comment lines between comment and unsafe)\n if (!foundSafety) {\n let checkRow = startRow - 1\n let nonCommentCount = 0\n while (checkRow >= 0 && nonCommentCount <= 3) {\n const rawLine = lines[checkRow]\n if (rawLine === undefined) {\n checkRow--\n continue\n }\n const line = rawLine.trim()\n if (line === '') {\n checkRow--\n continue\n }\n \n if (line.startsWith('//')) {\n if (/SAFETY\\s*:/i.test(line)) {\n foundSafety = true\n break\n }\n checkRow--\n continue\n }\n \n if (line.endsWith('*/')) {\n let blockRow = checkRow\n let blockContent = ''\n while (blockRow >= 0) {\n const rawBl = lines[blockRow]\n if (rawBl === undefined) {\n blockRow--\n continue\n }\n const bl = rawBl.trim()\n blockContent = bl + '\\n' + blockContent\n if (bl.startsWith('/*')) {\n break\n }\n blockRow--\n }\n if (/SAFETY\\s*:/i.test(blockContent)) {\n foundSafety = true\n break\n }\n checkRow = blockRow - 1\n continue\n }\n \n nonCommentCount++\n checkRow--\n }\n }\n \n if (!foundSafety) {\n const finding: Finding = {\n id: `${CHECK_ID}:${file.relativePath}:${match.startLine}:${match.startColumn ?? 0}:${i}`,\n checkId: CHECK_ID,\n category: 'security',\n severity: 'medium',\n message: getCopy('checks.rust-unsafe-blocks.message', match.nodeText),\n file: file.relativePath,\n line: match.startLine,\n column: match.startColumn,\n confidence: 'high',\n remediation,\n }\n setAnalysisType(finding, 'pattern')\n findings.push(finding)\n }\n }\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport type { Node as TSNode } from 'web-tree-sitter'\nimport { queryFile } from '../../ast/query.js'\nimport { getCopy } from '../../copy/index.js'\nimport { setAnalysisType } from '../helpers/finding-builder.js'\n\n/**\n * Surfaces unwrap, expect, or panic calls inside async Axum/Actix endpoint routing handlers.\n *\n * @attribution CWE-248\n */\n\nconst CHECK_ID = 'resilience.rust-handler-panics'\n\nconst RUST_QUERY = `\n(call_expression\n function: (field_expression\n value: (_)\n field: (field_identifier) @method\n (#match? @method \"^(unwrap|expect)$\"))) @match\n\n(macro_invocation\n macro: [(identifier) (scoped_identifier)] @name\n (#eq? @name \"panic\")) @match\n`\n\nfunction hasAsyncModifier(node: TSNode): boolean {\n for (let i = 0; i < node.childCount; i++) {\n const child = node.child(i)\n if (child && child.type === 'async') return true\n if (child && child.type === 'function_modifiers') {\n for (let j = 0; j < child.childCount; j++) {\n const modChild = child.child(j)\n if (modChild && modChild.type === 'async') return true\n }\n }\n }\n return false\n}\n\nregistry.register({\n id: CHECK_ID,\n name: getCopy('checks.rust-handler-panics.name'),\n description: getCopy('checks.rust-handler-panics.description'),\n category: 'resilience',\n severity: 'high',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const rustFiles = ctx.files.filter((file) => file.language === 'rust')\n if (rustFiles.length === 0) return []\n\n const findings: Finding[] = []\n const remediation = getCopy('remediation.resilience.rust-handler-panics')\n\n for (const file of rustFiles) {\n let code: string\n try {\n code = await file.content()\n } catch {\n continue\n }\n \n const isWebFile = /axum|actix/i.test(code)\n if (!isWebFile) continue\n\n const queryResult = await queryFile(file, RUST_QUERY, ctx.astCache)\n if (queryResult.degraded) continue\n\n const cacheKey = `${file.path}::${file.language}`\n const parsePromise = ctx.astCache?.get(cacheKey)\n if (!parsePromise) continue\n const parsed = await parsePromise\n if (!parsed || !parsed.tree) continue\n\n const parentMap = new Map<number, TSNode>()\n function walk(n: TSNode) {\n for (let i = 0; i < n.namedChildCount; i++) {\n const c = n.namedChild(i)\n if (c) {\n parentMap.set(c.id, n)\n walk(c)\n }\n }\n }\n walk(parsed.tree.rootNode)\n\n function findNodeAt(root: TSNode, line: number, column: number): TSNode | null {\n if (root.startPosition.row + 1 === line && root.startPosition.column + 1 === column) {\n return root\n }\n for (let i = 0; i < root.namedChildCount; i++) {\n const found = findNodeAt(root.namedChild(i)!, line, column)\n if (found) return found\n }\n return null\n }\n\n for (let i = 0; i < queryResult.matches.length; i++) {\n const match = queryResult.matches[i]\n if (!match) continue\n const node = findNodeAt(parsed.tree.rootNode, match.startLine, match.startColumn ?? 0)\n if (!node) continue\n\n let curr = node\n let enclosingFunction: TSNode | null = null\n while (curr) {\n if (curr.type === 'function_item') {\n enclosingFunction = curr\n break\n }\n const next = parentMap.get(curr.id)\n if (!next) break\n curr = next\n }\n\n if (enclosingFunction) {\n const isAsync = hasAsyncModifier(enclosingFunction)\n if (isAsync) {\n const finding: Finding = {\n id: `${CHECK_ID}:${file.relativePath}:${match.startLine}:${match.startColumn ?? 0}:${i}`,\n checkId: CHECK_ID,\n category: 'resilience',\n severity: 'high',\n message: getCopy('checks.rust-handler-panics.message', match.nodeText),\n file: file.relativePath,\n line: match.startLine,\n column: match.startColumn,\n confidence: 'high',\n remediation,\n }\n setAnalysisType(finding, 'pattern')\n findings.push(finding)\n }\n }\n }\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { getCopy } from '../../copy/index.js'\n\nconst REMEDIATION = getCopy('remediation.dependencies.cargo-unpinned-versions')\n\nfunction isBareSemver(version: string): boolean {\n // e.g. \"0.1\", \"1\", \"0.12\" — no patch number\n const trimmed = version.trim()\n if (trimmed === '*' || trimmed === 'latest') return true\n // Match simple semver without patch: digits.digits (no trailing .digits)\n if (/^\\d+\\.\\d+$/.test(trimmed)) return true\n // Single major version like \"1\"\n if (/^\\d+$/.test(trimmed)) return true\n return false\n}\n\nfunction isUnpinnedInlineTable(line: string): { name: string; reason: string } | null {\n const tableMatch = line.match(/^\\s*([A-Za-z0-9_-]+)\\s*=\\s*\\{(.+)\\}\\s*$/)\n if (!tableMatch) return null\n\n const name = tableMatch[1]!\n const body = tableMatch[2]!\n\n // Git dependency without rev, tag, or branch\n if (/git\\s*=/.test(body)) {\n const hasPin = /\\b(rev|tag|branch)\\s*=/.test(body)\n if (!hasPin) {\n return { name, reason: 'git dependency without rev, tag, or branch' }\n }\n return null\n }\n\n // Path-only dependency without version\n if (/path\\s*=/.test(body) && !/version\\s*=/.test(body)) {\n return { name, reason: 'path dependency without version' }\n }\n\n // Inline table with version field — check if version is bare semver\n const versionMatch = body.match(/version\\s*=\\s*\"([^\"]+)\"/)\n if (versionMatch) {\n const version = versionMatch[1]!\n if (isBareSemver(version)) {\n return { name, reason: `version \"${version}\" is unpinned` }\n }\n }\n\n return null\n}\n\nfunction isUnpinnedSimple(line: string): { name: string; reason: string } | null {\n // Simple \"dep = \\\"version\\\"\" format\n const simpleMatch = line.match(/^\\s*([A-Za-z0-9_-]+)\\s*=\\s*\"([^\"]+)\"\\s*$/)\n if (!simpleMatch) return null\n\n const name = simpleMatch[1]!\n const version = simpleMatch[2]!\n\n if (version === '*' || version === 'latest') {\n return { name, reason: `version \"${version}\" is completely unpinned` }\n }\n\n if (isBareSemver(version)) {\n return { name, reason: `version \"${version}\" is bare semver without patch` }\n }\n\n return null\n}\n\nfunction parseCargoToml(content: string, filePath: string): Finding[] {\n const findings: Finding[] = []\n const lines = content.split('\\n')\n let inDepSection = false\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n const sectionMatch = line.match(/^\\s*\\[(dependencies|dev-dependencies|build-dependencies)\\]\\s*$/)\n if (sectionMatch) {\n inDepSection = true\n continue\n }\n\n // Exit dep section on any new section header\n if (inDepSection && /^\\s*\\[/.test(line)) {\n inDepSection = false\n continue\n }\n\n if (!inDepSection) continue\n if (!line.trim() || line.trim().startsWith('#')) continue\n\n // Handle multiline inline tables (simple approach: if line has { but no }, accumulate)\n let currentLine = line\n const originalLineIndex = i\n if (currentLine.includes('{') && !currentLine.includes('}')) {\n let j = i + 1\n while (j < lines.length && !lines[j]!.includes('}')) {\n currentLine += ' ' + lines[j]!.trim()\n j++\n }\n if (j < lines.length) {\n currentLine += ' ' + lines[j]!.trim()\n i = j\n }\n }\n\n let match = isUnpinnedInlineTable(currentLine)\n if (!match) {\n match = isUnpinnedSimple(currentLine)\n }\n\n if (match) {\n findings.push({\n id: `cargo-unpinned-${findings.length + 1}`,\n checkId: 'dependencies.cargo-unpinned-versions',\n category: 'dependencies',\n severity: 'medium',\n message: `Cargo dependency \"${match.name}\" uses an unpinned version (${match.reason}). Pin to an exact version for reproducible builds.`,\n file: filePath,\n line: originalLineIndex + 1,\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n}\n\nregistry.register({\n id: 'dependencies.cargo-unpinned-versions',\n name: 'Unpinned Cargo dependency versions',\n description: 'Cargo.toml dependency with wildcard, bare semver, or unpinned git reference. Pin to an exact version.',\n category: 'dependencies',\n severity: 'medium',\n minTier: 'pro',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const findings: Finding[] = []\n\n for (const file of ctx.files) {\n if (!file.relativePath.endsWith('Cargo.toml')) continue\n const content = await file.content()\n findings.push(...parseCargoToml(content, file.relativePath))\n }\n\n return findings\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { execSync } from 'child_process'\nimport { join } from 'path'\nimport { getCopy } from '../../copy/index.js'\n\nconst REMEDIATION = getCopy('remediation.dependencies.cargo-known-cves')\n\ninterface CargoAuditAdvisory {\n id: string\n title: string\n url?: string\n}\n\ninterface CargoAuditVulnerability {\n advisory: CargoAuditAdvisory\n versions: { patched: string[]; unaffected: string[] }\n package: { name: string; version: string }\n}\n\ninterface CargoAuditOutput {\n vulnerabilities?: {\n list?: CargoAuditVulnerability[]\n }\n warnings?: {\n yanked?: Array<{ package: { name: string; version: string } }>\n }\n}\n\nfunction mapSeverity(_sev: string): Finding['severity'] {\n // cargo audit JSON doesn't include a severity field on advisories;\n // default to high since these are published security advisories.\n return 'high'\n}\n\nconst auditUnavailable = (): Finding[] => [{\n id: 'cargo-known-cves-audit-unavailable',\n checkId: 'dependencies.cargo-known-cves',\n category: 'dependencies',\n severity: 'medium',\n message: 'Could not execute or parse cargo audit output; CVE scan may be incomplete.',\n confidence: 'high',\n remediation: REMEDIATION,\n}]\n\nfunction parseCargoAudit(output: string, _lockfilePath: string): Finding[] {\n const data: CargoAuditOutput = JSON.parse(output)\n const findings: Finding[] = []\n\n if (data.vulnerabilities?.list) {\n for (const vuln of data.vulnerabilities.list) {\n findings.push({\n id: `cargo-cve-${vuln.advisory.id}`,\n checkId: 'dependencies.cargo-known-cves',\n category: 'dependencies',\n severity: mapSeverity('high'),\n message: `Known CVE in ${vuln.package.name}@${vuln.package.version}: ${vuln.advisory.title} (${vuln.advisory.id})`,\n lockfiles: ['Cargo.lock'],\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n }\n\n return findings\n}\n\nregistry.register({\n id: 'dependencies.cargo-known-cves',\n name: 'Known CVEs in Cargo dependencies',\n description: 'Cargo.lock dependencies have known security advisories from the RustSec database.',\n category: 'dependencies',\n severity: 'high',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const lockfilePath = join(ctx.targetDir, 'Cargo.lock')\n try {\n await import('fs').then((m) => m.promises.access(lockfilePath))\n } catch {\n // No Cargo.lock — skip silently\n return []\n }\n\n try {\n const output = execSync('cargo audit --json', {\n cwd: ctx.targetDir,\n stdio: 'pipe',\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n timeout: 30_000,\n })\n return parseCargoAudit(output, 'Cargo.lock')\n } catch (err) {\n const output = (err as { stdout?: string }).stdout\n if (output) {\n try {\n return parseCargoAudit(output, 'Cargo.lock')\n } catch {\n return auditUnavailable()\n }\n }\n return auditUnavailable()\n }\n },\n})\n","import { registry } from '../../registry/index.js'\nimport type { ScanContext } from '../../types/check.js'\nimport type { Finding } from '../../types/finding.js'\nimport { execFile } from 'child_process'\nimport { promisify } from 'util'\nimport { join } from 'path'\nimport { access } from 'fs/promises'\nimport { getCopy } from '../../copy/index.js'\n\n\nconst REMEDIATION = getCopy('remediation.dependencies.bundler-known-cves')\n\ninterface BundlerAuditAdvisory {\n id?: string\n cve?: string\n title?: string\n criticality?: string\n}\n\ninterface BundlerAuditVulnerability {\n name?: string\n version?: string\n gem?: { name?: string; version?: string }\n advisory?: BundlerAuditAdvisory\n}\n\ninterface BundlerAuditOutput {\n vulnerabilities?: BundlerAuditVulnerability[]\n}\n\nfunction isSevereEnough(sev: string): boolean {\n const order = ['info', 'low', 'moderate', 'medium', 'high', 'critical', 'unknown']\n const normalized = sev.toLowerCase()\n if (normalized === 'unknown') return true\n return order.indexOf(normalized) >= order.indexOf('moderate')\n}\n\nfunction mapSeverity(sev: string): Finding['severity'] {\n switch (sev.toLowerCase()) {\n case 'critical':\n return 'critical'\n case 'high':\n return 'high'\n case 'medium':\n case 'moderate':\n return 'medium'\n default:\n return 'low'\n }\n}\n\nconst auditUnavailable = (err?: { code?: string; message?: string }): Finding[] => {\n const isMissing = err && (err.code === 'ENOENT' || err.message?.includes('ENOENT'))\n return [{\n id: 'bundler-known-cves-audit-unavailable',\n checkId: 'dependencies.bundler-known-cves',\n category: 'dependencies',\n severity: isMissing ? 'low' : 'medium',\n message: isMissing\n ? 'bundler-audit not installed; Ruby CVE scan not performed'\n : 'Could not execute or parse bundle audit output; Ruby CVE scan may be incomplete.',\n confidence: 'high',\n remediation: REMEDIATION,\n }]\n}\n\nexport function parseBundlerAudit(output: string, lockfilePath: string): Finding[] {\n const data: BundlerAuditOutput = JSON.parse(output)\n const findings: Finding[] = []\n const vulns = data.vulnerabilities ?? []\n\n for (const vuln of vulns) {\n const gemName = vuln.gem?.name ?? vuln.name ?? 'unknown'\n const gemVersion = vuln.gem?.version ?? vuln.version ?? ''\n const advisory = vuln.advisory\n const criticality = advisory?.criticality ?? 'high'\n if (!isSevereEnough(criticality)) continue\n\n const advisoryId = advisory?.cve ?? advisory?.id ?? 'unknown'\n const title = advisory?.title ?? 'Security advisory'\n findings.push({\n id: `bundler-cve-${advisoryId}-${gemName}`,\n checkId: 'dependencies.bundler-known-cves',\n category: 'dependencies',\n severity: mapSeverity(criticality),\n message: `Known CVE in ${gemName}${gemVersion ? `@${gemVersion}` : ''}: ${title} (${advisoryId})`,\n lockfiles: [lockfilePath],\n confidence: 'high',\n remediation: REMEDIATION,\n })\n }\n\n return findings\n}\n\nregistry.register({\n id: 'dependencies.bundler-known-cves',\n name: 'Known CVEs in Bundler dependencies',\n description: 'Gemfile.lock dependencies have known security advisories from bundler-audit.',\n category: 'dependencies',\n severity: 'high',\n minTier: 'free',\n async run(ctx: ScanContext): Promise<Finding[]> {\n const execFileAsync = promisify(execFile)\n const lockfilePath = join(ctx.targetDir, 'Gemfile.lock')\n try {\n await access(lockfilePath)\n } catch {\n return []\n }\n\n try {\n await execFileAsync('bundle', ['audit', 'update'], {\n cwd: ctx.targetDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 30_000,\n })\n } catch (err) {\n const errorObj = err as { code?: string; message?: string }\n if (errorObj.code === 'ENOENT') {\n return auditUnavailable(errorObj)\n }\n console.warn(`[seaworthy] bundle audit update failed: ${errorObj.message || String(err)}`)\n }\n\n try {\n const { stdout } = await execFileAsync('bundle', ['audit', 'check', '--format', 'json'], {\n cwd: ctx.targetDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 30_000,\n })\n const findings = parseBundlerAudit(stdout, 'Gemfile.lock')\n return findings.length > 0 ? findings : []\n } catch (err) {\n const errorObj = err as { code?: string; message?: string; stdout?: string }\n if (errorObj.code === 'ENOENT') {\n return auditUnavailable(errorObj)\n }\n const output = errorObj.stdout\n if (output) {\n try {\n const findings = parseBundlerAudit(output, 'Gemfile.lock')\n return findings.length > 0 ? findings : []\n } catch {\n return auditUnavailable(errorObj)\n }\n }\n return auditUnavailable(errorObj)\n }\n },\n})\n","import { readFileSync, readdirSync, existsSync } from 'fs'\nimport { dirname, resolve as pathResolve } from 'path'\nimport { parse as parseYaml } from 'yaml'\nimport { ZodError } from 'zod'\nimport { ruleFileSchema } from './schema.js'\nimport type { RuleFile, LoadedRule, RuleSource } from './types.js'\nimport { registry } from '../registry/index.js'\nimport { createTreeSitterCheck } from '../checks/create-tree-sitter-check.js'\nimport { getCopy } from '../copy/index.js'\nimport type { CreateTreeSitterCheckOptions } from '../checks/create-tree-sitter-check.js'\nimport type { Category, Tier } from '../types/check.js'\nimport type { Severity, Confidence } from '../types/finding.js'\nimport type { Language } from '../types/source-file.js'\nimport type { CapturePosition } from '../ast/query.js'\nimport { runtimeModuleDir, runtimeRequire } from '../runtime/paths.js'\n\nconst loadedFiles = new Set<string>()\nconst idToFile = new Map<string, string>()\n\nconst require = runtimeRequire()\n\nfunction resolveCoreEntryDir(): string | null {\n try {\n return dirname(require.resolve('@seaworthy/core'))\n } catch {\n return null\n }\n}\n\nfunction makeLoadedFileKey(rulesDir: string, relativePath: string): string {\n return pathResolve(rulesDir, relativePath)\n}\n\nexport function _resetLoader(): void {\n loadedFiles.clear()\n idToFile.clear()\n}\n\ninterface LoadError {\n file: string\n pathInYaml: string\n message: string\n}\n\nexport class LoaderError extends Error {\n public readonly errors: LoadError[]\n\n constructor(errors: LoadError[]) {\n super(\n `Failed to load ${errors.length} YAML rule(s):\\n${errors\n .map((e) => ` ${e.file}: ${e.pathInYaml ? `${e.pathInYaml}: ` : ''}${e.message}`)\n .join('\\n')}`,\n )\n this.name = 'LoaderError'\n this.errors = errors\n }\n}\n\nfunction globYamlRecursive(dir: string, prefix = ''): string[] {\n const results: string[] = []\n let entries\n try {\n entries = readdirSync(dir, { withFileTypes: true })\n } catch {\n return []\n }\n\n for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n const fullPath = pathResolve(dir, entry.name)\n const relPath = prefix ? `${prefix}/${entry.name}` : entry.name\n\n if (entry.isDirectory()) {\n // Taint specs use a different schema; they are loaded by packages/core/src/taint/loader.ts\n if (relPath === 'internal/taint' || relPath.startsWith('internal/taint/')) {\n continue\n }\n results.push(...globYamlRecursive(fullPath, relPath))\n } else if (\n entry.isFile() &&\n relPath.endsWith('.yaml') &&\n !relPath.endsWith('.test.yaml')\n ) {\n results.push(relPath)\n }\n }\n\n return results\n}\n\nfunction resolveRulesRoot(): string {\n const moduleDirCandidates = [\n runtimeModuleDir(),\n resolveCoreEntryDir(),\n ].filter((candidate): candidate is string => Boolean(candidate))\n\n const candidates = [\n ...moduleDirCandidates.flatMap((moduleDir) => [\n pathResolve(moduleDir, '..', 'rules'),\n pathResolve(moduleDir, '..', '..', 'rules'),\n pathResolve(moduleDir, 'rules'),\n ]),\n ]\n for (const candidate of candidates) {\n if (existsSync(pathResolve(candidate, 'internal'))) return candidate\n }\n return candidates[candidates.length - 1]!\n}\n\nfunction determineSource(filePath: string): RuleSource {\n return filePath.startsWith('external/') || filePath.startsWith('external\\\\')\n ? 'external'\n : 'internal'\n}\n\nfunction loadRule(filePath: string, rulesDir: string): LoadedRule {\n const fullPath = pathResolve(rulesDir, filePath)\n const source = determineSource(filePath)\n\n let raw: string\n try {\n raw = readFileSync(fullPath, 'utf-8')\n } catch {\n throw new LoaderError([\n { file: filePath, pathInYaml: '', message: `Cannot read file` },\n ])\n }\n\n let parsed: unknown\n try {\n parsed = parseYaml(raw, { strict: true })\n if (parsed === null || parsed === undefined) {\n throw new Error('Empty YAML document')\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new LoaderError([\n { file: filePath, pathInYaml: '', message: `Parse error: ${message}` },\n ])\n }\n\n let validated: RuleFile\n try {\n validated = ruleFileSchema.parse(parsed) as RuleFile\n } catch (err) {\n if (err instanceof ZodError) {\n const issues: LoadError[] = err.issues.map((issue) => ({\n file: filePath,\n pathInYaml: issue.path.join('.'),\n message: issue.message,\n }))\n throw new LoaderError(issues)\n }\n throw err\n }\n\n const copyKeys = [\n validated.copy['name-key'],\n validated.copy['description-key'],\n validated.copy['message-key'],\n validated.copy['degraded-key'],\n validated.copy['remediation-key'],\n ]\n\n for (const copyKey of copyKeys) {\n try {\n (getCopy as (key: string) => string)(copyKey)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new LoaderError([\n { file: filePath, pathInYaml: 'copy', message: `Missing copy key: ${copyKey} — ${message}` },\n ])\n }\n }\n\n if (validated['message-captures'] && validated['message-captures'].length > 0) {\n const queryTexts = Object.values(validated.queries) as string[]\n for (const captureName of validated['message-captures']) {\n const found = queryTexts.some((q) => {\n const capRe = new RegExp(\n `@${captureName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?![a-zA-Z0-9_])`,\n )\n return capRe.test(q)\n })\n if (!found) {\n throw new LoaderError([\n {\n file: filePath,\n pathInYaml: 'message-captures',\n message: `Capture \"@${captureName}\" referenced in message-captures but not found in any query for rule \"${validated.id}\"`,\n },\n ])\n }\n }\n }\n\n if (validated.filters) {\n const queryTexts = Object.values(validated.queries) as string[]\n const filterCaptures = [\n ...Object.keys(validated.filters['exclude-captures'] ?? {}),\n ...Object.keys(validated.filters['require-captures'] ?? {}),\n ]\n for (const captureName of filterCaptures) {\n const found = queryTexts.some((q) => {\n const capRe = new RegExp(\n `@${captureName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?![a-zA-Z0-9_])`,\n )\n return capRe.test(q)\n })\n if (!found) {\n throw new LoaderError([\n {\n file: filePath,\n pathInYaml: 'filters',\n message: `Capture \"@${captureName}\" referenced in filters but not found in any query for rule \"${validated.id}\"`,\n },\n ])\n }\n }\n }\n\n if (validated.fix) {\n const captureName = validated.fix.range\n const queryTexts = Object.values(validated.queries) as string[]\n const found = queryTexts.some((q) => {\n const capRe = new RegExp(\n `@${captureName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(?![a-zA-Z0-9_])`,\n )\n return capRe.test(q)\n })\n if (!found) {\n throw new LoaderError([\n {\n file: filePath,\n pathInYaml: 'fix.range',\n message: `Capture \"@${captureName}\" referenced in fix.range but not found in any query for rule \"${validated.id}\"`,\n },\n ])\n }\n }\n\n return { file: filePath, source, rule: validated }\n}\n\nfunction buildOptions(loaded: LoadedRule): CreateTreeSitterCheckOptions {\n const { rule } = loaded\n const queries: Partial<Record<Language, string>> = {}\n for (const [lang, query] of Object.entries(rule.queries as Record<string, string>)) {\n queries[lang as Language] = query\n }\n\n const hasMessageCaptures =\n rule['message-captures'] && rule['message-captures'].length > 0\n\n const defaultMessageFactory = (captures: Record<string, string>) => {\n return (getCopy as (...args: string[]) => string)(\n rule.copy['message-key'],\n ...(rule['message-captures'] ?? []).map((c: string) => captures[c] ?? ''),\n )\n }\n\n let matchFilter: ((captures: Record<string, string>) => boolean) | undefined\n if (rule.filters) {\n matchFilter = (captures: Record<string, string>): boolean => {\n if (rule.filters!['exclude-captures']) {\n for (const [capture, values] of Object.entries(rule.filters!['exclude-captures']) as [string, string[]][]) {\n const captureText = captures[capture]\n if (captureText !== undefined && values.includes(captureText)) {\n return false\n }\n }\n }\n if (rule.filters!['require-captures']) {\n for (const [capture, values] of Object.entries(rule.filters!['require-captures']) as [string, string[]][]) {\n const captureText = captures[capture]\n if (captureText === undefined || !values.includes(captureText)) {\n return false\n }\n }\n }\n return true\n }\n }\n\n let fixFactory:\n | ((\n captures: Record<string, string>,\n capturePositions: Record<string, CapturePosition>,\n ) => { range: { startLine: number; startColumn: number; endLine: number; endColumn: number }; replacement: string } | undefined)\n | undefined\n\n if (rule.fix) {\n const captureName = rule.fix.range\n const replacement = rule.fix.replacement\n fixFactory = (\n _captures: Record<string, string>,\n capturePositions: Record<string, CapturePosition>,\n ) => {\n const pos = capturePositions[captureName]\n if (!pos) return undefined\n return {\n range: {\n startLine: pos.startLine,\n startColumn: pos.startColumn,\n endLine: pos.endLine,\n endColumn: pos.endColumn,\n },\n replacement,\n }\n }\n }\n\n return {\n id: rule.id,\n nameKey: rule.copy['name-key'],\n descriptionKey: rule.copy['description-key'],\n category: rule.category as Category,\n severity: rule.severity as Severity,\n minTier: rule['min-tier'] as Tier,\n queries,\n messageKey: rule.copy['message-key'],\n degradedMessageKey: rule.copy['degraded-key'],\n remediationKey: rule.copy['remediation-key'],\n confidence: (rule.confidence ?? 'high') as Confidence,\n messageFactory: hasMessageCaptures ? defaultMessageFactory : undefined,\n matchFilter,\n fixFactory,\n }\n}\n\nexport function loadAllRules(rulesDirOverride?: string): void {\n const rulesDir = rulesDirOverride ?? resolveRulesRoot()\n\n let relativePaths: string[]\n try {\n relativePaths = globYamlRecursive(rulesDir)\n } catch {\n return\n }\n\n const loadErrors: LoadError[] = []\n\n const loadAndRegister = (path: string) => {\n const cacheKey = makeLoadedFileKey(rulesDir, path)\n if (loadedFiles.has(cacheKey)) return\n\n let loaded: LoadedRule\n try {\n loaded = loadRule(path, rulesDir)\n } catch (err) {\n if (err instanceof LoaderError) {\n loadErrors.push(...err.errors)\n return\n }\n throw err\n }\n\n const existing = registry.getById(loaded.rule.id)\n if (existing) {\n const firstFile = idToFile.get(loaded.rule.id)\n const detail = firstFile ? ` (first registered from ${firstFile})` : ''\n loadErrors.push({\n file: path,\n pathInYaml: 'id',\n message: `Duplicate check id \"${loaded.rule.id}\" — already registered${detail}`,\n })\n return\n }\n\n loadedFiles.add(cacheKey)\n idToFile.set(loaded.rule.id, cacheKey)\n registry.register(createTreeSitterCheck(buildOptions(loaded)))\n }\n\n const externalPaths = relativePaths\n .filter((p) => p.startsWith('external/') || p.startsWith('external\\\\'))\n .sort()\n const internalPaths = relativePaths\n .filter((p) => !p.startsWith('external/') && !p.startsWith('external\\\\'))\n .sort()\n\n for (const path of externalPaths) {\n loadAndRegister(path)\n }\n\n for (const path of internalPaths) {\n loadAndRegister(path)\n }\n\n if (loadErrors.length > 0) {\n throw new LoaderError(loadErrors)\n }\n}\n","import { z } from 'zod'\n\nexport const LANGUAGE_CODES = [\n 'javascript',\n 'typescript',\n 'tsx',\n 'python',\n 'go',\n 'ruby',\n 'java',\n 'rust',\n 'php',\n 'bash',\n 'json',\n 'yaml',\n 'dockerfile',\n 'plaintext',\n 'html',\n 'css',\n] as const\n\nconst languageCodeSchema = z.enum(LANGUAGE_CODES)\n\nconst severitySchema = z.enum(['info', 'low', 'medium', 'high', 'critical'])\n\nconst categorySchema = z.enum([\n 'security',\n 'resilience',\n 'ops',\n 'dependencies',\n 'configuration',\n 'data-exposure',\n])\n\nconst tierSchema = z.enum(['free', 'pro'])\n\nconst confidenceSchema = z.enum(['low', 'medium', 'high'])\n\nexport const ruleFileSchema = z\n .strictObject({\n id: z.string(),\n severity: severitySchema,\n category: categorySchema,\n 'min-tier': tierSchema,\n languages: z.array(languageCodeSchema).min(1),\n copy: z.strictObject({\n 'name-key': z.string(),\n 'description-key': z.string(),\n 'message-key': z.string(),\n 'degraded-key': z.string(),\n 'remediation-key': z.string(),\n }),\n confidence: confidenceSchema.optional(),\n queries: z.record(z.string(), z.string()),\n 'message-captures': z.array(z.string()).min(1).optional(),\n filters: z\n .strictObject({\n 'exclude-captures': z.record(z.string(), z.array(z.string()).min(1)).optional(),\n 'require-captures': z.record(z.string(), z.array(z.string()).min(1)).optional(),\n })\n .optional(),\n fix: z\n .strictObject({\n range: z.string(),\n replacement: z.string(),\n })\n .optional(),\n })\n .superRefine((val, ctx) => {\n const validLanguageCodes: Set<string> = new Set(LANGUAGE_CODES)\n\n for (const queryLang of Object.keys(val.queries)) {\n if (!validLanguageCodes.has(queryLang)) {\n ctx.addIssue({\n code: 'custom',\n message: `Unknown language code in queries: ${queryLang}`,\n path: ['queries', queryLang],\n })\n }\n }\n\n const langSet = new Set(val.languages)\n const queryKeys = Object.keys(val.queries)\n if (\n langSet.size !== queryKeys.length ||\n queryKeys.some((k) => !langSet.has(k as (typeof val.languages)[number]))\n ) {\n ctx.addIssue({\n code: 'custom',\n message: `languages and queries keys must match exactly: languages=[${[...langSet].join(', ')}], queries=[${queryKeys.join(', ')}]`,\n path: ['languages'],\n })\n }\n\n if (!/^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$/.test(val.id)) {\n ctx.addIssue({\n code: 'custom',\n message: `id must match <category>.<check-name> in kebab-case`,\n path: ['id'],\n })\n }\n\n const idPrefix = val.id.split('.')[0]\n if (idPrefix !== val.category) {\n ctx.addIssue({\n code: 'custom',\n message: `id prefix \"${idPrefix}\" must match category \"${val.category}\"`,\n path: ['id'],\n })\n }\n })\n","// Types\nexport type { Check, ScanContext, Tier, Category, LLMProvider } from './types/check.js'\nexport type { Finding, Severity, Confidence } from './types/finding.js'\nexport type { SourceFile, Language } from './types/source-file.js'\nexport type { Result, ErrorCode, OkResult, FailResult } from './types/result.js'\nexport { ok, fail } from './types/result.js'\n\n// Registry\nexport { registry } from './registry/index.js'\n\n// Runner\nexport { ScanRunner, type ScanOptions, type ScanResult } from './runner/scan-runner.js'\n\n// Baseline\nexport { type BaselineState, type BaselineEntry, type BaselineDocument, computeBaseline, loadBaseline, saveBaseline, resolveBaselinePath } from './baseline.js'\n\n// Crawler\nexport { crawl, detectMonorepo, isMinifiedJavaScript, type CrawlOptions } from './crawler.js'\n\n// Git\nexport { isInsideGitRepo, listTrackedFiles, hasFileInGitHistory } from './git.js'\n\n// Parser\nexport { parseJsTs, parseJsTsSafe, type ASTNode } from './parser/index.js'\n\n// Providers\nexport { RateLimitedProvider, AnthropicProvider, OpenAIProvider, CircuitBreakerProvider, createProvider, resolvePreset, listPresetProviders, PROVIDER_PRESETS } from './providers/index.js'\nexport type { LLMProvider as LLMProviderInterface } from './providers/llm-provider.js'\n\n// Reporting\nexport { TerminalReporter } from './reporting/terminal-reporter.js'\nexport { JSONReporter } from './reporting/json-reporter.js'\nexport { HTMLReporter } from './reporting/html-reporter.js'\nexport { SarifReporter } from './reporting/sarif-reporter.js'\nexport type { SarifDocument, SarifResult, SarifLocation, SarifLevel } from './reporting/sarif-types.js'\n\n// License\nexport { LicenseClient, type LicenseTier } from './license/client.js'\nexport { LICENSE_SERVER_URL } from './license/config.js'\n\n// Auth\nexport { resolveAuth, type CredentialProvider } from './auth/index.js'\n\n// Config\nexport { SITE_URL } from './config/urls.js'\nexport { SKIP_DIRS, SKIP_EXTENSIONS, BINARY_PEEK_SIZE, DEFAULT_MAX_FILE_SIZE } from './config/ignore-patterns.js'\nexport {\n isNonProductionPath,\n isDocumentationPath,\n isMechanicalCheckExcludedPath,\n NON_PRODUCTION_PATH_PATTERNS,\n DOCUMENTATION_PATH_PATTERNS,\n} from './config/path-exclusions.js'\nexport { CONFIG_DIR, CACHE_DIR, AST_CACHE_DIR, DEP_CACHE_DIR } from './config/paths.js'\n\n// Cache\nexport { AstCache } from './cache/ast-cache.js'\nexport { DepCache } from './cache/dep-cache.js'\nexport { FileCache, hashKey } from './cache/file-cache.js'\n\n// Copy\nexport { getCopy } from './copy/index.js'\n\n// Check manifest (website data pipeline)\nexport { generateCheckManifest } from './checks/manifest.js'\nexport type { CheckManifestEntry } from './checks/manifest.js'\n\n// Errors\nexport { resolveErrorMessage } from './errors/resolve-error-message.js'\n\nimport './checks/security/hardcoded-secrets.js'\nimport './checks/security/committed-env.js'\nimport './checks/ops/debug-mode-enabled.js'\nimport './checks/ops/no-version-control.js'\nimport './checks/ops/hardcoded-localhost.js'\nimport './checks/dependencies/missing-lockfile.js'\nimport './checks/dependencies/known-cves.js'\nimport './checks/dependencies/dev-deps-in-prod.js'\nimport './checks/dependencies/unpinned-versions.js'\nimport './checks/dependencies/html-cdn-vulnerable-versions.js'\nimport './checks/dependencies/html-cdn-unpinned-versions.js'\nimport './checks/configuration/secrets-in-source.js'\nimport './checks/security/auth-missing-endpoints.js'\nimport './checks/security/cors-too-permissive.js'\nimport './checks/security/sql-injection-surface.js'\nimport './checks/security/sensitive-data-in-logs.js'\nimport './checks/resilience/no-rate-limiting.js'\nimport './checks/resilience/no-input-validation.js'\nimport './checks/resilience/missing-error-handling.js'\nimport './checks/resilience/no-pagination.js'\nimport './checks/resilience/missing-timeout.js'\nimport './checks/resilience/no-retry-logic.js'\nimport './checks/resilience/webhook-processing-defects.js'\nimport './checks/resilience/html-inline-resilience.js'\nimport './checks/ops/no-health-check.js'\nimport './checks/ops/missing-structured-logging.js'\nimport './checks/ops/no-graceful-shutdown.js'\nimport './checks/configuration/no-env-separation.js'\nimport './checks/configuration/default-credentials.js'\nimport './checks/data-exposure/verbose-errors.js'\nimport './checks/data-exposure/pii-in-responses.js'\nimport './checks/data-exposure/no-response-filtering.js'\nimport './checks/data-exposure/html-form-pii-exposure.js'\nimport './checks/security/xss-surface.js'\nimport './checks/security/os-command-injection.js'\nimport './checks/security/shell-arbitrary-evaluation.js'\nimport './checks/security/shell-unescaped-path-deletion.js'\nimport './checks/security/file-inclusion.js'\nimport './checks/security/open-redirect.js'\nimport './checks/security/unsafe-file-upload.js'\nimport './checks/security/unsafe-deserialization.js'\nimport './checks/security/hardcoded-passwords.js'\nimport './checks/security/html-missing-csp.js'\nimport './checks/security/html-static-host-headers.js'\nimport './checks/security/html-inline-unsafe-script.js'\nimport './checks/security/html-referrer-leak.js'\nimport './checks/security/html-css-comments-secrets.js'\nimport './checks/security/css-insecure-import.js'\nimport './checks/security/html-mixed-content.js'\nimport './checks/security/html-external-asset-integrity.js'\nimport './checks/security/html-insecure-form-action.js'\nimport './checks/security/html-iframe-sandbox.js'\nimport './checks/security/html-unsafe-embed.js'\nimport './checks/security/html-meta-redirect.js'\nimport './checks/security/html-base-tag-hijack.js'\nimport './checks/security/html-javascript-uri.js'\nimport './checks/security/html-import-map-integrity.js'\nimport './checks/security/css-data-exfiltration.js'\nimport './checks/security/css-external-font-integrity.js'\nimport './checks/security/insecure-random.js'\nimport './checks/security/weak-key-entropy.js'\nimport './checks/security/insecure-api-url-default.js'\nimport './checks/security/dynamic-sql-columns.js'\nimport './checks/security/weak-email-validation.js'\nimport './checks/security/idempotency-key-leak.js'\nimport './checks/data-exposure/plaintext-secret-in-email.js'\nimport './checks/security/taint-xss.js'\nimport './checks/security/taint-sql-injection.js'\nimport './checks/security/taint-command-injection.js'\nimport './checks/security/taint-path-traversal.js'\nimport './checks/security/taint-open-redirect.js'\nimport './checks/security/taint-prototype-pollution.js'\nimport './checks/security/taint-code-execution.js'\nimport './checks/security/missing-csrf-protection.js'\nimport './checks/security/weak-session-id.js'\nimport './checks/security/rails-mass-assignment.js'\nimport './checks/security/rails-insecure-session-config.js'\nimport './checks/security/xxe-surface.js'\nimport './checks/resilience/swallowed-catch.js'\nimport './checks/resilience/no-backoff-jitter.js'\nimport './checks/resilience/no-circuit-breaker.js'\nimport './checks/resilience/infinite-retry.js'\nimport './checks/ops/missing-observability.js'\nimport './checks/ops/secret-rotation-friction.js'\nimport './checks/ops/env-drift.js'\nimport './checks/data-exposure/composite-pii.js'\nimport './checks/data-exposure/derived-identifiers.js'\nimport './checks/data-exposure/unredacted-logs.js'\nimport './checks/security/permissive-grants.js'\nimport './checks/security/sql-rls-static.js'\nimport './checks/security/sql-security-definer-search-path.js'\nimport './checks/resilience/missing-transaction-guard.js'\nimport './checks/resilience/destructive-sql-migration.js'\nimport './checks/resilience/sql-broad-mutation.js'\nimport './checks/data-exposure/unprotected-sensitive-sql-columns.js'\nimport './checks/security/sql-missing-rls.js'\nimport './checks/security/rust-unsafe-blocks.js'\nimport './checks/resilience/rust-handler-panics.js'\nimport './checks/dependencies/cargo-unpinned-versions.js'\nimport './checks/dependencies/cargo-known-cves.js'\nimport './checks/dependencies/bundler-known-cves.js'\nimport { loadAllRules } from './rules/loader.js'\nimport { loadAllTaintRules } from './taint/loader.js'\n\nloadAllRules()\n// Side-effect: warm taint rule cache at boot. Errors are logged but not thrown\n// to avoid crashing the process on query validation warnings.\nloadAllTaintRules().catch((err) => {\n if (process.env.DEBUG || process.env.NODE_ENV === 'test') {\n console.error('[seaworthy] Taint rule loading failed:', err)\n }\n})\n","import {\n ScanRunner,\n TerminalReporter,\n JSONReporter,\n HTMLReporter,\n SarifReporter,\n createProvider,\n getCopy as getCoreCopy,\n type ScanResult,\n type Tier,\n type Confidence,\n type Category,\n} from '@seaworthy/core'\nimport { promises as fs } from 'fs'\nimport { dirname, resolve, relative, isAbsolute } from 'path'\nimport { getCopy, type CopyKey } from '../copy/index.js'\nimport { createCommand, type CommandContext, type CommandResult } from './createCommand.js'\n\nconst FREE_SCAN_TIMEOUT_MS = 60_000\nconst PRO_SCAN_TIMEOUT_MS = 600_000\n\nfunction resolveScanTimeoutMs(tier: Tier): number {\n const env = process.env.SEAWORTHY_SCAN_TIMEOUT_MS\n if (env) {\n const parsed = Number(env)\n if (Number.isFinite(parsed) && parsed > 0) {\n return parsed\n }\n }\n\n return tier === 'free' ? FREE_SCAN_TIMEOUT_MS : PRO_SCAN_TIMEOUT_MS\n}\n\nexport interface ScanArgs {\n targetDir: string\n format: 'terminal' | 'json' | 'html'\n output?: string\n sarif?: string\n sarifStdout?: boolean\n failOnFindings?: boolean\n llmApiKey?: string\n llmProvider?: string\n llmModel?: string\n llmApiUrl?: string\n maxFileSize?: number\n debug?: boolean\n baseline?: 'save' | string\n minConfidence?: 'high' | 'medium' | 'low'\n showIds?: boolean\n}\n\nconst CATEGORY_LABELS: Record<Category, string> = {\n security: getCopy('cli.category.security'),\n resilience: getCopy('cli.category.resilience'),\n ops: getCopy('cli.category.ops'),\n dependencies: getCopy('cli.category.dependencies'),\n configuration: getCopy('cli.category.configuration'),\n 'data-exposure': getCopy('cli.category.data-exposure'),\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(message)), ms)\n promise\n .then((value) => {\n clearTimeout(timer)\n resolve(value)\n })\n .catch((err) => {\n clearTimeout(timer)\n reject(err)\n })\n })\n}\n\n/**\n * Determine whether `outputPath` lies inside `targetDir` (including sub-directories).\n */\nfunction isInsideDirectory(outputPath: string, targetDir: string): boolean {\n const resolvedOutput = resolve(outputPath)\n const resolvedTarget = resolve(targetDir)\n const rel = relative(resolvedTarget, resolvedOutput)\n return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))\n}\n\nasync function executeScan(args: ScanArgs, ctx: CommandContext): Promise<CommandResult> {\n if (args.sarif && args.sarifStdout) {\n return { ok: false, code: 'cli.sarif.mutually_exclusive' }\n }\n if (args.sarifStdout && args.format === 'json') {\n return { ok: false, code: 'cli.sarif.stdout_conflict' }\n }\n\n if (ctx.tier === 'pro' && !args.llmApiKey && !process.env.SEAWORTHY_SKIP_LLM_CHECK) {\n console.error(getCopy('cli.warn.llmSkipped'))\n }\n\n let llm = null\n if (args.llmApiKey && args.llmProvider && !process.env.SEAWORTHY_SKIP_LLM_CHECK) {\n llm = createProvider({ provider: args.llmProvider, apiKey: args.llmApiKey, model: args.llmModel, baseUrl: args.llmApiUrl })\n }\n\n const showProgress = args.format === 'terminal' && !args.sarifStdout\n if (showProgress) {\n process.stderr.write(getCoreCopy('report.scanProgress.starting', args.targetDir) + '\\n')\n }\n\n const runner = new ScanRunner()\n const scanTimeoutMs = resolveScanTimeoutMs(ctx.tier!)\n const result: ScanResult = await withTimeout(\n runner.run({\n targetDir: args.targetDir,\n tier: ctx.tier!,\n llm,\n maxFileSize: args.maxFileSize,\n debug: args.debug,\n baseline: args.baseline,\n minConfidence: args.minConfidence as Confidence | undefined,\n onCategoryComplete: showProgress\n ? (category, count) => {\n const label = CATEGORY_LABELS[category] ?? category\n process.stderr.write(getCoreCopy('report.scanProgress.category', label, count) + '\\n')\n }\n : undefined,\n }),\n scanTimeoutMs,\n getCoreCopy('errors.scan.timed_out', Math.round(scanTimeoutMs / 1000))\n )\n\n const reportInput = {\n findings: result.findings,\n targetDir: args.targetDir,\n tier: ctx.tier!,\n licensedTo: ctx.licensedTo ?? 'free tier',\n scannedFileCount: result.scannedFileCount,\n skippedChecks: result.skippedChecks,\n showIds: args.showIds ?? args.debug,\n }\n\n let primaryOutput: string\n switch (args.format) {\n case 'json':\n primaryOutput = new JSONReporter().generate(reportInput)\n break\n case 'html':\n primaryOutput = new HTMLReporter().generate(reportInput)\n break\n case 'terminal':\n default:\n primaryOutput = new TerminalReporter().generate(reportInput)\n break\n }\n\n let sarifOutput: string | undefined\n if (args.sarif || args.sarifStdout) {\n sarifOutput = new SarifReporter().generate(reportInput)\n }\n\n if (args.sarif && sarifOutput) {\n const sarifPath = resolve(args.sarif)\n if (isInsideDirectory(sarifPath, args.targetDir)) {\n return { ok: false, code: 'cli.error.outputInsideTarget' }\n }\n await fs.mkdir(dirname(sarifPath), { recursive: true })\n await fs.writeFile(sarifPath, sarifOutput)\n }\n\n if (args.output) {\n const outputPath = resolve(args.output)\n if (isInsideDirectory(outputPath, args.targetDir)) {\n return { ok: false, code: 'cli.error.outputInsideTarget' }\n }\n await fs.mkdir(dirname(outputPath), { recursive: true })\n await fs.writeFile(outputPath, primaryOutput)\n if (args.failOnFindings && result.findings.length > 0) {\n return { ok: false, code: 'scan.findings_found' }\n }\n return { ok: true, output: getCopy('cli.reportWritten', outputPath) }\n }\n\n if (args.failOnFindings && result.findings.length > 0) {\n return { ok: false, code: 'scan.findings_found' }\n }\n\n const stdoutOutput = args.sarifStdout ? sarifOutput! : primaryOutput\n return { ok: true, output: stdoutOutput }\n}\n\nexport const scanCommand = createCommand<ScanArgs>({\n name: 'scan',\n description: 'Scan a directory for issues',\n handler: executeScan,\n})\n","import { SITE_URL } from '@seaworthy/core'\n\nconst copy = {\n 'cli.help.description': 'Seaworthy — static analysis for vibe coders',\n 'cli.help.usage': 'Usage: seaworthy [path] [options]',\n 'cli.help.options': 'Options',\n 'cli.help.learnMore': `Documentation: ${SITE_URL}/docs`,\n 'cli.setup.intro': 'Welcome to Seaworthy! Let\\'s get you set up.',\n 'cli.setup.licensePrompt': 'License key (press Enter to skip and scan free)',\n 'cli.setup.licenseHint': 'Buy a key at seaworthycode.com · Enter skips to free tier',\n 'cli.setup.providerPrompt': 'LLM provider for Pro checks',\n 'cli.setup.providerSkip': 'Skip — no LLM checks',\n 'cli.setup.apiKeyPrompt': 'API key for',\n 'cli.setup.modelPrompt': 'Model (press Enter for default)',\n 'cli.setup.baseUrlPrompt': 'Custom API base URL (press Enter to use default)',\n 'cli.setup.done': 'Config saved. Run `seaworthy .` to scan your project.',\n 'cli.setup.skipped': 'Setup skipped. Running free-tier scan.',\n 'cli.firstRun': 'First time? Let\\'s get you set up.',\n 'cli.category.security': 'Security',\n 'cli.category.resilience': 'Resilience',\n 'cli.category.ops': 'Ops Basics',\n 'cli.category.dependencies': 'Dependencies',\n 'cli.category.configuration': 'Configuration',\n 'cli.category.data-exposure': 'Data Exposure',\n 'cli.reportWritten': (path: string) => `Report written to ${path}`,\n 'cli.error.notADirectory': (path: string) => `Path is not a directory: ${path}`,\n 'cli.error.notFound': (path: string) => `Path not found: ${path}`,\n 'cli.error.mutuallyExclusive': '--json and --output cannot be used together',\n 'cli.error.outputInsideTarget': 'Cannot write report inside the scanned directory.',\n 'cli.help.flag.sarif': 'Write SARIF report to file',\n 'cli.help.flag.sarifStdout': 'Write SARIF report to stdout',\n 'cli.sarif.mutually_exclusive': 'Flags --sarif and --sarif-stdout cannot be used together.',\n 'cli.sarif.stdout_conflict': 'Flags --sarif-stdout and --json cannot be used together. Use --output to send JSON to a file.',\n 'cli.error.llmRequired':\n 'LLM API key required for Pro checks. Set it with seaworthy config or the SEAWORTHY_LLM_API_KEY environment variable.',\n 'cli.warn.llmSkipped':\n 'Pro checks skipped: no LLM API key configured. Set it with seaworthy config or the SEAWORTHY_LLM_API_KEY environment variable to enable semantic analysis.',\n 'cli.error.config.missingKey': 'Missing config key. Usage: seaworthy config <set|get> <key>',\n 'cli.error.config.missingValue': 'Missing config value. Usage: seaworthy config set <key> <value>',\n 'cli.error.config.unknownKey': 'Unknown config key. Valid keys: licenseKey, llmProvider, llmApiKey, llmModel, llmApiUrl',\n 'cli.error.config.invalidProvider': 'Invalid provider. Valid providers: anthropic, openai, kimi, moonshot, deepseek, gemini, ollama, openrouter',\n 'cli.error.config.invalidAction': 'Invalid config action. Usage: seaworthy config <set|get|list>',\n 'cli.config.setSuccess': (key: string) => `${key} updated.`,\n} as const\n\nexport type CopyKey = keyof typeof copy\n\ntype CopyValue<K extends CopyKey> = (typeof copy)[K]\n\ntype CopyArgs<K extends CopyKey> = CopyValue<K> extends (...args: infer P) => unknown\n ? P\n : never[]\n\nexport function getCopy<K extends CopyKey>(key: K, ...args: CopyArgs<K>): string {\n const value = copy[key]\n if (typeof value === 'function') {\n return (value as (...args: unknown[]) => string)(...args)\n }\n return value as string\n}\n","import type { LicenseTier } from '@seaworthy/core'\n\nexport interface CommandContext {\n tier?: LicenseTier\n licensedTo?: string\n}\n\nexport type CommandResult =\n | { ok: true; output?: string; filePath?: string }\n | { ok: false; code: string; detail?: string }\n\nexport interface CommandDefinition<TArgs> {\n name: string\n description: string\n handler: (args: TArgs, ctx: CommandContext) => Promise<CommandResult>\n}\n\nexport interface CreateCommandOptions {\n requireLicense?: boolean\n}\n\n/**\n * Factory for CLI commands. Wraps the raw handler to enforce license\n * validation and consistent error handling. Every `seaworthy` subcommand\n * (scan, config, logout) must use this factory per `route_handlers.md`.\n *\n * Wraps the handler in a try/catch so that infrastructure failures\n * (network, disk, LLM) produce a `{ ok: false }` result instead of\n * crashing the process.\n */\nexport function createCommand<TArgs>(\n definition: CommandDefinition<TArgs>,\n options?: CreateCommandOptions\n): CommandDefinition<TArgs> {\n const requireLicense = options?.requireLicense ?? true\n return {\n ...definition,\n handler: async (args: TArgs, ctx: CommandContext): Promise<CommandResult> => {\n if (requireLicense && !ctx.tier) {\n return { ok: false, code: 'errors.license.invalid' }\n }\n\n try {\n return await definition.handler(args, ctx)\n } catch (err) {\n return {\n ok: false,\n code: 'errors.unexpected',\n detail: err instanceof Error ? err.message : String(err),\n }\n }\n },\n }\n}\n","import { intro, outro, text, password, select, isCancel } from '@clack/prompts'\nimport { readConfig, writeConfig } from '../config/store.js'\nimport { getCopy } from '../copy/index.js'\nimport { listPresetProviders, resolvePreset } from '@seaworthy/core'\nimport { createCommand } from './createCommand.js'\n\nexport interface SetupArgs {\n action?: string\n}\n\nconst PROVIDERS_WITH_CUSTOM_URL = new Set(['ollama', 'openrouter'])\n\nasync function executeSetup(): Promise<{ ok: true; output?: string } | { ok: false; code: string; detail?: string }> {\n intro(getCopy('cli.setup.intro'))\n\n const config = await readConfig()\n\n // Step 1: License key\n const licenseKeyResult = await text({\n message: getCopy('cli.setup.licensePrompt'),\n placeholder: 'SW-XXXXXX',\n defaultValue: config.licenseKey ?? '',\n validate: () => undefined,\n })\n\n if (isCancel(licenseKeyResult)) {\n outro(getCopy('cli.setup.skipped'))\n return { ok: true }\n }\n\n const licenseKey = String(licenseKeyResult).trim() || undefined\n\n // Step 2: LLM provider\n const providers = listPresetProviders()\n const providerOptions = [\n { value: '', label: getCopy('cli.setup.providerSkip') },\n ...providers.map(p => ({ value: p, label: p })),\n ]\n\n const providerResult = await select({\n message: getCopy('cli.setup.providerPrompt'),\n options: providerOptions,\n initialValue: config.llmProvider ?? '',\n })\n\n if (isCancel(providerResult)) {\n outro(getCopy('cli.setup.skipped'))\n return { ok: true }\n }\n\n const llmProvider = String(providerResult) || undefined\n\n let llmApiKey: string | undefined = config.llmApiKey\n let llmModel: string | undefined = config.llmModel\n let llmApiUrl: string | undefined = config.llmApiUrl\n\n if (llmProvider) {\n // Step 3: API key\n const apiKeyResult = await password({\n message: `${getCopy('cli.setup.apiKeyPrompt')} ${llmProvider}`,\n validate: () => undefined,\n })\n\n if (isCancel(apiKeyResult)) {\n outro(getCopy('cli.setup.skipped'))\n return { ok: true }\n }\n\n llmApiKey = String(apiKeyResult).trim() || undefined\n\n // Step 4: Model (with preset default)\n const preset = resolvePreset(llmProvider)\n const modelResult = await text({\n message: getCopy('cli.setup.modelPrompt'),\n placeholder: preset?.defaultModel ?? '',\n defaultValue: config.llmModel ?? '',\n validate: () => undefined,\n })\n\n if (isCancel(modelResult)) {\n outro(getCopy('cli.setup.skipped'))\n return { ok: true }\n }\n\n llmModel = String(modelResult).trim() || undefined\n\n // Step 5: Custom base URL (only for providers that need it)\n if (PROVIDERS_WITH_CUSTOM_URL.has(llmProvider)) {\n const urlResult = await text({\n message: getCopy('cli.setup.baseUrlPrompt'),\n placeholder: preset?.baseUrl ?? '',\n defaultValue: config.llmApiUrl ?? '',\n validate: () => undefined,\n })\n\n if (isCancel(urlResult)) {\n outro(getCopy('cli.setup.skipped'))\n return { ok: true }\n }\n\n llmApiUrl = String(urlResult).trim() || undefined\n } else {\n llmApiUrl = undefined\n }\n }\n\n await writeConfig({ licenseKey, llmProvider, llmApiKey, llmModel, llmApiUrl })\n\n outro(getCopy('cli.setup.done'))\n return { ok: true }\n}\n\nexport const setupCommand = createCommand<SetupArgs>(\n {\n name: 'setup',\n description: 'Interactive first-run setup for license key and LLM provider',\n handler: async () => executeSetup(),\n },\n { requireLicense: false }\n)\n","import { promises as fs } from 'fs'\nimport { homedir } from 'os'\nimport { join } from 'path'\n\nfunction getConfigDir(): string {\n return process.env.SEAWORTHY_CONFIG_DIR ?? join(homedir(), '.seaworthy')\n}\n\nfunction getConfigFile(): string {\n return join(getConfigDir(), 'config')\n}\n\nexport interface UserConfig {\n licenseKey?: string\n llmProvider?: string\n llmApiKey?: string\n llmModel?: string\n llmApiUrl?: string\n}\n\nexport async function readConfig(): Promise<UserConfig> {\n try {\n const raw = await fs.readFile(getConfigFile(), 'utf-8')\n return JSON.parse(raw) as UserConfig\n } catch {\n return {}\n }\n}\n\nexport async function writeConfig(config: UserConfig): Promise<void> {\n await fs.mkdir(getConfigDir(), { recursive: true })\n await fs.writeFile(getConfigFile(), JSON.stringify(config, null, 2), {\n mode: 0o600,\n })\n await fs.chmod(getConfigFile(), 0o600)\n}\n","import type { CredentialProvider } from '@seaworthy/core'\nimport { readConfig } from '../config/store.js'\n\n/**\n * Credential provider that reads from the local filesystem\n * (`~/.seaworthy/config`).\n */\nexport class FsCredentialProvider implements CredentialProvider {\n async getCredentials() {\n const config = await readConfig()\n return {\n licenseKey: config.licenseKey,\n llmApiKey: config.llmApiKey,\n llmProvider: config.llmProvider,\n llmModel: config.llmModel,\n llmApiUrl: config.llmApiUrl,\n }\n }\n}\n","import { readFile } from 'fs/promises'\nimport { fileURLToPath } from 'url'\nimport { dirname, join } from 'path'\n\nconst NPM_REGISTRY_URL = 'https://registry.npmjs.org/seaworthy'\nconst UPDATE_TIMEOUT_MS = 3_000\n\ninterface NpmRegistryResponse {\n 'dist-tags'?: {\n latest?: string\n }\n}\n\n/**\n * Compare two semantic version strings (simple x.y.z comparison).\n *\n * @param current - The currently installed version.\n * @param latest - The latest version from the registry.\n * @returns True when `current` is strictly lower than `latest`.\n */\nfunction isLowerVersion(current: string, latest: string): boolean {\n const parse = (v: string) => v.split('.').map((n) => Number(n))\n const [cMajor = 0, cMinor = 0, cPatch = 0] = parse(current)\n const [lMajor = 0, lMinor = 0, lPatch = 0] = parse(latest)\n\n if (lMajor > cMajor) return true\n if (lMajor < cMajor) return false\n if (lMinor > cMinor) return true\n if (lMinor < cMinor) return false\n return lPatch > cPatch\n}\n\n/**\n * Read the version field from this package's package.json.\n */\nasync function getInstalledVersion(): Promise<string> {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '../package.json')\n const pkg = JSON.parse(await readFile(pkgPath, 'utf-8')) as { version: string }\n return pkg.version\n}\n\n/**\n * Check the npm registry for a newer version of Seaworthy.\n *\n * @returns An update notification string when a newer version exists,\n * otherwise `undefined`. Never throws.\n */\nexport async function checkUpdate(): Promise<string | undefined> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), UPDATE_TIMEOUT_MS)\n\n try {\n const response = await fetch(NPM_REGISTRY_URL, { signal: controller.signal })\n clearTimeout(timeout)\n\n if (!response.ok) {\n return undefined\n }\n\n const data = (await response.json()) as NpmRegistryResponse\n const latest = data['dist-tags']?.latest\n\n if (!latest) {\n return undefined\n }\n\n const installed = await getInstalledVersion()\n\n if (isLowerVersion(installed, latest)) {\n return `Update available: ${installed} → ${latest}. Run npm i -g seaworthy to update.`\n }\n\n return undefined\n } catch {\n clearTimeout(timeout)\n return undefined\n }\n}\n","import { readConfig, writeConfig, type UserConfig } from '../config/store.js'\nimport { getCopy } from '../copy/index.js'\nimport { listPresetProviders } from '@seaworthy/core'\nimport { createCommand, type CommandResult } from './createCommand.js'\n\nconst VALID_KEYS: (keyof UserConfig)[] = ['licenseKey', 'llmProvider', 'llmApiKey', 'llmModel', 'llmApiUrl']\n\nexport interface ConfigArgs {\n action: 'set' | 'get' | 'list'\n key?: string\n value?: string\n}\n\nfunction formatOutputValue(key: keyof UserConfig, value: UserConfig[keyof UserConfig]): string {\n if (value === undefined) return ''\n if (key === 'llmApiKey' || key === 'licenseKey') return '********'\n return value\n}\n\nasync function executeConfig(args: ConfigArgs): Promise<CommandResult> {\n const config = await readConfig()\n\n if (args.action === 'list') {\n const lines: string[] = []\n for (const key of VALID_KEYS) {\n const value = config[key]\n lines.push(`${key}=${formatOutputValue(key, value)}`)\n }\n return { ok: true, output: lines.join('\\n') }\n }\n\n if (!args.key) {\n return { ok: false, code: 'cli.error.config.missingKey' }\n }\n\n if (!VALID_KEYS.includes(args.key as keyof UserConfig)) {\n return { ok: false, code: 'cli.error.config.unknownKey', detail: args.key }\n }\n\n const key = args.key as keyof UserConfig\n\n if (args.action === 'get') {\n const value = config[key]\n return { ok: true, output: formatOutputValue(key, value) }\n }\n\n if (args.action === 'set') {\n if (args.value === undefined) {\n return { ok: false, code: 'cli.error.config.missingValue' }\n }\n\n if (key === 'llmProvider' && !listPresetProviders().includes(args.value)) {\n return { ok: false, code: 'cli.error.config.invalidProvider', detail: args.value }\n }\n\n const next: UserConfig = { ...config, [key]: args.value }\n await writeConfig(next)\n return { ok: true, output: getCopy('cli.config.setSuccess', args.key) }\n }\n\n return { ok: false, code: 'cli.error.config.invalidAction' }\n}\n\nexport const configCommand = createCommand<ConfigArgs>(\n {\n name: 'config',\n description: 'Manage Seaworthy configuration',\n handler: async (args) => executeConfig(args),\n },\n { requireLicense: false }\n)\n"],"mappings":"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ACF,oCACE;EACF,iCACE;EACF,+BACE;EACF,uCACE;EACF,wCACE;EACF,wCACE;EACF,kCACE;EACF,iCACE;EACF,4CACE;EACF,wCACE;EACF,kCACE;EACF,gCACE;EACF,iCACE;EACF,mCACE;EACF,kCACE;EACF,wCACE;EACF,oCACE;EACF,0CACE;EACF,2CACE;EACF,yCACE;EACF,qCACE;EACF,qCACE;EACF,0BACE;EACF,mCACE;EACF,yCACE;EACF,4CACE;EACF,6BACE;EACF,4BACE;EACF,iCACE;EACF,qCACE;EACF,kCACE;EACF,8BACE;EACF,iCACE;EACF,kCACE;EACF,sCACE;EACF,+BACE;EACF,iCACE;EACF,6BACE;EACF,yBACE;EACF,2BACE;EACF,wBACE;EACF,yBACE;EACF,iCACE;EACF,4BACE;EACF,kCACE;EACF,+BACE;EACF,gCACE;EACF,yBACE;EACF,qCACE;EACF,kCACE;EACF,qCACE;EACF,+BACE;EACF,kCACE;EACF,qCACE;EACF,4BACE;EACF,8BACE;EACF,6BACE;EACF,yCACE;EACF,8BACE;EACF,yCACE;EACF,mCACE;EACF,gCACE;EACF,kCACE;EACF,6BACE;EACF,+BACE;EACF,oCACE;EACF,+BACE;EACF,yBACE;EACF,uCACE;EACF,uCACE;EACF,kCACE;EACF,wCACE;EACF,0BACE;EACF,0BACE;EACF,6BACE;EACF,sCACE;EACF,sCACE;EACF,8BACE;EACF,+BACE;EACF,2BACE;EACF,oCACE;EACF,uCACE;EACF,mCACE;EACF,mCACE;EACF,mCACE;EACF,uCACE;EACF,0CACE;EACF,+BACE;EACF,6BACE;EACF,wCACE;EACF,8CACE;EACF,mCACE;EACF,qCACE;EACF,8BACE;EACF,gCACE;EACF,iCACE;EACF,6BACE;EACF,oCACE;EACF,uCACE;EACF,wBACE;EACF,wBACE;EACF,kCACE;EACF,sCACE;EACF,mCACE;EACF,kCACE;EACF,wCACE;EACF,mCACE;EACF,8BACE;EACF,oCACE;EA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","names":["existsSync","dirname","resolve","fileURLToPath","createRequire","access","resolve","homedir","join","join","readFileSync","relative","process","readFileSync","existsSync","join","pathResolve","pathToFileURL","fs","relative","execSync","dirname","createHash","TSQuery","z","TSLanguage","readdirSync","parseYaml","ZodError","env","check","text","ext","stat","isBinary","isGenerated","findings","resolve","process","version","styles","chalk","SEVERITY_ORDER","lines","relative","check","pathToFileURL","require","pathResolve","join","existsSync","readFileSync","parser","parsed","findingKey","fs","relative","CHECK_ID","REMEDIATION","regexCheck","TS_QUERIES","tsCheck","execSync","dirname","version","SCRIPT_OR_LINK_PATTERN","lineAndColumn","env","createHash","SEVERITY_ORDER","text","PROMPT_VERSION","fallbackPatterns","buildPrompt","parseResponse","promptTemplate","content","lines","password","pushFinding","QUERIES","QUERY","SCRIPT_BLOCK_PATTERN","LOCAL_DEV_URL_PATTERN","TYPE_PATTERN","EXTERNAL_URL_PATTERN","INTEGRITY_PATTERN","STYLE_BLOCK_PATTERN","STYLE_ATTR_PATTERN","LOCALHOST_PATTERN","lineText","copy","cacheKey","TSQuery","z","TSLanguage","resolveCopy","fileFindings","isEligibleFile","walk","findNodeAt","mapSeverity","auditUnavailable","isSevereEnough","resolveCoreEntryDir","readdirSync","parseYaml","ZodError","fs","dirname","resolve","relative","isAbsolute","copy","getCopy","env","getCopy","resolve","relative","isAbsolute","fs","dirname","text","fs","homedir","join","getCopy","text","fileURLToPath","dirname","join","parse","getConfigFile","join","homedir","access","getCopy","resolve","key","getCopy","resolve","dirname","fileURLToPath","existsSync","require","createRequire","getCopy"]}