849 lines
26 KiB
TypeScript
849 lines
26 KiB
TypeScript
import { constants } from "node:fs";
|
|
import {
|
|
mkdir,
|
|
mkdtemp,
|
|
open,
|
|
readFile,
|
|
rm,
|
|
symlink,
|
|
writeFile,
|
|
} from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
buildProductionModuleInventory,
|
|
evaluateRiskCoverage,
|
|
normalizeCoverageProducerPath,
|
|
parseRepositoryRiskCoveragePolicy,
|
|
parseRiskCoveragePolicy,
|
|
type ProductionModuleInventory,
|
|
} from "../../scripts/lib/risk-coverage.ts";
|
|
|
|
const roots: string[] = [];
|
|
const now = Date.parse("2026-08-02T00:00:00.000Z");
|
|
|
|
function counter(total = 1, covered = total, skipped = 0) {
|
|
return {
|
|
total,
|
|
covered,
|
|
skipped,
|
|
pct: total === 0 ? 100 : Math.floor((covered / total) * 10_000) / 100,
|
|
};
|
|
}
|
|
|
|
function metrics(total = 1, covered = total) {
|
|
return {
|
|
lines: counter(total, covered),
|
|
statements: counter(total, covered),
|
|
functions: counter(total, covered),
|
|
branches: counter(total, covered),
|
|
};
|
|
}
|
|
|
|
const fullMetrics = metrics();
|
|
|
|
function inventory(
|
|
files: readonly string[],
|
|
generatedExclusions: readonly string[] = [],
|
|
counterlessModules: readonly string[] = [],
|
|
): ProductionModuleInventory {
|
|
return {
|
|
files,
|
|
preExclusionTotal: files.length + generatedExclusions.length,
|
|
generatedExclusions,
|
|
counterBearingModules: files.filter(
|
|
(file) => !counterlessModules.includes(file),
|
|
),
|
|
counterlessModules,
|
|
};
|
|
}
|
|
|
|
async function repositoryFixture(): Promise<string> {
|
|
const root = await mkdtemp(path.join(tmpdir(), "risk-coverage-"));
|
|
roots.push(root);
|
|
await mkdir(path.join(root, "src/nested"), { recursive: true });
|
|
await Promise.all([
|
|
writeFile(path.join(root, "src/a.ts"), "export const a = 1;\n"),
|
|
writeFile(path.join(root, "src/nested/b.tsx"), "export const b = 2;\n"),
|
|
writeFile(path.join(root, "src/types.d.ts"), "declare const value: 1;\n"),
|
|
writeFile(path.join(root, "src/example.stories.tsx"), "export {};\n"),
|
|
writeFile(path.join(root, "src/generated.ts"), "export const generated = true;\n"),
|
|
writeFile(path.join(root, "src/ignored.js"), "export const ignored = true;\n"),
|
|
]);
|
|
return root;
|
|
}
|
|
|
|
function policy(overrides: Record<string, unknown> = {}) {
|
|
return {
|
|
schemaVersion: 2,
|
|
repositoryBaseline: 2,
|
|
generatedPaths: ["src/generated.ts"],
|
|
summary: {
|
|
lines: 80,
|
|
statements: 78,
|
|
functions: 85,
|
|
branches: 68,
|
|
},
|
|
criticalModules: [
|
|
{
|
|
path: "src/a.ts",
|
|
owner: "platform-runtime",
|
|
minimum: {
|
|
lines: 80,
|
|
statements: 78,
|
|
functions: 85,
|
|
branches: 68,
|
|
},
|
|
},
|
|
],
|
|
highRiskPaths: ["src/a.ts"],
|
|
waivers: [],
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
roots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
|
|
);
|
|
});
|
|
|
|
describe("repository-aware risk coverage", () => {
|
|
it("rejects the historical 14-file summary against the full repository", async () => {
|
|
const repositoryRoot = process.cwd();
|
|
const rawPolicy = JSON.parse(
|
|
await readFile("config/testing/risk-coverage.json", "utf8"),
|
|
) as unknown;
|
|
const summary = JSON.parse(
|
|
await readFile("tests/fixtures/coverage/repository-omission.json", "utf8"),
|
|
) as unknown;
|
|
const parsedPolicy = parseRepositoryRiskCoveragePolicy(rawPolicy, { now });
|
|
const productionInventory = await buildProductionModuleInventory({
|
|
repositoryRoot,
|
|
generatedPaths: parsedPolicy.generatedPaths,
|
|
});
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot,
|
|
inventory: productionInventory,
|
|
policy: parsedPolicy,
|
|
summary,
|
|
});
|
|
|
|
expect(result.selectedTotal).toBe(14);
|
|
expect(result.repositoryTotal).toBeGreaterThan(result.selectedTotal);
|
|
expect(result.uncoveredModules).toHaveLength(
|
|
result.repositoryTotal - result.selectedTotal,
|
|
);
|
|
expect(result.status).toBe("FAIL");
|
|
});
|
|
|
|
it("reports exact inventory and generated-exclusion provenance", async () => {
|
|
const repositoryRoot = await repositoryFixture();
|
|
const productionInventory = await buildProductionModuleInventory({
|
|
repositoryRoot,
|
|
generatedPaths: ["src/generated.ts"],
|
|
});
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot,
|
|
inventory: productionInventory,
|
|
policy: parseRiskCoveragePolicy(policy(), { now }),
|
|
summary: {
|
|
total: fullMetrics,
|
|
[path.join(repositoryRoot, "src/a.ts")]: fullMetrics,
|
|
},
|
|
});
|
|
|
|
expect(productionInventory).toEqual({
|
|
files: ["src/a.ts", "src/nested/b.tsx"],
|
|
preExclusionTotal: 3,
|
|
generatedExclusions: ["src/generated.ts"],
|
|
counterBearingModules: ["src/a.ts", "src/nested/b.tsx"],
|
|
counterlessModules: [],
|
|
});
|
|
expect(result).toMatchObject({
|
|
status: "FAIL",
|
|
selectedTotal: 1,
|
|
repositoryTotal: 2,
|
|
preExclusionTotal: 3,
|
|
generatedExclusionCount: 1,
|
|
generatedExclusions: ["src/generated.ts"],
|
|
uncoveredModules: ["src/nested/b.tsx"],
|
|
});
|
|
});
|
|
|
|
it("rejects arbitrary coverage paths instead of silently allowing inflation", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: metrics(2),
|
|
"src/a.ts": fullMetrics,
|
|
"tests/unit/a.test.ts": fullMetrics,
|
|
},
|
|
}),
|
|
).toThrow(/unexpected coverage path.*tests\/unit\/a\.test\.ts/u);
|
|
});
|
|
|
|
it("rejects outside and duplicate normalized producer paths", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const base = {
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
};
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
...base,
|
|
summary: { total: fullMetrics, "/outside/src/a.ts": fullMetrics },
|
|
}),
|
|
).toThrow(/outside repository/u);
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
...base,
|
|
summary: {
|
|
total: metrics(2),
|
|
"src/a.ts": fullMetrics,
|
|
"/repository/src/a.ts": fullMetrics,
|
|
},
|
|
}),
|
|
).toThrow(/duplicate coverage path/u);
|
|
});
|
|
|
|
it("accepts only explicitly configured generated coverage paths", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1 }),
|
|
{ now },
|
|
);
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"], ["src/generated.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: metrics(2, 1),
|
|
"src/a.ts": fullMetrics,
|
|
"src/generated.ts": metrics(1, 0),
|
|
},
|
|
}),
|
|
).not.toThrow();
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"], ["src/generated.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: metrics(2, 1),
|
|
"src/a.ts": fullMetrics,
|
|
"src/generated.ts": metrics(1, 0),
|
|
},
|
|
});
|
|
expect(
|
|
result.results.find(
|
|
({ scope, metric }) => scope === "total" && metric === "lines",
|
|
),
|
|
).toMatchObject({ received: 100, passed: true });
|
|
});
|
|
|
|
it("requires complete internally consistent Istanbul counters", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const base = {
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
};
|
|
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
...base,
|
|
summary: { total: fullMetrics, "src/a.ts": { ...fullMetrics, lines: { pct: 100 } } },
|
|
}),
|
|
).toThrow(/lines.*total.*covered.*skipped/u);
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
...base,
|
|
summary: {
|
|
total: fullMetrics,
|
|
"src/a.ts": {
|
|
...fullMetrics,
|
|
lines: { total: 2, covered: 1, skipped: 2, pct: 50 },
|
|
},
|
|
},
|
|
}),
|
|
).toThrow(/covered plus skipped.*total/u);
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
...base,
|
|
summary: {
|
|
total: fullMetrics,
|
|
"src/a.ts": {
|
|
...fullMetrics,
|
|
lines: { total: 3, covered: 2, skipped: 0, pct: 66.67 },
|
|
},
|
|
},
|
|
}),
|
|
).toThrow(/pct.*66\.66/u);
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
...base,
|
|
summary: {
|
|
total: metrics(0),
|
|
"src/a.ts": { ...fullMetrics, lines: counter(0, 0, 0) },
|
|
},
|
|
}),
|
|
).toThrow(/coverage total.*does not match/u);
|
|
});
|
|
|
|
it("recomputes all global counters and requires an exact producer total", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: metrics(2),
|
|
"src/a.ts": fullMetrics,
|
|
},
|
|
}),
|
|
).toThrow(/coverage total\.lines does not match recomputed inventory total/u);
|
|
});
|
|
|
|
it("fails an exact-consistent all-zero coverage universe", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: metrics(0),
|
|
"src/a.ts": metrics(0),
|
|
},
|
|
});
|
|
|
|
expect(result).toMatchObject({
|
|
status: "FAIL",
|
|
selectedTotal: 0,
|
|
repositoryTotal: 1,
|
|
uncoveredModules: ["src/a.ts"],
|
|
});
|
|
expect(result.failures).toContain(
|
|
"counter-bearing module has zero coverage totals: src/a.ts",
|
|
);
|
|
expect(result.failures).toEqual(
|
|
expect.arrayContaining([
|
|
"total.lines coverage total must be greater than 0",
|
|
"total.statements coverage total must be greater than 0",
|
|
"total.functions coverage total must be greater than 0",
|
|
"total.branches coverage total must be greater than 0",
|
|
]),
|
|
);
|
|
});
|
|
|
|
it("accepts exact all-zero rows only for statically counterless modules", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 2, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const productionInventory = inventory(
|
|
["src/a.ts", "src/type-only.ts"],
|
|
[],
|
|
["src/type-only.ts"],
|
|
);
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: productionInventory,
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: fullMetrics,
|
|
"src/a.ts": fullMetrics,
|
|
"src/type-only.ts": metrics(0),
|
|
},
|
|
});
|
|
|
|
expect(result).toMatchObject({
|
|
status: "PASS",
|
|
selectedTotal: 2,
|
|
repositoryTotal: 2,
|
|
counterBearingTotal: 1,
|
|
instrumentedCounterBearingTotal: 1,
|
|
counterlessTotal: 1,
|
|
counterlessModules: ["src/type-only.ts"],
|
|
uncoveredModules: [],
|
|
});
|
|
|
|
const mismatch = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: productionInventory,
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: metrics(2),
|
|
"src/a.ts": fullMetrics,
|
|
"src/type-only.ts": fullMetrics,
|
|
},
|
|
});
|
|
expect(mismatch.failures).toContain(
|
|
"counterless module has coverage counters: src/type-only.ts",
|
|
);
|
|
});
|
|
|
|
it("forbids policy-sensitive modules from being counterless", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"], [], ["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: { total: metrics(0), "src/a.ts": metrics(0) },
|
|
});
|
|
|
|
expect(result.failures).toEqual(
|
|
expect.arrayContaining([
|
|
"critical policy-sensitive module cannot be counterless: src/a.ts",
|
|
"high-risk policy-sensitive module cannot be counterless: src/a.ts",
|
|
]),
|
|
);
|
|
});
|
|
|
|
it("fails a critical threshold metric with a zero total even when pct is 100", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 2, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const criticalMetrics = { ...fullMetrics, lines: counter(0) };
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts", "src/nested/b.tsx"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: {
|
|
lines: counter(1),
|
|
statements: counter(2),
|
|
functions: counter(2),
|
|
branches: counter(2),
|
|
},
|
|
"src/a.ts": criticalMetrics,
|
|
"src/nested/b.tsx": fullMetrics,
|
|
},
|
|
});
|
|
|
|
expect(result.status).toBe("FAIL");
|
|
expect(result.selectedTotal).toBe(2);
|
|
expect(result.failures).toContain(
|
|
"src/a.ts.lines coverage total must be greater than 0",
|
|
);
|
|
expect(
|
|
result.results.find(
|
|
({ scope, metric }) => scope === "src/a.ts" && metric === "lines",
|
|
),
|
|
).toMatchObject({ received: 100, passed: false });
|
|
});
|
|
|
|
it("keeps a noncritical zero-function row when other metrics and repository functions exist", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 2, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const noncriticalMetrics = { ...fullMetrics, functions: counter(0) };
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts", "src/nested/b.tsx"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: {
|
|
lines: counter(2),
|
|
statements: counter(2),
|
|
functions: counter(1),
|
|
branches: counter(2),
|
|
},
|
|
"src/a.ts": fullMetrics,
|
|
"src/nested/b.tsx": noncriticalMetrics,
|
|
},
|
|
});
|
|
|
|
expect(result).toMatchObject({
|
|
status: "PASS",
|
|
selectedTotal: 2,
|
|
uncoveredModules: [],
|
|
});
|
|
});
|
|
|
|
it("accepts and validates Vitest branchesTrue without evaluating it", () => {
|
|
const parsedPolicy = parseRiskCoveragePolicy(
|
|
policy({ repositoryBaseline: 1, generatedPaths: [] }),
|
|
{ now },
|
|
);
|
|
const branchesTrue = counter(0);
|
|
expect(
|
|
evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: { ...fullMetrics, branchesTrue },
|
|
"src/a.ts": fullMetrics,
|
|
},
|
|
}),
|
|
).toMatchObject({ status: "PASS" });
|
|
expect(() =>
|
|
evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(["src/a.ts"]),
|
|
policy: parsedPolicy,
|
|
summary: {
|
|
total: {
|
|
...fullMetrics,
|
|
branchesTrue: { ...branchesTrue, pct: 0 },
|
|
},
|
|
"src/a.ts": fullMetrics,
|
|
},
|
|
}),
|
|
).toThrow(/branchesTrue\.pct.*100/u);
|
|
});
|
|
|
|
it("opens regular files with O_NOFOLLOW and fails a deterministic symlink swap", async () => {
|
|
const repositoryRoot = await repositoryFixture();
|
|
let observedFlags = 0;
|
|
await expect(
|
|
buildProductionModuleInventory({
|
|
repositoryRoot,
|
|
openFile: async (target, flags) => {
|
|
observedFlags = flags;
|
|
if (target.endsWith("src/a.ts")) {
|
|
throw Object.assign(new Error("injected link swap"), { code: "ELOOP" });
|
|
}
|
|
return open(target, flags);
|
|
},
|
|
}),
|
|
).rejects.toThrow(/unreadable.*src\/a\.ts/u);
|
|
expect(observedFlags & constants.O_NOFOLLOW).toBe(constants.O_NOFOLLOW);
|
|
});
|
|
|
|
it("fails closed when an opened inventory file has no stable identity", async () => {
|
|
const repositoryRoot = await repositoryFixture();
|
|
await expect(
|
|
buildProductionModuleInventory({
|
|
repositoryRoot,
|
|
openFile: async (target, flags) => {
|
|
const handle = await open(target, flags);
|
|
return {
|
|
stat: async () => {
|
|
const metadata = await handle.stat();
|
|
Object.defineProperties(metadata, {
|
|
dev: { value: 0 },
|
|
ino: { value: 0 },
|
|
});
|
|
return metadata;
|
|
},
|
|
readFile: async (encoding) => handle.readFile(encoding),
|
|
close: async () => handle.close(),
|
|
};
|
|
},
|
|
}),
|
|
).rejects.toThrow(/stable file identity unavailable/u);
|
|
});
|
|
|
|
it("matches the observed V8 counterless import and re-export syntax", async () => {
|
|
const repositoryRoot = await repositoryFixture();
|
|
await Promise.all([
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/type-only.ts"),
|
|
"export interface Shape { readonly id: string }\nexport type ShapeId = Shape['id'];\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/barrel.ts"),
|
|
"export type { Shape, ShapeId } from './type-only.ts';\nexport { type Shape as PublicShape } from './type-only.ts';\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/runtime-export.ts"),
|
|
"export const runtimeValue = 1;\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/side-effect.ts"),
|
|
"void globalThis;\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/import-type-empty.ts"),
|
|
"import type {} from './a.ts';\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/import-value-empty.ts"),
|
|
"import {} from './a.ts';\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/import-side-effect.ts"),
|
|
"import './a.ts';\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/import-value.ts"),
|
|
"import { a } from './a.ts';\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/reexport-named.ts"),
|
|
"export { a } from './a.ts';\n",
|
|
),
|
|
writeFile(
|
|
path.join(repositoryRoot, "src/reexport-star.ts"),
|
|
"export * from './a.ts';\n",
|
|
),
|
|
]);
|
|
|
|
const productionInventory = await buildProductionModuleInventory({
|
|
repositoryRoot,
|
|
generatedPaths: ["src/generated.ts"],
|
|
});
|
|
|
|
expect(productionInventory.counterlessModules).toEqual([
|
|
"src/barrel.ts",
|
|
"src/import-side-effect.ts",
|
|
"src/import-type-empty.ts",
|
|
"src/import-value-empty.ts",
|
|
"src/import-value.ts",
|
|
"src/reexport-named.ts",
|
|
"src/reexport-star.ts",
|
|
"src/type-only.ts",
|
|
]);
|
|
expect(productionInventory.counterBearingModules).toEqual([
|
|
"src/a.ts",
|
|
"src/nested/b.tsx",
|
|
"src/runtime-export.ts",
|
|
"src/side-effect.ts",
|
|
]);
|
|
});
|
|
|
|
it("rejects a post-lstat file identity swap even without relying on O_NOFOLLOW", async () => {
|
|
const repositoryRoot = await repositoryFixture();
|
|
const outside = await mkdtemp(path.join(tmpdir(), "risk-coverage-race-"));
|
|
roots.push(outside);
|
|
const outsideFile = path.join(outside, "replacement.ts");
|
|
await writeFile(outsideFile, "export const replacement = true;\n");
|
|
|
|
await expect(
|
|
buildProductionModuleInventory({
|
|
repositoryRoot,
|
|
openFile: async (target, flags) =>
|
|
open(target.endsWith("src/a.ts") ? outsideFile : target, flags),
|
|
}),
|
|
).rejects.toThrow(/changed during validation/u);
|
|
});
|
|
|
|
it("fails closed on empty, traversing, symlinked, or stale generated inventory", async () => {
|
|
const repositoryRoot = await repositoryFixture();
|
|
const emptyRoot = await mkdtemp(path.join(tmpdir(), "risk-coverage-empty-"));
|
|
roots.push(emptyRoot);
|
|
await mkdir(path.join(emptyRoot, "src"));
|
|
|
|
await expect(buildProductionModuleInventory({ repositoryRoot: emptyRoot })).rejects.toThrow(
|
|
/inventory is empty/u,
|
|
);
|
|
await expect(
|
|
buildProductionModuleInventory({ repositoryRoot, generatedPaths: ["../escape.ts"] }),
|
|
).rejects.toThrow(/repository-relative POSIX/u);
|
|
await expect(
|
|
buildProductionModuleInventory({ repositoryRoot, generatedPaths: ["src/missing.ts"] }),
|
|
).rejects.toThrow(/stale or not a production module/u);
|
|
|
|
const outside = await mkdtemp(path.join(tmpdir(), "risk-coverage-outside-"));
|
|
roots.push(outside);
|
|
await writeFile(path.join(outside, "linked.ts"), "export {};\n");
|
|
await symlink(path.join(outside, "linked.ts"), path.join(repositoryRoot, "src/link.ts"));
|
|
await expect(buildProductionModuleInventory({ repositoryRoot })).rejects.toThrow(
|
|
/symlink.*src\/link\.ts/u,
|
|
);
|
|
});
|
|
|
|
it("normalizes native Windows absolute producer paths but rejects POSIX backslashes", () => {
|
|
expect(
|
|
normalizeCoverageProducerPath({
|
|
repositoryRoot: "C:\\repo",
|
|
rawPath: "C:\\repo\\src\\nested\\a.ts",
|
|
platform: "win32",
|
|
}),
|
|
).toBe("src/nested/a.ts");
|
|
expect(() =>
|
|
normalizeCoverageProducerPath({
|
|
repositoryRoot: "/repository",
|
|
rawPath: "/repository/src\\a.ts",
|
|
platform: "posix",
|
|
}),
|
|
).toThrow(/POSIX separators/u);
|
|
expect(() =>
|
|
normalizeCoverageProducerPath({
|
|
repositoryRoot: "C:\\repo",
|
|
rawPath: "D:\\outside\\a.ts",
|
|
platform: "win32",
|
|
}),
|
|
).toThrow(/outside repository/u);
|
|
});
|
|
|
|
it("requires four positive metrics and canonical team ownership", () => {
|
|
expect(() =>
|
|
parseRiskCoveragePolicy(policy({ summary: { lines: 80 } }), { now }),
|
|
).toThrow(/summary must define all/u);
|
|
expect(() =>
|
|
parseRiskCoveragePolicy(policy({ summary: { lines: 80, statements: 78, functions: 85, branches: 0 } }), { now }),
|
|
).toThrow(/greater than 0/u);
|
|
expect(() =>
|
|
parseRiskCoveragePolicy(
|
|
policy({
|
|
criticalModules: [
|
|
{ path: "src/a.ts", owner: "Platform Runtime", minimum: policy().summary },
|
|
],
|
|
}),
|
|
{ now },
|
|
),
|
|
).toThrow(/canonical team id/u);
|
|
expect(() =>
|
|
parseRiskCoveragePolicy(
|
|
policy({
|
|
criticalModules: [
|
|
{ path: "src/a.ts", owner: "platform-runtime", minimum: { lines: 80 } },
|
|
],
|
|
}),
|
|
{ now },
|
|
),
|
|
).toThrow(/minimum must define all/u);
|
|
});
|
|
|
|
it("enforces ALL_POLICY_HIGH_RISK ownership without changed-file input", () => {
|
|
expect(() =>
|
|
parseRiskCoveragePolicy(
|
|
policy({ highRiskPaths: ["src/a.ts", "src/nested/b.tsx"] }),
|
|
{ now },
|
|
),
|
|
).toThrow(/high-risk module has no owner or waiver.*nested\/b/u);
|
|
|
|
const parsed = parseRiskCoveragePolicy(
|
|
policy({
|
|
highRiskPaths: ["src/a.ts", "src/nested/b.tsx"],
|
|
waivers: [
|
|
{
|
|
path: "src/nested/b.tsx",
|
|
owner: "runtime-security",
|
|
reason: "Temporary instrumentation gap",
|
|
expiresAt: "2026-08-03T00:00:00.000Z",
|
|
},
|
|
],
|
|
}),
|
|
{ now },
|
|
);
|
|
const result = evaluateRiskCoverage({
|
|
repositoryRoot: "/repository",
|
|
inventory: inventory(
|
|
["src/a.ts", "src/nested/b.tsx"],
|
|
["src/generated.ts"],
|
|
),
|
|
policy: parsed,
|
|
summary: {
|
|
total: metrics(2),
|
|
"src/a.ts": fullMetrics,
|
|
"src/nested/b.tsx": fullMetrics,
|
|
},
|
|
});
|
|
expect(result).toMatchObject({
|
|
ownershipScope: "ALL_POLICY_HIGH_RISK",
|
|
ownedHighRiskPaths: ["src/a.ts"],
|
|
waivedHighRiskPaths: ["src/nested/b.tsx"],
|
|
status: "PASS",
|
|
});
|
|
});
|
|
|
|
it.each([
|
|
[
|
|
{ path: "src/a.ts", owner: "Runtime Team", reason: "Temporary instrumentation gap", expiresAt: "2026-08-03T00:00:00.000Z" },
|
|
/canonical team id/u,
|
|
],
|
|
[
|
|
{ path: "src/a.ts", owner: "runtime-team", reason: "too short", expiresAt: "2026-08-03T00:00:00.000Z" },
|
|
/12 to 240/u,
|
|
],
|
|
[
|
|
{ path: "src/a.ts", owner: "runtime-team", reason: "Temporary\ninstrumentation gap", expiresAt: "2026-08-03T00:00:00.000Z" },
|
|
/control characters/u,
|
|
],
|
|
[
|
|
{ path: "src/a.ts", owner: "runtime-team", reason: "Temporary instrumentation gap", expiresAt: "2026-08-03T00:00:00Z" },
|
|
/canonical UTC ISO/u,
|
|
],
|
|
[
|
|
{ path: "src/a.ts", owner: "runtime-team", reason: "Temporary instrumentation gap", expiresAt: "2026-11-01T00:00:00.000Z" },
|
|
/90 days/u,
|
|
],
|
|
] as const)("rejects invalid waiver controls %#", (waiver, message) => {
|
|
expect(() =>
|
|
parseRiskCoveragePolicy(
|
|
policy({
|
|
criticalModules: [
|
|
{
|
|
path: "src/owned.ts",
|
|
owner: "platform-runtime",
|
|
minimum: policy().summary,
|
|
},
|
|
],
|
|
highRiskPaths: ["src/owned.ts", "src/a.ts"],
|
|
waivers: [waiver],
|
|
}),
|
|
{ now },
|
|
),
|
|
).toThrow(message);
|
|
});
|
|
|
|
it("rejects simultaneous critical ownership and waiver", () => {
|
|
expect(() =>
|
|
parseRiskCoveragePolicy(
|
|
policy({
|
|
waivers: [
|
|
{
|
|
path: "src/a.ts",
|
|
owner: "runtime-team",
|
|
reason: "Temporary instrumentation gap",
|
|
expiresAt: "2026-08-03T00:00:00.000Z",
|
|
},
|
|
],
|
|
}),
|
|
{ now },
|
|
),
|
|
).toThrow(/both a critical owner and waiver/u);
|
|
});
|
|
|
|
it("does not let repository policy omit or generate-exclude a required high-risk path", async () => {
|
|
const rawPolicy = JSON.parse(
|
|
await readFile("config/testing/risk-coverage.json", "utf8"),
|
|
) as Record<string, unknown>;
|
|
const missingPolicy = structuredClone(rawPolicy);
|
|
missingPolicy.highRiskPaths = (missingPolicy.highRiskPaths as string[]).filter(
|
|
(modulePath) => modulePath !== "src/adapters/http/http-execution-v3.ts",
|
|
);
|
|
expect(() => parseRepositoryRiskCoveragePolicy(missingPolicy, { now })).toThrow(
|
|
/required high-risk path.*http-execution-v3/u,
|
|
);
|
|
|
|
const excludedPolicy = structuredClone(rawPolicy);
|
|
excludedPolicy.generatedPaths = ["src/adapters/http/http-execution-v3.ts"];
|
|
expect(() => parseRepositoryRiskCoveragePolicy(excludedPolicy, { now })).toThrow(
|
|
/required high-risk path cannot be generated-excluded/u,
|
|
);
|
|
});
|
|
});
|