[ci] zizmor: security-lint GitHub Actions workflows (high-severity gate)#64
Merged
Conversation
6a208c1 to
69297f1
Compare
Wires zizmor (https://github.com/zizmorcore/zizmor) into `make ci` as a security-lint gate over `.github/workflows/`. Gates at `--min-severity=high` — the dangerous classes (template injection, untrusted input in run-blocks, over-broad permissions) — with lower-confidence findings tracked in FOLLOWUPS for incremental hardening. Audit + findings — 39 total in the v1.25.2 dry-run: Severity Audit Count -------- ------------------------ ----- High template-injection 1 ← FIXED INLINE High cache-poisoning 2 ← ignored with rationale Medium ref-version-mismatch 1 ← deferred (cosmetic) Low artipacked 18 ← deferred (defensive) Info template-injection 1 ← deferred (low confidence) Inline fix (the one dangerous finding): - `release.yml:45` — `tag="${{ inputs.tag }}"` was a textbook template-injection vector: the GitHub-side `${{ }}` interpolates the input value into the shell command BEFORE the shell sees it, bypassing shell quoting entirely. Reworked to pass via `env: INPUT_TAG: ${{ inputs.tag }}` so the shell quotes the value itself via `$INPUT_TAG`. zizmor audit-confidence: High; the only finding this PR fixes inline. Accept-the-risk ignores (`.github/zizmor.yml`): - Two `actions/setup-go@... with: cache: true` cache-poisoning warnings in `release.yml` (verify + build jobs). Both are zizmor-confidence-Low; the cache is keyed on go.sum which is the same trust root the M3 reproducible-rebuild + cosign + SLSA provenance chain already validates. Reverting `cache: true` adds ~30s per release with no integrity improvement. Deferred (separate FOLLOWUPS row) — the 18 low + 1 medium + 1 info findings are defensive hardening, not blockers. Cleanest path: lift the gate to `--min-severity=medium` then `low` one tier at a time in focused PRs. Install + invocation: - Local (macOS): `brew install zizmor` (1.25.2). - Local (Linux): `pip install zizmor==1.25.2`. - CI: pinned to v1.25.2 via `pip install --user` in the verify job. - `scripts/zizmor.sh` pins the invocation: `--config .github/zizmor.yml --min-severity=high --no-progress`. Closes the zizmor half of the FOLLOWUPS "CI Actions linters" row. actionlint half remains open (separate PR #62 in flight). Verification: - Dry-run: 39 total findings → after fix + ignores, 0 high. - `make zizmor` exit 0 (22 ignored, 16 suppressed, 0 high). - `make ci` exit 0 end-to-end (kernelevents test had one transient flake on first run; passed on retry). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Tri Lam <trilamsr@gmail.com>
Adds a `## [Unreleased] > ### Security` entry covering the user-visible security improvement that lands with this PR: the new `make zizmor` gate, the inline template-injection fix at release.yml:45, the two accept-the-risk inline ignores on the cache-poisoning warnings, and the FOLLOWUPS deferral for the 20 lower-severity findings. Mirrors the format of the SHA-pin + cosign-tightening entries that landed alongside the omnibus follow-ups PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Tri Lam <trilamsr@gmail.com>
e529eed to
47d5f26
Compare
This was referenced May 19, 2026
trilamsr
added a commit
that referenced
this pull request
May 19, 2026
## What this PR does Follow-up to #64 (zizmor security-lint gate). Trims comments that didn't pass the six-months-cold-reader test. The commit was prepared on the #64 branch but pushed seconds after that PR auto-merged, so it never made it in — re-applying as a standalone follow-up. Comments trimmed: - `scripts/zizmor.sh`: dropped per-flag descriptions in the header block — `--no-progress` and `--config` don't need explainers; the WHY for `--min-severity=high` stays. Also fixed a stale error- message prefix copied from register-lint. - `.github/zizmor.yml`: 6 lines → 3. Kept the one load-bearing claim ("ignores live inline"). - `release.yml` cache-poisoning ignores: 6 lines → 2. Kept the WHY (cache keyed on go.sum, trust root M3 already validates); dropped the meta-pointer to zizmor.yml (which no longer carries the rationale) and the audit-confidence parens. - `release.yml` INPUT_TAG env comment: 4 lines → 2. No behavior change. `make ci` exit 0 (one transient kernelevents flake on first run, passed on retry — same intermittent test seen in this session's PRs #55, #60, #62, #63, #64). ## Linked issue(s) _No linked issue._ Follows up #64. ## Release notes ```release-notes NONE ``` ## Checklist - [x] `make ci` exit 0 - [x] No behavior change; pure documentation hygiene - [x] Commits are signed off 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Tri Lam <trilamsr@gmail.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
trilamsr
added a commit
that referenced
this pull request
May 19, 2026
#68) ## What this PR does Two small fixes that turn this session's lessons into code instead of notes-to-self: ### 1. Deflake `TestJournaldSource_StreamsMockOutput` The 2s deadline for the mock-journalctl test was tight on loaded macOS / CI runners — subprocess spawn + fixture read + goroutine schedule could miss it. The test flaked on 5 of 5 PRs in this session that exercised the full suite (#55, #60, #62, #63, #64). Bumped the deadline 2s → 5s. The non-flake budget for "no record ever emitted" regressions stays well under the deadline; 5s just absorbs runner jitter without hiding real bugs. ### 2. Warn locally when `shellcheck` isn't on PATH `actionlint` silently skips run-block shellcheck when shellcheck isn't on PATH (macOS doesn't ship shellcheck by default). PR #62 passed `make actionlint` locally and then surfaced 4 shellcheck findings in CI — exactly the failure mode the gate is supposed to prevent. `make actionlint` now prints a `WARNING: shellcheck not on PATH; actionlint will skip run-block shellcheck.` line with `brew install` / `apt-get install` hints when the binary is missing. The underlying lint still runs; the warning just makes the gap visible to the macOS dev. ## Linked issue(s) _No linked issue._ ## Release notes ```release-notes NONE ``` ## Checklist - [x] `make ci` exit 0 (test passes deterministically with new deadline) - [x] `make actionlint` shows the warning when shellcheck is uninstalled (verified locally) - [x] No behavior change in CI (shellcheck already on Linux runners) - [x] Commits are signed off 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Tri Lam <trilamsr@gmail.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Wires zizmor into
make cias a security-lint gate over
.github/workflows/. Gates at--min-severity=high— the dangerous classes (template injection,untrusted input in run-blocks, over-broad permissions) — with
lower-confidence findings tracked in FOLLOWUPS for incremental
hardening.
Audit + findings (39 total in v1.25.2 dry-run)
template-injectionrelease.yml:45)cache-poisoning# zizmor: ignore[cache-poisoning]comments with rationaleref-version-mismatchartipackedtemplate-injectionThe one dangerous finding (fixed)
release.yml:45hadtag="${{ inputs.tag }}"— textbooktemplate-injection: GitHub interpolates
${{ }}into the shellcommand BEFORE the shell sees it, bypassing shell quoting entirely.
Reworked to pass via env var so the shell quotes the value itself.
zizmor audit-confidence: High; the only finding this PR fixes inline.
Accept-the-risk ignores
Two
actions/setup-go@... with: cache: truecache-poisoning warningsin
release.yml(verify + build jobs). Both ignored with rationalevia inline
# zizmor: ignore[cache-poisoning]comments on thecache: trueline — inline ignores move with the surrounding code,so future edits to the workflow don't reactivate the warning at a
shifted line number.
.github/zizmor.ymlcarries project-wide configonly.
Rationale: both are zizmor-confidence-Low; the cache is keyed on
go.sumwhich is the same trust root the M3 reproducible-rebuild +cosign + SLSA provenance chain already validates. Reverting
cache: trueadds ~30s per release with no integrity improvement.Deferred (separate FOLLOWUPS row)
The 18 low + 1 medium + 1 info findings are defensive hardening, not
blockers. Cleanest path: lift the gate to
--min-severity=mediumthen
lowone tier at a time in focused PRs. Trigger: when the M21supply-chain audit asks for it OR when external contributor onboarding
raises an Actions-security concern.
Install + invocation
brew install zizmor(1.25.2)pip install zizmor==1.25.2pip install --user;$HOME/.local/binappended to$GITHUB_PATHafter install so the next step finds the binaryscripts/zizmor.shpins--config .github/zizmor.yml --min-severity=high --no-progressCloses the FOLLOWUPS "CI Actions linters" row. Both halves now landed
— actionlint via #62, zizmor via this PR.
Linked issue(s)
No linked issue.
Release notes
Checklist
make zizmorexit 0 (22 ignored, 16 suppressed, 0 high findings)make ciexit 0 end-to-end (rebased onto post-[ci] actionlint: wire as a make ci gate via the go.mod tool stanza #62 main; both actionlint + zizmor in the chain).github/zizmor.ymlentries)## [Unreleased] > ### Securityentry addedTest plan
${{ ... }}directly in arun:block (or other high-severity zizmor audit class) fails CI🤖 Generated with Claude Code