Skip to content

ci: SHA-pin gate for GitHub Actions uses: refs (mache-b8900d)#470

Merged
jamestexas merged 2 commits into
mainfrom
dx/mache-b8900d-actions-pin-rule
Jul 2, 2026
Merged

ci: SHA-pin gate for GitHub Actions uses: refs (mache-b8900d)#470
jamestexas merged 2 commits into
mainfrom
dx/mache-b8900d-actions-pin-rule

Conversation

@jamestexas

Copy link
Copy Markdown
Contributor

Motivation

Dependabot bumps action refs but occasionally leaves a bare tag behind — it did on lfs-guard.yml in #457, caught only by hand. A bare tag (actions/checkout@v4) is a mutable, remotely-controlled pointer — a supply-chain foothold. This makes "all actions must be SHA-pinned" executable so the next one can't merge unnoticed.

Reframing vs the bead

mache-b8900d was filed as a find_smells rule, but find_smells is SQL-only over the parsed code .db, and workflow YAML isn't in that DB. A text rule would need a new engine rule-type — that's the larger mache-445887 ("find_smells as a standalone lint") work, out of scope here. So this delivers the value the way mache already does workflow/doc hygiene: a script + Taskfile target + CI wiring, mirroring scripts/docs-lint.sh.

Changes

  • scripts/actions-pin-lint.sh — flags any .github/workflows uses: ref whose @-suffix isn't a 40-hex SHA. Exempts local ./ composite refs and docker:// refs (different pinning format).
  • task actions:lint — wired into the check + ci aggregates and the GitHub CI lint job, so it gates PRs (taskfile-ci-parity: CI invokes the task target, not a re-implemented command).
  • Go tests (cmd/actions_pin_lint_test.go) — flags an unpinned ref, passes when pinned, exempts local/docker, and a live guard that the repo itself stays clean (a regression fails go test ./cmd/ too).

Pairs with actionlint (workflow syntax, mache-f60571); this is pinning.

Verification

  • task actions:lint → all refs SHA-pinned ✓ (incl. this PR's ci.yml edit)
  • go test ./cmd/ -run TestActionsPinLint → 3/3 pass
  • go vet + golangci-lint (pre-commit) → pass

Motivation: dependabot bumps action refs but occasionally leaves a bare tag
behind (it did on lfs-guard.yml in #457, caught only by hand). A bare tag is
a mutable, remotely-controlled pointer — a supply-chain foothold. This makes
the invariant executable so the next one can't merge unnoticed.

Reframing (vs the bead's original "find_smells rule" idea): find_smells is
SQL-only over the parsed code .db, and workflow YAML isn't in that DB — a
text rule would need a new engine rule-type (the larger mache-445887 work).
So this ships the value the way mache already does workflow/doc hygiene:
a script + Taskfile target + CI wiring, mirroring docs-lint.sh.

- scripts/actions-pin-lint.sh: flags any .github/workflows `uses:` ref whose
  @-suffix isn't a 40-hex SHA; exempts local (./) and docker:// refs.
- task actions:lint; wired into `check` + `ci` aggregates and the CI lint job
  (taskfile-ci-parity: CI invokes the task target).
- Go tests: flags unpinned, passes when pinned, and a live guard that the
  repo itself stays clean (fails `go test ./cmd/` on regression).

Pairs with actionlint (workflow syntax, mache-f60571); this is pinning.
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

find_smells (advisory)

Scoped to files changed in this PR. Rules below run on the standalone (no-LLO) cross-ref tables; _ast rules (cyclomatic_complexity, long_function, long_file, magic_int_in_comparison) are not exercised here.

No structural smells in changed files. ✓

Rules: the registry is cmd/smell_rules.go (source of truth); see the authoring guide to add one. Advisory only — these are heuristics, not gates.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a repo-enforced gate to ensure all GitHub Actions uses: references in .github/workflows/ are pinned to immutable identifiers, reducing supply-chain risk from mutable tags.

Changes:

  • Add scripts/actions-pin-lint.sh to detect non–SHA-pinned uses: refs under .github/workflows/.
  • Wire the lint into Taskfile (actions:lint) and aggregate gates (check and ci), and add it to the GitHub Actions CI lint job.
  • Add Go tests to validate the lint behavior and add a “repo stays clean” guard test.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
Taskfile.yml Adds actions:lint task and runs it as part of check and ci aggregates.
scripts/actions-pin-lint.sh Implements the workflow uses: pinning lint logic.
cmd/actions_pin_lint_test.go Adds unit tests and a repo-clean regression guard for the lint script.
.github/workflows/ci.yml Runs task actions:lint in the lint job to gate PRs in CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/actions-pin-lint.sh
Comment thread scripts/actions-pin-lint.sh Outdated
Comment thread scripts/actions-pin-lint.sh Outdated
…, portable grep, case-insensitive SHA

- Docker refs are no longer blanket-exempt: require docker://img@sha256:<64-hex>;
  a mutable docker tag is now flagged (was a supply-chain hole the comment
  claimed was covered).
- Replace GNU-only `grep -r --include` with portable `find … -exec grep -H`
  (BSD/macOS-safe, since this runs locally via task check/ci).
- Accept uppercase SHAs ([0-9a-fA-F]) for both 40-hex commit and 64-hex digest.
- Tests updated: mutable docker tag flagged; uppercase-SHA + docker-digest pass.
@jamestexas jamestexas enabled auto-merge (squash) July 2, 2026 01:00
@jamestexas jamestexas merged commit 192a779 into main Jul 2, 2026
15 checks passed
@jamestexas jamestexas deleted the dx/mache-b8900d-actions-pin-rule branch July 2, 2026 01:00
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