fix: unify release runtime coherence verification
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import { isVersionCompatible } from "../../src/application/policies/compatibility.ts";
|
||||
import { verifyContractSet } from "../../src/contracts/contract-set.ts";
|
||||
import type { InstalledContractPackageIdentity } from "../../src/contracts/external-contract-runtime.ts";
|
||||
import type { ReleaseArtifact } from "../../src/contracts/release-artifacts.ts";
|
||||
import { compareReleaseToRuntime } from "../../src/contracts/release-tokens.ts";
|
||||
|
||||
export type ReleaseRuntimeCoherenceInput = Readonly<{
|
||||
release: ReleaseArtifact;
|
||||
runtime: Readonly<{
|
||||
BUILD_ID: string;
|
||||
CONFIG_SCHEMA_VERSION: string;
|
||||
API_CONTRACT_VERSION?: string;
|
||||
RELEASE_ID: string;
|
||||
}>;
|
||||
contractPackages: readonly InstalledContractPackageIdentity[];
|
||||
}>;
|
||||
|
||||
export type ReleaseRuntimeCoherence = Readonly<{
|
||||
compatible: boolean;
|
||||
mismatches: readonly string[];
|
||||
warnings: readonly string[];
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Verifies the runtime identity using the release schema's own contract model.
|
||||
* V1 retains the scalar compatibility policy. V2 has no scalar projection: its
|
||||
* identity is the exact compiled package tuple set and canonical set digest.
|
||||
*/
|
||||
export async function verifyReleaseRuntimeCoherence(
|
||||
input: ReleaseRuntimeCoherenceInput,
|
||||
): Promise<ReleaseRuntimeCoherence> {
|
||||
if (input.release.schemaVersion === 1) {
|
||||
if (input.runtime.API_CONTRACT_VERSION === undefined) {
|
||||
return compareWithoutContractScalar(input, ["apiContractVersion"]);
|
||||
}
|
||||
return compareReleaseToRuntime(input.release, {
|
||||
...input.runtime,
|
||||
API_CONTRACT_VERSION: input.runtime.API_CONTRACT_VERSION,
|
||||
});
|
||||
}
|
||||
|
||||
const comparison = compareWithoutContractScalar(input);
|
||||
const contractSet = await verifyContractSet({
|
||||
expected: input.contractPackages,
|
||||
manifest: input.release.contractSet,
|
||||
});
|
||||
if (contractSet.ok) return comparison;
|
||||
|
||||
const mismatches = Object.freeze([
|
||||
...comparison.mismatches,
|
||||
contractSet.code,
|
||||
]);
|
||||
return Object.freeze({
|
||||
compatible: false,
|
||||
mismatches,
|
||||
warnings: comparison.warnings,
|
||||
});
|
||||
}
|
||||
|
||||
function compareWithoutContractScalar(
|
||||
input: Pick<ReleaseRuntimeCoherenceInput, "release" | "runtime">,
|
||||
initialMismatches: readonly string[] = [],
|
||||
): ReleaseRuntimeCoherence {
|
||||
const mismatches = [...initialMismatches];
|
||||
if (input.release.buildId !== input.runtime.BUILD_ID) {
|
||||
mismatches.push("buildId");
|
||||
}
|
||||
if (
|
||||
!isVersionCompatible(
|
||||
input.release.configSchemaVersion,
|
||||
input.runtime.CONFIG_SCHEMA_VERSION,
|
||||
)
|
||||
) {
|
||||
mismatches.push("configSchemaVersion");
|
||||
}
|
||||
const warnings =
|
||||
input.release.releaseId === input.runtime.RELEASE_ID
|
||||
? []
|
||||
: ["releaseId"];
|
||||
return Object.freeze({
|
||||
compatible: mismatches.length === 0,
|
||||
mismatches: Object.freeze(mismatches),
|
||||
warnings: Object.freeze(warnings),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user