Skip to content

Pin GitHub Actions to commit SHAs - #1240

Merged
paulinebm merged 1 commit into
mainfrom
security/pin-actions-to-sha
Sep 23, 2026
Merged

paulinebm merged 1 commit into
mainfrom
security/pin-actions-to-sha

Conversation

@hf-security-analysis

@hf-security-analysis hf-security-analysis Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Workflow hardening

Actions pinned to commit SHAs

A version tag is mutable. Whoever controls an action's repository can move v4
to different code, and every workflow referencing @v4 picks that up on the
next run with nothing to review. That is how tj-actions/changed-files shipped
a credential dumper to thousands of repositories in March 2025.

Pinning to a full commit SHA freezes the code that runs. The version tag stays
on the line as a comment, so the reference is still readable.

This pins, it does not upgrade. Every SHA below is the commit the tag
already resolves to today, so nothing about what your CI executes changes — it
only removes the ability for it to change without your knowing.

Workflow Before After
.github/workflows/deploy-hf-env.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/deploy-hf-env.yml uses: actions/setup-python@v7 uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
.github/workflows/docker-build.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/docker-build.yml uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
.github/workflows/docker-build.yml uses: docker/login-action@v4 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
.github/workflows/docker-build.yml uses: docker/metadata-action@v6 uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
.github/workflows/docker-build.yml uses: docker/build-push-action@v7 uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
.github/workflows/docker-build.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/docker-build.yml uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
.github/workflows/docker-build.yml uses: docker/login-action@v4 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
.github/workflows/docker-build.yml uses: docker/metadata-action@v6 uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
.github/workflows/docker-build.yml uses: docker/build-push-action@v7 uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
.github/workflows/manage-hf-collection.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/manage-hf-collection.yml uses: actions/setup-python@v7 uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
.github/workflows/openspiel_base_build.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/openspiel_base_build.yml uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
.github/workflows/openspiel_base_build.yml uses: docker/login-action@v4 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
.github/workflows/openspiel_base_build.yml uses: docker/metadata-action@v6 uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
.github/workflows/openspiel_base_build.yml uses: docker/build-push-action@v7 uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
.github/workflows/openspiel_base_build.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/openspiel_base_build.yml uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
.github/workflows/openspiel_base_build.yml uses: docker/login-action@v4 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
.github/workflows/openspiel_base_build.yml uses: docker/metadata-action@v6 uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
.github/workflows/openspiel_base_build.yml uses: docker/build-push-action@v7 uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
.github/workflows/package-ci.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/package-ci.yml uses: actions/setup-python@v7 uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
.github/workflows/test.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/test.yml uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
.github/workflows/test.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/test.yml uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
.github/workflows/test.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/test.yml uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
.github/workflows/test.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/test.yml uses: actions/setup-python@v7 uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
.github/workflows/test.yml uses: actions/checkout@v7 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
.github/workflows/test.yml uses: astral-sh/setup-uv@v7 uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0

Opened by the workflow security bot. It changes what this pull request says it
changes, and nothing else.


Note

Low Risk
Workflow-only supply-chain hardening with no application code changes; pinned SHAs correspond to the previously referenced tag versions.

