Skip to content

feat: pin actions to SHAs and gate the repo with zizmor - #3

Merged
mdozhdev merged 2 commits into
mainfrom
feat/pin-actions-and-gate
Sep 4, 2026
Merged

feat: pin actions to SHAs and gate the repo with zizmor#3
mdozhdev merged 2 commits into
mainfrom
feat/pin-actions-and-gate

Conversation

@mdozhdev

@mdozhdev mdozhdev commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Part of pubky/pubky-stack#281 — the "use hashes instead of versions" and "add scanners like zizmor" bullets.

Why

Every uses: reference in this repo resolved a mutable name. A tag is a label its owner can move; @main moves on every push. That is the tj-actions/changed-files failure mode, where moved tags leaked secrets from tens of thousands of repositories.

It matters more here than in a normal repo: 25 uses: references across 8 repositories consume this one at @main, and main currently has no protection and no rulesets.

What changed

Removed the transitive @main. build_and_push called get_head_commit_hash@main, so even a consumer pinning build_and_push to a SHA would still have pulled a floating ref through it. Those four lines of git rev-parse HEAD are now inline.

get_head_commit_hash itself stays — it has three external callers (pubky-app ×2, pubky-stack ×1) — and is marked deprecated in its description rather than deleted.

Pinned the five docker/* actions to commit SHAs, at their current major rather than the latest. Every one of them is a full major behind (v3→v4.3.0, v5→v6.2.0, v6→v7.3.0), so pinning current means this PR carries zero behaviour change. The upgrades arrive afterwards as separate, reviewable Dependabot PRs instead of riding along inside a security change.

Added Dependabot with a 7-day cooldown. A SHA pin without a bump bot is just a frozen vulnerable version; a bump bot without a cooldown proposes a freshly published release on the day it lands, which is the attack path above. (zizmor flagged the missing cooldown on my first attempt at this file — a fair demonstration of the check earning its place.)

Hoisted 11 shell interpolations out of run: blocks. ${{ inputs.x }} is pasted in as text before bash parses it, so whoever controls the value controls the script. All now pass through env: and are referenced as quoted variables.

Added zizmor as a blocking check, pinned to 1.30.0. Not latest — on a floating version, an upstream release that adds an audit turns this repo red with nobody having changed anything, and with a required check that is the merge queue down.

Verification

zizmor reports zero findings on this branch in online mode, against 18 findings on main (11 template-injection, 7 unpinned-uses, all High):

docker run --rm -e GH_TOKEN="$(gh auth token)" -v "$PWD:/src:ro" -w /src \
  ghcr.io/zizmorcore/zizmor:1.30.0 .

The check running on this PR is itself the proof the gate works.

Follow-ups, not in this PR

  • The check needs a ruleset to mean anything. main has no branch protection, so a required check can currently be pushed straight past. Filed separately — needs admin.
  • SARIF upload needs security-events: write, which fork PRs do not receive. If the check fails on an outside contribution, that is why.
  • Whether Dependabot picks up composite actions via the directories glob only shows on the first scheduled run. Renovate is the fallback if it misses them.
  • Consumers stay on @main for now; tagging and migration are a later round.

🤖 Generated with Claude Code

Every uses: reference here resolved a mutable name, in a public repo whose
main branch has no protection and which 25 call sites across 8 repositories
consume at @main.

- inline get_head_commit_hash into build_and_push, removing the transitive
  @main reference a consumer could not pin past
- pin the five docker/* actions to commit SHAs at their current major, so
  the change carries no behaviour difference; upgrades arrive as separate
  Dependabot PRs
- add Dependabot with a 7-day cooldown, so a pinned SHA does not become a
  frozen vulnerable version and a fresh release is never proposed on the
  day it lands
- hoist 11 shell interpolations of ${{ inputs.* }} into env: blocks
- add zizmor as a blocking check, pinned to 1.30.0 so an upstream release
  adding an audit cannot turn the repo red on its own

zizmor reports zero findings on this branch, online mode.

get_head_commit_hash stays in place, deprecated: it has three external
callers in pubky-app and pubky-stack.

Refs: pubky/pubky-stack#281

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

The hardening commit rewrote shell in all four actions and swapped six
action references for SHAs, but nothing in CI ever invoked them - only
zizmor ran. This builds a trivial image through build_and_push with
push disabled, on amd64 and on amd64+arm64, so the inlined commit-hash
step, the cache-value shell, the QEMU path and every pinned action are
executed rather than merely reviewed.

check_if_image_exists is asserted both ways against a public image.
get_head_commit_hash is covered because three consumers still call it.

registry_login is not covered: it cannot run without real registry
credentials.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mdozhdev
mdozhdev merged commit e6d3b38 into main Sep 4, 2026
6 checks passed
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