fix(release): reuse validation evidence after tooling updates (#130850)

* fix(release): trust ancestor validation evidence

* fix(release): read candidate auth schema
This commit is contained in:
Vincent Koc
2026-08-27 17:32:58 +08:00
committed by GitHub
parent 1cbcf141ed
commit 1c80cf86cf
7 changed files with 182 additions and 32 deletions
@@ -17,28 +17,72 @@ function makeStateDir(): string {
function writeSharedDatabase(
stateDir: string,
options: { asView?: boolean; storeJson?: string } = {},
options: {
asView?: boolean;
legacyStoreJson?: string;
schemaVersion?: 12 | 13;
storeJson?: string;
} = {},
): string {
const dbPath = path.join(stateDir, "state", "openclaw.sqlite");
mkdirSync(path.dirname(dbPath), { recursive: true });
const db = new DatabaseSync(dbPath);
try {
const schemaVersion = options.schemaVersion ?? 13;
db.exec(`PRAGMA user_version = ${schemaVersion};`);
const table = schemaVersion >= 13 ? "config_machine_state" : "auth_profile_stores";
if (options.asView) {
db.exec(`
CREATE VIEW config_machine_state AS
SELECT 'authProfiles.store' AS state_key, '{}' AS value_json, 1 AS updated_at_ms;
`);
if (table === "config_machine_state") {
db.exec(`
CREATE VIEW config_machine_state AS
SELECT 'authProfiles.store' AS state_key, '{}' AS value_json, 1 AS updated_at_ms;
`);
} else {
db.exec(`
CREATE VIEW auth_profile_stores AS
SELECT 'shared' AS store_key, '{}' AS store_json, 1 AS updated_at;
`);
}
} else {
if (table === "config_machine_state") {
db.exec(`
CREATE TABLE config_machine_state (
state_key TEXT NOT NULL PRIMARY KEY,
value_json TEXT NOT NULL,
updated_at_ms INTEGER NOT NULL
) STRICT;
`);
db.prepare("INSERT INTO config_machine_state VALUES (?, ?, ?)").run(
"authProfiles.store",
options.storeJson ?? "{}",
Date.now(),
);
} else {
db.exec(`
CREATE TABLE auth_profile_stores (
store_key TEXT NOT NULL PRIMARY KEY,
store_json TEXT NOT NULL,
updated_at INTEGER NOT NULL
) STRICT;
`);
db.prepare("INSERT INTO auth_profile_stores VALUES (?, ?, ?)").run(
"shared",
options.storeJson ?? "{}",
Date.now(),
);
}
}
if (options.legacyStoreJson !== undefined) {
db.exec(`
CREATE TABLE config_machine_state (
state_key TEXT NOT NULL PRIMARY KEY,
value_json TEXT NOT NULL,
updated_at_ms INTEGER NOT NULL
CREATE TABLE auth_profile_stores (
store_key TEXT NOT NULL PRIMARY KEY,
store_json TEXT NOT NULL,
updated_at INTEGER NOT NULL
) STRICT;
`);
db.prepare("INSERT INTO config_machine_state VALUES (?, ?, ?)").run(
"authProfiles.store",
options.storeJson ?? "{}",
db.prepare("INSERT INTO auth_profile_stores VALUES (?, ?, ?)").run(
"shared",
options.legacyStoreJson,
Date.now(),
);
}
@@ -101,6 +145,26 @@ describe("auth profile store E2E assertions", () => {
expect(readSharedAuthProfileStoreText(stateDir)).toBe('{"version":1}');
});
it("reads the release-owned shared row before schema v13", () => {
const stateDir = makeStateDir();
writeSharedDatabase(stateDir, {
schemaVersion: 12,
storeJson: '{"version":1,"schema":12}',
});
expect(readSharedAuthProfileStoreText(stateDir)).toBe('{"version":1,"schema":12}');
});
it("does not accept a retired shared row for schema v13", () => {
const stateDir = makeStateDir();
writeSharedDatabase(stateDir, {
legacyStoreJson: '{"version":1,"schema":12}',
storeJson: "",
});
expect(readSharedAuthProfileStoreText(stateDir)).toBe("");
});
it("returns empty when the shared database or table is absent", () => {
const stateDir = makeStateDir();
@@ -57,6 +57,7 @@ function writeAuthProfileStoreSqlite(stateDir: string) {
const db = new DatabaseSync(databasePath);
try {
db.exec(`
PRAGMA user_version = 13;
CREATE TABLE IF NOT EXISTS config_machine_state (
state_key TEXT NOT NULL PRIMARY KEY,
value_json TEXT NOT NULL,
@@ -43,6 +43,7 @@ function writeSharedAuthProfileStoreSqlite(home: string, store: unknown): void {
const db = new DatabaseSync(path.join(stateDir, "openclaw.sqlite"));
try {
db.exec(`
PRAGMA user_version = 13;
CREATE TABLE IF NOT EXISTS config_machine_state (
state_key TEXT NOT NULL PRIMARY KEY,
value_json TEXT NOT NULL,
+64 -12
View File
@@ -1376,7 +1376,55 @@ describe("release CI summary child correlation", () => {
});
});
it("rejects protected-tag evidence from a same-name branch or older ancestor", () => {
it("accepts protected-tag evidence from an older trusted tooling ancestor", () => {
const trustedWorkflowSha = "7".repeat(40);
const trustedWorkflowRef = `release-publish/${trustedWorkflowSha.slice(0, 12)}-123`;
const olderWorkflowSha = "6".repeat(40);
const olderWorkflowRef = `release-ci/${olderWorkflowSha.slice(0, 12)}-1783705000000`;
const olderFixture = trustedMainPackageFixture({
manifestVersion: 3,
targetSha: "8".repeat(40),
workflowFullRef: `refs/heads/${olderWorkflowRef}`,
workflowRef: olderWorkflowRef,
workflowSha: olderWorkflowSha,
});
olderFixture.manifest.targetRef = olderFixture.targetSha;
olderFixture.client.getRef = (fullRef: string) => ({
object: { sha: trustedWorkflowSha },
ref: fullRef,
});
olderFixture.client.compareCommitLineage = (base: string, head: string) => {
expect(base).toBe(olderWorkflowSha);
expect(head).toBe(trustedWorkflowSha);
return {
merge_base_commit: { sha: olderWorkflowSha },
status: "ahead",
};
};
expect(
validateReleaseRunEvidence(
{
repository: "openclaw/openclaw",
runId: olderFixture.runId,
trustedWorkflowFullRef: `refs/tags/${trustedWorkflowRef}`,
trustedWorkflowRef,
trustedWorkflowSha,
verifierSourceContent: readFileSync(SCRIPT),
verifierSourceSha: "c".repeat(40),
},
olderFixture.client,
),
).toMatchObject({
root: {
workflowRef: olderWorkflowRef,
workflowRefProof: "manifest-v3-protected-tag-tooling-lineage",
workflowSha: olderWorkflowSha,
},
});
});
it("rejects protected-tag evidence from a same-name branch or unrelated producer", () => {
const trustedWorkflowSha = "7".repeat(40);
const trustedWorkflowRef = `release-publish/${trustedWorkflowSha.slice(0, 12)}-123`;
const validFixture = trustedMainPackageFixture({
@@ -1399,34 +1447,38 @@ describe("release CI summary child correlation", () => {
),
).toThrow("must be a protected tag");
const olderWorkflowSha = "6".repeat(40);
const olderWorkflowRef = `release-ci/${olderWorkflowSha.slice(0, 12)}-1783705000000`;
const olderFixture = trustedMainPackageFixture({
const unrelatedWorkflowSha = "6".repeat(40);
const unrelatedWorkflowRef = `release-ci/${unrelatedWorkflowSha.slice(0, 12)}-1783705000000`;
const unrelatedFixture = trustedMainPackageFixture({
manifestVersion: 3,
targetSha: "8".repeat(40),
workflowFullRef: `refs/heads/${olderWorkflowRef}`,
workflowRef: olderWorkflowRef,
workflowSha: olderWorkflowSha,
workflowFullRef: `refs/heads/${unrelatedWorkflowRef}`,
workflowRef: unrelatedWorkflowRef,
workflowSha: unrelatedWorkflowSha,
});
olderFixture.manifest.targetRef = olderFixture.targetSha;
olderFixture.client.getRef = (fullRef: string) => ({
unrelatedFixture.manifest.targetRef = unrelatedFixture.targetSha;
unrelatedFixture.client.getRef = (fullRef: string) => ({
object: { sha: trustedWorkflowSha },
ref: fullRef,
});
unrelatedFixture.client.compareCommitLineage = () => ({
merge_base_commit: { sha: "5".repeat(40) },
status: "diverged",
});
expect(() =>
validateReleaseRunEvidence(
{
repository: "openclaw/openclaw",
runId: olderFixture.runId,
runId: unrelatedFixture.runId,
trustedWorkflowFullRef: `refs/tags/${trustedWorkflowRef}`,
trustedWorkflowRef,
trustedWorkflowSha,
verifierSourceContent: readFileSync(SCRIPT),
verifierSourceSha: "c".repeat(40),
},
olderFixture.client,
unrelatedFixture.client,
),
).toThrow("does not match trusted tooling");
).toThrow("not on the trusted tooling lineage");
const sameNameFixture = trustedMainPackageFixture({
manifestVersion: 3,
@@ -38,6 +38,7 @@ function writeAuthProfileStoreSqlite(stateDir: string, store: unknown) {
const db = new DatabaseSync(databasePath);
try {
db.exec(`
PRAGMA user_version = 13;
CREATE TABLE IF NOT EXISTS config_machine_state (
state_key TEXT NOT NULL PRIMARY KEY,
value_json TEXT NOT NULL,