Skip to content

fix(ci): verify tag-release artifacts against build attestations - #11325

Draft
basvandijk wants to merge 6 commits into
bas/verify-ledger-suite-artifactsfrom
bas/verify-tag-release-artifacts
Draft

fix(ci): verify tag-release artifacts against build attestations#11325
basvandijk wants to merge 6 commits into
bas/verify-ledger-suite-artifactsfrom
bas/verify-tag-release-artifacts

Conversation

@basvandijk

Copy link
Copy Markdown
Collaborator

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. Based on #11324's branch (it reuses the action); GitHub will retarget this PR to master when #11324 merges.

tag-release.yml downloaded 9 tool binaries, 2 OS images and 19 canister wasm/did pairs from the CDN with plain curl and published a sha256sums.txt computed 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

  • 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 — any CDN substitution fails the release. Pinning the release-testing signer additionally enforces that a release-* tag can only ship commits that went through the release-qualification pipeline.
  • sha256sums.txt now contains the verified build-time hashes (plus the hash of the locally assembled canisters.tar), covering exactly what ships.

Bugs fixed in passing

  • OS images were silently never attached: since 9bd0a407b7 (2024-08) the download step saved *-img.tar.zst while the files: 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 by ci/scripts/repro-check. fail_on_unmatched_files: true makes any repeat of this class of bug fail loudly.
  • On the workflow_dispatch path the release was created against the dispatched ref, not the requested tag — tag_name is now passed explicitly.
  • softprops/action-gh-release upgraded from the ancient v0.1.15 pin to the same v2.4.2 pin used by ledger-suite-release.yml.

Verification

🤖 Generated with Claude Code

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.

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.

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/tag-release.yml

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@basvandijk
basvandijk force-pushed the bas/verify-tag-release-artifacts branch from 262c7dd to e7bd9fd Compare August 27, 2026 22:04
basvandijk and others added 4 commits August 28, 2026 13:24
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
basvandijk force-pushed the bas/verify-tag-release-artifacts branch from e7bd9fd to e66fd44 Compare August 28, 2026 11:24
Comment thread .github/workflows/tag-release.yml Outdated
basvandijk and others added 2 commits August 28, 2026 12:27
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>

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants