Skip to content

Attest a published release that missed its attestation - #514

Merged
robzolkos merged 3 commits into
mainfrom
attest-published-release
Sep 28, 2026
Merged

robzolkos merged 3 commits into
mainfrom
attest-published-release

Conversation

@robzolkos

@robzolkos robzolkos commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

v1.7.0 published its assets, but the release run stopped at the size report before Attest build provenance, so the release has no GitHub attestations. mise requires attestations for a tool once an earlier version had them, so it refuses v1.7.0. That also breaks hey upgrade on installs that mise manages (#499).

Re-running the release job would not fix this: goreleaser would rebuild and re-sign, and the new digests would not match what is published. This adds a manually dispatched Attest a published release workflow (attest-release.yml, input tag) that attests the release as it already exists:

  1. Checks that the tag is a published, non-draft release.
  2. Runs cosign verify-blob on checksums.txt against the release run's own checksums.txt.bundle. It pins release.yml@refs/tags/<tag>, the same identity the installers and hey upgrade pin.
  3. Checks that every signed checksum matches the digest the releases API reports for the published asset of that name.
  4. Attests every asset listed in checksums.txt (the file is the index of subjects, not a subject itself) with the same pinned actions/attest-build-provenance that release.yml uses.

The job has contents: read, id-token: write and attestations: write permissions, and runs in the release environment. It is added to the sensitive-change gate and documented in RELEASING.md under "Missing attestation". tests/e2e/attest_release_workflow.bats pins the signer identity, the order of the steps, the shared action pin, and that the job keeps contents: read with no write permission.

The attestation's signer will be attest-release.yml on main, not release.yml at the tag. mise's GitHub backend passes no expected signer workflow (src/backend/github.rs: None, // We don't know the expected workflow), so any attestation from this repo satisfies it. hey upgrade's own verification uses the cosign bundle, not attestations, and is unaffected.

I ran the checks from steps 2 and 3 locally against v1.7.0: the bundle prints Verified OK, all 27 checksums match published assets, and a checksum with a changed digest is caught. actionlint and zizmor report nothing.

After merging:

gh workflow run attest-release.yml -f tag=v1.7.0
gh attestation verify hey_1.7.0_linux_amd64.tar.gz --repo basecamp/hey-cli

Refs #499


Summary by cubic

Adds a manually dispatched workflow that attests an already-published release that missed its build-provenance attestation, restoring mise and hey upgrade support for v1.7.0.

The workflow verifies checksums.txt against the release run's own cosign bundle pinned to release.yml@<tag>, checks every checksum against the published asset's digest, and then attests each asset listed in checksums.txt with the same pinned actions/attest-build-provenance as release.yml. Re-running the release job would rebuild and resign, changing digests, so this attestation matches the published assets instead. The attestation's signer is this workflow rather than release.yml; mise doesn't pin the signer workflow, so it satisfies the requirement. Also adds the workflow to the sensitive-change gate and documents the procedure in RELEASING.md, noting the attestations cover the assets named in the checksum file, not the file itself.

Written for commit 2aaeb47. Summary will update on new commits.

Review in cubic

v1.7.0 published its assets but the release run stopped at the size report
before "Attest build provenance", so it shipped without GitHub attestations.
mise requires them once an earlier version had them, and refuses the upgrade
(#499), which also breaks hey upgrade on installs managed by mise.

Re-running the release job would rebuild and re-sign, producing digests that
are not what was published. The new "Attest a published release" workflow
attests the release as it stands instead: it verifies checksums.txt against
the release run's own cosign bundle (release.yml at the tag, the identity the
installers pin), checks every checksum against the published asset's digest,
and then attests checksums.txt the way release.yml does. mise does not pin the
signer workflow, so an attestation signed by this workflow satisfies it.
@robzolkos
robzolkos requested a review from a team as a code owner September 28, 2026 17:20
Copilot AI balanced review requested due to automatic review settings September 28, 2026 17:20
@github-actions

Copy link
Copy Markdown

Sensitive Change Detection (shadow mode)

This PR modifies control-plane files:

  • .github/workflows/attest-release.yml
  • .github/workflows/sensitive-change-gate.yml

Shadow mode — this check is informational only. When activated, changes to these paths will require approval from a maintainer.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The documentation misidentifies the attestation subject, and the permission test does not enforce required read access.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

Adds a secure manual workflow for restoring missing provenance attestations on already-published releases.

Changes:

  • Verifies signed checksums against published assets before attestation.
  • Adds sensitive-change gating and static workflow tests.
  • Documents the release recovery procedure.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
.github/​workflows/​attest-release.yml Adds the manual verification and attestation workflow.
.github/​workflows/​sensitive-change-gate.yml Protects changes to the workflow.
tests/​e2e/​attest_release_workflow.bats Tests workflow ordering, identity, pinning, and permissions.
RELEASING.md Documents missing-attestation recovery.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/e2e/attest_release_workflow.bats Outdated
Comment thread RELEASING.md Outdated
Rejecting write permissions alone let contents: read be deleted, which would
leave the release download and the digest check unable to read the release.
subject-checksums treats checksums.txt as an index of subject names and
digests, so the attestations are for the assets it lists, not for the file.
That is why the verification example names an archive.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The implementation appears sound, but production supply-chain attestations and release-environment permissions require final human validation.

Review effort: Balanced
Findings: None

Resolved since last review (2)

@robzolkos
robzolkos merged commit a5272a4 into main Sep 28, 2026
26 checks passed
@robzolkos
robzolkos deleted the attest-published-release branch September 28, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants