diff --git a/.github/workflows/gate-failure-watch.yml b/.github/workflows/gate-failure-watch.yml index 1251cf70c4..47124b42d2 100644 --- a/.github/workflows/gate-failure-watch.yml +++ b/.github/workflows/gate-failure-watch.yml @@ -6,7 +6,31 @@ name: Scheduled Gate Failure Watch # update the same issue with the current rows and their delta; the next green # closes it. -on: +# zizmor flags `workflow_run` categorically -- "almost always used +# insecurely", at Medium audit confidence. The two ways it IS used insecurely +# are both closed here, in code, and each is checkable in one line: +# +# 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 run 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, nothing more. +# +# Dropping the trigger is not an alternative -- observing another workflow's +# completion IS the feature (#9830 measured a correctly-failing scheduled +# workflow staying red for nineteen days with nobody noticing). +# +# Ratchet: if this workflow ever gains an artifact download, a `head_sha` +# checkout, or a looser `if:`, delete the marker and let the gate fail. +on: # zizmor: ignore[dangerous-triggers] workflow_run: workflows: - Auto-Optimize App Patterns diff --git a/changelog.d/10386-zizmor-workflow-run.md b/changelog.d/10386-zizmor-workflow-run.md new file mode 100644 index 0000000000..8d35e09c1c --- /dev/null +++ b/changelog.d/10386-zizmor-workflow-run.md @@ -0,0 +1,20 @@ +Unbreak the `zizmor` gate, red on `main` since 2026-09-06 on one high finding: +`dangerous-triggers` against `gate-failure-watch.yml`'s `workflow_run`. + +zizmor flags that trigger categorically ("almost always used insecurely", at +Medium audit confidence). 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 executes only +the default-branch `scripts/gate_failure_watch.py`, so the triggering run's code +is never run and none of its artifacts are downloaded. + +Suppressed inline rather than in `.github/zizmor.yml`, so the justification sits +beside the trigger it excuses and carries its own ratchet: an artifact download, +a `head_sha` checkout, or a looser `if:` means deleting the marker and letting +the gate fail again. + +Verified against the pinned zizmor 1.28.0 with the workflow's own invocation — +`zizmor .github/ --min-severity high` goes from exit 14 with one high finding to +exit 0. The marker must trail the `on:` key; the identical text as a comment +block above it suppresses nothing.