Skip to content

Pin GitHub Actions to commit SHAs and add zizmor to CI #124

Description

@randomparity

Problem

All 8 GitHub Actions references in this repo ride mutable major tags (@v6/@v7). A tag is a movable pointer: whoever controls the action's repository can repoint it at new code, which then executes inside our CI with that workflow's token. sync-wiki.yml runs with contents: write and secrets.WIKI_TOKEN, so that is the blast radius of a compromised upstream tag.

zizmor is not run anywhere — not in CI, not in pre-commit — so nothing catches this today or prevents a regression tomorrow.

Evidence

zizmor .github/workflows/ on main (8aaee26) reports 17 findings: 8 x unpinned-uses (High), 4 x excessive-permissions (Medium), 5 x artipacked (Low).

Unpinned action references (High):

  • .github/workflows/lint.yml:16actions/checkout@v6
  • .github/workflows/lint.yml:19actions/setup-python@v6
  • .github/workflows/test.yml:16actions/checkout@v6
  • .github/workflows/test.yml:19actions/setup-python@v6
  • .github/workflows/test.yml:39actions/checkout@v6
  • .github/workflows/test.yml:42actions/setup-python@v6
  • .github/workflows/sync-wiki.yml:18actions/checkout@v6
  • .github/workflows/sync-wiki.yml:21actions/checkout@v6

Excessive permissions (Medium) — no permissions: block, so the job inherits the default token scope:

  • .github/workflows/lint.yml:12 (lint)
  • .github/workflows/test.yml:2 (workflow level)
  • .github/workflows/test.yml:12 (pytest)
  • .github/workflows/test.yml:29 (molecule)

Credential persistence (Low) — checkout leaves the token in .git/config because persist-credentials: false is not set:

  • .github/workflows/lint.yml:15
  • .github/workflows/test.yml:15
  • .github/workflows/test.yml:38
  • .github/workflows/sync-wiki.yml:17
  • .github/workflows/sync-wiki.yml:20

No zizmor anywhere: .github/workflows/ contains only lint.yml, test.yml, sync-wiki.yml; lint.yml:32-48 runs yamllint, ansible-lint, and a playbook syntax check. .pre-commit-config.yaml has no zizmor or actionlint hook.

Expected

Every action reference is pinned to a full commit SHA with a trailing version comment, and zizmor runs in CI failing the build on High-severity findings.

Proposed approach

  1. Pin all 8 references to full SHAs with a version comment, e.g.
    uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7

  2. Add the helpers:pinGitHubActionDigests preset to extends in renovate.json5:3-5. Renovate then keeps the digests current, and the existing automerge rule already lists digest in matchUpdateTypes, so digest refreshes merge themselves without adding review burden.

  3. Add a zizmor step to lint.yml.

  4. Add least-privilege permissions: blocks to the three jobs that lack them, and persist-credentials: false to the checkouts that do not push.

    Do not set persist-credentials: false on .github/workflows/sync-wiki.yml:20 — those persisted credentials are exactly what git push at .github/workflows/sync-wiki.yml:45 relies on. zizmor offers an auto-fix here that would break the wiki sync.

Notes

Extends the pinning precedent from #14 (container image versions) to the CI supply chain.

Filed from the review of #122 and #123, where these were recorded as pre-existing findings out of scope for a version bump. Both PRs touch every line listed above; merge them first or this work will conflict.

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort:MMedium — a session or twopriority:P2Medium prioritytype:choreMaintenance, CI, tooling, dependencies

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions