Skip to content

Pin GitHub Actions to commit SHAs and add Dependabot - #910

Merged
skearnes merged 2 commits into
mainfrom
pin-actions
Jul 28, 2026
Merged

Pin GitHub Actions to commit SHAs and add Dependabot#910
skearnes merged 2 commits into
mainfrom
pin-actions

Conversation

@skearnes

@skearnes skearnes commented Jul 28, 2026

Copy link
Copy Markdown
Member

Version tags are mutable. The tj-actions/changed-files compromise in March 2025 repointed every version tag at a commit that dumped runner secrets into build logs, hitting roughly 23,000 repositories; tag pinning offered no protection and SHA pinning offered complete protection.

This repository is the highest-value target in the org. publish.yml runs with id-token: write for PyPI Trusted Publishing, so any action step in that job can mint an OIDC token and publish an ord-schema release. It also publishes to npm and pushes tags with secrets.ACTIONS_PUSH.

No exceptions left

pypa/gh-action-pypi-publish could not be SHA-pinned — it is a container action resolved as ghcr.io/pypa/gh-action-pypi-publish:<ref>, and a commit SHA has no matching GHCR image (the workflow's own comment records that even v1.14.0 had no manifest at publish time). Rather than carry it as a documented exception, #911 replaced it with uv publish --trusted-publishing always, which is now merged into this branch.

uv performs the OIDC exchange itself and uploads PEP 740 attestations by default, so the release path lost nothing. Every uses: in this repository now resolves to a commit SHA, and every step in the id-token: write job is either a SHA-pinned action or a run: block.

Dependabot is the other half

Dependabot understands SHA-pinned actions and rewrites the SHA together with its trailing # vN comment, so pinned workflows keep tracking upstream. Without it, pinning freezes the workflows on whatever was current the day they were written.

That failure mode is already live in this org: ord-app and ord-infrastructure are fully SHA-pinned with no update mechanism, and both sit on astral-sh/setup-uv v5.4.2 while this repository runs v7. ord-app's actions/checkout pin is stale even within v4. Companion Dependabot PRs for those repositories, and the matching change in ord-data (#264), follow.

Updates are grouped so this arrives as one pull request a month rather than one per action.

Every pin resolves the tag that was already in use — checkout@v7, setup-python@v6, setup-node@v6, setup-go@v6, setup-uv@v7, setup-miniconda@v4 — so the pinning commit changes no behavior; the PyPI publisher swap in #911 is the one behavioral change on this branch. Resolved through the git refs API, dereferencing annotated tags to their commits. All pre-commit hooks pass.

🤖 Generated with Claude Code

Greptile Summary

Pins GitHub Actions to immutable commit SHAs and modernizes release maintenance.

  • Adds monthly grouped Dependabot updates for GitHub Actions.
  • Replaces mutable action tags across CI and release workflows with SHA pins.
  • Replaces the third-party PyPI publishing action with uv publish using trusted publishing.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
.github/dependabot.yml Adds a valid monthly updater that groups all GitHub Actions updates into one pull request.
.github/workflows/cleanup.yml Replaces mutable action version tags with immutable SHAs without changing workflow inputs.
.github/workflows/publish.yml Pins setup actions and moves PyPI trusted publishing from a third-party action to the installed uv CLI.
.github/workflows/run_tests.yml Pins all test-workflow actions to immutable SHAs while retaining their existing configuration.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    D[Dependabot monthly update] --> P[Update pinned action SHAs]
    P --> W[CI and release workflows]
    W --> B[Build and validate distributions]
    B --> U[uv trusted publishing]
    U --> PYPI[PyPI]
    B --> NPM[npm]
    PYPI --> G[Push version bump and tag]
    NPM --> G
Loading

Reviews (2): Last reviewed commit: "Publish to PyPI with uv instead of a thi..." | Re-trigger Greptile

Version tags are mutable. The tj-actions/changed-files compromise repointed
every tag at a commit that dumped runner secrets into build logs; only
SHA-pinned consumers were unaffected. publish.yml carries id-token: write for
PyPI Trusted Publishing, so an action step in that job can mint an OIDC token
and publish a release.

pypa/gh-action-pypi-publish stays on release/v1. It is a container action
resolved as ghcr.io/pypa/gh-action-pypi-publish:<ref>, and a SHA has no matching
GHCR image; the existing comment records that even v1.14.0 lacked a manifest.
That comment now says this is the deliberate exception rather than an oversight.

The Dependabot config is the half that makes SHA pinning sustainable: it
rewrites the SHA and its version comment together, so the workflows track
upstream instead of freezing. Grouped monthly to keep it to one pull request.

Every pin resolves the tag already in use, so behavior is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pypa/gh-action-pypi-publish was the last thing in this job that could not be
pinned to a commit SHA: it is a container action resolved as
ghcr.io/pypa/gh-action-pypi-publish:<ref>, and a SHA has no matching GHCR image.
That mattered because the job runs with id-token: write, so any step in it can
mint an OIDC token and publish a release.

uv does the trusted-publishing exchange itself and uploads PEP 740 attestations
by default, so the release path loses nothing and gains a fully pinned job. uv
is already present via setup-uv, which this branch pins.

--trusted-publishing always rather than the default automatic: it fails loudly
instead of falling back to looking for an API token that does not exist.
Verified locally that the invocation reaches the OIDC exchange and stops there
for want of a token. verify-metadata: false is moot -- twine check and
check_direct_dependencies.py already run against dist/ in the step above.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@skearnes
skearnes merged commit ec82928 into main Jul 28, 2026
23 checks passed
@skearnes
skearnes deleted the pin-actions branch July 28, 2026 23:39
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.

1 participant