80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import { mkdtemp, mkdir, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { describe, expect, test } from "vitest";
|
|
|
|
import {
|
|
canonicalJsonDigest,
|
|
canonicalValueBytes,
|
|
} from "../../src/security/canonical-digest.ts";
|
|
import {
|
|
verifySignedRelease,
|
|
verifySignedReleaseForTest,
|
|
} from "../../scripts/deploy/lib/release-common.mjs";
|
|
|
|
const h = (c: string) => c.repeat(64);
|
|
|
|
describe("protected release verification authority", () => {
|
|
test("production seam rejects caller-selected verifier, policy path, and time", async () => {
|
|
await expect(
|
|
verifySignedRelease({
|
|
signedManifestPath: "/not-used",
|
|
authorityRoot: "/not-used",
|
|
verifierModulePath: "/tmp/evil.mjs",
|
|
trustPolicyPath: "/tmp/evil.json",
|
|
now: "2000-01-01T00:00:00Z",
|
|
protectedState: {},
|
|
} as never),
|
|
).rejects.toThrow(/unknown|caller|production/i);
|
|
});
|
|
|
|
test("test seam still requires the protected trust-policy digest", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "portfolio-release-authority-"));
|
|
await mkdir(join(root, ".control"));
|
|
const signedManifestPath = join(root, "signed.json");
|
|
const trustPolicyPath = join(root, ".control", "release-trust.json");
|
|
const trustPolicy = {
|
|
schema: "portfolio-trust-policy/v1",
|
|
policyVersion: "test",
|
|
};
|
|
await writeFile(
|
|
signedManifestPath,
|
|
canonicalValueBytes({ schema: "signed" }),
|
|
);
|
|
await writeFile(trustPolicyPath, canonicalValueBytes(trustPolicy));
|
|
const protectedState = {
|
|
latestLedgerHeadHash: h("1"),
|
|
latestLedgerRevision: 1,
|
|
currentManifestDigest: null,
|
|
publisherFence: 0,
|
|
releaseTrustPolicyDigest: h("9"),
|
|
};
|
|
await expect(
|
|
verifySignedReleaseForTest({
|
|
signedManifestPath,
|
|
trustPolicyPath,
|
|
protectedState,
|
|
now: "2026-09-02T01:00:00Z",
|
|
verifySignedReleaseEnvelope: () => {
|
|
throw new Error("must not reach verifier");
|
|
},
|
|
}),
|
|
).rejects.toThrow(/trust.policy|authority|digest/i);
|
|
protectedState.releaseTrustPolicyDigest = canonicalJsonDigest(
|
|
"portfolio-trust-policy/v1",
|
|
trustPolicy,
|
|
);
|
|
await expect(
|
|
verifySignedReleaseForTest({
|
|
signedManifestPath,
|
|
trustPolicyPath,
|
|
protectedState,
|
|
now: "2026-09-02T01:00:00Z",
|
|
verifySignedReleaseEnvelope: () => {
|
|
throw new Error("reached-bound-verifier");
|
|
},
|
|
}),
|
|
).rejects.toThrow("reached-bound-verifier");
|
|
});
|
|
});
|