fix: 校验 consumer 级发布计划信封

This commit is contained in:
AgentRun Codex
2026-07-22 16:46:20 +02:00
parent d862eb9200
commit feedfabd98
4 changed files with 86 additions and 28 deletions
+1
View File
@@ -10,6 +10,7 @@ const envIdentityExcludedPaths = new Set([
"scripts/ci-plan.mjs",
"scripts/ci-plan.test.mjs",
"scripts/ci/verify-reviewed-plan.mjs",
"scripts/ci/verify-reviewed-plan.test.mjs",
]);
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
+1
View File
@@ -21,6 +21,7 @@ test("plan reuses a present env image without expanding build scope", async () =
await writeFile(join(root, "scripts", "ci-plan.mjs"), "planner-only\n");
await writeFile(join(root, "scripts", "ci-plan.test.mjs"), "planner-test-only\n");
await writeFile(join(root, "scripts", "ci", "verify-reviewed-plan.mjs"), "admission-only\n");
await writeFile(join(root, "scripts", "ci", "verify-reviewed-plan.test.mjs"), "admission-test-only\n");
assert.equal(calculateEnvIdentity({
root,
envIdentityFiles: ["src", "scripts"],
+37 -28
View File
@@ -1,34 +1,43 @@
#!/usr/bin/env node
import { readFile } from "node:fs/promises";
import { pathToFileURL } from "node:url";
const [actualPath, envelopePath] = process.argv.slice(2);
if (!actualPath || !envelopePath) throw new Error("usage: verify-reviewed-plan.mjs <actual-plan.json> <reviewed-plan-envelope>");
const actual = JSON.parse(await readFile(actualPath, "utf8"));
const envelope = (await readFile(envelopePath, "utf8")).trim();
const prefix = "unidesk-release-plan-v1.";
if (!envelope.startsWith(prefix)) throw new Error("reviewed plan envelope is missing or unsupported");
const expected = JSON.parse(Buffer.from(envelope.slice(prefix.length), "base64url").toString("utf8"));
const actualScope = scope(actual);
const expectedScope = scope(expected);
const additions = Object.fromEntries(Object.keys(actualScope).map((key) => [key, actualScope[key].filter((item) => !expectedScope[key].includes(item))]));
const result = {
event: "reviewed-plan-admission",
ok: expected.version === "v1"
&& expected.planIdentity === actual.planIdentity?.value
&& expected.target === actual.planIdentity?.inputs?.target
&& expected.consumer === actual.planIdentity?.inputs?.consumer
&& expected.sourceCommit === actual.sourceCommitId
&& expected.baseCommit === actual.baseCommitId
&& Object.values(additions).every((items) => items.length === 0),
expectedIdentity: expected.planIdentity ?? null,
actualIdentity: actual.planIdentity?.value ?? null,
expectedScope,
actualScope,
additions,
valuesPrinted: false,
};
process.stdout.write(`${JSON.stringify(result)}\n`);
if (!result.ok) process.exit(42);
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
const [actualPath, envelopePath] = process.argv.slice(2);
if (!actualPath || !envelopePath) throw new Error("usage: verify-reviewed-plan.mjs <actual-plan.json> <reviewed-plan-envelope>");
const actual = JSON.parse(await readFile(actualPath, "utf8"));
const envelope = (await readFile(envelopePath, "utf8")).trim();
const result = verifyReviewedPlan(actual, envelope);
process.stdout.write(`${JSON.stringify(result)}\n`);
if (!result.ok) process.exit(42);
}
export function verifyReviewedPlan(actual, envelope) {
const consumer = actual?.planIdentity?.inputs?.consumer;
if (typeof consumer !== "string" || consumer.length === 0) throw new Error("actual plan consumer is missing");
const prefix = `unidesk-release-plan-v1.${consumer}.`;
if (!envelope.startsWith(prefix)) throw new Error("reviewed plan envelope is missing, unsupported, or belongs to another consumer");
const expected = JSON.parse(Buffer.from(envelope.slice(prefix.length), "base64url").toString("utf8"));
const actualScope = scope(actual);
const expectedScope = scope(expected);
const additions = Object.fromEntries(Object.keys(actualScope).map((key) => [key, actualScope[key].filter((item) => !expectedScope[key].includes(item))]));
return {
event: "reviewed-plan-admission",
ok: expected.version === "v1"
&& expected.planIdentity === actual.planIdentity?.value
&& expected.target === actual.planIdentity?.inputs?.target
&& expected.consumer === consumer
&& expected.sourceCommit === actual.sourceCommitId
&& expected.baseCommit === actual.baseCommitId
&& Object.values(additions).every((items) => items.length === 0),
expectedIdentity: expected.planIdentity ?? null,
actualIdentity: actual.planIdentity?.value ?? null,
expectedScope,
actualScope,
additions,
valuesPrinted: false,
};
}
function scope(value) {
const sorted = (items) => [...new Set(Array.isArray(items) ? items.filter((item) => typeof item === "string" && item) : [])].sort();
+47
View File
@@ -0,0 +1,47 @@
import assert from "node:assert/strict";
import test from "node:test";
import { verifyReviewedPlan } from "./verify-reviewed-plan.mjs";
const consumer = "agentrun-nc01-v02";
const actual = {
sourceCommitId: "a".repeat(40),
baseCommitId: "b".repeat(40),
buildServices: [],
rolloutServices: ["agentrun-mgr"],
affectedServices: ["agentrun-mgr"],
planIdentity: {
value: `sha256:${"c".repeat(64)}`,
inputs: { target: "NC01", consumer },
},
};
function envelope(overrides = {}, envelopeConsumer = consumer) {
const reviewed = {
version: "v1",
planIdentity: actual.planIdentity.value,
target: "NC01",
consumer,
sourceCommit: actual.sourceCommitId,
baseCommit: actual.baseCommitId,
buildServices: [],
rolloutServices: ["agentrun-mgr"],
affectedServices: ["agentrun-mgr"],
...overrides,
};
return `unidesk-release-plan-v1.${envelopeConsumer}.${Buffer.from(JSON.stringify(reviewed)).toString("base64url")}`;
}
test("accepts the consumer-qualified reviewed plan envelope", () => {
assert.equal(verifyReviewedPlan(actual, envelope()).ok, true);
});
test("rejects an envelope addressed to another consumer", () => {
assert.throws(() => verifyReviewedPlan(actual, envelope({}, "agentrun-nc01-release")), /another consumer/u);
});
test("rejects actual scope that expands beyond the reviewed plan", () => {
const expanded = { ...actual, buildServices: ["agentrun-mgr"] };
const result = verifyReviewedPlan(expanded, envelope());
assert.equal(result.ok, false);
assert.deepEqual(result.additions.buildServices, ["agentrun-mgr"]);
});