Skip to content

ci: configure zizmor GHA security checks, fix findings#2632

Merged
danielroe merged 12 commits intomainfrom
serhalp/zizmor
Apr 26, 2026
Merged

ci: configure zizmor GHA security checks, fix findings#2632
danielroe merged 12 commits intomainfrom
serhalp/zizmor

Conversation

@serhalp
Copy link
Copy Markdown
Member

@serhalp serhalp commented Apr 26, 2026

🔗 Linked issue

N/A

🧭 Context

GitHub Actions workflows are a common attack vector for GitHub projects and their maintainers.

https://zizmor.sh implements a number of valuable checks that flag vulnerable patterns immediately on PRs, preventing them from reaching main. Let's give it a try.

📚 Description

This PR configures zizmor to run in CI, documents how to run it locally if needed, and fixes or suppresses all the issues identified by running a pedantic audit (see all rules here):

  • Apply principle of least privilege by always applying permissions to the exact step or job that actually needs it
    • ✅ Fixed 5 issues
  • Document why each permission is needed with a comment
    • ✅ Fixed 10 issues
  • Pin all actions and images to a specific commit or digest
    • ✅ Fixed 1 issue
    • Require inline comment with human-friendly version/release identifier
    • Require this identifier to actually match the commit/digest
      • ✅ Fixed 17 issues
  • Use persist-credentials: false for actions/checkout (by default it persists a GitHub token for later git command; disabling this decreases risk of credentials exposure through logs, disk, etc.)
    • ✅ Fixed 16 issues
  • Use concurrency controls in all workflows
    • ✅ Fixed 9 issues
  • Require names for all workflows
    • ✅ Fixed 3 issues

It posts nice inline annotations too!

Screenshot 2026-04-26 at 10 15 09

serhalp added 9 commits April 26, 2026 08:55
actions/checkout persists a GitHub token for later git commands unless told otherwise.

`persist-credentials: false` means later steps cannot accidentally use the token, it minimizes
the risk of credential exposure through logs, disk, etc.
See https://docs.zizmor.sh.

This runs on PRs and pushes to main. It uses the most basic "regular"
persona as a starting point.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs.npmx.dev Ready Ready Preview, Comment Apr 26, 2026 4:44pm
npmx.dev Ready Ready Preview, Comment Apr 26, 2026 4:44pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
npmx-lunaria Ignored Ignored Apr 26, 2026 4:44pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 74f7942f-1cfc-4275-8737-14f8ddd9aa8c

📥 Commits

Reviewing files that changed from the base of the PR and between 6e1a787 and a3e463d.

📒 Files selected for processing (1)
  • .github/workflows/deploy-canary.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/deploy-canary.yml

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added Zizmor security scanning to CI and new developer run tasks for local checks.
  • Documentation

    • Added contributor guidance for running and auto-fixing security scans locally.
  • Chores

    • Improved workflow reliability with run de-duplication and tightened job permissions.
    • Standardised checkout credential handling and updated workflow annotations and tooling pins.
    • Pinned a browser container image for reproducible CI runs.

Walkthrough

Adds a Zizmor security scan and related configuration, and hardens GitHub Actions workflows by adding concurrency controls, disabling persisted checkout credentials, tightening workflow permissions, and updating action version annotations across multiple workflows and docs.

Changes

Cohort / File(s) Summary
Workflow concurrency & checkout changes
.github/workflows/autofix.yml, .github/workflows/mirror-tangled.yml, .github/workflows/release-pr.yml, .github/workflows/release-tag.yml, .github/workflows/semantic-pull-requests.yml, .github/workflows/welcome-close.yml, .github/workflows/welcome-open.yml, .github/workflows/chromatic.yml, .github/workflows/dependency-diff.yml, .github/workflows/ci.yml, .github/workflows/deploy-canary.yml, .github/workflows/zizmor.yml
Added concurrency blocks to many workflows (where applicable) to cancel overlapping runs; set actions/checkout persist-credentials: false in most jobs (with explicit exceptions where noted); pinned Playwright container by digest in ci.yml; updated inline action version comments.
Workflow permission refinement
.github/workflows/dependency-diff-comment.yml, .github/workflows/lunaria.yml, .github/workflows/release-pr.yml, .github/workflows/stale.yml, .github/workflows/welcome-open.yml
Replaced broad top-level permissions with permissions: {} and reintroduced minimal, job-level permissions required for each job (e.g. contents: read, pull-requests: write, issues: write).
Zizmor CI and config
.github/workflows/zizmor.yml, .github/zizmor.yml
Added a new Zizmor workflow to run security scans (pedantic persona, annotations output, advanced mode off) and a Zizmor config file with rule exceptions for specific workflow files and an ignored lunaria action entry.
Action annotation updates
.../setup-vp uses across workflows (e.g. autofix.yml, ci.yml, deploy-canary.yml, release-tag.yml, chromatic.yml, etc.)
Updated inline version comments for voidzero-dev/setup-vp references from v1 to v1.6.0 (pinned action SHAs unchanged).
Documentation & local tooling
CONTRIBUTING.md, vite.config.ts
Documented running Zizmor locally and CI policy location; added zizmor and zizmor:fix dev tasks to Vite config.

Possibly related PRs

Suggested reviewers

  • ghostdevv
  • 43081j
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarises the main changes: configuring zizmor GitHub Actions security checks and fixing identified issues.
Description check ✅ Passed The description is well-related to the changeset, providing context about the zizmor tool, explaining the rationale for the changes, and detailing the specific security improvements made across workflows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch serhalp/zizmor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
.github/workflows/stale.yml (1)

9-11: Consider cancel-in-progress: false for the cron/manual stale runs.

Each job is capped at operations-per-run: 500. If a manual workflow_dispatch happens to coincide with the daily cron (or two manuals overlap), the in-flight run gets killed mid-batch and only a partial set of issues/PRs gets labelled/closed. Since the next daily run catches up, this is low-impact, but allowing the in-flight run to complete is generally preferable for batch maintenance jobs.

♻️ Proposed change
 concurrency:
   group: ${{ github.workflow }}
-  cancel-in-progress: true
+  cancel-in-progress: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/stale.yml around lines 9 - 11, The concurrency block
currently uses cancel-in-progress: true which will terminate an in-progress
stale workflow when a new cron or manual run starts; update the concurrency
configuration (the concurrency group and the cancel-in-progress setting
referenced in the concurrency block) to set cancel-in-progress: false so
in-flight stale runs are allowed to complete rather than being killed by
overlapping workflow_dispatch or cron triggers.
.github/zizmor.yml (1)

4-7: Line-pinned ignore is brittle; prefer an inline comment or file-only ignore.

lunaria.yml:38 will silently stop suppressing the finding if the lunariajs/action step moves to a different line (e.g., if a new step is inserted above it), and could even start suppressing an unrelated finding that happens to land on line 38. Since the rationale ("no tag refs upstream") is a property of the action itself, not the line, use an inline # zizmor: ignore[stale-action-refs] comment on the uses: line instead. This keeps the suppression with the action and survives line changes.

If inline comments are not available in your zizmor version, fall back to file-scoped ignores:

♻️ Proposed fallback change
 rules:
   stale-action-refs:
     ignore:
-      # lunariajs/action has no tag refs; keep the branch commit hash-pinned.
-      - lunaria.yml:38
+      # lunariajs/action has no tag refs; keep the branch commit hash-pinned.
+      - lunaria.yml
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/zizmor.yml around lines 4 - 7, Replace the brittle line-pinned
ignore "lunaria.yml:38" in the stale-action-refs ignore list with an inline
suppression on the action's uses: line in lunaria.yml (add a "# zizmor:
ignore[stale-action-refs]" comment next to the uses: for the lunariajs/action
step) so the suppression stays tied to the action itself; if your zizmor version
does not support inline comments, instead convert the entry into a file-scoped
ignore (e.g., reference lunaria.yml only) under stale-action-refs to avoid
line-number fragility while keeping the rationale that the action has no tag
refs upstream.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release-tag.yml:
- Around line 8-11: The concurrency block currently sets "cancel-in-progress:
true", which can leave release workflow state inconsistent; change the
concurrency configuration (the concurrency/group and cancel-in-progress
settings) so that cancel-in-progress is disabled for this release workflow —
e.g., remove or set "cancel-in-progress: false" in the concurrency block that
contains group: ${{ github.workflow }}-${{ github.ref }} so in-flight release
runs are allowed to finish instead of being terminated.

