Files
openclaw/scripts/validate-authorized-beta-focused-evidence.mts
Vincent Koc 3d302c58c6 fix(release): register focused beta evidence on main (#128391)
* fix(release): repair frozen beta validation blockers (#128137)

* fix(release): repair frozen beta validation blockers

* fix(release): bind reviewed scanner evidence

* test(release): align frozen beta validation contracts

* fix(release): accept statusless 9a83 QA evidence (#128188)

* fix(release): admit final beta QA evidence (#128231)

Admit the exact final beta candidate to the existing fail-closed statusless QA compatibility profile and its parameterized validation matrix.

* fix(release): authorize focused beta evidence
2026-08-23 15:48:04 -07:00

868 lines
29 KiB
TypeScript

#!/usr/bin/env node
import { execFileSync } from "node:child_process";
import { createHash } from "node:crypto";
import { mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { isRecord } from "./lib/record-shared.mjs";
type JsonRecord = Record<string, unknown>;
export type AuthorizedBetaFocusedPolicy = {
schema: string;
mode: string;
releaseTag: string;
releaseVersion: string;
baseCandidateSha: string;
candidateSha: string;
reviewedHeadSha: string;
candidateTreeSha: string;
baseTreeSha: string;
packageProjectionSha256: string;
eligibilityPlanDigest: string;
historicalToolingSha: string;
historicalToolingRef: string;
historicalFrv: {
runId: string;
runAttempt: number;
workflowPath: string;
workflowRef: string;
targetSha: string;
ciRunId: string;
ciFailedJobId: string;
ciAggregateJobId: string;
pluginRunId: string;
pluginFailedJobId: string;
pluginAggregateJobId: string;
releaseChecksRunId: string;
releaseChecksVerifierJobId: string;
performanceRunId: string;
performanceFailedJobId: string;
};
focusedProof: {
ciRunId: string;
ciTargetLogJobId: string;
ciSuccessJobId: string;
pluginRunId: string;
pluginTargetLogJobId: string;
pluginSuccessJobId: string;
};
changedPaths: Array<{
path: string;
status: string;
added: number;
deleted: number;
}>;
inventory: {
npmCount: number;
npmNamesSha256: string;
clawHubCount: number;
clawHubNamesSha256: string;
trustedPublisherCount: number;
trustedPublisherNamesSha256: string;
bootstrapCount: number;
bootstrapNamesSha256: string;
missingTrustedPublisherCount: number;
};
};
export type AuthorizedBetaFocusedProducerIdentity = {
repository: string;
runId: string;
runAttempt: number;
workflowPath: string;
workflowFullRef: string;
workflowRef: string;
workflowSha: string;
};
export type AuthorizedBetaFocusedEvidence = {
schema: "openclaw.authorized-beta-focused-evidence.v1";
mode: "authorized-beta-focused-v1";
policySha256: string;
releaseTag: string;
candidate: {
sha: string;
parentSha: string;
treeSha: string;
packageProjectionSha256: string;
changedPaths: AuthorizedBetaFocusedPolicy["changedPaths"];
};
producer: AuthorizedBetaFocusedProducerIdentity;
historical: {
frvRunId: string;
frvRunAttempt: number;
releaseChecksRunId: string;
performanceRunId: string;
};
focused: {
ciRunId: string;
ciJobId: string;
pluginRunId: string;
pluginJobId: string;
reviewedHeadSha: string;
};
inventory: {
eligibilityPlanDigest: string;
npmCount: number;
npmNamesSha256: string;
clawHubCount: number;
clawHubNamesSha256: string;
trustedPublisherCount: number;
trustedPublisherNamesSha256: string;
bootstrapCount: number;
bootstrapNamesSha256: string;
missingTrustedPublisherCount: number;
};
};
const SCRIPT_ROOT = dirname(fileURLToPath(import.meta.url));
const POLICY_PATH = resolve(SCRIPT_ROOT, "authorized-beta-focused-policy.json");
const REPOSITORY = "openclaw/openclaw";
const PRODUCER_WORKFLOW = ".github/workflows/authorized-beta-focused-validation.yml";
const SHA_PATTERN = /^[a-f0-9]{40}$/u;
const POSITIVE_INTEGER_PATTERN = /^[1-9][0-9]*$/u;
const PROTECTED_TAG_PATTERN = /^refs\/tags\/release-publish\/([a-f0-9]{12})-[1-9][0-9]*$/u;
function fail(message: string): never {
throw new Error(message);
}
function exactString(value: unknown, label: string): string {
if (typeof value !== "string" || value.length === 0) {
fail(`${label} must be a non-empty string`);
}
return value;
}
function exactPositiveInteger(value: unknown, label: string): number {
const normalized = typeof value === "number" ? String(value) : exactString(value, label);
if (!POSITIVE_INTEGER_PATTERN.test(normalized)) {
fail(`${label} must be a positive integer`);
}
return Number(normalized);
}
function exactJsonId(value: unknown, label: string): string {
if (typeof value === "number" && Number.isSafeInteger(value)) {
return String(value);
}
return exactString(value, label);
}
function stableJson(value: unknown): string {
if (Array.isArray(value)) {
return `[${value.map(stableJson).join(",")}]`;
}
if (value && typeof value === "object") {
return `{${Object.entries(value)
.toSorted(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
.join(",")}}`;
}
return JSON.stringify(value);
}
function sha256(value: string | Uint8Array): string {
return createHash("sha256").update(value).digest("hex");
}
export function digestAuthorizedBetaFocusedPolicy(policy: AuthorizedBetaFocusedPolicy): string {
return sha256(stableJson(policy));
}
export async function assertAuthorizedEligibilityPlanDigest(
plan: unknown,
expectedDigest: string,
): Promise<string> {
const { createReleasePlanLock } = await import("./release-plan-contract.mjs");
const digest = createReleasePlanLock(plan).digest;
if (digest !== expectedDigest) {
fail(`authorized eligibility plan digest mismatch: expected ${expectedDigest}, got ${digest}`);
}
return digest;
}
export function readAuthorizedBetaFocusedPolicy(): AuthorizedBetaFocusedPolicy {
return JSON.parse(readFileSync(POLICY_PATH, "utf8")) as AuthorizedBetaFocusedPolicy;
}
function git(repoRoot: string, args: string[]): string {
return execFileSync("git", args, {
cwd: repoRoot,
encoding: "utf8",
maxBuffer: 16 * 1024 * 1024,
}).trimEnd();
}
function gh(args: string[]): string {
return execFileSync("gh", args, {
encoding: "utf8",
maxBuffer: 32 * 1024 * 1024,
});
}
function ghJson(endpoint: string): JsonRecord {
const value: unknown = JSON.parse(gh(["api", endpoint]));
if (!isRecord(value)) {
fail(`${endpoint} must be an object`);
}
return value;
}
function normalizeRun(run: JsonRecord) {
return {
id: exactJsonId(run.id, "run id"),
attempt: exactPositiveInteger(run.run_attempt, "run attempt"),
name: exactString(run.name, "run name"),
path: exactString(run.path, "run path").split("@", 1)[0] ?? "",
event: exactString(run.event, "run event"),
status: exactString(run.status, "run status"),
conclusion:
run.conclusion === null || run.conclusion === undefined
? ""
: exactString(run.conclusion, "run conclusion"),
headBranch: exactString(run.head_branch, "run head branch"),
headSha: exactString(run.head_sha, "run head SHA"),
};
}
function normalizeJob(job: JsonRecord) {
return {
id: exactJsonId(job.id, "job id"),
runId: exactJsonId(job.run_id, "job run id"),
name: exactString(job.name, "job name"),
status: exactString(job.status, "job status"),
conclusion:
job.conclusion === null || job.conclusion === undefined
? ""
: exactString(job.conclusion, "job conclusion"),
headSha: exactString(job.head_sha, "job head SHA"),
};
}
function requireRun(params: {
runId: string;
attempt: number;
name: string;
path: string;
headBranch: string;
headSha: string;
conclusion?: string;
allowInProgress?: boolean;
}) {
const run = normalizeRun(ghJson(`repos/${REPOSITORY}/actions/runs/${params.runId}`));
const checks: Array<[string, string | number, string | number]> = [
["id", run.id, params.runId],
["attempt", run.attempt, params.attempt],
["name", run.name, params.name],
["path", run.path, params.path],
["event", run.event, "workflow_dispatch"],
["headBranch", run.headBranch, params.headBranch],
["headSha", run.headSha, params.headSha],
];
for (const [label, actual, expected] of checks) {
if (actual !== expected) {
fail(`run ${params.runId} ${label} mismatch: expected ${expected}, got ${actual}`);
}
}
if (params.allowInProgress) {
if (!["in_progress", "queued", "completed"].includes(run.status)) {
fail(`run ${params.runId} has unsupported producer status ${run.status}`);
}
} else if (run.status !== "completed" || run.conclusion !== (params.conclusion ?? "success")) {
fail(
`run ${params.runId} must be completed/${params.conclusion ?? "success"}, got ${run.status}/${run.conclusion}`,
);
}
return run;
}
function requireJob(params: {
jobId: string;
runId: string;
name: string;
conclusion: string;
headSha: string;
}) {
const job = normalizeJob(ghJson(`repos/${REPOSITORY}/actions/jobs/${params.jobId}`));
const checks: Array<[string, string, string]> = [
["id", job.id, params.jobId],
["runId", job.runId, params.runId],
["name", job.name, params.name],
["status", job.status, "completed"],
["conclusion", job.conclusion, params.conclusion],
["headSha", job.headSha, params.headSha],
];
for (const [label, actual, expected] of checks) {
if (actual !== expected) {
fail(`job ${params.jobId} ${label} mismatch: expected ${expected}, got ${actual}`);
}
}
}
function requireJobLogTarget(jobId: string, targetSha: string) {
const log = gh(["api", `repos/${REPOSITORY}/actions/jobs/${jobId}/logs`]);
if (!log.includes(targetSha)) {
fail(`job ${jobId} log does not bind target ${targetSha}`);
}
}
function requireHistoricalExecutionPlan(policy: AuthorizedBetaFocusedPolicy) {
const historical = policy.historicalFrv;
const directory = mkdtempSync(join(tmpdir(), "authorized-beta-focused-plan-"));
try {
gh([
"run",
"download",
historical.runId,
"--repo",
REPOSITORY,
"--name",
`full-release-execution-plan-${historical.runId}`,
"--dir",
directory,
]);
const planValue: unknown = JSON.parse(
readFileSync(join(directory, "full-release-execution-plan.json"), "utf8"),
);
if (!isRecord(planValue)) {
fail("historical full release execution plan must be an object");
}
const plan = planValue;
const checks: Array<[string, unknown, string | number]> = [
["parentRunId", plan.parentRunId, historical.runId],
["parentRunAttempt", plan.parentRunAttempt, historical.runAttempt],
["workflowRef", plan.workflowRef, historical.workflowRef],
["workflowSha", plan.workflowSha, policy.historicalToolingSha],
["targetSha", plan.targetSha, historical.targetSha],
["releaseProfile", plan.releaseProfile, "beta"],
["rerunGroup", plan.rerunGroup, "all"],
];
for (const [label, actual, expected] of checks) {
if (actual !== expected) {
fail(
`historical execution plan ${label} mismatch: expected ${expected}, got ${JSON.stringify(actual)}`,
);
}
}
if (!Array.isArray(plan.children)) {
fail("historical execution plan children must be an array");
}
const childRuns = new Map(
plan.children.map((entry: unknown) => {
if (!isRecord(entry)) {
fail("historical execution plan child must be an object");
}
return [
exactString(entry.key, "historical execution plan child key"),
exactJsonId(entry.runId, "historical execution plan child run id"),
];
}),
);
const expectedChildren = new Map([
["normalCi", historical.ciRunId],
["pluginPrerelease", historical.pluginRunId],
["releaseChecks", historical.releaseChecksRunId],
["productPerformance", historical.performanceRunId],
]);
for (const [key, expectedRunId] of expectedChildren) {
if (childRuns.get(key) !== expectedRunId) {
fail(`historical execution plan child ${key} must be run ${expectedRunId}`);
}
}
} finally {
rmSync(directory, { force: true, recursive: true });
}
}
export function digestAuthorizedPackageNames(names: string[]): string {
const sorted = [...names].toSorted();
if (new Set(sorted).size !== sorted.length) {
fail("package inventory contains duplicate names");
}
return sha256(`${sorted.join("\n")}\n`);
}
export function assertAuthorizedBetaFocusedCandidate(
policy: AuthorizedBetaFocusedPolicy,
candidateRoot: string,
) {
const actualHead = git(candidateRoot, ["rev-parse", "HEAD"]);
if (actualHead !== policy.candidateSha) {
fail(`candidate checkout must be ${policy.candidateSha}, got ${actualHead}`);
}
const parents = git(candidateRoot, ["rev-list", "--parents", "-n1", policy.candidateSha]).split(
" ",
);
if (parents.length !== 2 || parents[1] !== policy.baseCandidateSha) {
fail("candidate must be the direct child of the frozen base candidate");
}
const candidateTree = git(candidateRoot, ["rev-parse", `${policy.candidateSha}^{tree}`]);
const baseTree = git(candidateRoot, ["rev-parse", `${policy.baseCandidateSha}^{tree}`]);
try {
git(candidateRoot, ["cat-file", "-e", `${policy.reviewedHeadSha}^{commit}`]);
} catch {
git(candidateRoot, ["fetch", "--no-tags", "origin", policy.reviewedHeadSha]);
}
const reviewedTree = git(candidateRoot, ["rev-parse", `${policy.reviewedHeadSha}^{tree}`]);
if (
candidateTree !== policy.candidateTreeSha ||
baseTree !== policy.baseTreeSha ||
reviewedTree !== candidateTree
) {
fail("candidate/base/reviewed tree identity does not match the authorized policy");
}
const statuses = new Map(
git(candidateRoot, [
"diff",
"--name-status",
"--no-renames",
policy.baseCandidateSha,
policy.candidateSha,
])
.split("\n")
.filter(Boolean)
.map((line) => {
const [status, path] = line.split("\t");
return [path, status];
}),
);
const numstat = new Map(
git(candidateRoot, ["diff", "--numstat", policy.baseCandidateSha, policy.candidateSha])
.split("\n")
.filter(Boolean)
.map((line) => {
const [added, deleted, path] = line.split("\t");
return [path, { added: Number(added), deleted: Number(deleted) }];
}),
);
if (statuses.size !== policy.changedPaths.length || numstat.size !== policy.changedPaths.length) {
fail("candidate changed-path count does not match the authorized policy");
}
for (const expected of policy.changedPaths) {
const actualNumstat = numstat.get(expected.path);
if (
statuses.get(expected.path) !== expected.status ||
actualNumstat?.added !== expected.added ||
actualNumstat.deleted !== expected.deleted
) {
fail(`candidate diff does not match authorized path ${expected.path}`);
}
}
const excluded = new Set(policy.changedPaths.map((entry) => entry.path));
const projection = git(candidateRoot, ["ls-tree", "-r", policy.candidateSha])
.split("\n")
.filter((line) => line && !excluded.has(line.slice(line.indexOf("\t") + 1)))
.join("\n");
const projectionDigest = sha256(`${projection}\n`);
if (projectionDigest !== policy.packageProjectionSha256) {
fail("candidate published-byte projection digest does not match the authorized policy");
}
}
function assertHistoricalAndFocusedEvidence(policy: AuthorizedBetaFocusedPolicy) {
const historical = policy.historicalFrv;
requireHistoricalExecutionPlan(policy);
requireRun({
runId: historical.runId,
attempt: historical.runAttempt,
name: "Full Release Validation",
path: historical.workflowPath,
headBranch: historical.workflowRef,
headSha: policy.historicalToolingSha,
conclusion: "failure",
});
requireRun({
runId: historical.ciRunId,
attempt: 1,
name: `CI full-release-validation-${historical.runId}-${historical.runAttempt}-ci`,
path: ".github/workflows/ci.yml",
headBranch: historical.workflowRef,
headSha: policy.historicalToolingSha,
conclusion: "failure",
});
requireJob({
jobId: historical.ciFailedJobId,
runId: historical.ciRunId,
name: "check-lint",
conclusion: "failure",
headSha: policy.historicalToolingSha,
});
requireJob({
jobId: historical.ciAggregateJobId,
runId: historical.ciRunId,
name: "openclaw/ci-gate",
conclusion: "failure",
headSha: policy.historicalToolingSha,
});
requireRun({
runId: historical.pluginRunId,
attempt: 1,
name: `Plugin Prerelease full-release-validation-${historical.runId}-${historical.runAttempt}-plugin-prerelease`,
path: ".github/workflows/plugin-prerelease.yml",
headBranch: historical.workflowRef,
headSha: policy.historicalToolingSha,
conclusion: "failure",
});
requireJob({
jobId: historical.pluginFailedJobId,
runId: historical.pluginRunId,
name: "checks-node-extensions-shard-7",
conclusion: "failure",
headSha: policy.historicalToolingSha,
});
requireJob({
jobId: historical.pluginAggregateJobId,
runId: historical.pluginRunId,
name: "plugin-prerelease-suite",
conclusion: "failure",
headSha: policy.historicalToolingSha,
});
requireRun({
runId: historical.releaseChecksRunId,
attempt: 1,
name: `OpenClaw Release Checks full-release-validation-${historical.runId}-${historical.runAttempt}-release-checks`,
path: ".github/workflows/openclaw-release-checks.yml",
headBranch: historical.workflowRef,
headSha: policy.historicalToolingSha,
});
requireJob({
jobId: historical.releaseChecksVerifierJobId,
runId: historical.releaseChecksRunId,
name: "Verify release checks",
conclusion: "success",
headSha: policy.historicalToolingSha,
});
requireRun({
runId: historical.performanceRunId,
attempt: 1,
name: `OpenClaw Performance full-release-validation-${historical.runId}-${historical.runAttempt}`,
path: ".github/workflows/openclaw-performance.yml",
headBranch: historical.workflowRef,
headSha: policy.historicalToolingSha,
conclusion: "failure",
});
requireJob({
jobId: historical.performanceFailedJobId,
runId: historical.performanceRunId,
name: "OpenClaw source performance probes",
conclusion: "failure",
headSha: policy.historicalToolingSha,
});
const focused = policy.focusedProof;
requireRun({
runId: focused.ciRunId,
attempt: 1,
name: "CI beta3-slack-proof-e347223a",
path: ".github/workflows/ci.yml",
headBranch: policy.historicalToolingRef.replace("refs/tags/", ""),
headSha: policy.historicalToolingSha,
allowInProgress: true,
});
requireJob({
jobId: focused.ciSuccessJobId,
runId: focused.ciRunId,
name: "check-lint",
conclusion: "success",
headSha: policy.historicalToolingSha,
});
requireJob({
jobId: focused.ciTargetLogJobId,
runId: focused.ciRunId,
name: "preflight",
conclusion: "success",
headSha: policy.historicalToolingSha,
});
requireJobLogTarget(focused.ciTargetLogJobId, policy.reviewedHeadSha);
requireRun({
runId: focused.pluginRunId,
attempt: 1,
name: "Plugin Prerelease beta3-slack-proof-e347223a",
path: ".github/workflows/plugin-prerelease.yml",
headBranch: policy.historicalToolingRef.replace("refs/tags/", ""),
headSha: policy.historicalToolingSha,
conclusion: "failure",
});
requireJob({
jobId: focused.pluginSuccessJobId,
runId: focused.pluginRunId,
name: "checks-node-extensions-shard-7",
conclusion: "success",
headSha: policy.historicalToolingSha,
});
requireJob({
jobId: focused.pluginTargetLogJobId,
runId: focused.pluginRunId,
name: "Build plugin prerelease plan",
conclusion: "success",
headSha: policy.historicalToolingSha,
});
requireJobLogTarget(focused.pluginTargetLogJobId, policy.reviewedHeadSha);
}
function producerIdentity(args: ParsedArgs): AuthorizedBetaFocusedProducerIdentity {
const workflowFullRef = exactString(args["producer-workflow-full-ref"], "producer workflow ref");
const workflowSha = exactString(args["producer-workflow-sha"], "producer workflow SHA");
const protectedTag = PROTECTED_TAG_PATTERN.exec(workflowFullRef);
if (
!SHA_PATTERN.test(workflowSha) ||
!protectedTag ||
protectedTag[1] !== workflowSha.slice(0, 12)
) {
fail("focused evidence producer must use a SHA-bound protected release-publish tag");
}
return {
repository: REPOSITORY,
runId: exactString(args["producer-run-id"], "producer run id"),
runAttempt: exactPositiveInteger(args["producer-run-attempt"], "producer run attempt"),
workflowPath: PRODUCER_WORKFLOW,
workflowFullRef,
workflowRef: workflowFullRef.replace("refs/tags/", ""),
workflowSha,
};
}
function assertProducer(identity: AuthorizedBetaFocusedProducerIdentity, allowInProgress: boolean) {
requireRun({
runId: identity.runId,
attempt: identity.runAttempt,
name: "Authorized Beta Focused Validation",
path: identity.workflowPath,
headBranch: identity.workflowRef,
headSha: identity.workflowSha,
allowInProgress,
});
const ref = ghJson(`repos/${REPOSITORY}/git/ref/tags/${identity.workflowRef}`);
if (!isRecord(ref.object)) {
fail("protected tooling tag object must be an object");
}
const object = ref.object;
if (object.type !== "commit" || object.sha !== identity.workflowSha) {
fail("protected focused-evidence tooling tag does not resolve to the producer SHA");
}
}
async function produceAuthorizedEligibilityPlan(
policy: AuthorizedBetaFocusedPolicy,
candidateRoot: string,
) {
const directory = mkdtempSync(join(tmpdir(), "authorized-beta-focused-tooling-"));
const toolingRoot = join(directory, "tooling");
try {
// The producer binds its execution checkout to toolingSha. Run the frozen
// producer itself so this evidence cannot substitute the current workflow.
git(candidateRoot, [
"clone",
"--quiet",
"--shared",
"--no-checkout",
candidateRoot,
toolingRoot,
]);
git(toolingRoot, ["checkout", "--quiet", "--detach", policy.historicalToolingSha]);
symlinkSync(
resolve(SCRIPT_ROOT, "..", "node_modules"),
join(toolingRoot, "node_modules"),
"dir",
);
const lockJson = execFileSync(
process.execPath,
[
"--import",
"tsx",
"scripts/release-plan-producer.mts",
"--intent",
"publish",
"--candidate-sha",
policy.candidateSha,
"--candidate-ref",
`refs/tags/${policy.releaseTag}`,
"--tooling-sha",
policy.historicalToolingSha,
"--tooling-full-ref",
policy.historicalToolingRef,
],
{
cwd: toolingRoot,
encoding: "utf8",
env: process.env,
maxBuffer: 16 * 1024 * 1024,
},
);
const { parseReleasePlanLockJson } = await import("./release-plan-contract.mjs");
return parseReleasePlanLockJson(lockJson).plan;
} finally {
rmSync(directory, { force: true, recursive: true });
}
}
async function collectInventory(
policy: AuthorizedBetaFocusedPolicy,
candidateRoot: string,
includeTrust: boolean,
) {
const plan = await produceAuthorizedEligibilityPlan(policy, candidateRoot);
const eligibilityPlanDigest = await assertAuthorizedEligibilityPlanDigest(
plan,
policy.eligibilityPlanDigest,
);
const npmNames = plan.inventory.packages
.filter((entry) => entry.targets.includes("npm"))
.map((entry) => entry.name);
const clawHubNames = plan.inventory.packages
.filter((entry) => entry.targets.includes("clawhub"))
.map((entry) => entry.name);
const inventory = {
eligibilityPlanDigest,
npmCount: npmNames.length,
npmNamesSha256: digestAuthorizedPackageNames(npmNames),
clawHubCount: clawHubNames.length,
clawHubNamesSha256: digestAuthorizedPackageNames(clawHubNames),
trustedPublisherCount: policy.inventory.trustedPublisherCount,
trustedPublisherNamesSha256: policy.inventory.trustedPublisherNamesSha256,
bootstrapCount: policy.inventory.bootstrapCount,
bootstrapNamesSha256: policy.inventory.bootstrapNamesSha256,
missingTrustedPublisherCount: policy.inventory.missingTrustedPublisherCount,
};
if (includeTrust) {
const { collectPluginClawHubReleasePlan } = await import("./lib/plugin-clawhub-release.ts");
const trustPlan = await collectPluginClawHubReleasePlan({
rootDir: candidateRoot,
selectionMode: "all-publishable",
});
const trusted = trustPlan.candidates.map((entry) => entry.packageName);
const bootstrap = [...trustPlan.bootstrapCandidates, ...trustPlan.missingTrustedPublisher].map(
(entry) => entry.packageName,
);
inventory.trustedPublisherCount = trusted.length;
inventory.trustedPublisherNamesSha256 = digestAuthorizedPackageNames(trusted);
inventory.bootstrapCount = bootstrap.length;
inventory.bootstrapNamesSha256 = digestAuthorizedPackageNames(bootstrap);
inventory.missingTrustedPublisherCount = trustPlan.missingTrustedPublisher.length;
}
for (const [key, expected] of Object.entries(policy.inventory)) {
if (inventory[key as keyof typeof inventory] !== expected) {
fail(
`authorized inventory ${key} mismatch: expected ${expected}, got ${inventory[key as keyof typeof inventory]}`,
);
}
}
return inventory;
}
export function validateAuthorizedBetaFocusedArtifactShape(
evidence: AuthorizedBetaFocusedEvidence,
policy: AuthorizedBetaFocusedPolicy,
producer: AuthorizedBetaFocusedProducerIdentity,
expectedInventory: AuthorizedBetaFocusedEvidence["inventory"],
) {
if (
evidence.schema !== "openclaw.authorized-beta-focused-evidence.v1" ||
evidence.mode !== policy.mode ||
evidence.policySha256 !== digestAuthorizedBetaFocusedPolicy(policy) ||
evidence.releaseTag !== policy.releaseTag ||
stableJson(evidence.producer) !== stableJson(producer)
) {
fail("focused evidence artifact identity does not match the fixed policy");
}
if (
evidence.candidate.sha !== policy.candidateSha ||
evidence.candidate.parentSha !== policy.baseCandidateSha ||
evidence.candidate.treeSha !== policy.candidateTreeSha ||
evidence.candidate.packageProjectionSha256 !== policy.packageProjectionSha256 ||
stableJson(evidence.candidate.changedPaths) !== stableJson(policy.changedPaths)
) {
fail("focused evidence candidate projection does not match the fixed policy");
}
if (stableJson(evidence.inventory) !== stableJson(expectedInventory)) {
fail("focused evidence inventory does not match the repository-derived release plan");
}
}
type ParsedArgs = Record<string, string>;
function parseArgs(argv: string[]) {
const [command, ...rest] = argv;
if (command !== "create" && command !== "verify") {
fail("usage: validate-authorized-beta-focused-evidence.mts <create|verify> [options]");
}
const args: ParsedArgs = {};
for (let index = 0; index < rest.length; index += 2) {
const key = rest[index];
const value = rest[index + 1];
if (!key?.startsWith("--") || !value || value.startsWith("--")) {
fail(`invalid argument near ${key ?? "<missing>"}`);
}
args[key.slice(2)] = value;
}
return { command, args } as const;
}
async function main() {
const { command, args } = parseArgs(process.argv.slice(2));
const policy = readAuthorizedBetaFocusedPolicy();
const candidateRoot = resolve(exactString(args["candidate-root"], "candidate root"));
const artifactPath = resolve(exactString(args.artifact ?? args.output, "artifact path"));
const producer = producerIdentity(args);
assertAuthorizedBetaFocusedCandidate(policy, candidateRoot);
assertProducer(producer, command === "create");
assertHistoricalAndFocusedEvidence(policy);
if (command === "create") {
const inventory = await collectInventory(policy, candidateRoot, true);
const evidence: AuthorizedBetaFocusedEvidence = {
schema: "openclaw.authorized-beta-focused-evidence.v1",
mode: "authorized-beta-focused-v1",
policySha256: digestAuthorizedBetaFocusedPolicy(policy),
releaseTag: policy.releaseTag,
candidate: {
sha: policy.candidateSha,
parentSha: policy.baseCandidateSha,
treeSha: policy.candidateTreeSha,
packageProjectionSha256: policy.packageProjectionSha256,
changedPaths: policy.changedPaths,
},
producer,
historical: {
frvRunId: policy.historicalFrv.runId,
frvRunAttempt: policy.historicalFrv.runAttempt,
releaseChecksRunId: policy.historicalFrv.releaseChecksRunId,
performanceRunId: policy.historicalFrv.performanceRunId,
},
focused: {
ciRunId: policy.focusedProof.ciRunId,
ciJobId: policy.focusedProof.ciSuccessJobId,
pluginRunId: policy.focusedProof.pluginRunId,
pluginJobId: policy.focusedProof.pluginSuccessJobId,
reviewedHeadSha: policy.reviewedHeadSha,
},
inventory,
};
writeFileSync(artifactPath, `${stableJson(evidence)}\n`, { flag: "wx" });
console.log(`authorized beta focused evidence written: ${artifactPath}`);
return;
}
const evidence = JSON.parse(readFileSync(artifactPath, "utf8")) as AuthorizedBetaFocusedEvidence;
const inventory = {
eligibilityPlanDigest: policy.eligibilityPlanDigest,
...policy.inventory,
};
validateAuthorizedBetaFocusedArtifactShape(evidence, policy, producer, inventory);
console.log(
`authorized beta focused evidence verified for ${policy.releaseTag} at ${policy.candidateSha}`,
);
}
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
main().catch((error: unknown) => {
console.error(error instanceof Error ? error.message : "unknown error");
console.error("[authorized-beta-focused-evidence] FAILED (exit 1)");
process.exitCode = 1;
});
}