Overview
Replaces mutable @v* action references with immutable commit SHAs across six workflows (deploy-hf-env, docker-build, manage-hf-collection, openspiel_base_build, package-ci, and test). Each line keeps the former tag as an inline comment (e.g. # v7.0.1) so upgrades stay readable.

Affected third-party actions include actions/checkout, actions/setup-python, astral-sh/setup-uv, and the Docker build/login/metadata/build-push stack. Behavior should be unchanged—the SHAs match what those tags already pointed at; the goal is to stop tag retags from silently changing CI on the next run.

Reviewed by Cursor Bugbot for commit 81a4ce1. Bugbot is set up for automated code reviews on this repo. Configure here.

A tag is mutable: whoever controls the action's repository can move
`v4` to different code, and the next run picks it up with no diff to
review. Pinning to the commit SHA freezes the code that runs today.
@burtenshaw burtenshaw added enhancement New feature or request size: small Small pull request labels Sep 23, 2026 — with Cursor
@bot-ci-comment

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@cursor cursor Bot 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.

APPROVE at 81a4ce15

Pin-not-upgrade: mutable @vN tags → immutable commit SHAs with version comments. Does not touch publish-pypi.yml / publish-testpypi.yml (already SHA-pinned on main). Checkout/setup-python SHAs match what those publish workflows already use (3d3c42e5…, 5fda3b95…). No package cargo.

Timing: prefer merge after tomorrow’s v0.6.0 tag so PR CI (test.yml / package-ci.yml) doesn’t churn on the release day path. Safe either way — claimed SHAs are today’s tag tips.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot 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.

Alignment Review Report

Mechanical, repo-wide SHA-pin of GitHub Actions across 6 workflow files (deploy-hf-env, docker-build, manage-hf-collection, openspiel_base_build, package-ci, test). 7 distinct actions, all floating major tags → full 40-char commit SHAs annotated # vX.Y.Z. Verdict: security-positive, nothing blocking.

Automated Checks

  • Lint: PASS (N/A to diff) — the lint hook only covers Python (src/ tests/ envs/) and never touches .github/workflows/; a YAML-only diff introduces no lint surface. (Pre-existing envs/** reformat noise is unrelated to this PR.)
  • Debug code: CLEAN — check-debug.sh scans src/ only; every hit it reports (harbor/*, cli/*, core/mcp_client.py, …) is pre-existing and outside this PR's changed files. Zero debug code in the diff.

Open RFCs Context

Current rfcs/: 000/001/002/003/005/008/012 (In Review), 004 (Rubrics, no status header), 010/011 (Draft). None govern CI, GitHub Actions, or action/dependency pinning — no RFC surface for this change.

Tier 1: Fixes Required

None. I verified every pin against the GitHub API: each SHA equals its claimed # vX.Y.Z tag and equals the current tip of the floating major tag it replaces — i.e. zero behavioral change at merge, exactly as the PR body states ("this pins, it does not upgrade").

Action Pinned SHA Tag SHA==tag == @major tip
actions/checkout 3d3c42e5… v7.0.1 ✅ ✅ (v7)
actions/setup-python 5fda3b95… v7.0.0 ✅ ✅ (v7)
astral-sh/setup-uv 37802adc… v7.6.0 ✅ ✅ (v7) ¹
docker/setup-buildx-action f87e5991… v4.4.1 ✅ ✅ (v4)
docker/login-action dbcb8138… v4.6.0 ✅ ✅ (v4)
docker/metadata-action dc802804… v6.2.0 ✅ ✅ (v6)
docker/build-push-action c3c9e263… v7.4.0 ✅ ✅ (v7)

YAML parses cleanly for all 6 files; git merge-tree against main is conflict-free.

Tier 2: Alignment Discussion

Principle Conflicts

None identified. SHA-pinning is security-positive and reinforces the reproducibility posture (PRINCIPLES.md) and the "No credential exposure" invariant (INVARIANTS.md). The affected jobs authenticate via secrets.* / GHCR login / OIDC, and package-ci.yml already sets persist-credentials: false; freezing action code cuts supply-chain risk (the exact tj-actions/changed-files class of attack the PR body cites) without adding any credential or injection surface. PRINCIPLES/INVARIANTS govern the runtime API (Gym/MCP/rewards/client-server/container isolation) — untouched here.

RFC Conflicts

None identified. No RFC covers CI / GitHub Actions.

Summary

  • 0 mechanical issues to fix
  • 0 alignment points for human review
  • 0 RFC conflicts

Notes (non-blocking):

¹ astral-sh/setup-uv is pinned to v7.6.0, the tip of the repo's floating @v7. setup-uv's latest overall is v10.2.0 — this is not a defect: the PR correctly preserves the existing major (v7→v10 would be a separate, deliberate upgrade, and the repo intentionally tracks setup-uv @v7).

  • Completeness: after this PR, the only remaining floating (non-SHA) action ref in the whole .github/workflows/ tree is pypa/gh-action-pypi-publish@release/v1 (publish-pypi.yml:128, publish-testpypi.yml:143 — both untouched here). Prior hardening PRs (#1227 / #1228) already flagged that trusted-publisher branch ref as intentionally deferred to a human decision, so this PR sensibly leaves it alone and effectively completes the repo-wide pinning pass those PRs started.

Suggested reviewers: @burtenshaw (owns the CI workflows + .github/dependabot.yml); cc @sergiopaniego (last human author of docker-build.yml and openspiel_base_build.yml).

Open in Web View Automation 

Sent by Cursor Automation: Pre-review


- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

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.

Verified the four third-party Docker action pins here (the highest supply-chain sensitivity) against the GitHub API — each matches its # vX.Y.Z comment and the current tip of the @major tag it replaced, so they're behavior-preserving:

  • docker/setup-buildx-action f87e5991… = v4.4.1 (@v4 tip)
  • docker/login-action dbcb8138… = v4.6.0 (@v4 tip)
  • docker/metadata-action dc802804… = v6.2.0 (@v6 tip)
  • docker/build-push-action c3c9e263… = v7.4.0 (@v7 tip)

The same four pins are applied identically in openspiel_base_build.yml. ✅


- name: Install uv
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0

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.

astral-sh/setup-uv 37802adc… = v7.6.0, verified == the tip of the repo's floating @v7.

Heads-up for reviewers: setup-uv's latest release overall is v10.2.0, so this can read as "behind" — but it's correct here. The PR preserves the pinned major (v7); moving to v10 is a separate deliberate upgrade decision. actions/checkout@… = v7.0.1 on line 27 is likewise verified == @v7 tip. ✅

steps:
- name: Checkout code
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

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.

First-party pins verified: actions/checkout 3d3c42e5… = v7.0.1 and actions/setup-python 5fda3b95… = v7.0.0 (line 30) — both == their tag == @v7 tip. Nice that this checkout already sets persist-credentials: false; SHA-pin + no-persist is a solid supply-chain combination. ✅

@paulinebm
paulinebm merged commit e401886 into main Sep 23, 2026
14 checks passed
cursor Bot pushed a commit that referenced this pull request Sep 23, 2026
Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
cursor Bot added a commit that referenced this pull request Sep 24, 2026
OpenEnv 0.6.0

Breaking change
- `--llm-endpoint` / OpenAIClient now take a full base URL; the implicit port 8000 is gone. `http://localhost` means port 80; use `http://localhost:8000` or `--llm-port 8000` for the old behavior (#1189, landed via #1237).

New
- NovitaSandboxProvider: run an OpenEnv server in a Novita AI sandbox over wss://, from a registry image or a local Dockerfile; install with `pip install openenv[novita]` (#1191).
- RFC 008 Level 2 validation building blocks: manifest-v2, report-v2 and runtime-plan schemas, the severity-v2 policy, and DockerValidationProvider (#1178, #1179). The `openenv validate` CLI is unchanged in this release.

Fixes
- A failed `new_session()` no longer leaves the provider's container or sandbox running (#1145).

Repository and environment images (not in the wheel)
- coding_env `additional_imports` now extends the default safe-import allowlist (#1147).
- Environment lockfile security updates: anyio 4.14.2 and soupsieve 2.9.2 (#1196, #1197, #1201, #1202).
- CI hardening: per-job GITHUB_TOKEN scopes and SHA-pinned actions (#1221, #1223, #1225, #1226, #1228, #1239, #1240); validation-lab toolchain pins (#1229, #1230, #1231); docs navigation and Miles integration docs (#1219, #1220).

Known, accepted for this release: Novita provider debt (unbraced $ARG ordering in Dockerfile flattening, a tbench2 example readiness leak); fixes follow in #1235.

Validated: exact-head CI 13/13 on 0034202; TestPyPI 0.6.0.dev141 (run 35854754769) byte-identical to the release wheel apart from Version; clean wheel/sdist install, CLI, and Echo reset/step smoke.
@cursor cursor Bot mentioned this pull request Sep 24, 2026
21 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size: small Small pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants