fix(ci): verify tag-release artifacts against build attestations - #11325
Draft
basvandijk wants to merge 6 commits into
Draft
fix(ci): verify tag-release artifacts against build attestations#11325basvandijk wants to merge 6 commits into
basvandijk wants to merge 6 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Updates the tag-release workflow to publish only artifacts verified against build attestations.
Changes:
- Verifies binaries and canisters before packaging.
- Publishes verified checksums and fixes manual tag targeting.
- Removes unused OS images and makes missing release files fatal.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
basvandijk
force-pushed
the
bas/verify-tag-release-artifacts
branch
from
August 27, 2026 20:24
6d76d7a to
262c7dd
Compare
basvandijk
force-pushed
the
bas/verify-tag-release-artifacts
branch
from
August 27, 2026 22:04
262c7dd to
e7bd9fd
Compare
Third step for security finding 3618194 (MEDIUM, CWE-494), building on the producer-side attestations of #11323 and the fetch-verified-artifacts action of #11324. tag-release.yml downloaded 9 tool binaries, 2 OS images and 19 canister wasm/did pairs from the CDN with plain curl and published sha256sums.txt computed FROM THE DOWNLOADS THEMSELVES, so whoever can write to the CDN buckets could get their artifacts republished as an official GitHub release with matching checksums. Every download now goes through .github/actions/fetch-verified-artifacts: the per-directory SHA256SUMS is verified with `gh attestation verify --repo dfinity/ic --signer-workflow dfinity/ic/.github/workflows/release-testing.yml --source-digest <commit>` and each artifact is checked against the verified sums, failing the release on any mismatch. Pinning the release-testing.yml signer also enforces that a release-* tag can only ship commits that went through the release-qualification pipeline. sha256sums.txt is now the verified build-time hashes (plus the locally-assembled canisters.tar hash), not a re-hash of the downloads. Bugs fixed in passing: * The OS images had silently never been attached: since 9bd0a40 (2024-08) the download step saved setup-os-img.tar.zst / update-os-img.tar.zst while the publish step listed *.tar.gz, and softprops v0.1.15 only warned about the unmatched patterns. The image downloads are now dropped entirely (preserving the two-year de-facto release contents; the canonical image channel is the CDN + NNS election proposal hash, verified by ci/scripts/repro-check), and fail_on_unmatched_files makes any repeat of this bug fail loudly. * sha256sums.txt claimed to cover the release but only ever hashed *.gz and *.tar; it now covers exactly what ships. * On the workflow_dispatch path the softprops action defaulted tag_name to the dispatched ref, not the requested tag; tag_name is now passed explicitly. * softprops/action-gh-release upgraded from the v0.1.15 pin to the same v2.4.2 pin used by ledger-suite-release.yml. Verification: the workflow_dispatch dry-run path exercises checkout, download and verification without publishing; run it with a tag-name whose commit was built by release-testing.yml after #11323 merged. The verification failure paths (missing attestation, flipped hash, wrong --source-digest commit) were exercised in #11324 and fail closed. Note that a push-tag trigger runs the workflow file at the tag's commit, so this protects release-* tags on rc branches cut after this change reaches master; the arm64/darwin binary directories additionally need the SHA256SUMS files introduced by #11323. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The number resolves to nothing a future reader can look up; the comments already explain the property that matters (an integrity anchor independent of the CDN). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Companion to the source-ref binding added to the shared verifier: both fetch-verified-artifacts invocations now accept only attestations minted from refs/heads/(rc--|hotfix-|public-hotfix-).+, and the workflow's explicit permissions map gains attestations: read for `gh attestation verify`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drops the retired public-hotfix- pattern (that branch pattern is not push-restricted, so accepting it would let any Write user mint consumer-accepted attestations) and tightens .+ to [^/]+ since branch protections and workflow triggers match with fnmatch, where * does not cross '/'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
basvandijk
force-pushed
the
bas/verify-tag-release-artifacts
branch
from
August 28, 2026 11:24
e7bd9fd to
e66fd44
Compare
basvandijk
commented
Aug 28, 2026
Requested in review on #11325. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On workflow_dispatch the checkout resolved the raw tag-name input, which actions/checkout matches against branches *before* tags: an input naming a branch with no corresponding tag was checked out anyway (and action-gh-release would then create that tag itself, pointing at the default branch), and a branch sharing an existing tag's name shadowed the tag. Either way the verified artifact commit could differ from the commit the release tag points to. Qualify the input as refs/tags/<tag-name> so a nonexistent tag fails the checkout before any verification, and a name collision resolves to the tag. Also reject an empty tag-name explicitly: `required: true` is only enforced by the web UI, so an API-triggered dispatch could omit it and fall through to checking out the dispatched branch. Addresses the Copilot review comment on #11325. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Third step for security finding 3618194 (MEDIUM, CWE-494), building on the producer-side attestations of #11323 and the
fetch-verified-artifactsaction of #11324. Based on #11324's branch (it reuses the action); GitHub will retarget this PR to master when #11324 merges.tag-release.ymldownloaded 9 tool binaries, 2 OS images and 19 canister wasm/did pairs from the CDN with plain curl and published asha256sums.txtcomputed from the downloads themselves — pure self-attestation, so anyone with CDN/bucket write could get their artifacts republished as an official GitHub release with matching checksums.Changes
.github/actions/fetch-verified-artifacts: the per-directorySHA256SUMSis verified withgh attestation verify --repo dfinity/ic --signer-workflow dfinity/ic/.github/workflows/release-testing.yml --source-digest <commit>, and each artifact is checked against the verified sums — any CDN substitution fails the release. Pinning the release-testing signer additionally enforces that arelease-*tag can only ship commits that went through the release-qualification pipeline.sha256sums.txtnow contains the verified build-time hashes (plus the hash of the locally assembledcanisters.tar), covering exactly what ships.Bugs fixed in passing
9bd0a407b7(2024-08) the download step saved*-img.tar.zstwhile thefiles:list said*-img.tar.gz, and softprops v0.1.15 only warned. Per the agreed direction, the image downloads are dropped entirely — this preserves the two-year de-facto release contents; the canonical image channel is the CDN + NNS election proposal hash, verified byci/scripts/repro-check.fail_on_unmatched_files: truemakes any repeat of this class of bug fail loudly.workflow_dispatchpath the release was created against the dispatched ref, not the requested tag —tag_nameis now passed explicitly.softprops/action-gh-releaseupgraded from the ancient v0.1.15 pin to the same v2.4.2 pin used byledger-suite-release.yml.Verification
workflow_dispatchdry-run path exercises checkout → download → verification without publishing; run it with atag-namewhose commit was built byrelease-testing.ymlafter feat(ci): attest CDN artifact uploads with build provenance #11323 merged (the first rc branch cut after that merge).--source-digestcommit) were exercised directly in fix(ci): verify ledger-suite release artifacts against build attestations #11324 and fail closed with non-zero exit.release-*tags on rc branches cut after the change reaches master. The arm64/darwin binary directories additionally need theSHA256SUMSfiles that feat(ci): attest CDN artifact uploads with build provenance #11323 starts publishing.🤖 Generated with Claude Code