In @.github/workflows/welcome-open.yml:
- Line 22: The workflow comment on the uses line referencing
zephyrproject-rtos/action-first-interaction contains unsupported build metadata
"+zephyr.6"; update the comment after the action (the tag comment on the line
containing "uses:
zephyrproject-rtos/action-first-interaction@58853996b1ac504b8e0f6964301f369d2bb22e5c")
to remove the '+'—for example change "# tag=v1.1.1+zephyr.6" to "# tag=v1.1.1"
or to a dash-separated form like "# v1.1.1-zephyr.6" so the ref-version-mismatch
audit will match.

In @.github/workflows/zizmor.yml:
- Around line 15-17: The concurrency group fallback uses github.sha which is
unique per commit and prevents cancel-in-progress from working on
push/merge_group; update the concurrency block to use github.event.number ||
github.ref instead of github.event.number || github.sha so runs on the same ref
share a group and newer runs cancel older ones (look for the concurrency: group
setting in the workflow YAML).

In `@CONTRIBUTING.md`:
- Around line 137-157: Add a Table of Contents entry for the new subsection
titled "GitHub Actions security analysis" so the TOC under "Development
workflow" includes this item; update the TOC block (the list around the existing
"Available commands", "Clearing caches…", "Project structure" entries) to
include a matching bullet/link for "GitHub Actions security analysis" (use the
same anchor style/format as other TOC items) so the new subsection appears in
the document navigation.

---

Nitpick comments:
In @.github/workflows/stale.yml:
- Around line 9-11: The concurrency block currently uses cancel-in-progress:
true which will terminate an in-progress stale workflow when a new cron or
manual run starts; update the concurrency configuration (the concurrency group
and the cancel-in-progress setting referenced in the concurrency block) to set
cancel-in-progress: false so in-flight stale runs are allowed to complete rather
than being killed by overlapping workflow_dispatch or cron triggers.

In @.github/zizmor.yml:
- Around line 4-7: Replace the brittle line-pinned ignore "lunaria.yml:38" in
the stale-action-refs ignore list with an inline suppression on the action's
uses: line in lunaria.yml (add a "# zizmor: ignore[stale-action-refs]" comment
next to the uses: for the lunariajs/action step) so the suppression stays tied
to the action itself; if your zizmor version does not support inline comments,
instead convert the entry into a file-scoped ignore (e.g., reference lunaria.yml
only) under stale-action-refs to avoid line-number fragility while keeping the
rationale that the action has no tag refs upstream.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f8e7d442-ccf8-46b4-8697-402c39a1b827

📥 Commits

Reviewing files that changed from the base of the PR and between a89588c and 6e1a787.

📒 Files selected for processing (18)
  • .github/workflows/autofix.yml
  • .github/workflows/chromatic.yml
  • .github/workflows/ci.yml
  • .github/workflows/dependency-diff-comment.yml
  • .github/workflows/dependency-diff.yml
  • .github/workflows/deploy-canary.yml
  • .github/workflows/lunaria.yml
  • .github/workflows/mirror-tangled.yml
  • .github/workflows/release-pr.yml
  • .github/workflows/release-tag.yml
  • .github/workflows/semantic-pull-requests.yml
  • .github/workflows/stale.yml
  • .github/workflows/welcome-close.yml
  • .github/workflows/welcome-open.yml
  • .github/workflows/zizmor.yml
  • .github/zizmor.yml
  • CONTRIBUTING.md
  • vite.config.ts

