Skip to content

chore(ci): add zizmor workflow for github actions security analysis#471

Merged
jdx merged 3 commits into
mainfrom
ci/add-zizmor
May 12, 2026
Merged

chore(ci): add zizmor workflow for github actions security analysis#471
jdx merged 3 commits into
mainfrom
ci/add-zizmor

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented May 12, 2026

Adds zizmor to audit GitHub Actions workflows for security issues. Runs on push to main and on PRs that change .github/workflows/**. Fails CI on any finding.

🤖 Generated with Claude Code


Note

Medium Risk
Mostly CI/workflow hardening, but it also changes release automation (postversion.sh) and workflow permissions/credentials behavior, which could break tagging/publishing if misconfigured.

Overview
Adds a new zizmor workflow that runs on PRs/pushes touching .github/workflows/** to security-audit workflows.

Hardens existing workflows by defaulting to least-privilege permissions, setting actions/checkout to persist-credentials: false, and adjusting related behavior (e.g., scripts/postversion.sh now runs gh auth setup-git so git push still works; ci.yml disables mise-action caching; test.yml avoids interpolating steps.bad.outcome inside a shell string by passing it via env).

Reviewed by Cursor Bugbot for commit d878aee. Bugbot is set up for automated code reviews on this repo. Configure here.

@gemini-code-assist
Copy link
Copy Markdown

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 12, 2026

Greptile Summary

This PR adds a zizmor GitHub Actions security audit workflow and applies its findings across all existing workflows: adding persist-credentials: false to every checkout, tightening permissions to contents: read where possible, and fixing a script injection in test.yml.

  • New zizmor.yml: correctly scoped to .github/workflows/** on both push and pull_request triggers, uses pinned action SHAs, and runs with minimal permissions.
  • Security hardening across workflows: persist-credentials: false added to all checkout steps; postversion.sh compensates with gh auth setup-git before git operations.
  • release-plz.yml: receives persist-credentials: false but no corresponding credential setup, unlike postversion.sh which documents and fixes the same problem.

Confidence Score: 4/5

Safe to merge for all workflows except release-plz, where the credential fix applied to postversion.sh was not applied to the release-plz run that also pushes branches.

postversion.sh explicitly documents that persist-credentials: false breaks raw git push and adds gh auth setup-git as the fix. release-plz does the same kind of git push to create a PR branch, but the matching credential-setup step was not added, so the next release-plz run is likely to 403.

.github/workflows/release-plz.yml needs a gh auth setup-git step (or equivalent) before mise run release-plz.

Important Files Changed

Filename Overview
.github/workflows/zizmor.yml New zizmor security audit workflow; properly scoped with paths filter on both triggers, pinned SHAs, minimal permissions, and persist-credentials: false
.github/workflows/release-plz.yml Adds persist-credentials: false but omits the gh auth setup-git step that postversion.sh requires for the same reason — release-plz needs to git push a branch and will 403
scripts/postversion.sh Adds gh auth setup-git before git push operations to compensate for persist-credentials: false on checkout; well-explained in comments
.github/workflows/release.yml Moves permissions to job level, adds persist-credentials: false; release job uses gh auth setup-git via postversion.sh; enhance-release uses a PAT so contents: read is sufficient
.github/workflows/test.yml Adds persist-credentials: false to all checkout steps and fixes a script injection by moving steps.bad.outcome into an env var
.github/workflows/ci.yml Adds top-level contents: read permission and persist-credentials: false; also disables mise-action cache
.github/workflows/check-dist.yml Adds persist-credentials: false to checkout step
.github/workflows/codeql-analysis.yml Adds persist-credentials: false to checkout step
.github/workflows/test-redacted-env.yml Adds top-level contents: read permission and persist-credentials: false

Comments Outside Diff (1)

  1. .github/workflows/release-plz.yml, line 31-34 (link)

    P1 Missing credential setup before release-plz git push

    persist-credentials: false removes the git credential helper that actions/checkout would normally set up. release-plz creates a release PR by pushing a branch to GitHub — without the credential helper, that git push will 403. postversion.sh explicitly documents this exact problem and fixes it with gh auth setup-git before any git push. The same fix is needed here, added as a step before mise run release-plz.

    Fix in Claude Code

Fix All in Claude Code

Reviews (3): Last reviewed commit: "ci: address zizmor findings across exist..." | Re-trigger Greptile

Comment thread .github/workflows/zizmor.yml
Comment thread .github/workflows/zizmor.yml
Comment thread .github/workflows/zizmor.yml
jdx and others added 2 commits May 12, 2026 13:51
Address review feedback on PR #471.

- Add paths filter to the push trigger so the job only runs when
  workflow files change on main (matches the pull_request trigger).
- Set advanced-security: false on zizmor-action. With the default
  true, the action runs codeql-action/upload-sarif which needs
  security-events: write — the job only grants contents: read.
  Disabling it also makes zizmor's exit code drive CI failure,
  matching the "fails CI on any finding" intent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves all findings exposed by the new zizmor check in PR #471
so the audit can run clean. Verified locally with zizmor v1.24.1
(0 findings, 34 suppressed).

- artipacked: add `persist-credentials: false` to every
  `actions/checkout` step that didn't already set it.
- cache-poisoning: pass `cache: false` to mise-action in
  `ci.yml` (the lint/format job doesn't need a tool cache).
- template-injection: in test.yml's checksum_failure job,
  move `steps.bad.outcome` from inline template into an
  env var consumed by the shell script.
- excessive-permissions: add minimal workflow-level
  `permissions: contents: read` blocks to ci.yml, test.yml,
  and test-redacted-env.yml; move release.yml's workflow-
  level `contents: write` down to the `release` job only,
  with `enhance-release` getting `contents: read`.

postversion.sh now runs `gh auth setup-git` before
`git push` — the checkout uses `persist-credentials: false`,
so the token isn't in .git/config and raw `git push` would
otherwise 403.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdx jdx merged commit 46bb674 into main May 12, 2026
19 checks passed
@jdx jdx deleted the ci/add-zizmor branch May 12, 2026 20:00
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d878aee. Configure here.

fetch-depth: 0
submodules: recursive
token: ${{ secrets.RELEASE_PLZ_GITHUB_TOKEN }}
persist-credentials: false
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing gh auth setup-git breaks git push in release-plz

High Severity

Adding persist-credentials: false to the checkout in release-plz.yml removes stored git credentials, but scripts/release-plz.sh calls git push origin release --force which requires them. Unlike scripts/postversion.sh, which was updated with gh auth setup-git to restore credential access, release-plz.sh has no equivalent workaround. This will cause the release automation to fail with a 403 on every git push.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d878aee. Configure here.

jdx added a commit that referenced this pull request May 12, 2026
## Summary
- Follow-up to [#471](#471): the
release-plz checkout now uses `persist-credentials: false`, so the token
isn't written to `.git/config` and `git push origin release --force` in
[scripts/release-plz.sh](scripts/release-plz.sh) would 403.
- Mirror the workaround already applied to
[scripts/postversion.sh:9](scripts/postversion.sh:9) by calling `gh auth
setup-git` after the `git config user.{name,email}` block, before any
`git push`.

Flagged by Cursor Bugbot on
#471 (review).

## Test plan
- [ ] Next scheduled release-plz run (or manual `workflow_dispatch`)
successfully pushes the `release` branch without a 403.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk CI-only change that affects the release automation path; main
impact is whether the workflow can successfully push the `release`
branch.
> 
> **Overview**
> Fixes the `scripts/release-plz.sh` release automation to run `gh auth
setup-git` after setting the git author, ensuring `git push` works when
`actions/checkout` uses `persist-credentials: false`.
> 
> This prevents 403 failures when pushing the forced `release` branch
during automated version bump PR creation.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f694191. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdx jdx mentioned this pull request May 12, 2026
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.

1 participant