Skip to content

ci: add zizmor, fix found issues - #5387

Draft
kolyshkin wants to merge 9 commits into
opencontainers:mainfrom
kolyshkin:add-zizmor
Draft

ci: add zizmor, fix found issues#5387
kolyshkin wants to merge 9 commits into
opencontainers:mainfrom
kolyshkin:add-zizmor

Conversation

@kolyshkin

Copy link
Copy Markdown
Contributor

This is based on top of (and currently includes) #5385, thus the draft status. Will rebase once that one is merged.

See individual commits for details.

This is mostly shellcheck complaining about missing quotes (SC2046
and SC2086). Issues found by actionlint (which runs shellcheck for
all run: statements in GHA workflows.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin kolyshkin mentioned this pull request Aug 6, 2026
kolyshkin and others added 8 commits August 10, 2026 09:21
Debugging GHA yaml is not fun -- usually when there is an issue with a
workflow file, it just doesn't run.

Let's add a separate actionlint job to catch workflow issues.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
A version tag (even a "full" one like v7.0.1) is mutable: whoever
controls the action's repository can move it to point to any other
commit. Pinning to a full commit hash is the only way to get the exact
same action code on every run.

Found by zizmor's unpinned-uses audit. Dependabot is already enabled for
the github-actions ecosystem and knows how to update hash pins together
with their version comments, so this should not add maintenance burden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Two things, both applied by "zizmor --fix":

 - persist-credentials: false for actions/checkout. By default checkout
   leaves the credentials it used in .git/config, where any later step
   (or anything that archives the workspace) can pick them up. Nothing
   here pushes back to the repository, so they are not needed.

 - cache: false for actions/setup-go. These workflows are also triggered
   by pushing a v* tag, and validate.yml builds and uploads release
   binaries, so a cache entry poisoned from a pull request could in
   principle end up in a release build.

The remaining cache-poisoning finding (Lima VM images in test.yml) is
ignored inline: it caches downloaded VM images rather than build output,
and the suggested lookup-only: true would defeat the cache entirely by
re-downloading the image on every run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
As recommended by zizmor.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
zizmor is a static analysis tool for GitHub Actions workflows, focused
on security issues rather than correctness (which is what the separate
actionlint job is for).

Use the official action, which runs zizmor from a digest-pinned
container image. A few non-default settings:

 - version: pin it, so a new zizmor release adding new audits does not
   suddenly fail CI on an unrelated pull request. Bumping it is then a
   deliberate (and dependabot-able) change.

 - advanced-security: false + annotations: true. The default uploads
   SARIF to the repository's security tab, which needs the job to have
   security-events: write. Inline annotations are enough for us and
   keep the workflow at contents: read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Move "actions: write" from the workflow level to the only job that needs
it, so a job added later won't silently inherit it.

Found by zizmor's excessive-permissions audit (--persona=pedantic).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Cancel CI runs that are already superseded, rather than letting them run
to completion and waste runner time. This is most of what our CI queue
is spent on when a pull request is force-pushed a few times in a row.

For the three workflows that run on pull requests, the concurrency group
is keyed by PR number, so only runs of the same pull request cancel each
other. For anything else -- in particular pushes to main, to release-*,
and to a v* tag, the latter also producing the release binaries -- there
is no PR number, so the group falls back to the unique run_id and no run
is ever cancelled. Keying by github.head_ref instead would be wrong, as
two pull requests from different forks can use the same branch name.

scheduled.yml only triggers other workflows, so a single group for the
whole workflow is enough there.

Found by zizmor's concurrency-limits audit (--persona=pedantic).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
The lint job does not need read permission: golangci-lint-action only uses
pull-requests: read for its only-new-issues option, which we do not set.

The lint-extra step does its own "new code only" filtering with
--new-from-rev=HEAD~1, which is plain git against the fetch-depth: 2
checkout, and the PR annotations come from checks: write.

Found by zizmor's undocumented-permissions audit (--persona=pedantic).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant