77# on a bit-identical rebuild of all eight (a non-reproducible image fails the job
88# before anything is published), generates a CycloneDX SBOM, hashes everything
99# into SHA256SUMS, signs that with keyless cosign (sigstore/Fulcio via OIDC — no
10- # private key), and publishes the GitHub Release.
10+ # private key), and creates the GitHub Release as a DRAFT .
1111#
12- # `provenance` then emits SLSA build provenance for every released artifact via
13- # the slsa-github-generator reusable workflow (also keyless): a consumer can
14- # verify which workflow, at which commit, on which runner built each .uf2.
12+ # `provenance` emits SLSA build provenance for every released artifact via the
13+ # slsa-github-generator reusable workflow (also keyless) and uploads it to the
14+ # draft: a consumer can verify which workflow, at which commit, on which runner
15+ # built each .uf2.
16+ #
17+ # `publish` un-drafts the release once the provenance is attached — a release
18+ # becomes immutable on publish, so the provenance must land while it's a draft.
1519#
1620# The .uf2 images are UNSIGNED for secure boot — cosign + the SLSA provenance
1721# attest the BUILD, not the boot seal. On a secure-boot device, seal an image
@@ -159,14 +163,15 @@ jobs:
159163 } >> release-notes.md
160164 cat release-notes.md
161165
162- - name : create the GitHub Release
166+ - name : create the GitHub Release (draft — published after provenance)
163167 env :
164168 GH_TOKEN : ${{ github.token }}
165169 run : |
166170 tag="${{ steps.tag.outputs.tag }}"
167171 gh release create "$tag" \
168172 --title "RS-Key $tag" \
169173 --notes-file release-notes.md \
174+ --draft \
170175 dist/*
171176
172177 # SLSA build provenance for every released artifact, generated + signed in the
@@ -190,3 +195,21 @@ jobs:
190195 upload-assets : true
191196 upload-tag-name : " ${{ needs.build.outputs.tag }}"
192197 provenance-name : " rs-key-${{ needs.build.outputs.tag }}.intoto.jsonl"
198+
199+ # Publish (un-draft) the release only after the provenance asset is attached.
200+ # A release becomes immutable on publish, so the draft must carry everything —
201+ # artifacts (build) and provenance (provenance) — before this flips it live.
202+ publish :
203+ needs : [build, provenance]
204+ runs-on : ubuntu-latest
205+ timeout-minutes : 10
206+ permissions :
207+ contents : write # publish (un-draft) the release
208+ steps :
209+ - name : publish the draft release
210+ env :
211+ GH_TOKEN : ${{ github.token }}
212+ run : |
213+ gh release edit "${{ needs.build.outputs.tag }}" \
214+ --repo "${{ github.repository }}" \
215+ --draft=false
0 commit comments