fix: close coverage evidence races

This commit is contained in:
DongHyeonka
2026-08-02 08:43:44 +09:00
parent 67cd37659d
commit 8d6fbb97e9
7 changed files with 733 additions and 260 deletions
+44
View File
@@ -186,6 +186,34 @@ describe("repository-aware risk coverage", () => {
).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 }),
@@ -341,6 +369,22 @@ describe("repository-aware risk coverage", () => {
expect(observedFlags & constants.O_NOFOLLOW).toBe(constants.O_NOFOLLOW);
});
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-"));