From 5b2c718b57e850bbf7d05eed20cea7dbfeef1ade Mon Sep 17 00:00:00 2001 From: Wolfgang Schoenberger <221313372+wolfiesch@users.noreply.github.com> Date: Thu, 23 Jul 2026 20:49:03 -0700 Subject: [PATCH] fix(release): separate publication control from source --- .github/workflows/release.yml | 12 ++++++++-- scripts/check-release-consistency.mjs | 2 +- scripts/check-release-consistency.test.mjs | 27 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 64e6f7fc..9266c669 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -379,15 +379,23 @@ jobs: permissions: contents: write steps: - - name: Check out verified release source + - name: Check out trusted publication-control source + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + ref: ${{ github.sha }} + persist-credentials: false + + - name: Check out verified release content uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ needs.verify.outputs.source_sha }} + path: .release-source fetch-depth: 0 persist-credentials: false - name: Confirm the release tag still resolves to the verified source shell: bash + working-directory: .release-source env: SOURCE_SHA: ${{ needs.verify.outputs.source_sha }} run: | @@ -444,7 +452,7 @@ jobs: tag_name: ${{ env.RELEASE_TAG }} generate_release_notes: true fail_on_unmatched_files: true - body_path: docs/CURRENT_RELEASE_NOTES.md + body_path: .release-source/docs/CURRENT_RELEASE_NOTES.md files: | artifacts/T4-Code-*.apk artifacts/T4-Code-*.deb diff --git a/scripts/check-release-consistency.mjs b/scripts/check-release-consistency.mjs index 7d29d45f..45c4f844 100644 --- a/scripts/check-release-consistency.mjs +++ b/scripts/check-release-consistency.mjs @@ -1151,7 +1151,7 @@ export function collectReleaseConsistencyErrors(files, releaseTag) { ); requireText( releaseWorkflow, - "body_path: docs/CURRENT_RELEASE_NOTES.md", + "body_path: .release-source/docs/CURRENT_RELEASE_NOTES.md", ".github/workflows/release.yml", errors, ); diff --git a/scripts/check-release-consistency.test.mjs b/scripts/check-release-consistency.test.mjs index 471d87f1..c8469adf 100644 --- a/scripts/check-release-consistency.test.mjs +++ b/scripts/check-release-consistency.test.mjs @@ -458,6 +458,33 @@ test("historical repair keeps trusted verification code separate from immutable }); }); +test("historical repair keeps trusted publication control separate from release content", () => { + const publishJob = requiredWorkflowJob(files.get(".github/workflows/release.yml"), "publish"); + const controlCheckout = requiredNamedStep( + publishJob, + "Check out trusted publication-control source", + ); + const contentCheckout = requiredNamedStep(publishJob, "Check out verified release content"); + const tagStep = requiredNamedStep( + publishJob, + "Confirm the release tag still resolves to the verified source", + ); + const prepareStep = requiredNamedStep( + publishJob, + "Preserve an exact release or prepare an incomplete release for repair", + ); + const publishStep = requiredNamedStep(publishJob, "Publish GitHub release"); + const verifyStep = requiredNamedStep(publishJob, "Verify the exact remote release bundle"); + + assert.equal(controlCheckout.with.ref, "${{ github.sha }}"); + assert.equal(contentCheckout.with.ref, "${{ needs.verify.outputs.source_sha }}"); + assert.equal(contentCheckout.with.path, ".release-source"); + assert.equal(tagStep["working-directory"], ".release-source"); + assert.match(prepareStep.run, /^node scripts\/reconcile-release-assets\.mjs/u); + assert.equal(publishStep.with.body_path, ".release-source/docs/CURRENT_RELEASE_NOTES.md"); + assert.match(verifyStep.run, /^node scripts\/reconcile-release-assets\.mjs/u); +}); + test("rejects published app-wire version drift until release surfaces agree", () => { const drifted = changedRuntime("publishedAppWire", (record) => { record.version = "0.5.1";