chore: initialize from frontend template 4dc033c
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { verifyRollbackReleaseCoherence } from "../../scripts/drill-runbook.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 {
|
||||
ReleaseArtifact,
|
||||
RuntimeConfigArtifact,
|
||||
} from "../../src/contracts/release-artifacts.ts";
|
||||
import {
|
||||
compareReleaseToRuntime,
|
||||
RELEASE_TOKEN_REGISTRY,
|
||||
} from "../../src/contracts/release-tokens.ts";
|
||||
|
||||
const contractPackages = [
|
||||
{
|
||||
packageId: "@example/accounts",
|
||||
version: "1.2.3",
|
||||
digest: `sha256:${"1".repeat(64)}`,
|
||||
runtimeProtocolVersion: 1,
|
||||
sourceRevision: "a".repeat(40),
|
||||
},
|
||||
{
|
||||
packageId: "@example/billing",
|
||||
version: "2.3.4",
|
||||
digest: `sha256:${"2".repeat(64)}`,
|
||||
runtimeProtocolVersion: 1,
|
||||
sourceRevision: "b".repeat(40),
|
||||
},
|
||||
] as const satisfies readonly InstalledContractPackageIdentity[];
|
||||
|
||||
const releaseV1 = {
|
||||
schemaVersion: 1,
|
||||
appVersion: "1.0.0",
|
||||
buildId: "build-a",
|
||||
commitSha: "abc1234",
|
||||
configSchemaVersion: "1",
|
||||
apiContractVersion: "1.4.0",
|
||||
assetManifestHash: "assets-a",
|
||||
releaseId: "release-a",
|
||||
builtAt: "2026-08-01T00:00:00.000Z",
|
||||
routeChunks: {},
|
||||
} as const satisfies ReleaseArtifact;
|
||||
|
||||
const runtimeV1 = {
|
||||
APP_ENV: "local",
|
||||
API_BASE_URL: "http://localhost:8080/",
|
||||
REQUEST_TIMEOUT_MS: 10_000,
|
||||
MAX_RETRY_ATTEMPTS: 2,
|
||||
TELEMETRY_ENABLED: false,
|
||||
AUTH_MODE: "external",
|
||||
CONFIG_SCHEMA_VERSION: "1",
|
||||
API_CONTRACT_VERSION: "1.6.0",
|
||||
RELEASE_MANIFEST_URL: "/release-manifest.json",
|
||||
BUILD_ID: "build-a",
|
||||
RELEASE_ID: "release-a",
|
||||
} as const satisfies RuntimeConfigArtifact;
|
||||
|
||||
const runtimeV2 = {
|
||||
APP_ENV: "local",
|
||||
API_BASE_URL: "http://localhost:8080/",
|
||||
REQUEST_TIMEOUT_MS: 10_000,
|
||||
MAX_RETRY_ATTEMPTS: 2,
|
||||
TELEMETRY_ENABLED: false,
|
||||
AUTH_MODE: "external",
|
||||
CONFIG_SCHEMA_VERSION: "2.0",
|
||||
RELEASE_MANIFEST_URL: "/release-manifest.json",
|
||||
BUILD_ID: "build-a",
|
||||
RELEASE_ID: "release-a",
|
||||
CAPABILITY_OVERRIDES: {
|
||||
REALTIME: "DEFAULT",
|
||||
WEB_WORKER: "DEFAULT",
|
||||
SERVICE_WORKER: "DEFAULT",
|
||||
OFFLINE_COMMANDS: "DEFAULT",
|
||||
},
|
||||
} as const satisfies RuntimeConfigArtifact;
|
||||
|
||||
async function releaseV2With(
|
||||
packages: readonly InstalledContractPackageIdentity[],
|
||||
setDigest?: `sha256:${string}`,
|
||||
): Promise<ReleaseArtifact> {
|
||||
return {
|
||||
schemaVersion: 2,
|
||||
appVersion: "1.0.0",
|
||||
buildId: "build-a",
|
||||
commitSha: "abc1234",
|
||||
configSchemaVersion: "2.0",
|
||||
assetManifestHash: "assets-a",
|
||||
releaseId: "release-a",
|
||||
builtAt: "2026-08-01T00:00:00.000Z",
|
||||
routeChunks: {},
|
||||
contractSet: {
|
||||
setAlgorithm: "CA_CONTRACT_SET_V1",
|
||||
setDigest: setDigest ?? (await computeContractSetDigest(packages)),
|
||||
packages: [...packages],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function artifactReader(
|
||||
entries: Readonly<Record<string, unknown | Error>>,
|
||||
reads: string[] = [],
|
||||
): (path: string) => Promise<unknown> {
|
||||
return async (path) => {
|
||||
reads.push(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.
|
||||
expect(Object.keys(RELEASE_TOKEN_REGISTRY)).toHaveLength(9);
|
||||
expect(RELEASE_TOKEN_REGISTRY.contractSetDigest.compatibilityRole).toContain(
|
||||
"multi-package",
|
||||
);
|
||||
expect(RELEASE_TOKEN_REGISTRY.builtAt.compatibilityRole).toContain(
|
||||
"never cache identity",
|
||||
);
|
||||
});
|
||||
|
||||
it("compares the runtime config to the release structurally", () => {
|
||||
const release = {
|
||||
buildId: "build-a",
|
||||
configSchemaVersion: "1.0",
|
||||
apiContractVersion: "1.0",
|
||||
assetManifestHash: "assets-a",
|
||||
releaseId: "release-a",
|
||||
};
|
||||
expect(
|
||||
compareReleaseToRuntime(release, {
|
||||
BUILD_ID: "build-a",
|
||||
CONFIG_SCHEMA_VERSION: "1.2",
|
||||
API_CONTRACT_VERSION: "1.1",
|
||||
RELEASE_ID: "release-a",
|
||||
}),
|
||||
).toMatchObject({ compatible: true, mismatches: [] });
|
||||
});
|
||||
|
||||
it("rejects HTML-only rollback against a newer runtime config", () => {
|
||||
const oldRelease = {
|
||||
buildId: "build-old",
|
||||
configSchemaVersion: "1.0",
|
||||
apiContractVersion: "1.0",
|
||||
assetManifestHash: "assets-old",
|
||||
releaseId: "release-old",
|
||||
};
|
||||
expect(
|
||||
compareReleaseToRuntime(oldRelease, {
|
||||
BUILD_ID: "build-new",
|
||||
CONFIG_SCHEMA_VERSION: "2.0",
|
||||
API_CONTRACT_VERSION: "2.0",
|
||||
RELEASE_ID: "release-new",
|
||||
}),
|
||||
).toMatchObject({
|
||||
compatible: false,
|
||||
mismatches: ["buildId", "configSchemaVersion", "apiContractVersion"],
|
||||
});
|
||||
});
|
||||
|
||||
it("gives release verification and rollback drills the same V1/V2 tamper verdicts", async () => {
|
||||
const packageAdded = [
|
||||
...contractPackages,
|
||||
{
|
||||
packageId: "@example/notifications",
|
||||
version: "3.0.0",
|
||||
digest: `sha256:${"3".repeat(64)}`,
|
||||
runtimeProtocolVersion: 1,
|
||||
sourceRevision: "c".repeat(40),
|
||||
},
|
||||
] as const satisfies readonly InstalledContractPackageIdentity[];
|
||||
const packageRemoved = contractPackages.slice(0, 1);
|
||||
const versionChanged = [
|
||||
{ ...contractPackages[0], version: "1.2.4" },
|
||||
contractPackages[1],
|
||||
] as const satisfies readonly InstalledContractPackageIdentity[];
|
||||
const packageDigestChanged = [
|
||||
{
|
||||
...contractPackages[0],
|
||||
digest: `sha256:${"f".repeat(64)}`,
|
||||
},
|
||||
contractPackages[1],
|
||||
] as const satisfies readonly InstalledContractPackageIdentity[];
|
||||
const exactV2 = await releaseV2With(contractPackages);
|
||||
const matrix = [
|
||||
{
|
||||
name: "V1 scalar success",
|
||||
release: releaseV1,
|
||||
runtime: runtimeV1,
|
||||
expectedCompatible: true,
|
||||
},
|
||||
{
|
||||
name: "V1 scalar mismatch",
|
||||
release: releaseV1,
|
||||
runtime: { ...runtimeV1, API_CONTRACT_VERSION: "2.0.0" },
|
||||
expectedCompatible: false,
|
||||
},
|
||||
{
|
||||
name: "V2 exact package set",
|
||||
release: exactV2,
|
||||
runtime: runtimeV2,
|
||||
expectedCompatible: true,
|
||||
},
|
||||
{
|
||||
name: "V2 exact package set in non-canonical manifest order",
|
||||
release: await releaseV2With([...contractPackages].reverse()),
|
||||
runtime: runtimeV2,
|
||||
expectedCompatible: true,
|
||||
},
|
||||
{
|
||||
name: "V2 package added",
|
||||
release: await releaseV2With(packageAdded),
|
||||
runtime: runtimeV2,
|
||||
expectedCompatible: false,
|
||||
},
|
||||
{
|
||||
name: "V2 package removed",
|
||||
release: await releaseV2With(packageRemoved),
|
||||
runtime: runtimeV2,
|
||||
expectedCompatible: false,
|
||||
},
|
||||
{
|
||||
name: "V2 package version tampered",
|
||||
release: await releaseV2With(versionChanged),
|
||||
runtime: runtimeV2,
|
||||
expectedCompatible: false,
|
||||
},
|
||||
{
|
||||
name: "V2 package digest tampered",
|
||||
release: await releaseV2With(packageDigestChanged),
|
||||
runtime: runtimeV2,
|
||||
expectedCompatible: false,
|
||||
},
|
||||
{
|
||||
name: "V2 set digest tampered",
|
||||
release: await releaseV2With(
|
||||
contractPackages,
|
||||
`sha256:${"0".repeat(64)}`,
|
||||
),
|
||||
runtime: runtimeV2,
|
||||
expectedCompatible: false,
|
||||
},
|
||||
];
|
||||
|
||||
for (const fixture of matrix) {
|
||||
const input = { release: fixture.release, runtime: fixture.runtime };
|
||||
const verifierVerdict = (
|
||||
await verifyReleaseArtifactsCoherence({
|
||||
readArtifact: artifactReader({
|
||||
"dist/release-manifest.json": input.release,
|
||||
"dist/config.json": input.runtime,
|
||||
}),
|
||||
contractPackages,
|
||||
})
|
||||
).coherence.compatible;
|
||||
const rollbackDrillVerdict = (
|
||||
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,
|
||||
);
|
||||
expect(rollbackDrillVerdict, `${fixture.name}: rollback drill`).toBe(
|
||||
fixture.expectedCompatible,
|
||||
);
|
||||
expect(rollbackDrillVerdict, `${fixture.name}: identical verdict`).toBe(
|
||||
verifierVerdict,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
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 } });
|
||||
|
||||
const releaseOnlyMissingReads: string[] = [];
|
||||
await expect(
|
||||
verifyRollbackReleaseCoherence({
|
||||
readArtifact: artifactReader(
|
||||
{
|
||||
"dist/config.json": runtimeV2,
|
||||
...validPublic,
|
||||
},
|
||||
releaseOnlyMissingReads,
|
||||
),
|
||||
contractPackages,
|
||||
}),
|
||||
).rejects.toThrow("primary rollback artifact pair");
|
||||
expect(releaseOnlyMissingReads).toEqual([
|
||||
"dist/release-manifest.json",
|
||||
"dist/config.json",
|
||||
]);
|
||||
|
||||
const runtimeOnlyMissingReads: string[] = [];
|
||||
await expect(
|
||||
verifyRollbackReleaseCoherence({
|
||||
readArtifact: artifactReader(
|
||||
{
|
||||
"dist/release-manifest.json": exactV2,
|
||||
...validPublic,
|
||||
},
|
||||
runtimeOnlyMissingReads,
|
||||
),
|
||||
contractPackages,
|
||||
}),
|
||||
).rejects.toThrow("primary rollback artifact pair");
|
||||
expect(runtimeOnlyMissingReads).toEqual([
|
||||
"dist/release-manifest.json",
|
||||
"dist/config.json",
|
||||
]);
|
||||
|
||||
const missingPairReads: string[] = [];
|
||||
await expect(
|
||||
verifyRollbackReleaseCoherence({
|
||||
readArtifact: artifactReader(validPublic, missingPairReads),
|
||||
contractPackages,
|
||||
}),
|
||||
).resolves.toMatchObject({ coherence: { compatible: true } });
|
||||
expect(missingPairReads).toEqual([
|
||||
"dist/release-manifest.json",
|
||||
"dist/config.json",
|
||||
"public/release-manifest.json",
|
||||
"public/config.json",
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user