Comment on lines +8 to +11
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

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.

⚠️ Potential issue | 🟠 Major

cancel-in-progress: true on a release workflow can leave partial state.

This workflow pushes a git tag, creates a GitHub Release, and then publishes npmx-connector to npm in a downstream job. If a second push to release arrives mid-run (or this run is otherwise superseded), GitHub will SIGTERM the in-flight job and you can end up in inconsistent states such as:

  • tag pushed but the GitHub Release never created (the 📝 Generate release notes / 🚀 Create GitHub Release steps get killed), or
  • tag + Release exist but publish-connector is canceled before npm publish --provenance completes — leaving git/GitHub claiming a version that does not exist on the registry.

Releases on push to release are infrequent, so the throughput win from cancellation is negligible while the corruption risk is real. Recommend disabling cancellation on this workflow specifically.

🛡️ Proposed fix
 concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
-  cancel-in-progress: true
+  # Releases push tags, create GitHub releases, and publish to npm in sequence.
+  # Cancelling mid-run could leave a tag without a release, or a release without a published package.
+  cancel-in-progress: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
# Releases push tags, create GitHub releases, and publish to npm in sequence.
# Cancelling mid-run could leave a tag without a release, or a release without a published package.
cancel-in-progress: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-tag.yml around lines 8 - 11, The concurrency block
currently sets "cancel-in-progress: true", which can leave release workflow
state inconsistent; change the concurrency configuration (the concurrency/group
and cancel-in-progress settings) so that cancel-in-progress is disabled for this
release workflow — e.g., remove or set "cancel-in-progress: false" in the
concurrency block that contains group: ${{ github.workflow }}-${{ github.ref }}
so in-flight release runs are allowed to finish instead of being terminated.

pull-requests: write # post first-time contributor greeting comments
steps:
- uses: zephyrproject-rtos/action-first-interaction@58853996b1ac504b8e0f6964301f369d2bb22e5c
- uses: zephyrproject-rtos/action-first-interaction@58853996b1ac504b8e0f6964301f369d2bb22e5c # tag=v1.1.1+zephyr.6
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What version comment formats are accepted by zizmor's ref-version-mismatch audit? Does it accept "# tag=v1.2.3" or comments containing a "+" build metadata segment?

💡 Result:

Accepted version comment formats for zizmor’s ref-version-mismatch audit are determined by regexes that look for a version-like token inside a comment. 1) “# tag=v1.2.3” Yes, it accepts this format (and similar non-whitespace tags): it matches comments of the form # tag= where is captured as any non-whitespace sequence. So “# tag=v1.2.3” is accepted. 2) Comments containing a “+” build metadata segment (example: “v1.2.3+build.1”) No—based on the regexes’ allowed character sets for the version token, a “+” will not be captured/recognized as part of the version. Why: the audit’s “tag=” pattern captures any non-whitespace token, but the other supported “shorthand” patterns for version comments (e.g., “# v1.2.3-rc.1” and “# version: 2.8.0”) only allow prerelease parts made of [\w.-]+ and an optional hyphen prerelease, i.e. they do not include “+” in the allowed characters. In particular, “# v<digits...>(-[\w.-]+)?” does not permit “+” in the captured version. Practical guidance: if you want ref-version-mismatch to reliably recognize the version tag, stick to the supported forms like “# tag=vX.Y.Z” or “# vX.Y.Z-rc.1” / “# version: X.Y.Z” style, and avoid SemVer build metadata suffixes using “+”.

Citations:


Remove the + build metadata from the version comment to ensure zizmor's ref-version-mismatch audit properly recognises the version.

The +zephyr.6 suffix is not supported. The audit's version patterns only allow characters matching [\w.-] (word characters, dots, and hyphens), so the + will cause version matching to fail. Use # tag=v1.1.1 or # v1.1.1-zephyr.6 instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/welcome-open.yml at line 22, The workflow comment on the
uses line referencing zephyrproject-rtos/action-first-interaction contains
unsupported build metadata "+zephyr.6"; update the comment after the action (the
tag comment on the line containing "uses:
zephyrproject-rtos/action-first-interaction@58853996b1ac504b8e0f6964301f369d2bb22e5c")
to remove the '+'—for example change "# tag=v1.1.1+zephyr.6" to "# tag=v1.1.1"
or to a dash-separated form like "# v1.1.1-zephyr.6" so the ref-version-mismatch
audit will match.

Comment on lines +15 to +17
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
cancel-in-progress: true
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.

⚠️ Potential issue | 🟡 Minor

Concurrency fallback uses github.sha, which makes cancel-in-progress a no-op on push/merge_group.

For pull_request events, github.event.number resolves to the PR number, so this works as intended. However, for push and merge_group events github.event.number is undefined and the fallback github.sha is unique per commit, so each run lands in its own concurrency group and nothing is ever cancelled. The standard pattern (and what the PR description documents) is github.event.number || github.ref, which lets newer commits on the same ref cancel in-flight runs.

🔧 Proposed fix
 concurrency:
-  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
+  group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
   cancel-in-progress: true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
cancel-in-progress: true
concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
cancel-in-progress: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/zizmor.yml around lines 15 - 17, The concurrency group
fallback uses github.sha which is unique per commit and prevents
cancel-in-progress from working on push/merge_group; update the concurrency
block to use github.event.number || github.ref instead of github.event.number ||
github.sha so runs on the same ref share a group and newer runs cancel older
ones (look for the concurrency: group setting in the workflow YAML).

Comment thread CONTRIBUTING.md
Comment on lines +137 to +157
### GitHub Actions security analysis

CI runs [zizmor](https://docs.zizmor.sh/) against the repository's GitHub Actions workflows. The shared policy lives in `.github/zizmor.yml`, and the `zizmor` task uses the same pedantic persona as CI.

You may run it locally by [installing `zizmor`](https://docs.zizmor.sh/installation/) and running:

```bash
pnpm vp run zizmor
```

Some audits resolve action refs and vulnerability metadata through GitHub. To run those online checks locally, authenticate with the GitHub CLI and pass its token:

```bash
GH_TOKEN="$(gh auth token)" pnpm vp run zizmor
```

To fix audit findings automatically, run:

```bash
GH_TOKEN="$(gh auth token)" pnpm vp run zizmor:fix
```
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.

⚠️ Potential issue | 🟡 Minor

Missing Table of Contents entry for the new section.

The new "GitHub Actions security analysis" subsection has been added under "Development workflow" but is not listed in the TOC at lines 32–37. For consistency with the surrounding subsections (Available commands, Clearing caches…, Project structure, etc.), please add an entry.

📝 Proposed TOC update
 - [Development workflow](`#development-workflow`)
   - [Available commands](`#available-commands`)
+  - [GitHub Actions security analysis](`#github-actions-security-analysis`)
   - [Clearing caches during development](`#clearing-caches-during-development`)
   - [Project structure](`#project-structure`)
   - [Local connector CLI](`#local-connector-cli`)
   - [Mock connector (for local development)](`#mock-connector-for-local-development`)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CONTRIBUTING.md` around lines 137 - 157, Add a Table of Contents entry for
the new subsection titled "GitHub Actions security analysis" so the TOC under
"Development workflow" includes this item; update the TOC block (the list around
the existing "Available commands", "Clearing caches…", "Project structure"
entries) to include a matching bullet/link for "GitHub Actions security
analysis" (use the same anchor style/format as other TOC items) so the new
subsection appears in the document navigation.

@danielroe danielroe enabled auto-merge April 26, 2026 16:42
@danielroe danielroe added this pull request to the merge queue Apr 26, 2026
Merged via the queue into main with commit 69351cf Apr 26, 2026
25 checks passed
@danielroe danielroe deleted the serhalp/zizmor branch April 26, 2026 16:51
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