fix: fail closed in release drill verification

This commit is contained in:
DongHyeonka
2026-08-02 03:54:58 +09:00
parent 990603e24a
commit 172a26b8bd
3 changed files with 216 additions and 65 deletions
+76 -10
View File
@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { verifyRollbackReleaseCoherence } from "../../scripts/drill-runbook.ts";
import { verifyReleaseRuntimeCoherence } from "../../scripts/lib/release-runtime-coherence.ts";
import { verifyReleaseArtifactsCoherence } from "../../scripts/verify-release.ts";
import type { InstalledContractPackageIdentity } from "../../src/contracts/external-contract-runtime.ts";
import { computeContractSetDigest } from "../../src/contracts/contract-set-canonical.ts";
import type {
@@ -98,6 +98,19 @@ async function releaseV2With(
};
}
function artifactReader(
entries: Readonly<Record<string, unknown | Error>>,
): (path: string) => Promise<unknown> {
return async (path) => {
const value = entries[path];
if (value === undefined) {
throw Object.assign(new Error(`missing ${path}`), { code: "ENOENT" });
}
if (value instanceof Error) throw value;
return value;
};
}
describe("release coherence", () => {
it("owns all nine release tokens and keeps builtAt diagnostic-only", () => {
// §5.2 adds contractSetDigest beside the legacy apiContractVersion scalar.
@@ -234,17 +247,25 @@ describe("release coherence", () => {
];
for (const fixture of matrix) {
const input = {
release: fixture.release,
runtime: fixture.runtime,
contractPackages,
};
const input = { release: fixture.release, runtime: fixture.runtime };
const verifierVerdict = (
await verifyReleaseRuntimeCoherence(input)
).compatible;
await verifyReleaseArtifactsCoherence({
readArtifact: artifactReader({
"dist/release-manifest.json": input.release,
"dist/config.json": input.runtime,
}),
contractPackages,
})
).coherence.compatible;
const rollbackDrillVerdict = (
await verifyRollbackReleaseCoherence(input)
).compatible;
await verifyRollbackReleaseCoherence({
readArtifact: artifactReader({
"dist/release-manifest.json": fixture.release,
"dist/config.json": fixture.runtime,
}),
contractPackages,
})
).coherence.compatible;
expect(verifierVerdict, `${fixture.name}: verifier`).toBe(
fixture.expectedCompatible,
);
@@ -256,4 +277,49 @@ describe("release coherence", () => {
);
}
});
it("falls back to public rollback artifacts only when primary dist is absent", async () => {
const exactV2 = await releaseV2With(contractPackages);
const tamperedPrimary = await releaseV2With(contractPackages.slice(0, 1));
const validPublic = {
"public/release-manifest.json": exactV2,
"public/config.json": runtimeV2,
};
const unavailablePrimary = [
new SyntaxError("invalid primary JSON"),
Object.assign(new Error("unreadable primary"), { code: "EACCES" }),
{ ...exactV2, unexpected: "tampered" },
];
for (const primaryFailure of unavailablePrimary) {
await expect(
verifyRollbackReleaseCoherence({
readArtifact: artifactReader({
"dist/release-manifest.json": primaryFailure,
"dist/config.json": runtimeV2,
...validPublic,
}),
contractPackages,
}),
).rejects.toBeDefined();
}
await expect(
verifyRollbackReleaseCoherence({
readArtifact: artifactReader({
"dist/release-manifest.json": tamperedPrimary,
"dist/config.json": runtimeV2,
...validPublic,
}),
contractPackages,
}),
).resolves.toMatchObject({ coherence: { compatible: false } });
await expect(
verifyRollbackReleaseCoherence({
readArtifact: artifactReader(validPublic),
contractPackages,
}),
).resolves.toMatchObject({ coherence: { compatible: true } });
});
});