From 7d192c9a859d22508ff0042152c152f7fddee08d Mon Sep 17 00:00:00 2001 From: Nathan Vale Date: Sun, 9 Aug 2026 13:23:44 +1000 Subject: [PATCH 1/2] fix(release): preserve historical proof policy --- .github/workflows/release.yml | 10 ++++++++-- scripts/release-validate.test.ts | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8399717..615a2fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -359,7 +359,7 @@ jobs: compatibility: name: Release compatibility (${{ matrix.target }}) - if: needs.resolve.outputs.mode == 'publish' || needs.resolve.outputs.mode == 'repair' + if: needs.resolve.outputs.mode == 'publish' needs: - resolve - candidate @@ -406,7 +406,13 @@ jobs: package: name: Prove release candidate - if: needs.resolve.outputs.mode == 'publish' || needs.resolve.outputs.mode == 'repair' + if: >- + always() && + needs.resolve.result == 'success' && + needs.candidate.result == 'success' && + (needs.resolve.outputs.mode == 'publish' || needs.resolve.outputs.mode == 'repair') && + (needs.compatibility.result == 'success' || + (needs.resolve.outputs.mode == 'repair' && needs.compatibility.result == 'skipped')) needs: - resolve - candidate diff --git a/scripts/release-validate.test.ts b/scripts/release-validate.test.ts index 24f8454..e432d2f 100644 --- a/scripts/release-validate.test.ts +++ b/scripts/release-validate.test.ts @@ -337,8 +337,20 @@ test("release workflow is pinned and publishes proven assets after validation", workflow.indexOf("\n candidate:\n"), workflow.indexOf("\n compatibility:\n"), ) + const compatibilityJob = workflow.slice( + workflow.indexOf("\n compatibility:\n"), + workflow.indexOf("\n package:\n"), + ) + const packageJob = workflow.slice( + workflow.indexOf("\n package:\n"), + workflow.indexOf("\n release:\n"), + ) expect(candidateJob).toContain(" permissions:\n actions: read\n contents: read\n") expect(candidateJob).toContain("persist-credentials: false") + expect(compatibilityJob).toContain("if: needs.resolve.outputs.mode == 'publish'") + expect(packageJob).toContain("always()") + expect(packageJob).toContain("needs.compatibility.result == 'skipped'") + expect(packageJob).toContain("needs.resolve.outputs.mode == 'repair'") expect(workflow.match(/--dir "\$RUNNER_TEMP\/platform-candidate"/g)).toHaveLength(2) expect(maintainJob).toContain("persist-credentials: false") expect(maintainJob).toContain("group: release-maintenance") From edcddf6323ea80ec1240719348537e6fd0acecdf Mon Sep 17 00:00:00 2001 From: Nathan Vale Date: Sun, 9 Aug 2026 13:46:56 +1000 Subject: [PATCH 2/2] test(release): bind historical proof gate --- scripts/release-validate.test.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/scripts/release-validate.test.ts b/scripts/release-validate.test.ts index e432d2f..c1ca255 100644 --- a/scripts/release-validate.test.ts +++ b/scripts/release-validate.test.ts @@ -257,6 +257,10 @@ test("release validation rejects a duplicate changelog heading", () => { test("release workflow is pinned and publishes proven assets after validation", () => { const workflow = readFileSync(join(root, ".github", "workflows", "release.yml"), "utf8") + const parsedWorkflow = Bun.YAML.parse(workflow) as { + jobs: Record + } + const normalizePredicate = (predicate: string | undefined) => predicate?.replace(/\s+/g, " ") const finalReleaseJob = workflow.slice(workflow.indexOf(" release:\n")) const compareStepStart = finalReleaseJob.indexOf(" - name: Compare release assets before mutation\n") const uploadStepStart = finalReleaseJob.indexOf(" - name: Add or replace admitted release assets\n") @@ -337,20 +341,14 @@ test("release workflow is pinned and publishes proven assets after validation", workflow.indexOf("\n candidate:\n"), workflow.indexOf("\n compatibility:\n"), ) - const compatibilityJob = workflow.slice( - workflow.indexOf("\n compatibility:\n"), - workflow.indexOf("\n package:\n"), - ) - const packageJob = workflow.slice( - workflow.indexOf("\n package:\n"), - workflow.indexOf("\n release:\n"), - ) expect(candidateJob).toContain(" permissions:\n actions: read\n contents: read\n") expect(candidateJob).toContain("persist-credentials: false") - expect(compatibilityJob).toContain("if: needs.resolve.outputs.mode == 'publish'") - expect(packageJob).toContain("always()") - expect(packageJob).toContain("needs.compatibility.result == 'skipped'") - expect(packageJob).toContain("needs.resolve.outputs.mode == 'repair'") + expect(normalizePredicate(parsedWorkflow.jobs.compatibility.if)).toBe( + "needs.resolve.outputs.mode == 'publish'", + ) + expect(normalizePredicate(parsedWorkflow.jobs.package.if)).toBe( + "always() && needs.resolve.result == 'success' && needs.candidate.result == 'success' && (needs.resolve.outputs.mode == 'publish' || needs.resolve.outputs.mode == 'repair') && (needs.compatibility.result == 'success' || (needs.resolve.outputs.mode == 'repair' && needs.compatibility.result == 'skipped'))", + ) expect(workflow.match(/--dir "\$RUNNER_TEMP\/platform-candidate"/g)).toHaveLength(2) expect(maintainJob).toContain("persist-credentials: false") expect(maintainJob).toContain("group: release-maintenance")