Skip to content

chore(workflows): SHA-pin third-party GitHub Actions#94

Merged
cmeans-claude-dev[bot] merged 4 commits into
mainfrom
chore/sha-pin-actions
May 2, 2026
Merged

chore(workflows): SHA-pin third-party GitHub Actions#94
cmeans-claude-dev[bot] merged 4 commits into
mainfrom
chore/sha-pin-actions

Conversation

@cmeans-claude-dev
Copy link
Copy Markdown
Contributor

@cmeans-claude-dev cmeans-claude-dev Bot commented May 2, 2026

Summary

Closes #46.

Every external action in .github/workflows/*.yml was previously pinned to a major-version tag (actions/checkout@v6, astral-sh/setup-uv@v7, etc.) — and pypa/gh-action-pypi-publish@release/v1 was even pinned to a branch ref, which can move under us. A minor release within a major can introduce security or behavior regressions without detection on a tag-only pin.

This PR converts every third-party uses: line to an immutable 40-char commit SHA with a trailing # v<version> comment (the GitHub-recommended supply-chain pattern).

Pins applied

Action Version SHA
actions/checkout v6.0.2 de0fac2e4500dabe0009e67214ff5f5447ce83dd
astral-sh/setup-uv v7.6.0 37802adc94f370d6bfd71619e3f0bf239e1f3b78
actions/setup-python v6.2.0 a309ff8b426b58ec0e2a45f0f869d46889d02405
actions/upload-artifact v7.0.1 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
actions/download-artifact v8.0.1 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
actions/cache v5.0.5 27d5ce7f107fe9357f9df03efb73ab90386fccae
codecov/codecov-action v6.0.0 57e3a136b779b570ffcdbf80b3bdc90e7fab3de2
pypa/gh-action-pypi-publish v1.14.0 cef221092ed1bacb1cc03d23a2d87d1d172e277b

SHAs were resolved from repos/{owner}/{repo}/git/refs/tags/<tag> (with the annotated-tag deref through git/tags/<sha>); the pypa one came from repos/pypa/gh-action-pypi-publish/branches/release/v1 and matches the v1.14.0 tag exactly.

Files changed

  • .github/workflows/ci.yml
  • .github/workflows/publish.yml
  • .github/workflows/test-publish.yml
  • .github/workflows/vdsm.yml
  • CHANGELOG.md### Changed entry under ## Unreleased

Out of scope (intentionally)

  • Local composite actions under ./.github/actions/* are NOT pinned. They live in-repo and are reviewed on merge; pinning their SHA would produce stale-SHA noise on every internal change.
  • dependabot-changelog.yml was already SHA-pinned (PR fix(workflow): bump dependabot/fetch-metadata to v3.1.0 (closes auto-CHANGELOG empty-versions bug) #60 work). It served as the template this PR uses for the rest.
  • pr-labels.yml, pr-labels-ci.yml, qa-gate.yml — these workflows use no uses: lines (entirely run-step). Nothing to pin.

Why no manual SHA tracker

Dependabot's existing github-actions ecosystem in .github/dependabot.yml will propose SHA bump PRs weekly so the pins stay fresh without manual maintenance. That's the second AC item from the issue, already in place since the existing config was set up for tag-pin updates and works equally well for SHA-pin updates.

Test plan

  • CI green (lint, typecheck, test 3.11/3.12/3.13, vdsm, version-sync, validate-server-json)
  • All workflow YAML files parse: for f in .github/workflows/*.yml; do python -c "import yaml; yaml.safe_load(open('$f'))"; done
  • grep -rn "^\s*-\? *uses: " .github/workflows/ | grep -v "uses: \./\." | grep -vE "@[0-9a-f]{40}" returns empty (no plain-tag pins on third-party actions remain)
  • Functional smoke deferred to next Dependabot run, which will exercise the SHA-pin format end-to-end by proposing a bump

🤖 Generated with Claude Code

Closes #46.

Every external action in .github/workflows/*.yml was previously
pinned to a major-version tag — and pypa/gh-action-pypi-publish
was even pinned to a *branch* ref (release/v1), which can move
under us. A minor release within a major can introduce security
or behavior regressions without detection on a tag-only pin.

Now every third-party `uses:` line carries an immutable 40-char
commit SHA with a trailing `# v<version>` comment for human
readability (the GitHub-recommended supply-chain pattern).

Eight actions pinned across ci.yml, publish.yml, test-publish
.yml, vdsm.yml:

  actions/checkout                 v6.0.2 (de0fac2e...)
  astral-sh/setup-uv               v7.6.0 (37802adc...)
  actions/setup-python             v6.2.0 (a309ff8b...)
  actions/upload-artifact          v7.0.1 (043fb46d...)
  actions/download-artifact        v8.0.1 (3e5f45b2...)
  actions/cache                    v5.0.5 (27d5ce7f...)
  codecov/codecov-action           v6.0.0 (57e3a136...)
  pypa/gh-action-pypi-publish      v1.14.0 (cef22109...)

Local composite actions under ./.github/actions/* are deliberately
not pinned (in-repo, reviewed on merge — pinning them would
produce stale-SHA noise on every internal change).

dependabot-changelog.yml was already SHA-pinned (PR #60 work)
and serves as the template the rest of the workflows now match.

Dependabot's existing github-actions ecosystem in
.github/dependabot.yml will propose SHA bump PRs weekly so the
pins stay fresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA label May 2, 2026
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added Ready for QA Dev work complete — QA can begin review and removed Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA labels May 2, 2026
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Owner

@cmeans cmeans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The prior CI run failed only on TestSearch::test_search_keyword_finds_directory — DSM's search service didn't propagate the freshly-created `Bambu Studio` directory to the index within the 6-attempt retry budget (synoindex registration was confirmed in the run log; just a slow indexer). Documented flake in CLAUDE.md "Search tests can be flaky". Retriggering CI; SHA pins have no functional impact on the search code path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA Ready for QA Dev work complete — QA can begin review and removed Ready for QA Dev work complete — QA can begin review Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA labels May 2, 2026
Two consecutive vdsm runs on this branch failed only on
TestSearch::test_search_keyword_finds_directory; the
preceding main run passed the same test on attempt 5 of
6 (search_files saw the directory after ~75s of indexer
warmup), and our runs got 0 results across all six. Pure
DSM Universal Search propagation latency variance —
documented in CLAUDE.md as a known vdsm flake. SHA pins
resolve to the same underlying code that `@v5`/`@v6`
resolved to today, so they can't be the cause.

vdsm has `continue-on-error: true` and is not a required
check, but retrying once more in case the indexer is
quicker on this run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA Ready for QA Dev work complete — QA can begin review and removed Ready for QA Dev work complete — QA can begin review Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA labels May 2, 2026
@cmeans cmeans added QA Active QA is actively reviewing; Dev should not push changes and removed Ready for QA Dev work complete — QA can begin review labels May 2, 2026
Copy link
Copy Markdown
Owner

@cmeans cmeans left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Round 1 — PASS (no findings)

Reviewed on head 096b7bc (4 commits in branch: SHA-pin work + CHANGELOG backfill + 2 empty-commit retriggers for the documented TestSearch vdsm flake).

SHA verification

Independently resolved each tag against the GitHub API via gh api repos/{owner}/{repo}/commits/{tag}. All 8 SHAs match the PR body's table exactly:

Action Tag SHA (resolved)
actions/checkout v6.0.2 de0fac2e4500dabe0009e67214ff5f5447ce83dd
astral-sh/setup-uv v7.6.0 37802adc94f370d6bfd71619e3f0bf239e1f3b78
actions/setup-python v6.2.0 a309ff8b426b58ec0e2a45f0f869d46889d02405
actions/upload-artifact v7.0.1 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
actions/download-artifact v8.0.1 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
actions/cache v5.0.5 27d5ce7f107fe9357f9df03efb73ab90386fccae
codecov/codecov-action v6.0.0 57e3a136b779b570ffcdbf80b3bdc90e7fab3de2
pypa/gh-action-pypi-publish v1.14.0 cef221092ed1bacb1cc03d23a2d87d1d172e277b

Coverage

The test-plan audit grep -rn "^\s*-\? *uses: " .github/workflows/ | grep -v "uses: \./\." | grep -vE "@[0-9a-f]{40}" returns empty (exit 1) — no plain-tag pins remain on third-party actions. Full enumeration of uses: lines confirms:

  • All third-party uses: carry a SHA + # v<version> comment.
  • Local composites (./.github/actions/install-mcp-publisher) correctly NOT pinned (in-repo, reviewed on merge).
  • dependabot-changelog.yml (already pinned by PR #60) verified intact: actions/create-github-app-token@1b10c78c # v3.1.1, actions/checkout@de0fac2e # v6.0.2, dependabot/fetch-metadata@25dd0e34 # v3.1.0. Same actions/checkout SHA as the rest of the workflows — consistent.

YAML parse

All 8 workflow files (ci.yml, dependabot-changelog.yml, pr-labels-ci.yml, pr-labels.yml, publish.yml, qa-gate.yml, test-publish.yml, vdsm.yml) yaml.safe_load-clean.

vdsm flake context

Two empty retrigger commits (d99f3c3, 096b7bc) on the branch are CI-retry only. Commit messages document the failure as TestSearch::test_search_keyword_finds_directory — DSM Universal Search propagation latency variance, already documented in CLAUDE.md as a known flake; SHA pins resolve to identical underlying code as @v6/@v7/etc, so they can't be the cause. Confirmed by reading the workflow itself: vdsm.yml:27 continue-on-error: true — vdsm is non-blocking by design; the green status here is just the eventual successful retry, not a gate condition.

Local stack

  • uv run pytest → 599 passed, 112 deselected, 96.26% coverage. Identical to post-#92 baseline; PR doesn't touch any code paths.
  • uv run ruff check src/ tests/, mypy src/ clean.

Out-of-scope claims

PR body's "out of scope" list (local composites, dependabot-changelog already pinned, no-uses: workflows) verified by exhaustive grep -E "uses: " .github/workflows/*.yml enumeration — every external uses: line is now SHA-pinned, every local-composite uses: line is not, and pr-labels.yml / pr-labels-ci.yml / qa-gate.yml indeed have no uses: lines (run-step only).

Issue #46 ACs

  • AC 1 (SHA-pin third-party actions): ✓ — all 8.
  • AC 2 (Dependabot proposes bumps weekly): ✓ — relies on existing .github/dependabot.yml github-actions ecosystem entry, which works equivalently for SHA pins as it did for tag pins.

PR-body checkboxes

Boxes 1–3 flipped (CI green; YAML parse; audit grep). Box 4 (functional smoke via next Dependabot run) is post-merge — flips on its own when Dependabot opens its next bump PR.

Disposition

Ready for QA Signoff applied as the final act. With this in, #51's LOW/docs/chore queue is empty (#42 / #43 / #45 / #46 all cleared this cycle); only the architectural ADR (#47) and the post-baggage feature batch (#48–50) remain in the original tracker. Plus newer follow-ups #25 / #75 / #76 / #93.

@cmeans
Copy link
Copy Markdown
Owner

cmeans commented May 2, 2026

Applying Ready for QA Signoff — clean supply-chain hardening PR. All 8 PR-listed SHAs independently re-resolved against GitHub API and match exactly. Audit grep grep -rn "^\s*-\? *uses: " .github/workflows/ | grep -v "uses: \./\." | grep -vE "@[0-9a-f]{40}" returns empty — no plain-tag pins remain on third-party actions. yaml.safe_load clean on all 8 workflow files. Local composites correctly not pinned. dependabot-changelog.yml's already-pinned entries verified intact. Two empty retrigger commits document a known TestSearch vdsm-indexer flake (not blocking — vdsm has continue-on-error: true). Local 599/96.26% (post-#92 baseline preserved), CI 12/12 green incl. vdsm. Boxes 1-3 flipped; #4 (Dependabot bump smoke) is post-merge. Closes #46 — empties #51's LOW/docs/chore queue.

@cmeans cmeans added Ready for QA Signoff QA passed — ready for maintainer final review and merge QA Approved Manual QA testing completed and passed and removed QA Active QA is actively reviewing; Dev should not push changes Ready for QA Signoff QA passed — ready for maintainer final review and merge labels May 2, 2026
@cmeans-claude-dev cmeans-claude-dev Bot merged commit 79933a7 into main May 2, 2026
38 checks passed
@cmeans-claude-dev cmeans-claude-dev Bot deleted the chore/sha-pin-actions branch May 2, 2026 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

QA Approved Manual QA testing completed and passed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pin third-party GitHub Actions to commit SHAs (supply-chain hardening)

2 participants