Skip to content

Harden CI: pin release-pipeline actions to commit SHAs - #5281

Merged
vivekchand merged 1 commit into
mainfrom
harden/pin-release-pipeline-actions
Aug 28, 2026
Merged

Harden CI: pin release-pipeline actions to commit SHAs#5281
vivekchand merged 1 commit into
mainfrom
harden/pin-release-pipeline-actions

Conversation

@vivekchand

Copy link
Copy Markdown
Owner

Addresses the Scorecard PinnedDependencies findings for the four workflows that build, sign and publish releases.

What this does

Every third-party action referenced by publish.yml, release-on-merge.yml, release-canary.yml and desktop-artifacts.yml now resolves to a full 40-character commit SHA, with the semver it came from in a trailing comment:

Action Pinned to Version Uses
actions/checkout 3d3c42e5aac5ba805825da76410c181273ba90b1 v7.0.1 ×6
actions/setup-python 5fda3b95a4ea91299a34e894583c3862153e4b97 v7.0.0 ×7
actions/setup-node 820762786026740c76f36085b0efc47a31fe5020 v7.0.0 ×3
actions/upload-artifact ea165f8d65b6e75b540449e92b4886f43607fa02 v4.6.2 ×3
actions/download-artifact d3f86a106a0bac45b974a628896c90dbdf5c8093 v4.3.0 ×1
actions/attest-build-provenance 96278af6caaf10aea03fd8d33a09a777ca52d62f v3.2.0 ×1
pypa/gh-action-pypi-publish dc37677b2e1c63e2034f94d8a5b11f265b73ba33 v1.14.2 ×1
azure/login 7184910d9eb2b1c5e48f7073824a90609bb9b6d6 v2.3.1 ×1
softprops/action-gh-release 3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 v2.6.2 ×1

Why this batch, and why it matters more than the others

A version tag is mutable: actions/checkout@v7 is whatever v7 points at the next time a runner resolves it. Pinning to a commit fixes what runs in CI in this repository's own history.

These four workflows are where that matters most, because they are the ones holding real authority — this is the pipeline that pushes to PyPI, signs the macOS and Windows desktop builds, and publishes GitHub releases.

Two references in particular:

  • pypa/gh-action-pypi-publish@release/v1 was pointing at a branch, not even a tag — a ref designed to move — while being the step that authenticates to PyPI via Trusted Publishing. It is now pinned to dc37677b, the commit release/v1 resolves to today, which is exactly v1.14.2.
  • azure/login@v2 and softprops/action-gh-release@v2 hold the Azure code-signing OIDC credential and the release-publishing token respectively.

A note on annotated tags

Three of these actions publish annotated tags, where refs/tags/vX.Y.Z names a tag object rather than a commit. uses: resolves against commits, so the tag-object SHA would fail at "Set up job". Each ref was peeled (refs/tags/vX.Y.Z^{}) and the commit SHA pinned:

Action Tag object (wrong) Commit (pinned)
actions/attest-build-provenance v3.2.0 62fc1d59… 96278af6…
azure/login v2.3.1 2035af27… 7184910d…
pypa/gh-action-pypi-publish v1.14.2 a892a5a6… dc37677b…

Scope

Pins only — no version changes, no permission changes. Each action was pinned to the latest patch within the major tag it already used, so upload-artifact@v4 stays on v4 rather than being pulled up to the v7 used in ci.yml. This is a supply-chain fix, not an upgrade; mixing the two would make a CI regression much harder to bisect. Dependabot's open github-actions PRs still propose those major bumps separately.

No permissions: block is touched. The write scopes these workflows need (contents: write, id-token: write, attestations: write) are untouched from #5250/#5253.

Verification

  • All 34 workflow files parse: python3 -c "import yaml,glob; [yaml.safe_load(open(f)) for f in glob.glob('.github/workflows/*.yml')]" — OK.
  • python3 scripts/check_action_refs.py — OK (23 distinct references, offline shape checks pass). The live resolution runs in supply-chain.yml.
  • Every SHA was resolved directly from the upstream repository with git ls-remote, not from memory.
  • The diff is 25 insertions / 25 deletions and every changed line is a uses: line — no structural, job, or permission changes.
  • No unpinned uses: reference remains in these four files.

Notes

No-PRD: CI/supply-chain hardening confined to .github/; no product surface changes.


Generated by Claude Code

Pins every third-party action in the four release/publish workflows
(publish, release-on-merge, release-canary, desktop-artifacts) to a full
40-character commit SHA with the semver it came from in a trailing
comment. 25 uses: lines, no version changes, no permission changes.

Includes pypa/gh-action-pypi-publish, which was on the moving
release/v1 branch despite holding PyPI publish rights.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K754j6t7Lvc2aLTJtnC3G4
@8090-software-factory

Copy link
Copy Markdown

✅ Drift Bot (ClawMetry): no drift detected

Drift Bot analyzed the changed files against this project's blueprints and requirements and found no drift.

@vivekchand
vivekchand merged commit 5833ffd into main Aug 28, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants