Skip to content

fix(security): SHA-pin all third-party GitHub Actions in reusable workflows#27

Merged
muntianus merged 1 commit into
mainfrom
claude/security-fix-pin-actions-2UIPT
May 30, 2026
Merged

fix(security): SHA-pin all third-party GitHub Actions in reusable workflows#27
muntianus merged 1 commit into
mainfrom
claude/security-fix-pin-actions-2UIPT

Conversation

@muntianus
Copy link
Copy Markdown
Owner

Summary

Addresses Medium F-001 from the audit landed in #25 — biggest leverage point in the second wave because reusable workflows here are consumed by every muntianus/* repo via @main.

A tag-pinned third-party action upstream that goes hostile would execute in every consumer's CI with whatever secrets the consumer forwards: VPS_SSH_KEY, ANTHROPIC_API_KEY, GITHUB_TOKEN. Replacing every uses: …@vN with uses: …@<40-char-sha> # vN closes that vector.

Changes

  • All uses: directives in .github/workflows/{claude,governance-ops,openapi-sync,reusable-ci-go,reusable-ci-node,reusable-deploy-vps,reusable-security-gate,update-profile-readme}.yml now reference a 40-char commit SHA, with the moving tag preserved in a trailing comment so bumps stay reviewable.

  • AGENTS.md hard-rule Org foundation pack: reusable workflows + agent guidance #3 tightened: SHA-pin third-party actions is now an org-wide expectation, with the git ls-remote verification command inline so future bumps don't drift.

Actions pinned

Action Tag SHA
actions/checkout v4 34e114876b0b11c390a56381ad16ebd13914f8d5
actions/checkout v5 93cb6efe18208431cddfb8368fd83d5badbf9bfd
actions/setup-go v6 4a3601121dd01d1626a1e23e37211e3254c1c06c
actions/setup-node v6 48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
actions/setup-python v5 a26af69be951a213d495a4c3e4e4022e16d87065
actions/upload-artifact v4 ea165f8d65b6e75b540449e92b4886f43607fa02
anthropics/claude-code-action v1 537ffff2eff706bd7e3e1c3daf2d4b39067a9f85
appleboy/scp-action v0.1.7 917f8b81dfc1ccd331fef9e2d61bdc6c8be94634
appleboy/ssh-action v1.2.0 7eaf76671a0d7eec5d98ee897acda4f968735a17
golangci/golangci-lint-action v7 9fae48acfc02a90574d7c304a1758ef9895495fa

