Skip to content

CI hardening: make workflows statically verifiable (zizmor)#2281

Open
maresb wants to merge 8 commits into
pymc-devs:mainfrom
maresb:worktree-fix-code-scanning
Open

CI hardening: make workflows statically verifiable (zizmor)#2281
maresb wants to merge 8 commits into
pymc-devs:mainfrom
maresb:worktree-fix-code-scanning

Conversation

@maresb

@maresb maresb commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Clears all 10 open code-scanning (zizmor) alerts, plus the pedantic-persona findings so the workflows are fully statically verifiable.

"Hardening" here means making the workflows pass zizmor cleanly — not substantially changing runtime behavior. Every change is either a no-op at runtime or a like-for-like refactor:

  • persist-credentials: false on the slow-tests checkout (that job uses github.token, not the persisted git credential).
  • Dependabot cooldown (7 days).
  • Explicit least-privilege permissions: top-level permissions: {} + per-job grants (replaces the implicit broad default; behavior unchanged for the token scopes actually used).
  • Same-line permission explanation comments.
  • Concurrency blocks (cancel-in-progress: true on mypy; false on the scheduled slow-tests / numba-bump jobs so they're never killed mid-run).
  • Explicit job names (name == id, so no check-run names change → required checks unaffected).
  • zizmor.yml switched to the official zizmorcore/zizmor-action (defaults preserve current behavior).
  • pypi.yml: compute should_run directly in the job output instead of an echo-to-$GITHUB_OUTPUT step (also drops the shell block carrying the benign template-injection finding).

One commit per fix type. Both zizmor personas (default + pedantic) report zero findings; pypi.yml and zizmor.yml verified against online audits too.

🤖 Generated with Claude Code

maresb and others added 8 commits July 9, 2026 17:09
Avoid persisting the GitHub credential in the local git config after
checkout (zizmor: artipacked). The job authenticates its issue-updating
script via github.token in env, not the persisted git credential.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reduce exposure to freshly-published compromised or yanked versions
(zizmor: dependabot-cooldown).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the default (broad) GITHUB_TOKEN permissions with an explicit
top-level 'permissions: {}' deny-all, granting each job only what it
needs (zizmor: excessive-permissions):

- test.yml: per-job 'contents: read' on the jobs that check out code.
- mypy.yml: 'contents: read' on the mypy job.
- slow-tests-issue.yml: move 'issues: write' from workflow level to the
  update-comment job.
- numba-upper-bound.yml: move 'contents: write' / 'pull-requests: write'
  from workflow level to the bump job.

Top-level '{}' means a newly added job inherits no permissions unless it
opts in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Give every job-level permission an explanatory same-line comment
(zizmor: undocumented-permissions). For pypi.yml this moves the existing
above-the-block comments onto each grant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a concurrency block so redundant runs are handled (zizmor:
concurrency-limits):

- mypy.yml: cancel-in-progress on new pushes to the same PR/branch,
  mirroring test.yml (saves CI minutes).
- slow-tests-issue.yml, numba-upper-bound.yml: serialize with
  cancel-in-progress: false so a scheduled issue update / commit-and-PR
  is never killed mid-run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Name the previously-anonymous jobs (zizmor: anonymous-definition). Names
match the job id (or an existing style), so no check-run names change and
branch-protection required checks are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switch zizmor.yml to the recommended workflow from
https://docs.zizmor.sh/integrations/, pinned to zizmor-action v0.5.7.
Defaults preserve current behavior: version=latest, online-audits=true
(via the workflow token), advanced-security=true (SARIF upload to code
scanning), inputs='.', persona=regular. Replaces the manual
setup-cached-uv + uvx + codeql upload-sarif steps.

The recommended workflow also ships a top-level 'permissions: {}',
scoped+documented job grants, and (added here) a concurrency block, so
the file is pedantic-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dedicated 'Set should_run output' step only echoed a computed
boolean into $GITHUB_OUTPUT. A job output can reference step outputs
directly, so move the expression into outputs.should_run and drop the
step. Simpler, and it removes the shell 'run:' block that carried the
(benign) template-injection finding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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