fix(db): close round-2 review evasions in writer-coverage assertion
ci/woodpecker/pr/ci Pipeline was successful

Per the second M4-1a detached review (REQUEST_CHANGES, R1-R8):

- R1: prong (i) now tracks namespace destructuring, nested namespace
  re-exports (ns.schema.companies), and literal dynamic-import bindings
  (destructured and namespace) per contract rev 9.
- R2: capability-conduit fixpoint (computeCapabilityConduits) closes
  driver/factory laundering through export-from modules.
- R3: dynamic-import check is per call site with a full-literal tail
  match, so concatenated specifiers no longer pass.
- R4: computed-member calls with literal verb names (obj['insert'],
  obj['query']) and spaced member access are flagged.
- R5: prong (ii) adjacency tolerates schema qualification, interposed
  block comments, COPY, and escaped quotes.
- R6/R8: header documents KNOWN RESIDUALS (DI receiver rename in
  capability-free files, computed non-literal member access, scan
  perimeter) with the measured counterfactuals.
- createRequire fails outside a 5-module measured register (R1 route).
- 15 new permanent evasion controls (E9-E23) with helper-file conduits
  run through the production analyzer.

Calibration: tree-wide prong test green with zero new exclusions;
tsc, eslint, and the full package suite pass.
This commit is contained in:
fred
2026-08-27 16:38:48 -05:00
parent 8305d129a2
commit 7dedc8d3c0
+347 -46
View File
@@ -28,11 +28,31 @@
* receiver backstop still fires on db/client-shaped receivers. * receiver backstop still fires on db/client-shaped receivers.
* `sql.raw` is tracked through import aliasing and namespaces. * `sql.raw` is tracked through import aliasing and namespaces.
* *
* Runtime code-construction primitives (eval, new Function) and non-literal * Runtime code-construction primitives (eval, new Function) fail anywhere —
* dynamic imports fail anywhere — allowlist and register included. This is * allowlist and register included: constructed code defeats every static
* deliberately stricter than the contract's minimum: an unanalyzable import * prong, so there is no enumerated disposition path for it. Unanalyzable
* or constructed code defeats every static prong, so there is no enumerated * import routes (a dynamic import whose specifier is not a single string
* disposition path for them. * literal, and createRequire) fail everywhere except their own enumerated
* disposition registers below. A LITERAL dynamic import is an import edge
* like any static import (contract rev 9): its bindings (destructured or
* namespace) feed prong (i) exactly as static import bindings do.
*
* KNOWN RESIDUALS (deliberate, reviewed trade-offs — not claims of closure):
* - In a file with NO detected raw capability (no driver/factory import on
* any tracked route), prong (iii) falls back to a conventional-receiver
* backstop (db/client/pool/tx/…). A dependency-injected handle bound to
* an unconventional name in such a file is an OPEN evasion path. The
* counterfactual was measured: any-receiver flagging in capability-free
* files false-positives on real non-SQL .execute()/.query() sites
* (runtime-provider-registry, connector-lease, the log CLI), so the
* residual is accepted and reviews of DI provider modules carry it.
* - Computed member access with a NON-literal name (obj[verb]()) is not
* statically resolvable; literal computed access (obj['insert']()) is
* flagged. Constructing the verb at runtime is adjacent to eval and is
* expected to be caught in review.
* - The scan perimeter is <root>/<pkg>/src for the three roots; production
* TS outside a src/ directory (e.g. packages/mosaic/framework/**) is not
* scanned (verified free of db/driver/execute references at review time).
* *
* The writer allowlist names hierarchy command/repository modules ONLY. It is * The writer allowlist names hierarchy command/repository modules ONLY. It is
* empty today: the hierarchy command family (M4-1b) has not landed, so no * empty today: the hierarchy command family (M4-1b) has not landed, so no
@@ -140,6 +160,18 @@ const MIGRATE_TIER_IMPORTERS: string[] = [
const DYNAMIC_IMPORT_REGISTER: string[] = [ const DYNAMIC_IMPORT_REGISTER: string[] = [
'plugins/macp/src/index.ts', // loads the ACP runtime SDK from a configured sdkRoot; no db access 'plugins/macp/src/index.ts', // loads the ACP runtime SDK from a configured sdkRoot; no db access
]; ];
/**
* Enumerated disposition for createRequire (an unanalyzable CJS import
* route). Every entry uses it for package.json version reads or module
* resolution only (measured); every other prong still applies in full.
*/
const CREATE_REQUIRE_REGISTER: string[] = [
'packages/mosaic/src/cli.ts', // package.json version read
'packages/mosaic/src/commands/gateway/daemon.ts', // module path resolution
'packages/mosaic/src/commands/launch.ts', // package.json version read + resolution
'packages/mosaic/src/commands/lease-activation-probe.ts', // injectable module resolver default
'plugins/macp/src/index.ts', // OpenCode SDK resolution
];
/** Importers of the db-handle factories (measured set; a new importer must be reviewed in). */ /** Importers of the db-handle factories (measured set; a new importer must be reviewed in). */
const DB_FACTORY_SYMBOLS = ['createDb', 'createPgliteDb']; const DB_FACTORY_SYMBOLS = ['createDb', 'createPgliteDb'];
const DB_FACTORY_IMPORTERS: string[] = [ const DB_FACTORY_IMPORTERS: string[] = [
@@ -435,51 +467,155 @@ interface ClassAliases {
namespaces: string[]; // namespace identifiers over a schema source namespaces: string[]; // namespace identifiers over a schema source
} }
/** Parse an import named-binding list ("a, b as c") into locals bound to class symbols. */
function importBindings(namedList: string, named: Set<string>): void {
for (const part of namedList.split(',')) {
const seg = part.trim();
if (!seg || seg.startsWith('type ')) continue;
const asMatch = /^(\w+)\s+as\s+(\w+)$/.exec(seg);
const original = asMatch ? asMatch[1]! : seg;
const local = asMatch ? asMatch[2]! : seg;
if (CLASS_SYMBOLS.includes(original)) named.add(local);
}
}
/** Parse a destructuring pattern ("a, b: c") into locals bound to class symbols. */
function destructureBindings(pattern: string, named: Set<string>): void {
for (const part of pattern.split(',')) {
const seg = part.trim();
if (!seg) continue;
const m = /^(\w+)\s*(?::\s*(\w+))?$/.exec(seg);
if (m && CLASS_SYMBOLS.includes(m[1]!)) named.add(m[2] ?? m[1]!);
}
}
function isSchemaSpecifier(
rel: string,
spec: string,
conduits: Set<string>,
fileSet: Set<string>,
): boolean {
if (spec === '@mosaicstack/db') return true;
const r = resolveSpecifier(rel, spec, fileSet);
return r !== null && conduits.has(r);
}
function classAliases(f: FileFacts, conduits: Set<string>, fileSet: Set<string>): ClassAliases { function classAliases(f: FileFacts, conduits: Set<string>, fileSet: Set<string>): ClassAliases {
const named = new Set<string>(); const named = new Set<string>();
const namespaces = new Set<string>(); const namespaces = new Set<string>();
for (const m of f.code.matchAll(IMPORT_RE)) { for (const m of f.code.matchAll(IMPORT_RE)) {
const [, typeOnly, , namedList, nsName, , spec] = m; const [, typeOnly, , namedList, nsName, , spec] = m;
if (typeOnly) continue; if (typeOnly) continue;
const fromSchema = if (!isSchemaSpecifier(f.rel, spec!, conduits, fileSet)) continue;
spec === '@mosaicstack/db' ||
(() => {
const r = resolveSpecifier(f.rel, spec!, fileSet);
return r !== null && conduits.has(r);
})();
if (!fromSchema) continue;
if (nsName) namespaces.add(nsName); if (nsName) namespaces.add(nsName);
if (namedList) { if (namedList) importBindings(namedList, named);
for (const part of namedList.split(',')) { }
const seg = part.trim(); // Literal dynamic imports of a schema source are import edges like any
if (!seg || seg.startsWith('type ')) continue; // other (contract rev 9): both binding shapes feed prong (i).
const asMatch = /^(\w+)\s+as\s+(\w+)$/.exec(seg); for (const m of f.code.matchAll(
const original = asMatch ? asMatch[1]! : seg; /(?:const|let|var)\s*(?:\{([^}]*)\}|(\w+))\s*=\s*await\s+import\s*\(\s*(['"])([^'"]+)\3\s*\)/g,
const local = asMatch ? asMatch[2]! : seg; )) {
if (CLASS_SYMBOLS.includes(original)) named.add(local); const [, pattern, nsName, , spec] = m;
} if (!isSchemaSpecifier(f.rel, spec!, conduits, fileSet)) continue;
if (nsName) namespaces.add(nsName);
if (pattern) destructureBindings(pattern, named);
}
// Destructuring from a schema namespace binds class symbols to locals:
// `import * as s from '@mosaicstack/db'; const { companies } = s;`
for (const ns of [...namespaces]) {
for (const m of f.code.matchAll(
new RegExp(`(?:const|let|var)\\s*\\{([^}]*)\\}\\s*=\\s*${ns}\\b`, 'g'),
)) {
destructureBindings(m[1]!, named);
} }
} }
return { named: [...named], namespaces: [...namespaces] }; return { named: [...named], namespaces: [...namespaces] };
} }
/**
* Capability conduits: modules that re-export raw-execution capability, so a
* consumer can obtain it without a literal driver/factory specifier.
* `driver` — re-exports (star, named, or default) from a driver package or
* another driver conduit; importing ANYTHING from one confers driver
* capability (the conduit module itself is additionally flagged by prong
* (iii)'s literal check, so these routes fail at both ends).
* `factory` — re-exports createDb/createPgliteDb from the db package or
* another factory conduit; importing from one while referencing a factory
* symbol confers factory capability.
*/
function computeCapabilityConduits(
files: FileFacts[],
fileSet: Set<string>,
): { driver: Set<string>; factory: Set<string> } {
const driver = new Set<string>();
const factory = new Set<string>();
const isDriverSpec = (rel: string, spec: string): boolean => {
if (DRIVER_SPECIFIERS.includes(spec)) return true;
const r = resolveSpecifier(rel, spec, fileSet);
return r !== null && driver.has(r);
};
const isFactorySpec = (rel: string, spec: string): boolean => {
if (spec === '@mosaicstack/db') return true;
const r = resolveSpecifier(rel, spec, fileSet);
return r !== null && factory.has(r);
};
let changed = true;
while (changed) {
changed = false;
for (const f of files) {
for (const m of f.code.matchAll(EXPORT_FROM_RE)) {
if (m[1]) continue; // export type — erased
const spec = m[3]!;
if (!driver.has(f.rel) && isDriverSpec(f.rel, spec)) {
driver.add(f.rel);
changed = true;
}
if (!factory.has(f.rel) && isFactorySpec(f.rel, spec)) {
const named = m[2];
if (named === undefined || /\b(createDb|createPgliteDb)\b/.test(named)) {
factory.add(f.rel);
changed = true;
}
}
}
// `export { default as x } from 'postgres'` matches EXPORT_FROM_RE's
// named branch above; `export x from` is not valid syntax — covered.
}
}
return { driver, factory };
}
/** Value-import edge naming one of `symbols` (named import from anywhere, or literal dynamic package import while using the symbol). */ /** Value-import edge naming one of `symbols` (named import from anywhere, or literal dynamic package import while using the symbol). */
function hasSymbolImportEdge(code: string, symbols: string[], packageName: string): boolean { function hasSymbolImportEdge(code: string, symbols: string[], packageName: string): boolean {
const pkg = packageName.replace('/', '\\/');
const staticEdge = new RegExp( const staticEdge = new RegExp(
`import\\s*(?!type\\b)(?:\\w+\\s*,\\s*)?\\{[^}]*\\b(${symbols.join('|')})\\b[^}]*\\}\\s*from\\s*['"][^'"]+['"]`, `import\\s*(?!type\\b)(?:\\w+\\s*,\\s*)?\\{[^}]*\\b(${symbols.join('|')})\\b[^}]*\\}\\s*from\\s*['"][^'"]+['"]`,
).test(code); ).test(code);
const usesSymbol = new RegExp(`\\b(${symbols.join('|')})\\b`).test(code); const usesSymbol = new RegExp(`\\b(${symbols.join('|')})\\b`).test(code);
const dynamicEdge = const dynamicEdge = usesSymbol && new RegExp(`import\\s*\\(\\s*['"]${pkg}['"]\\s*\\)`).test(code);
usesSymbol && // Namespace form: `import * as ns from '<pkg>'` + `ns.<symbol>` usage.
new RegExp(`import\\s*\\(\\s*['"]${packageName.replace('/', '\\/')}['"]\\s*\\)`).test(code); let nsEdge = false;
return staticEdge || dynamicEdge; for (const m of code.matchAll(
new RegExp(`import\\s*\\*\\s*as\\s+(\\w+)\\s*from\\s*['"]${pkg}['"]`, 'g'),
)) {
if (new RegExp(`\\b${m[1]}\\s*\\.\\s*(${symbols.join('|')})\\b`).test(code)) nsEdge = true;
}
return staticEdge || dynamicEdge || nsEdge;
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// The analyzer — pure over (rel, source) so the evasion controls below can // The analyzer — pure over (rel, source) so the evasion controls below can
// feed synthetic files through the exact production logic. // feed synthetic files through the exact production logic.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function analyzeFile(f: FileFacts, conduits: Set<string>, fileSet: Set<string>): Violation[] { interface AnalysisCtx {
fileSet: Set<string>;
conduits: Set<string>; // schema-symbol sources (prong i)
driverConduits: Set<string>; // driver-capability re-exporters (prong iii)
factoryConduits: Set<string>; // factory-capability re-exporters (prong iii)
}
function analyzeFile(f: FileFacts, ctx: AnalysisCtx): Violation[] {
const { fileSet, conduits, driverConduits, factoryConduits } = ctx;
const violations: Violation[] = []; const violations: Violation[] = [];
const rel = f.rel; const rel = f.rel;
const code = f.code; const code = f.code;
@@ -491,9 +627,20 @@ function analyzeFile(f: FileFacts, conduits: Set<string>, fileSet: Set<string>):
if (/\beval\s*\(|\bnew\s+Function\s*\(/.test(code)) { if (/\beval\s*\(|\bnew\s+Function\s*\(/.test(code)) {
violations.push({ file: rel, prong: 'code-construction', detail: 'eval/new Function' }); violations.push({ file: rel, prong: 'code-construction', detail: 'eval/new Function' });
} }
// Non-literal dynamic import: makes the import graph unanalyzable. // Dynamic import whose specifier is not a single string literal: the
if (!DYNAMIC_IMPORT_REGISTER.includes(rel) && /\bimport\s*\(\s*(?!['"])/.test(code)) { // import graph becomes unanalyzable. Checked per call site, so a literal
violations.push({ file: rel, prong: 'dynamic-import', detail: 'non-literal import()' }); // first fragment ('x' + y) does not slip past.
if (!DYNAMIC_IMPORT_REGISTER.includes(rel)) {
for (const m of code.matchAll(/\bimport\s*\(/g)) {
const tail = code.slice((m.index ?? 0) + m[0].length);
if (!/^\s*(['"])(?:[^'"\\]|\\.)*?\1\s*[,)]/.test(tail)) {
violations.push({ file: rel, prong: 'dynamic-import', detail: 'non-literal import()' });
}
}
}
// createRequire: an unanalyzable CJS import route.
if (!CREATE_REQUIRE_REGISTER.includes(rel) && /\bcreateRequire\s*\(/.test(code)) {
violations.push({ file: rel, prong: 'dynamic-import', detail: 'createRequire()' });
} }
const aliases = classAliases(f, conduits, fileSet); const aliases = classAliases(f, conduits, fileSet);
@@ -502,11 +649,13 @@ function analyzeFile(f: FileFacts, conduits: Set<string>, fileSet: Set<string>):
if (!inAllowlist) { if (!inAllowlist) {
const targets: string[] = [...aliases.named]; const targets: string[] = [...aliases.named];
for (const ns of aliases.namespaces) { for (const ns of aliases.namespaces) {
for (const s of CLASS_SYMBOLS) targets.push(`${ns}\\.${s}`); // Allow intermediate property segments: ns.schema.companies (nested
// namespace re-exports) as well as ns.companies.
for (const s of CLASS_SYMBOLS) targets.push(`${ns}(?:\\s*\\.\\s*\\w+)*\\s*\\.\\s*${s}`);
} }
if (targets.length > 0) { if (targets.length > 0) {
const writeRe = new RegExp( const writeRe = new RegExp(
`\\.(insert|update|delete)\\s*\\(\\s*(${targets.join('|')})\\b`, `\\.\\s*(insert|update|delete)\\s*\\(\\s*(${targets.join('|')})\\b`,
'g', 'g',
); );
for (const m of code.matchAll(writeRe)) { for (const m of code.matchAll(writeRe)) {
@@ -519,13 +668,43 @@ function analyzeFile(f: FileFacts, conduits: Set<string>, fileSet: Set<string>):
} }
} }
// Computed member access with a literal verb name (obj['insert'](…))
// bypasses dot-based call detection; the tree has no legitimate use of the
// form (measured), so it fails outright. Write verbs fail outside the
// allowlist; execution verbs fail outside allowlist register.
if (!inAllowlist) {
const writeBracket = /\[\s*['"](insert|update|delete)['"]\s*\]\s*\(/g;
for (const m of code.matchAll(writeBracket)) {
violations.push({
file: rel,
prong: 'i-symbol',
detail: `['${m[1]}']() computed-member write call`,
});
}
if (!inRegister) {
for (const m of code.matchAll(/\[\s*['"](execute|query|unsafe)['"]\s*\]\s*\(/g)) {
violations.push({
file: rel,
prong: 'iii-raw-execution',
detail: `['${m[1]}']() computed-member execution call`,
});
}
}
}
// Prong (ii): class-table names in string/template spans with SQL context. // Prong (ii): class-table names in string/template spans with SQL context.
// The SQL keyword must be ADJACENT to the table name (optionally quoted): // The SQL keyword must be ADJACENT to the table name — co-residence
// co-residence anywhere in one span over-matches prose (English "from" plus // anywhere in one span over-matches prose ("pnpm workspaces" plus an
// "pnpm workspaces" in an embedded doc string is not SQL). // unrelated "from" in an embedded doc string is not SQL). Adjacency
// tolerates schema qualification (public.hierarchy_grants), interposed
// block comments, and quoting (including escaped quotes in span text).
if (!inAllowlist && !isSchemaDefinition) { if (!inAllowlist && !isSchemaDefinition) {
const kw =
'(?:insert\\s+into|update|delete\\s+from|from|join|truncate(?:\\s+table)?|alter\\s+table|drop\\s+table|references|into|copy)';
const gap = '(?:\\s|/\\*[\\s\\S]*?\\*/)+';
const q = `(?:\\\\?["'\`])?`;
const sqlAdjacentRe = new RegExp( const sqlAdjacentRe = new RegExp(
`\\b(insert\\s+into|update|delete\\s+from|from|join|truncate(\\s+table)?|alter\\s+table|drop\\s+table|references|into)\\s+["'\`]?(${CLASS_TABLES.join('|')})\\b`, `\\b${kw}${gap}${q}(?:\\w+\\s*\\.\\s*)?${q}(${CLASS_TABLES.join('|')})\\b`,
'i', 'i',
); );
for (const span of f.spans) { for (const span of f.spans) {
@@ -541,15 +720,28 @@ function analyzeFile(f: FileFacts, conduits: Set<string>, fileSet: Set<string>):
// Prong (iii): content-independent raw execution. // Prong (iii): content-independent raw execution.
if (!inAllowlist && !inRegister) { if (!inAllowlist && !inRegister) {
const driverImport = new RegExp( const literalDriver = new RegExp(
`(from\\s*|import\\s*\\(\\s*)['"](${DRIVER_SPECIFIERS.map((s) => s.replace('/', '\\/')).join('|')})['"]`, `(from\\s*|import\\s*\\(\\s*)['"](${DRIVER_SPECIFIERS.map((s) => s.replace('/', '\\/')).join('|')})['"]`,
).test(code); ).test(code);
// Any value import from a driver conduit confers driver capability.
let conduitDriver = false;
let factoryConduitImport = false;
for (const m of f.code.matchAll(IMPORT_RE)) {
if (m[1]) continue; // import type — erased
const r = resolveSpecifier(rel, m[6]!, fileSet);
if (r !== null && driverConduits.has(r)) conduitDriver = true;
if (r !== null && factoryConduits.has(r)) factoryConduitImport = true;
}
const driverImport = literalDriver || conduitDriver;
const usesFactorySymbol = /\b(createDb|createPgliteDb)\b/.test(code);
const factoryImport = const factoryImport =
hasSymbolImportEdge(code, DB_FACTORY_SYMBOLS, '@mosaicstack/db') || hasSymbolImportEdge(code, DB_FACTORY_SYMBOLS, '@mosaicstack/db') ||
(factoryConduitImport && usesFactorySymbol) ||
(aliases.namespaces.length > 0 && (aliases.namespaces.length > 0 &&
new RegExp(`\\b(${aliases.namespaces.join('|')})\\.(createDb|createPgliteDb)\\b`).test( usesFactorySymbol &&
code, new RegExp(
)); `\\b(${aliases.namespaces.join('|')})(?:\\s*\\.\\s*\\w+)*\\s*\\.\\s*(createDb|createPgliteDb)\\b`,
).test(code));
if (driverImport) { if (driverImport) {
violations.push({ file: rel, prong: 'iii-raw-execution', detail: 'direct driver import' }); violations.push({ file: rel, prong: 'iii-raw-execution', detail: 'direct driver import' });
// A driver client exposes query/execute/unsafe as raw primitives: // A driver client exposes query/execute/unsafe as raw primitives:
@@ -624,6 +816,13 @@ describe('hierarchy writer coverage (contract 1 §6.3b)', () => {
return { rel, code, spans }; return { rel, code, spans };
}); });
const conduits = computeSchemaConduits(files, fileSet); const conduits = computeSchemaConduits(files, fileSet);
const capConduits = computeCapabilityConduits(files, fileSet);
const ctx: AnalysisCtx = {
fileSet,
conduits,
driverConduits: capConduits.driver,
factoryConduits: capConduits.factory,
};
it('scans a non-empty production source set including plugins', () => { it('scans a non-empty production source set including plugins', () => {
expect(files.length).toBeGreaterThan(100); expect(files.length).toBeGreaterThan(100);
@@ -638,6 +837,7 @@ describe('hierarchy writer coverage (contract 1 §6.3b)', () => {
...MIGRATE_TIER_IMPORTERS, ...MIGRATE_TIER_IMPORTERS,
...DB_FACTORY_IMPORTERS, ...DB_FACTORY_IMPORTERS,
...DYNAMIC_IMPORT_REGISTER, ...DYNAMIC_IMPORT_REGISTER,
...CREATE_REQUIRE_REGISTER,
]) { ]) {
expect(existsSync(join(REPO_ROOT, p)), `enumerated module missing: ${p}`).toBe(true); expect(existsSync(join(REPO_ROOT, p)), `enumerated module missing: ${p}`).toBe(true);
} }
@@ -650,7 +850,7 @@ describe('hierarchy writer coverage (contract 1 §6.3b)', () => {
}); });
it('three-prong writer coverage holds over the production tree', () => { it('three-prong writer coverage holds over the production tree', () => {
const violations = files.flatMap((f) => analyzeFile(f, conduits, fileSet)); const violations = files.flatMap((f) => analyzeFile(f, ctx));
expect( expect(
violations, violations,
violations.map((v) => `[prong ${v.prong}] ${v.file}: ${v.detail}`).join('\n'), violations.map((v) => `[prong ${v.prong}] ${v.file}: ${v.detail}`).join('\n'),
@@ -711,7 +911,11 @@ describe('hierarchy writer coverage (contract 1 §6.3b)', () => {
// be flagged by the analyzer, and the two legitimate controls must pass. // be flagged by the analyzer, and the two legitimate controls must pass.
// Synthetic files run through the exact production analyzer. // Synthetic files run through the exact production analyzer.
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
const EVASIONS: Array<{ name: string; src: string }> = [ const EVASIONS: Array<{
name: string;
src: string;
extras?: Array<{ rel: string; src: string }>;
}> = [
{ {
name: 'E1 namespace import write', name: 'E1 namespace import write',
src: `import * as dbSchema from '@mosaicstack/db';\nimport { db } from './x.js';\nexport async function f() { await db.insert(dbSchema.companies).values({}); }`, src: `import * as dbSchema from '@mosaicstack/db';\nimport { db } from './x.js';\nexport async function f() { await db.insert(dbSchema.companies).values({}); }`,
@@ -752,6 +956,85 @@ describe('hierarchy writer coverage (contract 1 §6.3b)', () => {
name: 'C-eval', name: 'C-eval',
src: `export function f(s: string) { return eval(s); }`, src: `export function f(s: string) { return eval(s); }`,
}, },
// --- round-2 review shapes (R1R5) ---
{
name: 'E9 namespace destructuring',
src: `import * as dbSchema from '@mosaicstack/db';\nimport { db } from './x.js';\nconst { companies } = dbSchema;\nexport async function f() { await db.insert(companies).values({}); }`,
},
{
name: 'E10 nested namespace re-export',
src: `import * as ns from './evasion-mid.js';\nimport { db } from './x.js';\nexport async function f() { await db.insert(ns.schema.companies).values({}); }`,
extras: [
{
rel: 'packages/db/src/evasion-mid.ts',
src: `export * as schema from '@mosaicstack/db';`,
},
],
},
{
name: 'E11 literal dynamic import, destructured binding',
src: `import { db } from './x.js';\nexport async function f() { const { companies } = await import('@mosaicstack/db'); await db.insert(companies).values({}); }`,
},
{
name: 'E12 literal dynamic import, namespace binding',
src: `import { db } from './x.js';\nexport async function f() { const m = await import('@mosaicstack/db'); await db.insert(m.companies).values({}); }`,
},
{
name: 'E13 createRequire outside its register',
src: `import { createRequire } from 'node:module';\nconst require = createRequire(import.meta.url);\nexport const pg = require('postgres');`,
},
{
name: 'E14 factory capability laundered through re-export',
src: `import * as dbns from './evasion-mid2.js';\nexport async function f(t: string) { await dbns.createDb('u').execute('DELETE FROM ' + t); }`,
extras: [
{
rel: 'packages/db/src/evasion-mid2.ts',
src: `export { createDb } from '@mosaicstack/db';`,
},
],
},
{
name: 'E15 driver default laundered through re-export',
src: `import pg from './evasion-mid3.js';\nexport async function f(t: string) { const c = pg('u'); await c.unsafe('TRUNCATE ' + t); }`,
extras: [
{
rel: 'packages/db/src/evasion-mid3.ts',
src: `export { default } from 'postgres';`,
},
],
},
{
name: 'E16 concatenated dynamic-import specifier',
src: `export async function f() { const m = await import('@mosaicstack/' + 'db'); return m; }`,
},
{
name: 'E17 computed-member write call',
src: `import { companies } from '@mosaicstack/db';\nimport { db } from './x.js';\nexport async function f() { await db['insert'](companies).values({}); }`,
},
{
name: 'E18 spaced member access write',
src: `import { companies } from '@mosaicstack/db';\nimport { db } from './x.js';\nexport async function f() { await db . insert (companies).values({}); }`,
},
{
name: 'E19 computed-member execution call',
src: `export class R { constructor(private client: { query(s: string): Promise<unknown> }) {}\n async f(t: string) { await this.client['query']('TRUNCATE ' + t); } }`,
},
{
name: 'E20 schema-qualified table in SQL span',
src: `export const q = 'DELETE FROM public.hierarchy_grants WHERE role = $1';`,
},
{
name: 'E21 comment interposed in SQL span',
src: `export const q = 'DELETE FROM /* audit */ hierarchy_grants WHERE role = $1';`,
},
{
name: 'E22 COPY statement in SQL span',
src: `export const q = 'COPY hierarchy_grants FROM STDIN';`,
},
{
name: 'E23 escaped-backtick-quoted table in SQL span',
src: 'export const q = `DELETE FROM \\`hierarchy_grants\\` WHERE role = 1`;',
},
]; ];
const CLEAN_CONTROLS: Array<{ name: string; src: string }> = [ const CLEAN_CONTROLS: Array<{ name: string; src: string }> = [
{ {
@@ -773,9 +1056,20 @@ describe('hierarchy writer coverage (contract 1 §6.3b)', () => {
for (const e of EVASIONS) { for (const e of EVASIONS) {
const rel = 'packages/db/src/evasion-sample.ts'; const rel = 'packages/db/src/evasion-sample.ts';
const synthetic: FileFacts = { rel, ...lexSource(e.src) }; const synthetic: FileFacts = { rel, ...lexSource(e.src) };
const synthSet = new Set([...fileSet, rel, barrel.rel]); const extraFacts: FileFacts[] = (e.extras ?? []).map((x) => ({
const synthConduits = computeSchemaConduits([...files, barrel, synthetic], synthSet); rel: x.rel,
const v = analyzeFile(synthetic, synthConduits, synthSet); ...lexSource(x.src),
}));
const synthFiles = [...files, barrel, ...extraFacts, synthetic];
const synthSet = new Set([...fileSet, rel, barrel.rel, ...extraFacts.map((x) => x.rel)]);
const synthCap = computeCapabilityConduits(synthFiles, synthSet);
const synthCtx: AnalysisCtx = {
fileSet: synthSet,
conduits: computeSchemaConduits(synthFiles, synthSet),
driverConduits: synthCap.driver,
factoryConduits: synthCap.factory,
};
const v = analyzeFile(synthetic, synthCtx);
expect(v.length, `evasion not caught: ${e.name}`).toBeGreaterThan(0); expect(v.length, `evasion not caught: ${e.name}`).toBeGreaterThan(0);
} }
}); });
@@ -784,9 +1078,16 @@ describe('hierarchy writer coverage (contract 1 §6.3b)', () => {
for (const c of CLEAN_CONTROLS) { for (const c of CLEAN_CONTROLS) {
const rel = 'packages/db/src/clean-sample.ts'; const rel = 'packages/db/src/clean-sample.ts';
const synthetic: FileFacts = { rel, ...lexSource(c.src) }; const synthetic: FileFacts = { rel, ...lexSource(c.src) };
const synthFiles = [...files, synthetic];
const synthSet = new Set([...fileSet, rel]); const synthSet = new Set([...fileSet, rel]);
const synthConduits = computeSchemaConduits([...files, synthetic], synthSet); const synthCap = computeCapabilityConduits(synthFiles, synthSet);
const v = analyzeFile(synthetic, synthConduits, synthSet); const synthCtx: AnalysisCtx = {
fileSet: synthSet,
conduits: computeSchemaConduits(synthFiles, synthSet),
driverConduits: synthCap.driver,
factoryConduits: synthCap.factory,
};
const v = analyzeFile(synthetic, synthCtx);
expect( expect(
v, v,
`false positive on ${c.name}: ${v.map((x) => `${x.prong}:${x.detail}`).join('; ')}`, `false positive on ${c.name}: ${v.map((x) => `${x.prong}:${x.detail}`).join('; ')}`,