Test plan

  • actionlint -no-color .github/workflows/*.yml clean.
  • rg "uses: [^./]+@v[0-9]" .github/workflows/ returns empty — no tag-pinned external actions left.
  • Reviewer: spot-check one or two SHAs against the upstream repos (e.g. git ls-remote https://github.com/appleboy/ssh-action refs/tags/v1.2.0).

Follow-up (separate PR)

F-002 from the same audit: this repo still has no release tag. Downstream consumers reference @main, so a merge here ships immediately org-wide. After this lands, cut v1.0.0 and migrate consumers to @v1.0.0 (or its SHA).

https://claude.ai/code/session_01NXqUreamtsrtqYAVBURZY4


Generated by Claude Code

…kflows

Addresses Medium F-001 from docs/security/audit-2026-05.md (PR
#25). Reusable workflows in this repo are consumed by every
muntianus/* repo via @main, so a tag-pinned third-party action
upstream that goes hostile would execute in every consumer's CI
with the secrets that consumer forwards (VPS_SSH_KEY,
ANTHROPIC_API_KEY, GITHUB_TOKEN). Replacing every `uses: …@vN`
with `uses: …@<40-char-sha> # vN` closes that vector.

Actions pinned (SHA resolved from
`git ls-remote https://github.com/<org>/<action> refs/tags/<tag>`):

  actions/checkout                 v4, v5
  actions/setup-go                 v6
  actions/setup-node               v6
  actions/setup-python             v5
  actions/upload-artifact          v4
  anthropics/claude-code-action    v1
  appleboy/scp-action              v0.1.7
  appleboy/ssh-action              v1.2.0
  golangci/golangci-lint-action    v7

Also tighten the org rule in AGENTS.md so consumers know SHA-
pinning is the standard and how to verify when bumping.

`actionlint -no-color .github/workflows/*.yml` clean.

Followup: cut a v1 release tag on this repo and migrate
downstream consumers from `@main` references to `@v1` (F-002 in
the same audit).

https://claude.ai/code/session_01NXqUreamtsrtqYAVBURZY4
@muntianus muntianus merged commit deb9a4d into main May 30, 2026
1 check passed
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates AGENTS.md to document a rule requiring SHA-pinning for third-party GitHub Actions. The review feedback correctly points out that using git ls-remote directly on refs/tags/<tag> can return the tag object's SHA instead of the dereferenced commit SHA for annotated tags, which would cause GitHub Actions to fail. It suggests updating the command to query refs/tags/<tag>\* to ensure the correct commit SHA is retrieved.

Comment thread AGENTS.md
Comment on lines +37 to +38
reusables already follow this — keep it that way when bumping. Verify
the SHA with `git ls-remote https://github.com/<org>/<action> refs/tags/<tag>`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If a tag is an annotated tag (which is common for release tags), querying refs/tags/<tag> directly with git ls-remote will only return the tag object's SHA, not the actual commit SHA. GitHub Actions require the actual commit SHA to run; using the tag object's SHA will cause the workflow to fail.

Using a wildcard \* (or querying refs/tags/<tag>^{}) ensures you can see and copy the dereferenced commit SHA (marked with ^{}).

Suggested change
reusables already follow this — keep it that way when bumping. Verify
the SHA with `git ls-remote https://github.com/<org>/<action> refs/tags/<tag>`.
reusables already follow this — keep it that way when bumping. Verify
the commit SHA with <code>git ls-remote https://github.com/<org>/<action> refs/tags/<tag>\*</code> (use the dereferenced ^{} SHA for annotated tags).

muntianus added a commit that referenced this pull request May 30, 2026
…29)

Architectural design for cutting v1.0.0 on this repo and migrating
consumers from raw-SHA pinning (post #27) to the hybrid pattern
@<sha> # v1.0.0. Hybrid is the only strategy that's positive across
immutable-execution, readable-diff, Dependabot-friendly, and tag-
rewrite-resistant — see comparison table.

Key decisions:
- Cut v1.0.0 + push floating v1 major; release-please with
  release-type: simple owns subsequent versioning from Conventional
  Commits.
- Consumers pin @<sha> # v1.0.0; Dependabot rewrites BOTH lines on
  bump since dependabot-core PR #5951 (2024).
- v* tags protected via rulesets (legacy tag-protection-rules
  deprecated): restrict creation/update/deletion, bypass = repo admins
  only.
- Defines what counts as a "breaking change" for a reusable workflow
  (inputs/secrets/outputs/permissions/observable side effects).
- Honest critique: hybrid wins for our 5-consumer scale; raw @v1 is
  unacceptable for workflows that handle secrets (tj-actions/changed-
  files March 2025 incident as reference).

Includes:
- 8-step one-shot rollout checklist (Conventional Commits adoption →
  release-please wiring → v1.0.0 cut → floating v1 → ruleset → 5
  consumer PRs → Dependabot enablement)
- release-please.yml workflow skeleton with floating-v1-tag move step
- per-consumer dependabot.yml skeleton with grouped bumps under
  muntianus-workflows pattern
- ongoing release process narrative

No automation wired yet — that's the PR after this design lands.

https://claude.ai/code/session_01NXqUreamtsrtqYAVBURZY4

Co-authored-by: claude <noreply@anthropic.com>
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