@syntopica/db-quality 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +114 -0
- package/assets/db-quality.yml +26 -0
- package/assets/drizzle-eslint.config.mjs +22 -0
- package/assets/prisma-lint.json +5 -0
- package/bin/codeality-db.mjs +2 -0
- package/dist/cli.js +1636 -0
- package/dist/cli.js.map +1 -0
- package/package.json +85 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/audit/isSupabaseHost.ts","../src/config/ConfigError.ts","../src/audit/auditPlan.ts","../src/audit/resolveAuditTarget.ts","../src/adapters/soda/runSoda.ts","../src/adapters/soda/dataSourceType.ts","../src/config/isDisabled.ts","../src/model/fingerprintFinding.ts","../src/adapters/soda/parseSodaResults.ts","../src/adapters/soda/renderSodaConfiguration.ts","../src/tools/ToolMissingError.ts","../src/adapters/supabase/ADVISOR_SEVERITY.ts","../src/adapters/supabase/parseAdvisorReport.ts","../src/adapters/supabase/parseCliError.ts","../src/adapters/supabase/supabaseJson.ts","../src/audit/targetArgs.ts","../src/adapters/supabase/runAdvisors.ts","../src/adapters/supabase/parseBloat.ts","../src/adapters/supabase/parseIndexStats.ts","../src/adapters/supabase/runInspect.ts","../src/model/compareFindings.ts","../src/audit/runAudit.ts","../src/check/renderFindings.ts","../src/check/renderFindingsJson.ts","../src/commands/parseCommandArgs.ts","../src/model/ExitCode.ts","../src/commands/reportCommandError.ts","../src/config/readConfig.ts","../src/config/CONFIG_FILENAME.ts","../src/config/expectConfig.ts","../src/config/auditSectionFrom.ts","../src/config/CONFIG_KEYS.ts","../src/config/configSection.ts","../src/config/isStringList.ts","../src/config/drizzleSectionFrom.ts","../src/config/stackSectionsFrom.ts","../src/config/configFromDocument.ts","../src/commands/auditCommand.ts","../src/commands/baselineCommand.ts","../src/baseline/BASELINE_FILENAME.ts","../src/baseline/BASELINE_USAGE.ts","../src/baseline/baselineActionFrom.ts","../src/baseline/classifyFindings.ts","../src/baseline/readBaseline.ts","../src/baseline/renderClassified.ts","../src/baseline/writeBaseline.ts","../src/adapters/drizzle/parseEslintReport.ts","../src/assetPath.ts","../src/adapters/drizzle/runDrizzleLint.ts","../src/adapters/prisma/parsePrismaLintReport.ts","../src/adapters/prisma/runPrismaLint.ts","../src/adapters/sqlite/sqliteFinding.ts","../src/adapters/sqlite/sqliteQuery.ts","../src/adapters/sqlite/sqliteRows.ts","../src/adapters/sqlite/foreignKeyFindings.ts","../src/adapters/sqlite/integrityFindings.ts","../src/adapters/sqlite/hasPrimaryKey.ts","../src/adapters/sqlite/primaryKeyFindings.ts","../src/adapters/sqlite/runSqliteChecks.ts","../src/model/normalizeSqlText.ts","../src/sql/statementAtLine.ts","../src/adapters/squawk/parseSquawkReport.ts","../src/adapters/squawk/SUPABASE_SQUAWK_EXCLUDES.ts","../src/adapters/squawk/runSquawk.ts","../src/rules/makeSqlFinding.ts","../src/sql/qualifiedName.ts","../src/rules/policyTable.ts","../src/rules/authUidNotWrapped.ts","../src/rules/definerWithoutSearchPath.ts","../src/rules/permissivePolicy.ts","../src/rules/policyTables.ts","../src/rules/matchedTables.ts","../src/rules/rlsEnabledTables.ts","../src/rules/rlsEnabledNoPolicy.ts","../src/rules/createdTables.ts","../src/rules/tableWithoutRls.ts","../src/rules/SQL_RULES.ts","../src/rules/runSqlRules.ts","../src/sql/readMigrationSet.ts","../src/sql/quotedSpanEnd.ts","../src/sql/stripSqlComments.ts","../src/sql/splitSqlStatements.ts","../src/check/runCheck.ts","../src/packageVersion.ts","../src/commands/checkCommand.ts","../src/gate/gateExitCode.ts","../src/gate/gateStages.ts","../src/gate/renderGateReport.ts","../src/gate/runStage.ts","../src/gate/runGate.ts","../src/commands/gateCommand.ts","../src/init/applyInit.ts","../src/init/planConfigFile.ts","../src/config/detectStacks.ts","../src/config/findSqliteFiles.ts","../src/config/isDirectory.ts","../src/init/planPackageScript.ts","../src/init/PACKAGE_MANIFEST.ts","../src/init/planWorkflow.ts","../src/init/planInit.ts","../src/init/renderInitPlan.ts","../src/commands/initCommand.ts","../src/cli/COMMANDS.ts","../src/cli/USAGE.ts","../src/cli/runCli.ts","../src/tools/spawnRunner.ts","../src/tools/packageBinPath.ts"],"sourcesContent":["import { argv, cwd, exit, stderr, stdout } from 'node:process'\n\nimport { runCli } from '@/cli/runCli.js'\nimport { spawnRunner } from '@/tools/spawnRunner.js'\n\nexit(\n runCli(argv.slice(2), {\n root: cwd(),\n runner: spawnRunner,\n stdout: (text) => {\n stdout.write(text)\n },\n stderr: (text) => {\n stderr.write(text)\n },\n }),\n)\n","/** Whether a database URL points at a Supabase project, where advisors and inspect can answer. */\nexport const isSupabaseHost = (dbUrl: string): boolean => {\n try {\n const { hostname } = new URL(dbUrl)\n return (\n hostname.endsWith('.supabase.co') ||\n hostname.endsWith('.pooler.supabase.com')\n )\n } catch {\n return false\n }\n}\n","/** Invalid or missing configuration: exit code 2. */\nexport class ConfigError extends Error {}\n","import type { AuditTarget } from '@/audit/AuditTarget.js'\nimport { isSupabaseHost } from '@/audit/isSupabaseHost.js'\nimport { ConfigError } from '@/config/ConfigError.js'\nimport type { DbQualityConfig } from '@/config/DbQualityConfig.js'\n\n/**\n * Which live adapters a target can run. Advisors and inspect need a Supabase\n * project; Soda needs a URL with a password, which a linked target lacks.\n * A target that can run neither is a configuration error, not a clean pass.\n */\nexport const auditPlan = (\n config: DbQualityConfig,\n target: AuditTarget,\n): { supabase: boolean; soda: boolean; skipped: string[] } => {\n const supabase = 'linked' in target || isSupabaseHost(target.dbUrl)\n const soda = config.audit.soda !== undefined && 'dbUrl' in target\n const skipped = [\n ...(supabase\n ? []\n : ['supabase: skipped, --db-url is not a Supabase project host']),\n ...(config.audit.soda !== undefined && !soda\n ? [\n 'soda: skipped, a linked target carries no database password; pass --db-url',\n ]\n : []),\n ]\n if (!supabase && !soda) {\n throw new ConfigError(\n 'nothing to audit: not a Supabase host and audit.soda is not configured',\n )\n }\n return { supabase, soda, skipped }\n}\n","import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { AuditTarget } from '@/audit/AuditTarget.js'\nimport type { AuditTargetFlags } from '@/audit/AuditTargetFlags.js'\nimport { ConfigError } from '@/config/ConfigError.js'\n\nexport const resolveAuditTarget = (\n root: string,\n values: AuditTargetFlags,\n): AuditTarget => {\n if (values['db-url']) return { dbUrl: values['db-url'] }\n if (values.linked) {\n if (!existsSync(join(root, 'supabase/.temp/project-ref'))) {\n throw new ConfigError(\n 'project is not linked; run \"supabase link\" or pass --db-url',\n )\n }\n return { linked: true }\n }\n throw new ConfigError('audit needs --linked or --db-url')\n}\n","import {\n existsSync,\n mkdtempSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\n\nimport { dataSourceType } from '@/adapters/soda/dataSourceType.js'\nimport { parseSodaResults } from '@/adapters/soda/parseSodaResults.js'\nimport { renderSodaConfiguration } from '@/adapters/soda/renderSodaConfiguration.js'\nimport type { SodaTarget } from '@/adapters/soda/SodaTarget.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\nimport { ToolMissingError } from '@/tools/ToolMissingError.js'\n\n// `--with setuptools` and SETUPTOOLS_USE_DISTUTILS are not optional: Soda 4.25\n// imports distutils, which Python 3.12 removed. Measured 2026-09-25.\nexport const runSoda = (\n runner: CommandRunner,\n root: string,\n soda: SodaTarget,\n disabled: string[],\n): Finding[] => {\n const scratch = mkdtempSync(join(tmpdir(), 'codeality-db-soda-'))\n try {\n const configuration = join(scratch, 'configuration.yml')\n const results = join(scratch, 'results.json')\n writeFileSync(configuration, renderSodaConfiguration('codeality', soda.url))\n const result = runner(\n 'uvx',\n [\n '--with',\n 'setuptools',\n '--from',\n `soda-core-${dataSourceType(soda.url)}`,\n 'soda',\n 'scan',\n '-d',\n 'codeality',\n '-c',\n configuration,\n '-srf',\n results,\n `${soda.dir}/checks.yml`,\n ],\n { cwd: root, env: { SETUPTOOLS_USE_DISTUTILS: 'local' } },\n )\n if (result.missing) throw new ToolMissingError('uvx', 'install uv')\n if (!existsSync(results)) {\n const tail = result.stderr.trim().slice(-500)\n throw new Error(\n `soda scan produced no results (exit ${String(result.status)}): ${tail}`,\n )\n }\n return parseSodaResults(readFileSync(results, 'utf8'), soda.dir, disabled)\n } finally {\n rmSync(scratch, { recursive: true, force: true })\n }\n}\n","import { ConfigError } from '@/config/ConfigError.js'\n\nexport const dataSourceType = (url: string): 'postgres' | 'mysql' => {\n const scheme = url.split(':')[0] ?? ''\n if (scheme === 'postgres' || scheme === 'postgresql') return 'postgres'\n if (scheme === 'mysql') return 'mysql'\n throw new ConfigError(\n `Soda supports postgres and mysql URLs, not \"${scheme}\"`,\n )\n}\n","export const isDisabled = (code: string, disabled: string[]): boolean =>\n disabled.includes(code)\n","import { createHash } from 'node:crypto'\n\nimport type { Finding } from '@/model/Finding.js'\n\n// The line is deliberately excluded: a migration inserted above must not\n// renew every finding below it. The context (the normalised statement, or the\n// tool's message) is what tells two findings on one path apart.\nexport const fingerprintFinding = (\n finding: Omit<Finding, 'fingerprint'>,\n context: string,\n): string =>\n createHash('sha256')\n .update(['1', finding.code, finding.path, context].join('|'))\n .digest('hex')\n .slice(0, 16)\n","import type { SodaCheckResult } from '@/adapters/soda/SodaCheckResult.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\n\nexport const parseSodaResults = (\n json: string,\n sodaDir: string,\n disabled: string[],\n): Finding[] => {\n const { checks } = JSON.parse(json) as { checks: SodaCheckResult[] }\n return checks.flatMap((check) => {\n if (check.outcome !== 'fail' && check.outcome !== 'warn') return []\n const code = `BDB700/${check.name}`\n if (isDisabled(code, disabled)) return []\n const partial = {\n code,\n severity:\n check.outcome === 'fail' ? ('error' as const) : ('warn' as const),\n path: `${sodaDir}/checks.yml`,\n line: 0,\n message: `check ${check.outcome === 'fail' ? 'failed' : 'warned'}: ${check.name}`,\n subject: [check.table, check.column].filter(Boolean).join('.'),\n }\n return [\n { ...partial, fingerprint: fingerprintFinding(partial, check.name) },\n ]\n })\n}\n","import { dataSourceType } from '@/adapters/soda/dataSourceType.js'\n\nexport const renderSodaConfiguration = (name: string, url: string): string => {\n const type = dataSourceType(url)\n const parsed = new URL(url)\n const lines = [\n `data_source ${name}:`,\n ` type: ${type}`,\n ` host: ${parsed.hostname}`,\n ` port: ${parsed.port || (type === 'postgres' ? '5432' : '3306')}`,\n ` username: ${decodeURIComponent(parsed.username)}`,\n ` password: ${JSON.stringify(decodeURIComponent(parsed.password))}`,\n ` database: ${parsed.pathname.slice(1)}`,\n ...(type === 'postgres' ? [' schema: public'] : []),\n ]\n return `${lines.join('\\n')}\\n`\n}\n","/** A required executable is absent: exit code 3, never a skip. */\nexport class ToolMissingError extends Error {\n constructor(tool: string, hint: string) {\n super(`${tool} is not installed or not on PATH; ${hint}`)\n }\n}\n","import type { AdvisorEntry } from '@/adapters/supabase/AdvisorEntry.js'\nimport type { Severity } from '@/model/Severity.js'\n\nexport const ADVISOR_SEVERITY: Record<AdvisorEntry['level'], Severity> = {\n ERROR: 'error',\n WARN: 'warn',\n INFO: 'info',\n}\n","import { ADVISOR_SEVERITY } from '@/adapters/supabase/ADVISOR_SEVERITY.js'\nimport type { AdvisorEntry } from '@/adapters/supabase/AdvisorEntry.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\n\nexport const parseAdvisorReport = (\n stdout: string,\n disabled: string[],\n): Finding[] => {\n const { results } = JSON.parse(stdout) as { results: AdvisorEntry[] }\n return results.flatMap((entry) => {\n const code = `BDB500/${entry.name}`\n if (isDisabled(code, disabled)) return []\n const subject =\n entry.metadata?.schema && entry.metadata.name\n ? `${entry.metadata.schema}.${entry.metadata.name}`\n : ''\n const partial = {\n code,\n severity: ADVISOR_SEVERITY[entry.level],\n path: 'supabase',\n line: 0,\n message: entry.detail.replaceAll('\\\\`', '`'),\n subject,\n }\n return [\n { ...partial, fingerprint: fingerprintFinding(partial, entry.detail) },\n ]\n })\n}\n","import type { CliError } from '@/adapters/supabase/CliError.js'\n\n// The CLI prints progress lines before the document and may print more after\n// it, so the JSON is searched for and parsed up to each closing brace in turn\n// rather than from the first byte to the last.\nexport const parseCliError = (text: string): CliError | undefined => {\n const start = text.indexOf('{\"_tag\":\"Error\"')\n if (start === -1) return undefined\n for (\n let end = text.indexOf('}', start);\n end !== -1;\n end = text.indexOf('}', end + 1)\n ) {\n try {\n const { error } = JSON.parse(text.slice(start, end + 1)) as {\n error: CliError\n }\n return { code: error.code, message: error.message }\n } catch {\n // Not the closing brace of the document yet; try the next one.\n }\n }\n return { code: 'unknown', message: text.slice(start, start + 200) }\n}\n","import { parseCliError } from '@/adapters/supabase/parseCliError.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\nimport { ToolMissingError } from '@/tools/ToolMissingError.js'\n\n/**\n * Runs one Supabase CLI command that answers with a JSON document and returns\n * that document's text. The CLI reports its own failures, an expired login or\n * a project of another account among them, as a `{\"_tag\":\"Error\"}` document.\n */\nexport const supabaseJson = (\n runner: CommandRunner,\n root: string,\n args: string[],\n label: string,\n): string => {\n const result = runner('supabase', args, { cwd: root })\n if (result.missing)\n throw new ToolMissingError('supabase', 'install the Supabase CLI')\n const failure = parseCliError(`${result.stdout}\\n${result.stderr}`)\n if (failure || result.status !== 0) {\n const code = failure?.code ?? String(result.status)\n throw new Error(\n `${label} failed: ${code}: ${failure?.message ?? result.stderr.trim()}`,\n )\n }\n return result.stdout.slice(result.stdout.indexOf('{'))\n}\n","import type { AuditTarget } from '@/audit/AuditTarget.js'\n\n/** The Supabase CLI flags that name the database to inspect. */\nexport const targetArgs = (target: AuditTarget): string[] =>\n 'dbUrl' in target ? ['--db-url', target.dbUrl] : ['--linked']\n","import { parseAdvisorReport } from '@/adapters/supabase/parseAdvisorReport.js'\nimport { supabaseJson } from '@/adapters/supabase/supabaseJson.js'\nimport type { AuditTarget } from '@/audit/AuditTarget.js'\nimport { targetArgs } from '@/audit/targetArgs.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\n\nexport const runAdvisors = (\n runner: CommandRunner,\n root: string,\n target: AuditTarget,\n disabled: string[],\n): Finding[] =>\n parseAdvisorReport(\n supabaseJson(\n runner,\n root,\n [\n 'db',\n 'advisors',\n '--type',\n 'all',\n '--output-format',\n 'json',\n ...targetArgs(target),\n ],\n 'supabase advisors',\n ),\n disabled,\n )\n","import type { BloatRow } from '@/adapters/supabase/BloatRow.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\n\nexport const parseBloat = (\n stdout: string,\n threshold: number,\n disabled: string[],\n): Finding[] => {\n if (isDisabled('BDB602', disabled)) return []\n const { rows } = JSON.parse(stdout) as { rows: BloatRow[] }\n return rows\n .filter((row) => Number(row.bloat) > threshold)\n .map((row) => {\n const partial = {\n code: 'BDB602',\n severity: 'warn' as const,\n path: 'supabase',\n line: 0,\n message: `bloat factor ${row.bloat}, ${row.waste} wasted`,\n subject: row.name,\n }\n return { ...partial, fingerprint: fingerprintFinding(partial, row.name) }\n })\n}\n","import type { IndexStatRow } from '@/adapters/supabase/IndexStatRow.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\n\n// A primary key index is never \"unused\" in a way anyone can act on.\nexport const parseIndexStats = (\n stdout: string,\n disabled: string[],\n): Finding[] => {\n if (isDisabled('BDB601', disabled)) return []\n const { rows } = JSON.parse(stdout) as { rows: IndexStatRow[] }\n return rows\n .filter(\n (row) =>\n (row.unused || row.index_scans === '0') && !row.name.endsWith('_pkey'),\n )\n .map((row) => {\n const partial = {\n code: 'BDB601',\n severity: 'info' as const,\n path: 'supabase',\n line: 0,\n message: `index has never been scanned (${row.size})`,\n subject: row.name,\n }\n return { ...partial, fingerprint: fingerprintFinding(partial, row.name) }\n })\n}\n","import { parseBloat } from '@/adapters/supabase/parseBloat.js'\nimport { parseIndexStats } from '@/adapters/supabase/parseIndexStats.js'\nimport { supabaseJson } from '@/adapters/supabase/supabaseJson.js'\nimport type { AuditTarget } from '@/audit/AuditTarget.js'\nimport { targetArgs } from '@/audit/targetArgs.js'\nimport type { DbQualityConfig } from '@/config/DbQualityConfig.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\n\nexport const runInspect = (\n runner: CommandRunner,\n root: string,\n target: AuditTarget,\n config: Pick<DbQualityConfig, 'audit' | 'disable'>,\n): Finding[] => {\n const query = (report: string): string =>\n supabaseJson(\n runner,\n root,\n [\n 'inspect',\n 'db',\n report,\n '--output-format',\n 'json',\n ...targetArgs(target),\n ],\n `supabase inspect ${report}`,\n )\n return [\n ...parseIndexStats(query('index-stats'), config.disable),\n ...parseBloat(query('bloat'), config.audit.bloatThreshold, config.disable),\n ]\n}\n","import type { Finding } from '@/model/Finding.js'\n\nexport const compareFindings = (a: Finding, b: Finding): number =>\n a.path.localeCompare(b.path) ||\n a.line - b.line ||\n a.code.localeCompare(b.code)\n","import { runSoda } from '@/adapters/soda/runSoda.js'\nimport { runAdvisors } from '@/adapters/supabase/runAdvisors.js'\nimport { runInspect } from '@/adapters/supabase/runInspect.js'\nimport type { AuditContext } from '@/audit/AuditContext.js'\nimport { auditPlan } from '@/audit/auditPlan.js'\nimport { compareFindings } from '@/model/compareFindings.js'\nimport type { Finding } from '@/model/Finding.js'\n\nexport const runAudit = ({\n root,\n config,\n runner,\n target,\n}: AuditContext): Finding[] => {\n const plan = auditPlan(config, target)\n const findings: Finding[] = []\n if (plan.soda && 'dbUrl' in target && config.audit.soda !== undefined) {\n const soda = { dir: config.audit.soda, url: target.dbUrl }\n findings.push(...runSoda(runner, root, soda, config.disable))\n }\n if (plan.supabase) {\n findings.push(\n ...runAdvisors(runner, root, target, config.disable),\n ...runInspect(runner, root, target, config),\n )\n }\n return findings.sort(compareFindings)\n}\n","import type { Finding } from '@/model/Finding.js'\n\nexport const renderFindings = (findings: Finding[]): string =>\n [\n ...findings.map(\n (f) =>\n `${f.path}:${String(f.line)}: ${f.code} ${f.message}${f.subject ? ` (${f.subject})` : ''}`,\n ),\n `${String(findings.length)} findings`,\n ].join('\\n')\n","import type { Finding } from '@/model/Finding.js'\n\nexport const renderFindingsJson = (findings: Finding[]): string =>\n JSON.stringify({ schemaVersion: 1, findings }, null, 2)\n","import { parseArgs } from 'node:util'\n\nimport type { ParsedArgs } from '@/commands/ParsedArgs.js'\nimport { ConfigError } from '@/config/ConfigError.js'\n\nexport const parseCommandArgs = (\n argv: string[],\n options: Record<string, { type: 'boolean' | 'string' }>,\n): ParsedArgs => {\n try {\n const parsed = parseArgs({\n args: argv,\n options,\n allowPositionals: true,\n strict: true,\n })\n return { values: parsed.values, positionals: parsed.positionals }\n } catch (error) {\n throw new ConfigError((error as Error).message)\n }\n}\n","/** The four exit codes the CLI ever returns. A skipped required tool is never OK. */\nexport const ExitCode = {\n OK: 0,\n FINDINGS: 1,\n CONFIGURATION: 2,\n INFRASTRUCTURE: 3,\n} as const\n","import { ConfigError } from '@/config/ConfigError.js'\nimport { ExitCode } from '@/model/ExitCode.js'\n\n/** Prints the failure and returns its exit code: 2 for configuration, 3 for everything else. */\nexport const reportCommandError = (\n error: unknown,\n stderr: (text: string) => void,\n): number => {\n const configuration = error instanceof ConfigError\n const message = error instanceof Error ? error.message : String(error)\n stderr(`${configuration ? 'configuration error' : 'error'}: ${message}\\n`)\n return configuration ? ExitCode.CONFIGURATION : ExitCode.INFRASTRUCTURE\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { CONFIG_FILENAME } from '@/config/CONFIG_FILENAME.js'\nimport { ConfigError } from '@/config/ConfigError.js'\nimport type { DbQualityConfig } from '@/config/DbQualityConfig.js'\nimport { configFromDocument } from '@/config/configFromDocument.js'\n\nexport const readConfig = (root: string): DbQualityConfig => {\n const path = join(root, CONFIG_FILENAME)\n if (!existsSync(path)) {\n throw new ConfigError(\n `${CONFIG_FILENAME} not found in ${root}; run \"codeality-db init\"`,\n )\n }\n let document: unknown\n try {\n document = JSON.parse(readFileSync(path, 'utf8'))\n } catch (error) {\n throw new ConfigError(\n `${CONFIG_FILENAME} is not valid JSON: ${(error as Error).message}`,\n )\n }\n return configFromDocument(document)\n}\n","export const CONFIG_FILENAME = 'codeality-db.json'\n","import { ConfigError } from '@/config/ConfigError.js'\n\nexport const expectConfig = (condition: boolean, message: string): void => {\n if (!condition) throw new ConfigError(message)\n}\n","import type { DbQualityConfig } from '@/config/DbQualityConfig.js'\nimport { expectConfig } from '@/config/expectConfig.js'\n\nexport const auditSectionFrom = (\n audit: Record<string, unknown> | undefined,\n): DbQualityConfig['audit'] => {\n const inGate = audit?.['inGate'] ?? true\n const bloatThreshold = audit?.['bloatThreshold'] ?? 5\n const soda = audit?.['soda']\n expectConfig(typeof inGate === 'boolean', 'audit.inGate must be a boolean')\n expectConfig(\n typeof bloatThreshold === 'number',\n 'audit.bloatThreshold must be a number',\n )\n expectConfig(\n soda === undefined || typeof soda === 'string',\n 'audit.soda must be a string',\n )\n return {\n inGate: inGate as boolean,\n bloatThreshold: bloatThreshold as number,\n ...(soda === undefined ? {} : { soda: soda as string }),\n }\n}\n","export const CONFIG_KEYS = new Set([\n 'schemaVersion',\n 'supabase',\n 'prisma',\n 'drizzle',\n 'sqlite',\n 'audit',\n 'disable',\n])\n","import { ConfigError } from '@/config/ConfigError.js'\n\n/** The named section as an object, undefined when absent, ConfigError when it is not an object. */\nexport const configSection = (\n raw: Record<string, unknown>,\n name: string,\n): Record<string, unknown> | undefined => {\n const value = raw[name]\n if (value === undefined) return undefined\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new ConfigError(`${name} must be an object`)\n }\n return value as Record<string, unknown>\n}\n","export const isStringList = (value: unknown): value is string[] =>\n Array.isArray(value) && value.every((item) => typeof item === 'string')\n","import { ConfigError } from '@/config/ConfigError.js'\nimport type { DbQualityConfig } from '@/config/DbQualityConfig.js'\nimport { isStringList } from '@/config/isStringList.js'\n\nexport const drizzleSectionFrom = (\n drizzle: Record<string, unknown>,\n): NonNullable<DbQualityConfig['drizzle']> => {\n const roots = drizzle['roots']\n const objectNames = drizzle['objectNames'] ?? ['db', 'tx']\n if (!isStringList(roots))\n throw new ConfigError('drizzle.roots must be a list of strings')\n if (!isStringList(objectNames)) {\n throw new ConfigError('drizzle.objectNames must be a list of strings')\n }\n return { roots, objectNames }\n}\n","import { ConfigError } from '@/config/ConfigError.js'\nimport { configSection } from '@/config/configSection.js'\nimport { drizzleSectionFrom } from '@/config/drizzleSectionFrom.js'\nimport { isStringList } from '@/config/isStringList.js'\nimport type { StackSections } from '@/config/StackSections.js'\n\nexport const stackSectionsFrom = (\n raw: Record<string, unknown>,\n): StackSections => {\n const stacks: StackSections = {}\n const supabase = configSection(raw, 'supabase')\n if (supabase) {\n const migrations = supabase['migrations']\n if (typeof migrations !== 'string')\n throw new ConfigError('supabase.migrations must be a string')\n stacks.supabase = { migrations }\n }\n const prisma = configSection(raw, 'prisma')\n if (prisma) {\n const schema = prisma['schema']\n if (typeof schema !== 'string')\n throw new ConfigError('prisma.schema must be a string')\n stacks.prisma = { schema }\n }\n const drizzle = configSection(raw, 'drizzle')\n if (drizzle) stacks.drizzle = drizzleSectionFrom(drizzle)\n const sqlite = configSection(raw, 'sqlite')\n if (sqlite) {\n const files = sqlite['files']\n if (!isStringList(files))\n throw new ConfigError('sqlite.files must be a list of strings')\n stacks.sqlite = { files }\n }\n return stacks\n}\n","import { auditSectionFrom } from '@/config/auditSectionFrom.js'\nimport { CONFIG_KEYS } from '@/config/CONFIG_KEYS.js'\nimport { ConfigError } from '@/config/ConfigError.js'\nimport { configSection } from '@/config/configSection.js'\nimport type { DbQualityConfig } from '@/config/DbQualityConfig.js'\nimport { isStringList } from '@/config/isStringList.js'\nimport { stackSectionsFrom } from '@/config/stackSectionsFrom.js'\n\n/** Validates a parsed codeality-db.json and fills its defaults; ConfigError on any defect. */\nexport const configFromDocument = (document: unknown): DbQualityConfig => {\n if (\n typeof document !== 'object' ||\n document === null ||\n Array.isArray(document)\n ) {\n throw new ConfigError('configuration must be an object')\n }\n const raw = document as Record<string, unknown>\n for (const key of Object.keys(raw)) {\n if (!CONFIG_KEYS.has(key)) throw new ConfigError(`unknown key \"${key}\"`)\n }\n if (raw['schemaVersion'] !== 1)\n throw new ConfigError('schemaVersion must be 1')\n const disable = raw['disable'] ?? []\n if (!isStringList(disable))\n throw new ConfigError('disable must be a list of strings')\n return {\n schemaVersion: 1,\n ...stackSectionsFrom(raw),\n audit: auditSectionFrom(configSection(raw, 'audit')),\n disable,\n }\n}\n","import { auditPlan } from '@/audit/auditPlan.js'\nimport { resolveAuditTarget } from '@/audit/resolveAuditTarget.js'\nimport { runAudit } from '@/audit/runAudit.js'\nimport { renderFindings } from '@/check/renderFindings.js'\nimport { renderFindingsJson } from '@/check/renderFindingsJson.js'\nimport type { CommandIo } from '@/commands/CommandIo.js'\nimport { parseCommandArgs } from '@/commands/parseCommandArgs.js'\nimport { reportCommandError } from '@/commands/reportCommandError.js'\nimport { readConfig } from '@/config/readConfig.js'\nimport { ExitCode } from '@/model/ExitCode.js'\n\nexport const auditCommand = (argv: string[], io: CommandIo): number => {\n try {\n const { values } = parseCommandArgs(argv, {\n json: { type: 'boolean' },\n linked: { type: 'boolean' },\n 'db-url': { type: 'string' },\n })\n const config = readConfig(io.root)\n const target = resolveAuditTarget(io.root, {\n linked: values['linked'] === true,\n 'db-url': values['db-url'] as string | undefined,\n })\n for (const notice of auditPlan(config, target).skipped)\n io.stderr(`${notice}\\n`)\n const findings = runAudit({\n root: io.root,\n config,\n runner: io.runner,\n target,\n })\n io.stdout(\n `${values['json'] === true ? renderFindingsJson(findings) : renderFindings(findings)}\\n`,\n )\n return findings.length > 0 ? ExitCode.FINDINGS : ExitCode.OK\n } catch (error) {\n return reportCommandError(error, io.stderr)\n }\n}\n","import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { BASELINE_FILENAME } from '@/baseline/BASELINE_FILENAME.js'\nimport { baselineActionFrom } from '@/baseline/baselineActionFrom.js'\nimport { classifyFindings } from '@/baseline/classifyFindings.js'\nimport { readBaseline } from '@/baseline/readBaseline.js'\nimport { renderClassified } from '@/baseline/renderClassified.js'\nimport { writeBaseline } from '@/baseline/writeBaseline.js'\nimport { runCheck } from '@/check/runCheck.js'\nimport type { CommandIo } from '@/commands/CommandIo.js'\nimport { parseCommandArgs } from '@/commands/parseCommandArgs.js'\nimport { reportCommandError } from '@/commands/reportCommandError.js'\nimport { ConfigError } from '@/config/ConfigError.js'\nimport { readConfig } from '@/config/readConfig.js'\nimport { ExitCode } from '@/model/ExitCode.js'\nimport { PACKAGE_VERSION } from '@/packageVersion.js'\n\nexport const baselineCommand = (argv: string[], io: CommandIo): number => {\n try {\n const { values, positionals } = parseCommandArgs(argv, {\n 'check-stale': { type: 'boolean' },\n })\n const action = baselineActionFrom(positionals)\n if (action === 'create' && existsSync(join(io.root, BASELINE_FILENAME))) {\n throw new ConfigError(\n `${BASELINE_FILENAME} exists; use \"baseline update\" to rewrite it`,\n )\n }\n const findings = runCheck({\n root: io.root,\n config: readConfig(io.root),\n runner: io.runner,\n })\n if (action !== 'check') {\n const entries = findings.map((f) => f.fingerprint)\n writeBaseline(io.root, {\n schemaVersion: 1,\n toolVersion: PACKAGE_VERSION,\n entries,\n })\n io.stdout(\n `recorded ${String(findings.length)} findings in ${BASELINE_FILENAME}\\n`,\n )\n return ExitCode.OK\n }\n const classified = classifyFindings(findings, readBaseline(io.root))\n io.stdout(`${renderClassified(classified)}\\n`)\n const stale =\n values['check-stale'] === true && classified.resolved.length > 0\n return classified.new.length > 0 || stale ? ExitCode.FINDINGS : ExitCode.OK\n } catch (error) {\n return reportCommandError(error, io.stderr)\n }\n}\n","export const BASELINE_FILENAME = '.codeality-db-baseline.json'\n","export const BASELINE_USAGE =\n 'usage: codeality-db baseline create|update|check [--check-stale]'\n","import { BASELINE_USAGE } from '@/baseline/BASELINE_USAGE.js'\nimport type { BaselineAction } from '@/baseline/BaselineAction.js'\nimport { ConfigError } from '@/config/ConfigError.js'\n\nexport const baselineActionFrom = (positionals: string[]): BaselineAction => {\n const action = positionals[0]\n if (action === 'create' || action === 'update' || action === 'check')\n return action\n throw new ConfigError(BASELINE_USAGE)\n}\n","import type { BaselineFile } from '@/baseline/BaselineFile.js'\nimport type { ClassifiedFindings } from '@/baseline/ClassifiedFindings.js'\nimport type { Finding } from '@/model/Finding.js'\n\n// A baseline entry nothing reports any more is resolved, and reporting it is\n// what stops dead debt being carried forever.\nexport const classifyFindings = (\n findings: Finding[],\n baseline: BaselineFile,\n): ClassifiedFindings => {\n const entries = new Set(baseline.entries)\n const current = new Set(findings.map((finding) => finding.fingerprint))\n return {\n new: findings.filter((finding) => !entries.has(finding.fingerprint)),\n known: findings.filter((finding) => entries.has(finding.fingerprint)),\n resolved: baseline.entries.filter((entry) => !current.has(entry)).sort(),\n }\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { BASELINE_FILENAME } from '@/baseline/BASELINE_FILENAME.js'\nimport type { BaselineFile } from '@/baseline/BaselineFile.js'\nimport { ConfigError } from '@/config/ConfigError.js'\n\nexport const readBaseline = (root: string): BaselineFile => {\n const path = join(root, BASELINE_FILENAME)\n if (!existsSync(path)) {\n throw new ConfigError(\n `${BASELINE_FILENAME} not found; run \"codeality-db baseline create\"`,\n )\n }\n const document = JSON.parse(\n readFileSync(path, 'utf8'),\n ) as Partial<BaselineFile>\n if (document.schemaVersion !== 1 || !Array.isArray(document.entries)) {\n throw new ConfigError(`${BASELINE_FILENAME} is not a version 1 baseline`)\n }\n return {\n schemaVersion: 1,\n toolVersion: document.toolVersion ?? '',\n entries: [...document.entries].sort(),\n }\n}\n","import type { ClassifiedFindings } from '@/baseline/ClassifiedFindings.js'\nimport { renderFindings } from '@/check/renderFindings.js'\n\n/** The counts line, then the new findings when there are any. */\nexport const renderClassified = (classified: ClassifiedFindings): string => {\n const counts = `${String(classified.new.length)} new, ${String(classified.known.length)} known, ${String(classified.resolved.length)} resolved`\n return classified.new.length > 0\n ? `${counts}\\n${renderFindings(classified.new)}`\n : counts\n}\n","import { renameSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { BASELINE_FILENAME } from '@/baseline/BASELINE_FILENAME.js'\nimport type { BaselineFile } from '@/baseline/BaselineFile.js'\n\n/** Writes the baseline atomically: a temporary file, then a rename over the target. */\nexport const writeBaseline = (root: string, baseline: BaselineFile): void => {\n const path = join(root, BASELINE_FILENAME)\n const document = {\n schemaVersion: 1,\n toolVersion: baseline.toolVersion,\n entries: [...baseline.entries].sort(),\n }\n writeFileSync(`${path}.tmp`, `${JSON.stringify(document, null, 2)}\\n`)\n renameSync(`${path}.tmp`, path)\n}\n","import { relative } from 'node:path'\n\nimport type { EslintFileResult } from '@/adapters/drizzle/EslintFileResult.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\n\nexport const parseEslintReport = (\n stdout: string,\n root: string,\n disabled: string[],\n): Finding[] => {\n if (!stdout.trim()) return []\n let files: EslintFileResult[]\n try {\n files = JSON.parse(stdout) as EslintFileResult[]\n } catch {\n throw new Error(`eslint produced no JSON report: ${stdout.slice(0, 200)}`)\n }\n return files.flatMap((file) =>\n file.messages.flatMap((message) => {\n if (!message.ruleId?.startsWith('drizzle/')) return []\n const rule = message.ruleId.slice('drizzle/'.length)\n const code = `BDB300/${rule}`\n if (isDisabled(code, disabled)) return []\n const partial = {\n code,\n severity: 'error' as const,\n path: relative(root, file.filePath).replaceAll('\\\\', '/'),\n line: message.line,\n message: message.message,\n subject: rule,\n }\n return [\n {\n ...partial,\n fingerprint: fingerprintFinding(partial, message.message),\n },\n ]\n }),\n )\n}\n","import { fileURLToPath } from 'node:url'\n\n// `assets/` is one level up from both `dist/cli.js` (the bundle) and `src/`.\nexport const assetPath = (name: string): string =>\n fileURLToPath(new URL(`../assets/${name}`, import.meta.url))\n","import { parseEslintReport } from '@/adapters/drizzle/parseEslintReport.js'\nimport { assetPath } from '@/assetPath.js'\nimport type { DbQualityConfig } from '@/config/DbQualityConfig.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\nimport { ToolMissingError } from '@/tools/ToolMissingError.js'\n\n// Runs from the project root: ESLint ignores any file outside its cwd, which\n// is what an earlier attempt from another directory reported as \"all files\n// matching the pattern are ignored\".\n// `--no-config-lookup` does not stop ESLint reading the project's own\n// eslint-suppressions.json, and an entry there that no longer matches makes\n// it exit 2 with no report; the flag turns that into a pass (measured on a\n// project whose suppressions had gone stale, 2026-09-25).\nexport const runDrizzleLint = (\n runner: CommandRunner,\n root: string,\n drizzle: NonNullable<DbQualityConfig['drizzle']>,\n disabled: string[],\n): Finding[] => {\n const result = runner(\n 'eslint',\n [\n '--no-config-lookup',\n '-c',\n assetPath('drizzle-eslint.config.mjs'),\n '-f',\n 'json',\n '--pass-on-unpruned-suppressions',\n ...drizzle.roots,\n ],\n {\n cwd: root,\n env: { CODEALITY_DB_DRIZZLE_OBJECTS: drizzle.objectNames.join(',') },\n },\n )\n if (result.missing) {\n throw new ToolMissingError(\n 'eslint',\n 'add eslint, eslint-plugin-drizzle and typescript-eslint as devDependencies',\n )\n }\n if (result.status !== 0 && result.status !== 1) {\n throw new Error(\n `eslint exited ${String(result.status)}: ${result.stderr.trim()}`,\n )\n }\n return parseEslintReport(result.stdout, root, disabled)\n}\n","import type { PrismaViolation } from '@/adapters/prisma/PrismaViolation.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\n\nexport const parsePrismaLintReport = (\n stderr: string,\n disabled: string[],\n): Finding[] => {\n if (!stderr.trim()) return []\n let violations: PrismaViolation[]\n try {\n violations = (JSON.parse(stderr) as { violations: PrismaViolation[] })\n .violations\n } catch {\n throw new Error(\n `prisma-lint produced no JSON report: ${stderr.slice(0, 200)}`,\n )\n }\n return violations.flatMap((violation) => {\n const code = `BDB200/${violation.ruleName}`\n if (isDisabled(code, disabled)) return []\n const partial = {\n code,\n severity: 'warn' as const,\n path: violation.fileName,\n line: violation.location.startLine,\n message: violation.message,\n subject: /Field \"([^\"]+)\"/.exec(violation.message)?.[1] ?? '',\n }\n return [\n {\n ...partial,\n fingerprint: fingerprintFinding(partial, violation.message),\n },\n ]\n })\n}\n","import { parsePrismaLintReport } from '@/adapters/prisma/parsePrismaLintReport.js'\nimport { assetPath } from '@/assetPath.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\nimport { ToolMissingError } from '@/tools/ToolMissingError.js'\n\n// prisma-lint writes its JSON report to stderr, and exits 1 whenever it has\n// one violation to report. Both are its documented behaviour, not a bug here.\nexport const runPrismaLint = (\n runner: CommandRunner,\n root: string,\n schemaPath: string,\n disabled: string[],\n): Finding[] => {\n const result = runner(\n 'prisma-lint',\n ['-c', assetPath('prisma-lint.json'), '-o', 'json', schemaPath],\n { cwd: root },\n )\n if (result.missing) {\n throw new ToolMissingError(\n 'prisma-lint',\n 'add prisma-lint as a devDependency',\n )\n }\n if (result.status !== 0 && result.status !== 1) {\n throw new Error(\n `prisma-lint exited ${String(result.status)}: ${result.stderr.trim()}`,\n )\n }\n return parsePrismaLintReport(result.stderr, disabled)\n}\n","import type { SqliteFindingInput } from '@/adapters/sqlite/SqliteFindingInput.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\n\n/** Zero or one finding on a SQLite file: none when the code is disabled. Line is always 0. */\nexport const sqliteFinding = (\n input: SqliteFindingInput,\n disabled: string[],\n): Finding[] => {\n if (isDisabled(input.code, disabled)) return []\n const partial = {\n code: input.code,\n severity: input.severity,\n path: input.file,\n line: 0,\n message: input.message,\n subject: input.subject,\n }\n return [\n { ...partial, fingerprint: fingerprintFinding(partial, input.context) },\n ]\n}\n","import type { CommandRunner } from '@/tools/CommandRunner.js'\nimport { ToolMissingError } from '@/tools/ToolMissingError.js'\n\nexport const sqliteQuery = (\n runner: CommandRunner,\n root: string,\n file: string,\n sql: string,\n): string => {\n const result = runner('sqlite3', ['-json', '-readonly', file, sql], {\n cwd: root,\n })\n if (result.missing) {\n throw new ToolMissingError(\n 'sqlite3',\n 'install the sqlite3 command line shell',\n )\n }\n if (result.status !== 0)\n throw new Error(`sqlite3 failed on ${file}: ${result.stderr.trim()}`)\n return result.stdout\n}\n","import { sqliteQuery } from '@/adapters/sqlite/sqliteQuery.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\n\n/** The rows of one read-only query, as `sqlite3 -json` prints them; none when it prints nothing. */\nexport const sqliteRows = <T>(\n runner: CommandRunner,\n root: string,\n file: string,\n sql: string,\n): T[] => {\n const out = sqliteQuery(runner, root, file, sql).trim()\n return out ? (JSON.parse(out) as T[]) : []\n}\n","import { sqliteFinding } from '@/adapters/sqlite/sqliteFinding.js'\nimport { sqliteRows } from '@/adapters/sqlite/sqliteRows.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\n\n/** BDB402: one finding per row `PRAGMA foreign_key_check` reports. */\nexport const foreignKeyFindings = (\n runner: CommandRunner,\n root: string,\n file: string,\n disabled: string[],\n): Finding[] =>\n sqliteRows<{ table: string; rowid: number; parent: string }>(\n runner,\n root,\n file,\n 'PRAGMA foreign_key_check',\n ).flatMap((row) =>\n sqliteFinding(\n {\n code: 'BDB402',\n severity: 'error',\n file,\n subject: row.table,\n message: `row ${String(row.rowid)} references missing ${row.parent}`,\n context: `${row.table}:${String(row.rowid)}:${row.parent}`,\n },\n disabled,\n ),\n )\n","import { sqliteFinding } from '@/adapters/sqlite/sqliteFinding.js'\nimport { sqliteRows } from '@/adapters/sqlite/sqliteRows.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\n\n/** BDB401: `PRAGMA integrity_check` answered anything but a single `ok`. */\nexport const integrityFindings = (\n runner: CommandRunner,\n root: string,\n file: string,\n disabled: string[],\n): Finding[] => {\n const rows = sqliteRows<{ integrity_check: string }>(\n runner,\n root,\n file,\n 'PRAGMA integrity_check',\n )\n const first = rows[0]?.integrity_check ?? 'no result'\n if (rows.length === 1 && first === 'ok') return []\n return sqliteFinding(\n {\n code: 'BDB401',\n severity: 'error',\n file,\n subject: '',\n message: `integrity_check: ${first}`,\n context: first,\n },\n disabled,\n )\n}\n","export const hasPrimaryKey = (createSql: string): boolean => {\n const text = createSql.toLowerCase()\n return text.startsWith('create virtual table') || text.includes('primary key')\n}\n","import { hasPrimaryKey } from '@/adapters/sqlite/hasPrimaryKey.js'\nimport { sqliteFinding } from '@/adapters/sqlite/sqliteFinding.js'\nimport { sqliteRows } from '@/adapters/sqlite/sqliteRows.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\n\n/** BDB403: every user table whose CREATE statement declares no primary key. */\nexport const primaryKeyFindings = (\n runner: CommandRunner,\n root: string,\n file: string,\n disabled: string[],\n): Finding[] =>\n sqliteRows<{ name: string; sql: string }>(\n runner,\n root,\n file,\n \"select name, sql from sqlite_master where type = 'table' and name not like 'sqlite_%'\",\n ).flatMap((row) =>\n hasPrimaryKey(row.sql)\n ? []\n : sqliteFinding(\n {\n code: 'BDB403',\n severity: 'warn',\n file,\n subject: row.name,\n message: 'table has no primary key',\n context: row.name,\n },\n disabled,\n ),\n )\n","import { foreignKeyFindings } from '@/adapters/sqlite/foreignKeyFindings.js'\nimport { integrityFindings } from '@/adapters/sqlite/integrityFindings.js'\nimport { primaryKeyFindings } from '@/adapters/sqlite/primaryKeyFindings.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\n\nexport const runSqliteChecks = (\n runner: CommandRunner,\n root: string,\n files: string[],\n disabled: string[],\n): Finding[] =>\n files.flatMap((file) => [\n ...integrityFindings(runner, root, file, disabled),\n ...foreignKeyFindings(runner, root, file, disabled),\n ...primaryKeyFindings(runner, root, file, disabled),\n ])\n","export const normalizeSqlText = (text: string): string =>\n text.toLowerCase().replaceAll(/\\s+/g, ' ').trim()\n","import type { MigrationFile } from '@/sql/MigrationFile.js'\nimport type { SqlStatement } from '@/sql/SqlStatement.js'\n\nexport const statementAtLine = (\n file: MigrationFile,\n line: number,\n): SqlStatement | undefined =>\n [...file.statements].reverse().find((statement) => statement.line <= line)\n","import type { SquawkEntry } from '@/adapters/squawk/SquawkEntry.js'\nimport { isDisabled } from '@/config/isDisabled.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\nimport { normalizeSqlText } from '@/model/normalizeSqlText.js'\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\nimport { statementAtLine } from '@/sql/statementAtLine.js'\n\nexport const parseSquawkReport = (\n stdout: string,\n set: MigrationFile[],\n disabled: string[],\n): Finding[] => {\n if (!stdout.trim()) return []\n let entries: SquawkEntry[]\n try {\n entries = JSON.parse(stdout) as SquawkEntry[]\n } catch {\n throw new Error(`squawk produced no JSON report: ${stdout.slice(0, 200)}`)\n }\n return entries.flatMap((entry) => {\n const code = `BDB100/${entry.rule_name}`\n if (isDisabled(code, disabled)) return []\n const file = set.find((candidate) => candidate.path === entry.file)\n const statement = file ? statementAtLine(file, entry.line) : undefined\n const partial = {\n code,\n severity:\n entry.level === 'Error' ? ('error' as const) : ('warn' as const),\n path: entry.file,\n line: entry.line,\n message: entry.message,\n subject: entry.rule_name,\n }\n const context = statement ? normalizeSqlText(statement.text) : entry.message\n return [{ ...partial, fingerprint: fingerprintFinding(partial, context) }]\n })\n}\n","// Supabase applies each migration inside one transaction with the CLI's own\n// timeouts, so the lock, timeout and CONCURRENTLY rules describe a deployment\n// model these projects do not have. Measured 2026-09-25 over six repositories:\n// these four were 80% of every squawk line and none of them was actionable.\nexport const SUPABASE_SQUAWK_EXCLUDES = [\n 'prefer-robust-stmts',\n 'require-lock-timeout',\n 'require-statement-timeout',\n 'require-concurrent-index-creation',\n]\n","import { parseSquawkReport } from '@/adapters/squawk/parseSquawkReport.js'\nimport { SUPABASE_SQUAWK_EXCLUDES } from '@/adapters/squawk/SUPABASE_SQUAWK_EXCLUDES.js'\nimport type { Finding } from '@/model/Finding.js'\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\nimport { ToolMissingError } from '@/tools/ToolMissingError.js'\n\nexport const runSquawk = (\n runner: CommandRunner,\n root: string,\n set: MigrationFile[],\n disabled: string[],\n): Finding[] => {\n const result = runner(\n 'squawk',\n [\n '--reporter',\n 'json',\n '--exclude',\n SUPABASE_SQUAWK_EXCLUDES.join(','),\n ...set.map((f) => f.path),\n ],\n { cwd: root },\n )\n if (result.missing)\n throw new ToolMissingError('squawk', 'add squawk-cli as a devDependency')\n if (result.status !== 0 && result.status !== 1) {\n throw new Error(\n `squawk exited ${String(result.status)}: ${result.stderr.trim()}`,\n )\n }\n return parseSquawkReport(result.stdout, set, disabled)\n}\n","import type { Finding } from '@/model/Finding.js'\nimport { fingerprintFinding } from '@/model/fingerprintFinding.js'\nimport { normalizeSqlText } from '@/model/normalizeSqlText.js'\nimport type { SqlRule } from '@/rules/SqlRule.js'\nimport type { StatementRef } from '@/rules/StatementRef.js'\n\nexport const makeSqlFinding = (\n rule: Pick<SqlRule, 'code' | 'severity'>,\n { file, statement }: StatementRef,\n subject: string,\n message: string,\n): Finding => {\n const partial = {\n code: rule.code,\n severity: rule.severity,\n path: file.path,\n line: statement.line,\n message,\n subject,\n }\n return {\n ...partial,\n fingerprint: fingerprintFinding(partial, normalizeSqlText(statement.text)),\n }\n}\n","export const qualifiedName = (raw: string): string => {\n const parts = raw\n .trim()\n .split('.')\n .map((part) => part.replaceAll('\"', '').toLowerCase())\n return parts.length === 1 ? `public.${parts[0] ?? ''}` : parts.join('.')\n}\n","import { normalizeSqlText } from '@/model/normalizeSqlText.js'\nimport { qualifiedName } from '@/sql/qualifiedName.js'\nimport type { SqlStatement } from '@/sql/SqlStatement.js'\n\nexport const policyTable = (statement: SqlStatement): string | undefined => {\n const match =\n /^create policy .+? on ((?:\"[^\"]+\"|[\\w$]+)(?:\\.(?:\"[^\"]+\"|[\\w$]+))?)/.exec(\n normalizeSqlText(statement.text),\n )\n return match?.[1] === undefined ? undefined : qualifiedName(match[1])\n}\n","import { normalizeSqlText } from '@/model/normalizeSqlText.js'\nimport { makeSqlFinding } from '@/rules/makeSqlFinding.js'\nimport { policyTable } from '@/rules/policyTable.js'\nimport type { SqlRule } from '@/rules/SqlRule.js'\n\nexport const authUidNotWrapped: SqlRule = {\n code: 'BDB004',\n name: 'auth-uid-not-wrapped',\n severity: 'warn',\n run: (set) =>\n set.flatMap((file) =>\n file.statements\n .filter((statement) => {\n const text = normalizeSqlText(statement.text)\n return (\n text.startsWith('create policy') &&\n /(?<!\\(select )auth\\.(?:uid|jwt)\\(\\)/.test(text)\n )\n })\n .map((statement) =>\n makeSqlFinding(\n authUidNotWrapped,\n { file, statement },\n policyTable(statement) ?? '',\n 'auth.uid() or auth.jwt() is re-evaluated per row; wrap it as (select auth.uid()) so Postgres caches it as an initplan',\n ),\n ),\n ),\n}\n","import { normalizeSqlText } from '@/model/normalizeSqlText.js'\nimport { makeSqlFinding } from '@/rules/makeSqlFinding.js'\nimport type { SqlRule } from '@/rules/SqlRule.js'\nimport { qualifiedName } from '@/sql/qualifiedName.js'\n\nexport const definerWithoutSearchPath: SqlRule = {\n code: 'BDB005',\n name: 'definer-without-search-path',\n severity: 'warn',\n run: (set) =>\n set.flatMap((file) =>\n file.statements.flatMap((statement) => {\n const text = normalizeSqlText(statement.text)\n const head =\n /^create (?:or replace )?(?:function|procedure) ((?:\"[^\"]+\"|[\\w$]+)(?:\\.(?:\"[^\"]+\"|[\\w$]+))?)\\s*\\(/.exec(\n text,\n )\n if (\n !head?.[1] ||\n !text.includes(' security definer') ||\n text.includes(' set search_path')\n ) {\n return []\n }\n return [\n makeSqlFinding(\n definerWithoutSearchPath,\n { file, statement },\n qualifiedName(head[1]),\n 'SECURITY DEFINER function without \"set search_path\": a caller can shadow the objects it touches',\n ),\n ]\n }),\n ),\n}\n","import { normalizeSqlText } from '@/model/normalizeSqlText.js'\nimport { makeSqlFinding } from '@/rules/makeSqlFinding.js'\nimport { policyTable } from '@/rules/policyTable.js'\nimport type { SqlRule } from '@/rules/SqlRule.js'\n\nexport const permissivePolicy: SqlRule = {\n code: 'BDB001',\n name: 'permissive-policy',\n severity: 'warn',\n run: (set) =>\n set.flatMap((file) =>\n file.statements\n .filter((statement) => {\n const text = normalizeSqlText(statement.text)\n return (\n text.startsWith('create policy') &&\n /(?:using|with check) \\( ?true ?\\)/.test(text)\n )\n })\n .map((statement) =>\n makeSqlFinding(\n permissivePolicy,\n { file, statement },\n policyTable(statement) ?? '',\n 'policy is permissive: using (true) or with check (true) lets every row through for the granted role',\n ),\n ),\n ),\n}\n","import { policyTable } from '@/rules/policyTable.js'\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\n\nexport const policyTables = (set: MigrationFile[]): Set<string> => {\n const tables = new Set<string>()\n for (const file of set)\n for (const statement of file.statements) {\n const table = policyTable(statement)\n if (table) tables.add(table)\n }\n return tables\n}\n","import { normalizeSqlText } from '@/model/normalizeSqlText.js'\nimport type { StatementRef } from '@/rules/StatementRef.js'\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\nimport { qualifiedName } from '@/sql/qualifiedName.js'\n\n/** Qualified names captured by group 1 of `pattern`, each mapped to its first statement. */\nexport const matchedTables = (\n set: MigrationFile[],\n pattern: RegExp,\n): Map<string, StatementRef> => {\n const tables = new Map<string, StatementRef>()\n for (const file of set)\n for (const statement of file.statements) {\n const match = pattern.exec(normalizeSqlText(statement.text))\n if (!match?.[1]) continue\n const name = qualifiedName(match[1])\n if (!tables.has(name)) tables.set(name, { file, statement })\n }\n return tables\n}\n","import { matchedTables } from '@/rules/matchedTables.js'\nimport type { StatementRef } from '@/rules/StatementRef.js'\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\n\n/** Tables whose row level security a migration enables, mapped to that statement. */\nexport const rlsEnabledTables = (\n set: MigrationFile[],\n): Map<string, StatementRef> =>\n matchedTables(\n set,\n /^alter table (?:if exists )?(?:only )?((?:\"[^\"]+\"|[\\w$]+)(?:\\.(?:\"[^\"]+\"|[\\w$]+))?) enable row level security/,\n )\n","import { makeSqlFinding } from '@/rules/makeSqlFinding.js'\nimport { policyTables } from '@/rules/policyTables.js'\nimport { rlsEnabledTables } from '@/rules/rlsEnabledTables.js'\nimport type { SqlRule } from '@/rules/SqlRule.js'\n\nexport const rlsEnabledNoPolicy: SqlRule = {\n code: 'BDB002',\n name: 'rls-enabled-no-policy',\n severity: 'info',\n run: (set) => {\n const withPolicy = policyTables(set)\n return [...rlsEnabledTables(set)]\n .filter(([table]) => !withPolicy.has(table))\n .map(([table, ref]) =>\n makeSqlFinding(\n rlsEnabledNoPolicy,\n ref,\n table,\n 'RLS is enabled but no migration defines a policy: only the service role can reach this table',\n ),\n )\n },\n}\n","import { matchedTables } from '@/rules/matchedTables.js'\nimport type { StatementRef } from '@/rules/StatementRef.js'\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\n\n/** Tables created in `public`, each mapped to the statement that creates it. */\nexport const createdTables = (\n set: MigrationFile[],\n): Map<string, StatementRef> =>\n new Map(\n [\n ...matchedTables(\n set,\n /^create (?:unlogged |temp(?:orary)? )?table (?:if not exists )?((?:\"[^\"]+\"|[\\w$]+)(?:\\.(?:\"[^\"]+\"|[\\w$]+))?)/,\n ),\n ].filter(([name]) => name.startsWith('public.')),\n )\n","import { createdTables } from '@/rules/createdTables.js'\nimport { makeSqlFinding } from '@/rules/makeSqlFinding.js'\nimport { rlsEnabledTables } from '@/rules/rlsEnabledTables.js'\nimport type { SqlRule } from '@/rules/SqlRule.js'\n\nexport const tableWithoutRls: SqlRule = {\n code: 'BDB003',\n name: 'table-without-rls',\n severity: 'warn',\n run: (set) => {\n const enabled = rlsEnabledTables(set)\n return [...createdTables(set)]\n .filter(([table]) => !enabled.has(table))\n .map(([table, ref]) =>\n makeSqlFinding(\n tableWithoutRls,\n ref,\n table,\n 'table in public never enables row level security: it is readable through the Data API by anyone holding the anon key',\n ),\n )\n },\n}\n","import { authUidNotWrapped } from '@/rules/authUidNotWrapped.js'\nimport { definerWithoutSearchPath } from '@/rules/definerWithoutSearchPath.js'\nimport { permissivePolicy } from '@/rules/permissivePolicy.js'\nimport { rlsEnabledNoPolicy } from '@/rules/rlsEnabledNoPolicy.js'\nimport type { SqlRule } from '@/rules/SqlRule.js'\nimport { tableWithoutRls } from '@/rules/tableWithoutRls.js'\n\nexport const SQL_RULES: SqlRule[] = [\n permissivePolicy,\n rlsEnabledNoPolicy,\n tableWithoutRls,\n authUidNotWrapped,\n definerWithoutSearchPath,\n]\n","import { isDisabled } from '@/config/isDisabled.js'\nimport { compareFindings } from '@/model/compareFindings.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { SQL_RULES } from '@/rules/SQL_RULES.js'\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\n\nexport const runSqlRules = (\n set: MigrationFile[],\n disabled: string[],\n): Finding[] =>\n SQL_RULES.filter((rule) => !isDisabled(rule.code, disabled))\n .flatMap((rule) => rule.run(set))\n .sort(compareFindings)\n","import { readdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { MigrationFile } from '@/sql/MigrationFile.js'\nimport { splitSqlStatements } from '@/sql/splitSqlStatements.js'\n\nexport const readMigrationSet = (\n root: string,\n migrationsDir: string,\n): MigrationFile[] =>\n readdirSync(join(root, migrationsDir))\n .filter((name) => name.endsWith('.sql'))\n .sort()\n .map((name) => ({\n path: `${migrationsDir.replaceAll('\\\\', '/')}/${name}`,\n statements: splitSqlStatements(\n readFileSync(join(root, migrationsDir, name), 'utf8'),\n ),\n }))\n","/**\n * End offset (exclusive) of the string, quoted identifier or dollar-quoted\n * body that starts at `index`, or undefined when nothing quoted starts there.\n * An unterminated span runs to the end of the text.\n */\nexport const quotedSpanEnd = (\n sql: string,\n index: number,\n): number | undefined => {\n const dollar = /^\\$[a-z_]*\\$/i.exec(sql.slice(index, index + 64))\n if (dollar) {\n const end = sql.indexOf(dollar[0], index + dollar[0].length)\n return end === -1 ? sql.length : end + dollar[0].length\n }\n const quote = sql[index]\n if (quote !== \"'\" && quote !== '\"') return undefined\n const end = sql.indexOf(quote, index + 1)\n return end === -1 ? sql.length : end + 1\n}\n","import { quotedSpanEnd } from '@/sql/quotedSpanEnd.js'\n\n// Comments become nothing but their newlines, so the line numbers of what\n// follows are unchanged. Strings, quoted identifiers and dollar-quoted bodies\n// are copied through untouched: a `--` inside them is data.\nexport const stripSqlComments = (sql: string): string => {\n let out = ''\n let index = 0\n while (index < sql.length) {\n const quoted = quotedSpanEnd(sql, index)\n if (quoted !== undefined) {\n out += sql.slice(index, quoted)\n index = quoted\n } else if (sql.startsWith('--', index)) {\n const end = sql.indexOf('\\n', index)\n index = end === -1 ? sql.length : end\n } else if (sql.startsWith('/*', index)) {\n const end = sql.indexOf('*/', index + 2)\n const stop = end === -1 ? sql.length : end + 2\n out += sql.slice(index, stop).replaceAll(/[^\\n]/g, '')\n index = stop\n } else {\n out += sql.charAt(index)\n index += 1\n }\n }\n return out\n}\n","import { quotedSpanEnd } from '@/sql/quotedSpanEnd.js'\nimport type { SqlStatement } from '@/sql/SqlStatement.js'\nimport { stripSqlComments } from '@/sql/stripSqlComments.js'\n\nexport const splitSqlStatements = (sql: string): SqlStatement[] => {\n const text = stripSqlComments(sql)\n const statements: SqlStatement[] = []\n let start = 0\n const flush = (end: number): void => {\n const raw = text.slice(start, end)\n const leading = raw.length - raw.trimStart().length\n const body = raw.trim()\n if (body) {\n const line =\n 1 + (text.slice(0, start + leading).match(/\\n/g)?.length ?? 0)\n statements.push({ text: body, line })\n }\n start = end + 1\n }\n let index = 0\n while (index < text.length) {\n const quoted = quotedSpanEnd(text, index)\n if (quoted !== undefined) index = quoted\n else {\n if (text[index] === ';') flush(index)\n index += 1\n }\n }\n flush(text.length)\n return statements\n}\n","import { runDrizzleLint } from '@/adapters/drizzle/runDrizzleLint.js'\nimport { runPrismaLint } from '@/adapters/prisma/runPrismaLint.js'\nimport { runSqliteChecks } from '@/adapters/sqlite/runSqliteChecks.js'\nimport { runSquawk } from '@/adapters/squawk/runSquawk.js'\nimport type { CheckContext } from '@/check/CheckContext.js'\nimport { compareFindings } from '@/model/compareFindings.js'\nimport type { Finding } from '@/model/Finding.js'\nimport { runSqlRules } from '@/rules/runSqlRules.js'\nimport { readMigrationSet } from '@/sql/readMigrationSet.js'\n\n/** Every static adapter the configuration enables, in one sorted list. Errors propagate. */\nexport const runCheck = ({ root, config, runner }: CheckContext): Finding[] => {\n const findings: Finding[] = []\n if (config.supabase) {\n const set = readMigrationSet(root, config.supabase.migrations)\n findings.push(\n ...runSqlRules(set, config.disable),\n ...runSquawk(runner, root, set, config.disable),\n )\n }\n if (config.prisma) {\n findings.push(\n ...runPrismaLint(runner, root, config.prisma.schema, config.disable),\n )\n }\n if (config.drizzle)\n findings.push(\n ...runDrizzleLint(runner, root, config.drizzle, config.disable),\n )\n if (config.sqlite) {\n findings.push(\n ...runSqliteChecks(runner, root, config.sqlite.files, config.disable),\n )\n }\n return findings.sort(compareFindings)\n}\n","import { createRequire } from 'node:module'\n\n// Read at runtime from the package's own manifest so the bundle never carries\n// a copy that drifts from `package.json`. Both `dist/cli.js` and `src/` sit\n// one level below the package root.\nexport const PACKAGE_VERSION: string = (\n createRequire(import.meta.url)('../package.json') as { version: string }\n).version\n","import { renderFindings } from '@/check/renderFindings.js'\nimport { renderFindingsJson } from '@/check/renderFindingsJson.js'\nimport { runCheck } from '@/check/runCheck.js'\nimport type { CommandIo } from '@/commands/CommandIo.js'\nimport { parseCommandArgs } from '@/commands/parseCommandArgs.js'\nimport { reportCommandError } from '@/commands/reportCommandError.js'\nimport { readConfig } from '@/config/readConfig.js'\nimport { ExitCode } from '@/model/ExitCode.js'\n\nexport const checkCommand = (argv: string[], io: CommandIo): number => {\n try {\n const { values } = parseCommandArgs(argv, { json: { type: 'boolean' } })\n const findings = runCheck({\n root: io.root,\n config: readConfig(io.root),\n runner: io.runner,\n })\n io.stdout(\n `${values['json'] === true ? renderFindingsJson(findings) : renderFindings(findings)}\\n`,\n )\n return findings.length > 0 ? ExitCode.FINDINGS : ExitCode.OK\n } catch (error) {\n return reportCommandError(error, io.stderr)\n }\n}\n","import type { StageResult } from '@/gate/StageResult.js'\nimport { ExitCode } from '@/model/ExitCode.js'\n\nexport const gateExitCode = (results: StageResult[]): number => {\n if (results.some((result) => result.status === 'failed-to-run'))\n return ExitCode.INFRASTRUCTURE\n if (results.some((result) => result.status === 'findings'))\n return ExitCode.FINDINGS\n return ExitCode.OK\n}\n","import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { runAudit } from '@/audit/runAudit.js'\nimport { BASELINE_FILENAME } from '@/baseline/BASELINE_FILENAME.js'\nimport { classifyFindings } from '@/baseline/classifyFindings.js'\nimport { readBaseline } from '@/baseline/readBaseline.js'\nimport type { CheckContext } from '@/check/CheckContext.js'\nimport { runCheck } from '@/check/runCheck.js'\nimport type { Stage } from '@/gate/Stage.js'\n\n// A recorded baseline is the migration plan; the gate must honour it, or\n// recording debt could never turn the gate green. Audit runs when the project\n// is linked unless the configuration says otherwise: a linked project whose\n// CI has no token must switch it off explicitly rather than pass by accident.\nexport const gateStages = (context: CheckContext): Stage[] => {\n const hasBaseline = existsSync(join(context.root, BASELINE_FILENAME))\n const linked = existsSync(join(context.root, 'supabase/.temp/project-ref'))\n return [\n hasBaseline\n ? {\n name: 'baseline-check',\n run: () =>\n classifyFindings(runCheck(context), readBaseline(context.root)).new,\n }\n : { name: 'check', run: () => runCheck(context) },\n {\n name: 'audit',\n run: () =>\n context.config.audit.inGate && linked\n ? runAudit({ ...context, target: { linked: true } })\n : 'not-applicable',\n },\n ]\n}\n","import type { StageResult } from '@/gate/StageResult.js'\n\nexport const renderGateReport = (results: StageResult[]): string =>\n results\n .flatMap((result) => [\n `${result.status.padStart(22)} ${result.name.padEnd(14)}${result.durationSeconds.toFixed(2).padStart(8)}s`,\n ...(result.status === 'passed' ||\n result.status === 'skipped-not-applicable' ||\n !result.detail\n ? []\n : result.detail.split('\\n').map((line) => ` ${line}`)),\n ])\n .join('\\n')\n","import { performance } from 'node:perf_hooks'\n\nimport { renderFindings } from '@/check/renderFindings.js'\nimport type { Stage } from '@/gate/Stage.js'\nimport type { StageResult } from '@/gate/StageResult.js'\nimport type { StageStatus } from '@/gate/StageStatus.js'\n\nexport const runStage = (stage: Stage): StageResult => {\n const started = performance.now()\n const done = (status: StageStatus, detail: string): StageResult => ({\n name: stage.name,\n status,\n durationSeconds: (performance.now() - started) / 1000,\n detail,\n })\n try {\n const outcome = stage.run()\n if (outcome === 'not-applicable') return done('skipped-not-applicable', '')\n return outcome.length === 0\n ? done('passed', '')\n : done('findings', renderFindings(outcome))\n } catch (error) {\n return done(\n 'failed-to-run',\n error instanceof Error ? error.message : String(error),\n )\n }\n}\n","import { runStage } from '@/gate/runStage.js'\nimport type { Stage } from '@/gate/Stage.js'\nimport type { StageResult } from '@/gate/StageResult.js'\n\n// Every stage runs: stopping at the first failure means the same tool is\n// fixed over and over and the rest of the picture never appears.\nexport const runGate = (stages: Stage[]): StageResult[] => stages.map(runStage)\n","import type { CommandIo } from '@/commands/CommandIo.js'\nimport { parseCommandArgs } from '@/commands/parseCommandArgs.js'\nimport { reportCommandError } from '@/commands/reportCommandError.js'\nimport { readConfig } from '@/config/readConfig.js'\nimport { gateExitCode } from '@/gate/gateExitCode.js'\nimport { gateStages } from '@/gate/gateStages.js'\nimport { renderGateReport } from '@/gate/renderGateReport.js'\nimport { runGate } from '@/gate/runGate.js'\n\nexport const gateCommand = (argv: string[], io: CommandIo): number => {\n try {\n const { values } = parseCommandArgs(argv, { json: { type: 'boolean' } })\n const results = runGate(\n gateStages({\n root: io.root,\n config: readConfig(io.root),\n runner: io.runner,\n }),\n )\n const report =\n values['json'] === true\n ? JSON.stringify({ schemaVersion: 1, stages: results }, null, 2)\n : renderGateReport(results)\n io.stdout(`${report}\\n`)\n return gateExitCode(results)\n } catch (error) {\n return reportCommandError(error, io.stderr)\n }\n}\n","import { mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\n\nimport type { ManagedFile } from '@/init/ManagedFile.js'\n\nexport const applyInit = (root: string, plan: ManagedFile[]): void => {\n for (const file of plan) {\n const writes = file.disposition === 'create' || file.disposition === 'merge'\n if (!writes || file.content === undefined) continue\n mkdirSync(dirname(join(root, file.path)), { recursive: true })\n writeFileSync(join(root, file.path), file.content)\n }\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { CONFIG_FILENAME } from '@/config/CONFIG_FILENAME.js'\nimport { configFromDocument } from '@/config/configFromDocument.js'\nimport { detectStacks } from '@/config/detectStacks.js'\nimport type { ManagedFile } from '@/init/ManagedFile.js'\n\nexport const planConfigFile = (root: string, force: boolean): ManagedFile => {\n const content = `${JSON.stringify({ schemaVersion: 1, ...detectStacks(root) }, null, 2)}\\n`\n const path = join(root, CONFIG_FILENAME)\n if (!existsSync(path)) {\n return {\n path: CONFIG_FILENAME,\n disposition: 'create',\n detail: 'from the detected stacks',\n content,\n }\n }\n try {\n configFromDocument(JSON.parse(readFileSync(path, 'utf8')))\n return { path: CONFIG_FILENAME, disposition: 'unchanged', detail: 'valid' }\n } catch (error) {\n return force\n ? {\n path: CONFIG_FILENAME,\n disposition: 'merge',\n detail: 'replaced (--force)',\n content,\n }\n : {\n path: CONFIG_FILENAME,\n disposition: 'conflict',\n detail: (error as Error).message,\n }\n }\n}\n","import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { DbQualityConfig } from '@/config/DbQualityConfig.js'\nimport { findSqliteFiles } from '@/config/findSqliteFiles.js'\nimport { isDirectory } from '@/config/isDirectory.js'\n\nexport const detectStacks = (\n root: string,\n): Omit<DbQualityConfig, 'audit' | 'disable' | 'schemaVersion'> => {\n const sqliteFiles = findSqliteFiles(root)\n const hasDrizzle = ['ts', 'js', 'mjs'].some((ext) =>\n existsSync(join(root, `drizzle.config.${ext}`)),\n )\n const drizzleRoots = ['src', 'server', 'app', 'lib', 'db'].filter((name) =>\n isDirectory(join(root, name)),\n )\n return {\n ...(isDirectory(join(root, 'supabase/migrations'))\n ? { supabase: { migrations: 'supabase/migrations' } }\n : {}),\n ...(existsSync(join(root, 'prisma/schema.prisma'))\n ? { prisma: { schema: 'prisma/schema.prisma' } }\n : {}),\n ...(hasDrizzle\n ? { drizzle: { roots: drizzleRoots, objectNames: ['db', 'tx'] } }\n : {}),\n ...(sqliteFiles.length > 0 ? { sqlite: { files: sqliteFiles } } : {}),\n }\n}\n","import { readdirSync } from 'node:fs'\nimport { join, relative } from 'node:path'\n\n/** SQLite files at depth <= 2 under the root, as sorted root-relative paths. */\nexport const findSqliteFiles = (root: string): string[] => {\n // Hidden directories hold tool state, never the project's data: a pnpm\n // store keeps an index.db, and .git, .codegraph and friends keep their own.\n const skipped = new Set(['node_modules', 'dist', 'coverage'])\n const found: string[] = []\n const walk = (directory: string, depth: number): void => {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n if (skipped.has(entry.name) || entry.name.startsWith('.')) continue\n const path = join(directory, entry.name)\n if (entry.isDirectory() && depth < 2) walk(path, depth + 1)\n else if (entry.isFile() && /\\.(?:db|sqlite|sqlite3)$/.test(entry.name)) {\n found.push(relative(root, path).replaceAll('\\\\', '/'))\n }\n }\n }\n walk(root, 0)\n return found.sort()\n}\n","import { existsSync, statSync } from 'node:fs'\n\nexport const isDirectory = (path: string): boolean =>\n existsSync(path) && statSync(path).isDirectory()\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ManagedFile } from '@/init/ManagedFile.js'\nimport { PACKAGE_MANIFEST } from '@/init/PACKAGE_MANIFEST.js'\n\nexport const planPackageScript = (\n root: string,\n force: boolean,\n): ManagedFile => {\n const path = join(root, PACKAGE_MANIFEST)\n if (!existsSync(path)) {\n return {\n path: PACKAGE_MANIFEST,\n disposition: 'unchanged',\n detail: 'no package.json',\n }\n }\n const manifest = JSON.parse(readFileSync(path, 'utf8')) as {\n scripts?: Record<string, string>\n }\n const current = manifest.scripts?.['db:gate']\n if (current === 'codeality-db gate') {\n return {\n path: PACKAGE_MANIFEST,\n disposition: 'unchanged',\n detail: 'db:gate present',\n }\n }\n if (current !== undefined && !force) {\n return {\n path: PACKAGE_MANIFEST,\n disposition: 'conflict',\n detail: `db:gate is \"${current}\"`,\n }\n }\n const scripts = { ...manifest.scripts, 'db:gate': 'codeality-db gate' }\n const content = `${JSON.stringify({ ...manifest, scripts }, null, 2)}\\n`\n return {\n path: PACKAGE_MANIFEST,\n disposition: 'merge',\n detail: 'add scripts.db:gate',\n content,\n }\n}\n","export const PACKAGE_MANIFEST = 'package.json'\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { assetPath } from '@/assetPath.js'\nimport type { ManagedFile } from '@/init/ManagedFile.js'\n\nexport const planWorkflow = (root: string, force: boolean): ManagedFile => {\n const relative = '.github/workflows/db-quality.yml'\n const content = readFileSync(assetPath('db-quality.yml'), 'utf8')\n const path = join(root, relative)\n if (!existsSync(path)) {\n const detail = 'runs codeality-db gate on push and pull request'\n return { path: relative, disposition: 'create', detail, content }\n }\n if (readFileSync(path, 'utf8') === content) {\n return { path: relative, disposition: 'unchanged', detail: 'identical' }\n }\n return force\n ? {\n path: relative,\n disposition: 'merge',\n detail: 'replaced (--force)',\n content,\n }\n : {\n path: relative,\n disposition: 'conflict',\n detail: 'differs from the shipped workflow',\n }\n}\n","import type { ManagedFile } from '@/init/ManagedFile.js'\nimport { planConfigFile } from '@/init/planConfigFile.js'\nimport { planPackageScript } from '@/init/planPackageScript.js'\nimport { planWorkflow } from '@/init/planWorkflow.js'\n\nexport const planInit = (root: string, force: boolean): ManagedFile[] => [\n planConfigFile(root, force),\n planPackageScript(root, force),\n planWorkflow(root, force),\n]\n","import type { ManagedFile } from '@/init/ManagedFile.js'\n\nexport const renderInitPlan = (plan: ManagedFile[]): string =>\n plan\n .map(\n (file) => `${file.disposition.padEnd(9)} ${file.path} ${file.detail}`,\n )\n .join('\\n')\n","import type { CommandIo } from '@/commands/CommandIo.js'\nimport { parseCommandArgs } from '@/commands/parseCommandArgs.js'\nimport { reportCommandError } from '@/commands/reportCommandError.js'\nimport { ConfigError } from '@/config/ConfigError.js'\nimport { applyInit } from '@/init/applyInit.js'\nimport { planInit } from '@/init/planInit.js'\nimport { renderInitPlan } from '@/init/renderInitPlan.js'\nimport { ExitCode } from '@/model/ExitCode.js'\n\nexport const initCommand = (argv: string[], io: CommandIo): number => {\n try {\n const { values } = parseCommandArgs(argv, {\n check: { type: 'boolean' },\n apply: { type: 'boolean' },\n force: { type: 'boolean' },\n })\n const force = values['force'] === true\n const plan = planInit(io.root, force)\n io.stdout(`${renderInitPlan(plan)}\\n`)\n if (values['check'] === true) {\n return plan.every((file) => file.disposition === 'unchanged')\n ? ExitCode.OK\n : ExitCode.FINDINGS\n }\n if (values['apply'] !== true && !force) return ExitCode.OK\n if (plan.some((file) => file.disposition === 'conflict')) {\n throw new ConfigError('conflicts remain; resolve them or pass --force')\n }\n applyInit(io.root, plan)\n return ExitCode.OK\n } catch (error) {\n return reportCommandError(error, io.stderr)\n }\n}\n","import { auditCommand } from '@/commands/auditCommand.js'\nimport { baselineCommand } from '@/commands/baselineCommand.js'\nimport { checkCommand } from '@/commands/checkCommand.js'\nimport type { CommandIo } from '@/commands/CommandIo.js'\nimport { gateCommand } from '@/commands/gateCommand.js'\nimport { initCommand } from '@/commands/initCommand.js'\n\nexport const COMMANDS: Record<\n string,\n (argv: string[], io: CommandIo) => number\n> = {\n init: initCommand,\n check: checkCommand,\n audit: auditCommand,\n gate: gateCommand,\n baseline: baselineCommand,\n}\n","export const USAGE = `usage: codeality-db [--project <dir>] <command> [options]\n\n init [--check|--apply|--force] detect stacks, write codeality-db.json, the db:gate script and the CI workflow\n check [--json] static findings from the repository alone\n audit --linked|--db-url <url> [--json] findings from the live database\n gate [--json] check (or baseline check) and the linked audit, one exit code\n baseline create|update|check [--check-stale] record, refresh or enforce the debt the project carries\n\nexit codes: 0 passed, 1 findings, 2 invalid usage or configuration, 3 required tool missing or unusable\n`\n","import { COMMANDS } from '@/cli/COMMANDS.js'\nimport { USAGE } from '@/cli/USAGE.js'\nimport type { CommandIo } from '@/commands/CommandIo.js'\nimport { ExitCode } from '@/model/ExitCode.js'\nimport { PACKAGE_VERSION } from '@/packageVersion.js'\n\n/** Dispatches the argument vector (without the node and script entries) and returns the exit code. */\nexport const runCli = (argv: string[], io: CommandIo): number => {\n const args = [...argv]\n if (args.includes('--version')) {\n io.stdout(`codeality-db ${PACKAGE_VERSION}\\n`)\n return ExitCode.OK\n }\n if (args.includes('--help') || args.includes('-h')) {\n io.stdout(USAGE)\n return ExitCode.OK\n }\n let root = io.root\n if (args[0] === '--project') {\n root = args[1] ?? ''\n args.splice(0, 2)\n }\n const [command, ...rest] = args\n const handler = command === undefined ? undefined : COMMANDS[command]\n if (!handler) {\n io.stderr(USAGE)\n return ExitCode.CONFIGURATION\n }\n return handler(rest, { ...io, root })\n}\n","import { spawnSync } from 'node:child_process'\nimport { delimiter, join } from 'node:path'\nimport { env as processEnv } from 'node:process'\n\nimport type { CommandRunner } from '@/tools/CommandRunner.js'\nimport { packageBinPath } from '@/tools/packageBinPath.js'\n\nexport const spawnRunner: CommandRunner = (command, args, options) => {\n // The project's tools win; the package's own follow; the shell's PATH last.\n const path = [\n join(options.cwd, 'node_modules/.bin'),\n packageBinPath(),\n processEnv['PATH'] ?? '',\n ].join(delimiter)\n const child = spawnSync(command, args, {\n cwd: options.cwd,\n encoding: 'utf8',\n maxBuffer: 64 * 1024 * 1024,\n env: { ...processEnv, ...options.env, PATH: path },\n })\n // The typings promise strings, but a spawn that never started hands back null.\n const output: { stdout: string | null; stderr: string | null } = child\n return {\n status: child.status ?? -1,\n stdout: output.stdout ?? '',\n stderr: output.stderr ?? '',\n missing:\n (child.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT',\n }\n}\n","import { fileURLToPath } from 'node:url'\n\n// The package's own `node_modules/.bin`: one level up from both `dist/cli.js`\n// and `src/tools/`. When a consumer installs the peers next to this package\n// rather than in the project, or runs the bin from a checkout, this is where\n// squawk, prisma-lint and eslint live.\nexport const packageBinPath = (): string =>\n fileURLToPath(new URL('../node_modules/.bin', import.meta.url))\n"],"mappings":"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","names":["existsSync","join","join","existsSync","stdout","stdout","stdout","argv","stderr","existsSync","readFileSync","join","join","existsSync","readFileSync","argv","existsSync","join","existsSync","readFileSync","join","join","existsSync","readFileSync","writeFileSync","join","join","writeFileSync","stdout","stderr","stdout","readFileSync","join","end","join","readFileSync","argv","existsSync","join","argv","existsSync","join","existsSync","join","argv","writeFileSync","join","existsSync","readFileSync","join","existsSync","join","readdirSync","join","relative","existsSync","existsSync","join","join","existsSync","readFileSync","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","readFileSync","join","relative","readFileSync","join","existsSync","argv","argv","join","fileURLToPath","join"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@syntopica/db-quality",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"packageManager": "pnpm@12.5.1",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"description": "Database quality gate: lint Supabase migrations, Prisma and Drizzle schemas and SQLite files, audit a live Supabase project, carry debt in a baseline",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/syntopica/codeality.git",
|
|
11
|
+
"directory": "packages/db-quality"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/syntopica/codeality/tree/main/packages/db-quality#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/syntopica/codeality/issues"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=22"
|
|
23
|
+
},
|
|
24
|
+
"bin": {
|
|
25
|
+
"codeality-db": "bin/codeality-db.mjs"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"README.md",
|
|
30
|
+
"assets",
|
|
31
|
+
"bin",
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"lint": "eslint src tests bin --max-warnings 0",
|
|
37
|
+
"lint:fix": "eslint src tests bin --fix",
|
|
38
|
+
"lint:suppress": "eslint src tests bin --suppress-all",
|
|
39
|
+
"lint:prune": "eslint src tests bin --prune-suppressions",
|
|
40
|
+
"type-check": "tsc --noEmit -p tsconfig.json",
|
|
41
|
+
"test": "vitest run --coverage",
|
|
42
|
+
"publish:check": "baseline-licenses && publint --strict"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"eslint": ">=9.0.0",
|
|
46
|
+
"eslint-plugin-drizzle": ">=0.2.0",
|
|
47
|
+
"prisma-lint": ">=0.13.0",
|
|
48
|
+
"squawk-cli": ">=2.0.0",
|
|
49
|
+
"typescript-eslint": ">=8.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependenciesMeta": {
|
|
52
|
+
"eslint": {
|
|
53
|
+
"optional": true
|
|
54
|
+
},
|
|
55
|
+
"eslint-plugin-drizzle": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"prisma-lint": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"squawk-cli": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"typescript-eslint": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@syntopica/eslint-config": "workspace:*",
|
|
70
|
+
"@syntopica/quality-config": "workspace:*",
|
|
71
|
+
"@syntopica/tsconfig": "workspace:*",
|
|
72
|
+
"@types/node": "^26.6.2",
|
|
73
|
+
"@vitest/coverage-v8": "^5.0.1",
|
|
74
|
+
"eslint": "^10.11.0",
|
|
75
|
+
"eslint-plugin-drizzle": "^0.2.3",
|
|
76
|
+
"eslint-plugin-regexp": "^3.3.1",
|
|
77
|
+
"prisma-lint": "^0.13.1",
|
|
78
|
+
"publint": "^0.3.24",
|
|
79
|
+
"squawk-cli": "^2.66.0",
|
|
80
|
+
"tsup": "^8.5.1",
|
|
81
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
82
|
+
"typescript-eslint": "^8.70.1",
|
|
83
|
+
"vitest": "^5.0.1"
|
|
84
|
+
}
|
|
85
|
+
}
|