Skip to content

feat: add reusable zizmor workflow audit - #104

Merged
oc-tmueller merged 4 commits into
mainfrom
ci/zizmor
Oct 26, 2026
Merged

oc-tmueller merged 4 commits into
mainfrom
ci/zizmor

Conversation

@oc-tmueller

@oc-tmueller oc-tmueller commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Adds .github/workflows/zizmor.yml, a reusable zizmor audit of the calling repository's workflows, composite actions and Dependabot config. It is the base of an org-wide rollout: every public owncloud repo with workflows gets a thin caller (usage in docs/zizmor.md), and admin then makes Zizmor / Zizmor a required check.

Depends on owncloud/admin#310 (allowlists zizmorcore/zizmor-action). Until that merges, the whole CI run fails at startup ("The action zizmorcore/zizmor-action@85b2b9f… is not allowed"). A disallowed action in a called workflow rejects the entire run, not just the job. Re-run CI after #310 merges.

How the workflow behaves

  • Blocking: any finding, at any severity, fails the job. It runs zizmor-action in annotations mode with advanced-security: false. That needs only contents: read, so it also passes on fork PRs. SARIF mode would need security-events: write and reports to the Security tab instead of failing.
  • Pinned: zizmor-action v0.7.1 by SHA, zizmor 1.31.1. The action pip-installs a hash-locked wheel.
  • Org default config: applied when the repo has no zizmor.yml of its own. owncloud/* may stay ref-pinned, so every ...@main caller keeps working, and everything else must be SHA-pinned, which the org allowlist enforces anyway. A repository config replaces the default rather than merging with it, as documented.
  • Self-test: test.yml runs the audit on this repository.

This repository's own findings (separate commit)

  • artipacked: persist-credentials: false on every checkout. None of these jobs runs git after checkout.
  • github-app: the calens, translation-sync and trigger-docs-build App tokens request only what they use. translation-sync asks for members: read only when team_reviewers is set, since create-github-app-token skips an empty permission input. No caller sets it today.
  • ref-version-mismatch: setup-php's tag is 2.40.0, without a v. zizmor's auto-fix would have written # master, because a stray upstream tag of that name points at the same commit.
  • self-repository: test.yml calls the local workflows as $/..., GitHub's self-repository syntax since July 2026. Files written to the workspace at runtime cannot redirect it the way they can ./.... This PR's CI run is the proof that the syntax parses.
  • Suppressed inline, with the reason on the line:
    • unpinned-images: the database tags come from the caller's input.
    • adhoc-packages: pnpm is pinned by the app's package.json.
    • superfluous-actions: the release publish step can't be exercised in CI.

Noticed, not changed here

🤖 Generated with Claude Code

oc-tmueller and others added 4 commits October 26, 2026 10:16
Ahead of the zizmor workflow audit, which fails on any finding:

- artipacked: checkouts set persist-credentials: false. None of these
  jobs runs a git operation after checkout; the two that open PRs
  (calens, translation-sync) already set it and push through
  peter-evans/create-pull-request with an App token.
- github-app: the calens, translation-sync and trigger-docs-build App
  tokens request only what they use (contents + pull-requests write to
  open the PR; actions write to dispatch the docs build), instead of
  inheriting every permission of the installation.
- ref-version-mismatch: setup-php's tag is 2.40.0, without the v.
- self-repository: test.yml calls the local workflows as $/... instead
  of ./..., which cannot be redirected by files written to the
  workspace at runtime.
- unpinned-images, adhoc-packages, superfluous-actions: suppressed
  inline with the reason. The database image tags come from the
  caller's input, the pnpm version from the app's package.json, and
  the release publish step only runs on a real release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
zizmor statically audits GitHub Actions workflows, composite actions and
Dependabot config: template injection, excessive permissions, persisted
credentials, unpinned or impostor actions, known-vulnerable actions.
Callers get a blocking check: annotations mode exits non-zero on any
finding and needs only contents: read, so it also runs on fork PRs.

zizmor hash-pins every `uses:` by default, which would flag every
owncloud/reusable-workflows/...@main caller. Without a repository
config the workflow therefore applies an org default that keeps
owncloud/* ref-pinned and hash-pins everything else. This repository
runs the audit on itself from test.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
Narrowing the App token to contents + pull-requests write dropped the
organization Members: read that requesting team reviewers needs. Ask
for it only when team_reviewers is set; create-github-app-token skips
an empty permission input. No caller sets team_reviewers today.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com>
@oc-tmueller
oc-tmueller requested a review from a team as a code owner October 26, 2026 09:23
@oc-tmueller

Copy link
Copy Markdown
Contributor Author

@phil-davis @jvillafanez

@phil-davis phil-davis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks reasonable.

@oc-tmueller oc-tmueller reopened this Oct 26, 2026
@oc-tmueller
oc-tmueller merged commit 363e01a into main Oct 26, 2026
35 checks passed
@oc-tmueller
oc-tmueller deleted the ci/zizmor branch October 26, 2026 11:51
This was referenced Oct 26, 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.

2 participants