Skip to content

fix(ci): document why gate-failure-watch's workflow_run trigger is safe - #10386

Closed
proggeramlug wants to merge 2 commits into
mainfrom
fix/zizmor-gate-failure-watch
Closed

proggeramlug wants to merge 2 commits into
mainfrom
fix/zizmor-gate-failure-watch

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

zizmor has been red on main since 2026-09-06 — the day gate-failure-watch.yml landed — on a single high finding:

error[dangerous-triggers]: use of fundamentally insecure workflow trigger
  --> .github/workflows/gate-failure-watch.yml:9:1
   = note: audit confidence → Medium

It was not in the CI run's job list, which is why it is easy to miss: zizmor is its own workflow, so a triage that reads only the CI run's failures never sees it.

This is a suppression of a high-severity finding, so the case for it should be checkable rather than taken on trust. zizmor flags workflow_run categorically — "almost always used insecurely", at Medium audit confidence. The two ways it is used insecurely are both already closed in this file, and each is one line to verify:

  1. It never runs for untrusted input. The observe job's if: admits only schedule, or workflow_dispatch/repository_dispatch/push whose head_branch is main or a v* tag. A fork PR's run satisfies none of those, so the write-capable token is never reachable from a contributor-controlled trigger.
  2. It never executes the triggering run's code. The checkout pins ref: main with persist-credentials: false, and the only thing executed is scripts/gate_failure_watch.py out of that trusted default-branch checkout. Nothing is taken from the triggering run — no artifact download, no head_sha checkout.

Permissions are actions: read, contents: read, issues: write — enough to read a run's conclusion and file one issue, and nothing else.

Removing the trigger is not an alternative: observing another workflow's completion is the feature. #9830 measured a correctly-failing scheduled workflow that stayed red for nineteen days with nobody noticing, which is what this exists to prevent.

Suppressed inline, not in .github/zizmor.yml. The justification then sits next to the trigger it excuses rather than in a file three directories away, and it carries its own ratchet: if this workflow ever gains an artifact download, a head_sha checkout, or a looser if:, the marker has to go and the gate fails again. That matches .github/zizmor.yml's own stated rule — "never add without a dated reason" — and the one inline precedent already in the tree (soak-autofix.yml's artipacked).

Validation — against the real tool, not by reasoning:

  • Installed the pinned zizmor 1.28.0 (external-tools.json tools.zizmor) and ran the workflow's own invocation, zizmor .github/ --min-severity high: exit 14 with one high finding before, exit 0 and "No findings to report" after.
  • That check earned its keep: the same justification written as a comment block above on: suppresses nothing — exit 14, unchanged. The marker must trail the on: key. I would have shipped the non-working form otherwise.
  • check_gate_freshness.py, gate_failure_watch.py --self-test and --check-config all pass, and the file still parses as YAML with both triggers intact.

If you would rather not carry a suppressed high finding at all, the honest alternative is to drop workflow_run and lose the observer — I did not take that decision unilaterally.

Summary by CodeRabbit

  • Chores

    • Updated automated security checks so the workflow validation gate passes successfully.
    • Added safeguards and review guidance to preserve the workflow’s existing security posture if its behavior changes.
  • Documentation

    • Documented why the workflow configuration is considered safe and the conditions that would require renewed security review.

Ralph Küpper added 2 commits September 16, 2026 18:49
zizmor has been red on main since 2026-09-06, the day gate-failure-watch.yml
landed, on one high finding: dangerous-triggers against its `workflow_run`.
The audit flags that trigger categorically -- "almost always used insecurely",
at Medium confidence -- and this workflow is one of the cases where it is not.

Both insecure uses are already closed in the file. The `observe` job's `if:`
admits only schedule, or dispatch/push on main or a v* tag, so a fork PR's run
can never reach the write-capable token; and the checkout pins `ref: main` with
`persist-credentials: false` and runs only the default-branch
scripts/gate_failure_watch.py, so the triggering run's code is never executed
and none of its artifacts are downloaded. Permissions are actions:read,
contents:read, issues:write.

Suppressed inline rather than in .github/zizmor.yml so the justification sits
next to the trigger it excuses, and carries its own ratchet: an artifact
download, a head_sha checkout or a looser `if:` means deleting the marker.

Removing the trigger is not an option -- observing another workflow's
completion is the feature, and #9830 measured a correctly-failing scheduled
workflow staying red for nineteen days unnoticed.

Verified with the pinned zizmor 1.28.0 (external-tools.json) using the
workflow's own invocation: `zizmor .github/ --min-severity high` goes from
exit 14 with one high finding to exit 0, "No findings to report". The marker
has to trail the `on:` key -- the same text as a comment block above it does
not suppress anything, which is why this was checked against the real tool
rather than reasoned about.
@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: f7d5d8dd-25e8-4af4-985e-a5816f9987a1

📥 Commits

Reviewing files that changed from the base of the PR and between 99363be and e78ccc3.

📒 Files selected for processing (2)
  • .github/workflows/gate-failure-watch.yml
  • changelog.d/10386-zizmor-workflow-run.md

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The workflow documents why its workflow_run trigger is permitted, adds an inline zizmor suppression, and records conditions that require removing the suppression. A changelog fragment records the rationale and verification result.

Changes

Workflow audit annotation

Layer / File(s) Summary
Document workflow trigger safety
.github/workflows/gate-failure-watch.yml, changelog.d/10386-zizmor-workflow-run.md
The workflow documents its trigger restrictions, permissions, trusted checkout, and suppression removal conditions. The changelog records the zizmor finding, inline marker placement, and verification result.

Priority: ⬇️ Low

Estimated code review effort: 1 (Trivial) | ~5 minutes

Change: Other

Merge Risk: ⚪ Minimal · up to e78cc

The PR only documents and suppresses an existing workflow audit finding; no production or security regression is established.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: documenting and suppressing the zizmor finding for the gate-failure-watch workflow_run trigger.
Description check ✅ Passed The description is detailed and directly explains the change, security rationale, suppression conditions, and validation results. It does not use the template headings or include the checklist, but it…
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/zizmor-gate-failure-watch

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.

@proggeramlug

Copy link
Copy Markdown
Contributor Author

Landed via merge train #10397 (v0.5.1584). All source commits preserve authorship; merged main matches the validated train exactly.

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.

1 participant