From 40d245fe45ce0d4ea2f2d2c36c114ab97648cebd Mon Sep 17 00:00:00 2001 From: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:17:31 -0400 Subject: [PATCH] ci(release): gate signing behind release preflight Prevents SignPath requests until all blocking release gates pass. --- .github/workflows/release-cut.yml | 24 +++++++++++++++++++ .../release-cut-token-permissions.test.mjs | 1 + .../skill-sharing-release-workflow.test.mjs | 21 ++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/.github/workflows/release-cut.yml b/.github/workflows/release-cut.yml index 01cc16c6bda..71f9e8ca03f 100644 --- a/.github/workflows/release-cut.yml +++ b/.github/workflows/release-cut.yml @@ -1122,10 +1122,33 @@ jobs: retention-days: 7 if-no-files-found: ignore + # Why: artifact jobs submit Windows binaries to SignPath. Keep every + # quota-consuming build behind all blocking release gates so a late test + # failure cannot create signing requests that can never be published. + release-preflight: + needs: + - cut + - terminal-rendering-golden + - skill-sharing-release-gate + - skill-sharing-linux-floor-release-gate + if: >- + always() && + needs.cut.outputs.should_release == 'true' && + needs.terminal-rendering-golden.result == 'success' && + needs.skill-sharing-release-gate.result == 'success' && + needs.skill-sharing-linux-floor-release-gate.result == 'success' + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Confirm blocking release gates passed + run: echo "All blocking release gates passed; artifact builds may start." + build: needs: - cut - create-release + - release-preflight if: needs.cut.outputs.should_release == 'true' strategy: fail-fast: false @@ -2026,6 +2049,7 @@ jobs: needs: - cut - create-release + - release-preflight if: needs.cut.outputs.should_release == 'true' # Why: SignPath requires every job in this signing workflow to be # GitHub-hosted. The actual mac build runs in release-mac-build.yml so diff --git a/config/scripts/release-cut-token-permissions.test.mjs b/config/scripts/release-cut-token-permissions.test.mjs index f18b2b26eba..f2f544a8f27 100644 --- a/config/scripts/release-cut-token-permissions.test.mjs +++ b/config/scripts/release-cut-token-permissions.test.mjs @@ -31,6 +31,7 @@ const EXPECTED_MATRIX = { }, [`${RELEASE_WORKFLOW}#post-release-e2e`]: { actions: 'write' }, [`${RELEASE_WORKFLOW}#publish-release`]: { contents: 'write' }, + [`${RELEASE_WORKFLOW}#release-preflight`]: { contents: 'read' }, [`${RELEASE_WORKFLOW}#skill-sharing-linux-floor-release-gate`]: { contents: 'read' }, [`${RELEASE_WORKFLOW}#skill-sharing-release-gate`]: { contents: 'read' }, [`${RELEASE_WORKFLOW}#terminal-rendering-golden`]: { contents: 'read' }, diff --git a/config/scripts/skill-sharing-release-workflow.test.mjs b/config/scripts/skill-sharing-release-workflow.test.mjs index b6611a1aa18..2978b058305 100644 --- a/config/scripts/skill-sharing-release-workflow.test.mjs +++ b/config/scripts/skill-sharing-release-workflow.test.mjs @@ -10,6 +10,27 @@ function stepNamed(job, name) { } describe('skill-sharing release workflow', () => { + it('keeps artifact builds behind every blocking release gate', () => { + const preflight = workflow.jobs['release-preflight'] + const build = workflow.jobs.build + const macBuild = workflow.jobs['build-mac'] + + expect(preflight.needs).toEqual([ + 'cut', + 'terminal-rendering-golden', + 'skill-sharing-release-gate', + 'skill-sharing-linux-floor-release-gate' + ]) + expect(preflight.if).toContain('always()') + expect(preflight.if).toContain("needs.terminal-rendering-golden.result == 'success'") + expect(preflight.if).toContain("needs.skill-sharing-release-gate.result == 'success'") + expect(preflight.if).toContain( + "needs.skill-sharing-linux-floor-release-gate.result == 'success'" + ) + expect(build.needs).toContain('release-preflight') + expect(macBuild.needs).toContain('release-preflight') + }) + it('blocks publication on native Windows, macOS, and the Linux floor', () => { const platform = workflow.jobs['skill-sharing-release-gate'] const linux = workflow.jobs['skill-sharing-linux-floor-release-gate']