Skip to content

Audit GitHub workflows with zizmor - #520

Open
joe4dev wants to merge 2 commits into
mainfrom
devx-1144-audit-lstk-github-workflows-with-zizmor
Open

joe4dev wants to merge 2 commits into
mainfrom
devx-1144-audit-lstk-github-workflows-with-zizmor

Conversation

@joe4dev

@joe4dev joe4dev commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Motivation

Our workflows are SHA-pinned (DEVX-978), but nothing audits them for the other common GitHub Actions weaknesses: persisted credentials, template injection, over-broad GITHUB_TOKEN scopes, secrets: inherit, and cache poisoning in the release job. zizmor catches these and is used in localstack-pro; this PR adds it and fixes what it currently finds.

FYI: I fixed other violations previously such as pinning in #486 and #511

Solution

  • Gate: a new zizmor.yml workflow runs zizmor via the pre-commit hook on PRs, pushes to main, and weekly (online audits compare pins against upstream, which can change without a commit). It fails on every finding at the default persona; the 10 accepted findings carry an inline # zizmor: ignore[<audit>] <reason>.
  • One zizmor version, bumped by Dependabot: the hook rev in .pre-commit-config.yaml is the single pin; CI installs pre-commit from .github/tools/requirements.txt. New Dependabot pre-commit and pip entries, plus a 7-day cooldown on all ecosystems (security updates exempt).
  • Fixes:
    • persist-credentials: false on every checkout that doesn't push.
    • Template injection: ${{ }} moved into env: in the release-tag action and the integration result check.
    • Least-privilege permissions: (workflow-level {} / contents: read, per-job grants). The weekly release's ci job grants exactly the scopes ci.yml declares.
    • secrets: inherit replaced by passing only LOCALSTACK_AUTH_TOKEN; a direct tag push still sees all repo secrets.
    • No Go/npm cache in the publishing release job.
    • uses: $/... for the local action and reusable workflow, so they run from the workflow's own commit rather than whatever create-release-tag.yml checked out.

$/ needs zizmor ≥ 1.29 locally; actionlint 1.7.12 doesn't understand it yet (not run in this repo).

Testing

No tag or release was created; release-path tests ran as renamed copies on a scratch branch (push-triggered, create-tag job removed), since deleted.

  • Weekly release copy: checkouts without the PAT, bump detection, the $/ call to ci.yml with narrowed permissions (validated incl. the skipped release), and LOCALSTACK_AUTH_TOKEN reaching the integration tests all passed.
  • Secret scoping: with a workflow_call.secrets block declaring one secret, a direct push still saw PRO_ACCESS_TOKEN, NPM_AUTH_TOKEN and LSTK_EXTENSIONS_READ_TOKEN, so the tag-push release job keeps its tokens.
  • Tag-push credential path: PAT-persisted checkout pushed and deleted a throwaway branch with GITHUB_TOKEN at contents: read.
  • Dispatched on this branch: zizmor.yml, trivy.yml, sync-labels.yml, ci.yml all passed (one flaky Windows test, TestConfigLoadFailureRendersJSONEnvelope, passed on re-run).
  • Untested until after merge: enforce-labels.yml (pull_request_target runs main's copy), weekly-go-upgrade.yml (a branch dispatch would rewrite chore(go): weekly Go toolchain upgrade #469), the $/ composite action (it pushes a tag), and the real release.
Docs

Nothing user-facing: CI and contributor tooling only. CLAUDE.md notes the new pre-commit hook and how to reproduce the audit locally (GH_TOKEN=$(gh auth token) pre-commit run zizmor --all-files).

Review

Human review advised: it changes permissions and secrets in the release and publish workflows, which only the weekly release and a tag push fully exercise.

Todo

  • After merge: make "Audit workflows" a required status check
  • Watch the first weekly release and Dependabot run ($/ refs, new ecosystems)
  • Suggested follow-up: Migrate to npm trusted publishing using OICD instead of long-lived tokens. This would fix the findings ignore[use-trusted-publishing]

Closes DEVX-1144

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@joe4dev joe4dev added semver: patch docs: skip Pull request does not require documentation changes labels Sep 28, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@joe4dev
joe4dev marked this pull request as ready for review September 28, 2026 12:51
@joe4dev
joe4dev requested review from a team and peter-smith-phd as code owners September 28, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs: skip Pull request does not require documentation changes semver: patch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant