Skip to content

ci: use zizmor to lint for CI security issues - #721

Merged
taobojlen merged 5 commits into
roostorg:mainfrom
taobojlen:tao/lint-github-actions
Jun 15, 2026
Merged

ci: use zizmor to lint for CI security issues#721
taobojlen merged 5 commits into
roostorg:mainfrom
taobojlen:tao/lint-github-actions

Conversation

@taobojlen

@taobojlen taobojlen commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Context & Requests for Reviewers

This PR introduces zizmor, a static analysis tool for GitHub Actions.

I suggest we do this because it's an automated and low-friction way to ensure that our CI follows security best practices.

There are two parts to this:

  1. I ran zizmor locally and fixed its findings. Most of these were automatic fixes, with the exception of:
    • moving github.base_ref into env: variables to avoid template injection
    • removing the checks:write permission from the apply_pr_checks workflow, and instead giving this permission to only the check_api_server job where it's actually needed.
  2. I also added a new Github Actions workflow that runs zizmor in CI. This is a great way to ensure that we don't accidentally weaken our security posture in future PRs.
  3. Finally, I removed the caching step from the mdbook workflow.
    • This is because zizmor flagged a cache poisoning risk. In practice this couldn't occur, but I figured it was simpler to remove the caching entirely, because:
    • I can see from MDBook download + cache speedup #14 that we used to build mdbook from source, which was slow. But now that we're downloading the built package, the benefit of also caching it is limited -- it might save a couple of seconds at most.

Tests

Basically, ensure that CI continues to pass :-)

(Optional) Rollout Plan

There's a slight challenge with this, in that some workflows (mdbook and publishing packages/images) only run on main. I can trigger these manually via workflow_dispatch once they are merged to main. But, they have side effects (like publishing a package!).

So I think the best approach there is just to be ready for potential issues the next time we run these, so we can fix them quickly.

Summary by CodeRabbit

  • Chores
    • Integrated automated security vulnerability detection into the CI/CD pipeline.
    • Configured dependency update cooldown periods to reduce update frequency and improve stability.
    • Enhanced CI/CD security practices with improved credential handling.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

persist-credentials: false is added to actions/checkout steps across all workflows. apply_pr_checks.yaml narrows root permissions to contents: read, moves migration diff logic to use a BASE_REF env var, and adds explicit job-level permissions to the API server job. mdbook.yml refactors scripts to use env vars and simplifies mdBook install. A new zizmor.yml workflow runs static security analysis on workflows. Dependabot gains a 7-day cooldown on all update entries.

Changes

Workflow Security Hardening

Layer / File(s) Summary
Permission narrowing and script env-var refactoring in apply_pr_checks
.github/workflows/apply_pr_checks.yaml
Root permissions narrowed to contents: read; BASE_REF env var introduced so migration-order git checkout and diff use it instead of inline expressions; API server job gains explicit job-level contents, actions, and checks: write permissions; all checkout steps set persist-credentials: false.
mdBook workflow script and install refactoring
.github/workflows/mdbook.yml
Checkout disables credential persistence; deployment-path script switched to INPUTS_REF env var; mdBook install runs unconditionally; deploy step reads path from env variable.
persist-credentials hardening across remaining workflows
.github/workflows/checklist.yaml, .github/workflows/publish-db-migrator.yaml, .github/workflows/publish-docker.yaml, .github/workflows/publish-types.yaml
Adds persist-credentials: false to actions/checkout in checklist, publish-db-migrator, all four jobs in publish-docker, and publish-types.
New zizmor security scanning workflow
.github/workflows/zizmor.yml
New workflow running zizmorcore/zizmor-action@v1.25.2 on push to main and all pull requests, with concurrency cancellation, empty top-level permissions, job-level security-events: write, and persist-credentials: false checkout.
Dependabot cooldown configuration
.github/dependabot.yml
Adds cooldown: { default-days: 7 } to all seven Dependabot update entries (Docker, npm /, /db, /migrator, /server, /client, /nodejs-instrumentation).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

ci

Suggested reviewers

  • cassidyjames
  • julietshen
  • vinaysrao1
  • dom-notion
  • pawiecz
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: introducing zizmor, a CI security linting tool for GitHub Actions workflows.
Description check ✅ Passed The PR description follows the template structure with complete Context & Requests for Reviewers and Tests sections, providing clear context about zizmor integration, rationale, and testing expectations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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

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.

@taobojlen
taobojlen marked this pull request as ready for review June 8, 2026 11:58
@taobojlen
taobojlen force-pushed the tao/lint-github-actions branch from 6cdb7e8 to c3ed221 Compare June 8, 2026 12:03
Comment thread .github/workflows/zizmor.yml
Comment thread .github/workflows/zizmor.yml
@taobojlen
taobojlen force-pushed the tao/lint-github-actions branch from 561ccfc to ee6400f Compare June 9, 2026 08:53
@taobojlen
taobojlen requested a review from juanmrad June 9, 2026 08:55
@taobojlen
taobojlen force-pushed the tao/lint-github-actions branch from 5b6a738 to cf9547e Compare June 9, 2026 16:20
@taobojlen

Copy link
Copy Markdown
Contributor Author

zizmor failed in CI because we don't use dependabot cooldowns. i added a .github/zizmor.yml file to ignore this for now.

Comment thread .github/zizmor.yml Outdated
@@ -0,0 +1,7 @@
# zizmor configuration

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we do not run dependabot consistently, and we also don't do merges of dependabot without proper review. Technically right now we are not merging any dependabot pr until we go over package updates with care and manual testing.

so to ask: could we resolve this finding in dependabot.yml instead of suppressing it here? Adding a cooldown directly means we fix the actual finding rather than mute it, and we can then delete this zizmor.yml entirely (no standing exception to maintain).

Since cooldown doesn't apply to security updates and we batch-review Dependabot PRs manually anyway, a short default is essentially free and even trims PR churn:

    schedule:
      interval: 'weekly'
    cooldown:
      default-days: 7

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure thing! That's done now.

@taobojlen
taobojlen force-pushed the tao/lint-github-actions branch from c68c5dc to 99b2688 Compare June 12, 2026 14:32

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/publish-docker.yaml:
- Around line 27-29: The concurrency group currently uses only github.ref which
causes manual dispatches with different inputs to collide; update the
concurrency group expression (the "group" key under concurrency) to include the
workflow_dispatch input (e.g., the "version" input) or alternatively detect
workflow_dispatch and disable cancel-in-progress for that event; locate the
concurrency block (group: publish-docker-${{ github.ref }} / cancel-in-progress:
true) and modify the group to incorporate the input (for example append -${{
github.event.inputs.version }}), or set cancel-in-progress to false when
github.event_name == 'workflow_dispatch'.
🪄 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 Plus

Run ID: 88d5b59b-081d-4cf3-b11a-06aceba0581e

📥 Commits

Reviewing files that changed from the base of the PR and between 561ccfc and 99b2688.

📒 Files selected for processing (9)
  • .github/dependabot.yml
  • .github/workflows/apply_pr_checks.yaml
  • .github/workflows/check_if_directory_changed.yaml
  • .github/workflows/checklist.yaml
  • .github/workflows/mdbook.yml
  • .github/workflows/publish-db-migrator.yaml
  • .github/workflows/publish-docker.yaml
  • .github/workflows/publish-types.yaml
  • .github/workflows/zizmor.yml
✅ Files skipped from review due to trivial changes (1)
  • .github/dependabot.yml
🚧 Files skipped from review as they are similar to previous changes (5)
  • .github/workflows/checklist.yaml
  • .github/workflows/publish-db-migrator.yaml
  • .github/workflows/zizmor.yml
  • .github/workflows/check_if_directory_changed.yaml
  • .github/workflows/mdbook.yml

@coderabbitai coderabbitai Bot 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/publish-docker.yaml:
- Around line 27-29: The concurrency group currently uses only github.ref which
causes manual dispatches with different inputs to collide; update the
concurrency group expression (the "group" key under concurrency) to include the
workflow_dispatch input (e.g., the "version" input) or alternatively detect
workflow_dispatch and disable cancel-in-progress for that event; locate the
concurrency block (group: publish-docker-${{ github.ref }} / cancel-in-progress:
true) and modify the group to incorporate the input (for example append -${{
github.event.inputs.version }}), or set cancel-in-progress to false when
github.event_name == 'workflow_dispatch'.
🪄 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 Plus

Run ID: 88d5b59b-081d-4cf3-b11a-06aceba0581e

📥 Commits

Reviewing files that changed from the base of the PR and between 561ccfc and 99b2688.

📒 Files selected for processing (9)
  • .github/dependabot.yml
  • .github/workflows/apply_pr_checks.yaml
  • .github/workflows/check_if_directory_changed.yaml
  • .github/workflows/checklist.yaml
  • .github/workflows/mdbook.yml
  • .github/workflows/publish-db-migrator.yaml
  • .github/workflows/publish-docker.yaml
  • .github/workflows/publish-types.yaml
  • .github/workflows/zizmor.yml
✅ Files skipped from review due to trivial changes (1)
  • .github/dependabot.yml
🚧 Files skipped from review as they are similar to previous changes (5)
  • .github/workflows/checklist.yaml
  • .github/workflows/publish-db-migrator.yaml
  • .github/workflows/zizmor.yml
  • .github/workflows/check_if_directory_changed.yaml
  • .github/workflows/mdbook.yml
🛑 Comments failed to post (1)
.github/workflows/publish-docker.yaml (1)

27-29: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include workflow_dispatch inputs in the concurrency key.

Line 28 keys manual backfills only by github.ref, so two dispatches from main for different version values will cancel each other mid-publish. That breaks the new backfill path the input was added for. Include the version input in the group, or disable cancellation for workflow_dispatch.

Suggested fix
 concurrency:
-  group: publish-docker-${{ github.ref }}
-  cancel-in-progress: true
+  group: publish-docker-${{ github.ref }}-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.run_id }}
+  cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
📝 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.

concurrency:
  group: publish-docker-${{ github.ref }}-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.run_id }}
  cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-docker.yaml around lines 27 - 29, The concurrency
group currently uses only github.ref which causes manual dispatches with
different inputs to collide; update the concurrency group expression (the
"group" key under concurrency) to include the workflow_dispatch input (e.g., the
"version" input) or alternatively detect workflow_dispatch and disable
cancel-in-progress for that event; locate the concurrency block (group:
publish-docker-${{ github.ref }} / cancel-in-progress: true) and modify the
group to incorporate the input (for example append -${{
github.event.inputs.version }}), or set cancel-in-progress to false when
github.event_name == 'workflow_dispatch'.

@taobojlen
taobojlen requested a review from juanmrad June 12, 2026 15:11
taobojlen and others added 5 commits June 15, 2026 09:21
Fix zizmor findings across the workflows:
- Move `github.base_ref`/`inputs.ref`/step-output expressions out of
  `run:` blocks into `env:` vars to avoid template injection.
- Scope `checks: write` down from the workflow level to only the
  `check_api_server` job in apply_pr_checks.yaml.
- Add `persist-credentials: false` to checkout steps.
- Add a zizmor CI workflow to run the audit on push and PRs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zizmor's cache-poisoning auto-fix added `lookup-only: true` to the
mdbook cache step. Because the install step was gated on
`cache-hit != 'true'`, a cache hit then skipped both the download and
the install, leaving mdbook-bin/ empty and breaking the build.

The original win (PR roostorg#14 / issue roostorg#3) was switching from compiling
mdbook from source to downloading the prebuilt release; the cache was
only a marginal optimization on top. Removing it keeps that win,
fixes the break, and resolves the cache-poisoning finding cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@taobojlen
taobojlen force-pushed the tao/lint-github-actions branch from 99b2688 to 14d994c Compare June 15, 2026 08:22
@taobojlen
taobojlen merged commit f396968 into roostorg:main Jun 15, 2026
7 of 8 checks passed
@taobojlen
taobojlen deleted the tao/lint-github-actions branch June 15, 2026 08:23
cassidyjames pushed a commit that referenced this pull request Jun 24, 2026
* Harden GitHub Actions workflows per zizmor audit

Fix zizmor findings across the workflows:
- Move `github.base_ref`/`inputs.ref`/step-output expressions out of
  `run:` blocks into `env:` vars to avoid template injection.
- Scope `checks: write` down from the workflow level to only the
  `check_api_server` job in apply_pr_checks.yaml.
- Add `persist-credentials: false` to checkout steps.
- Add a zizmor CI workflow to run the audit on push and PRs.

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

* mdbook: drop broken cache step, install binary unconditionally

zizmor's cache-poisoning auto-fix added `lookup-only: true` to the
mdbook cache step. Because the install step was gated on
`cache-hit != 'true'`, a cache hit then skipped both the download and
the install, leaving mdbook-bin/ empty and breaking the build.

The original win (PR #14 / issue #3) was switching from compiling
mdbook from source to downloading the prebuilt release; the cache was
only a marginal optimization on top. Removing it keeps that win,
fixes the break, and resolves the cache-poisoning finding cleanly.

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

* address PR comments

* ignore dependabot cooldowns in zizmor

* add dependency cooldown to dependabot

---------

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.

2 participants