@@ -36,7 +36,7 @@ rulesets; they are not meant to run against this repo.
3636
3737## Commit conventions
3838
39- - Commit as the repo owner (Mark Matyas). Use a ` Signed-off-by: ` trailer
39+ - Commit as the repo owner (Mark Matyas) or other human directing an agent to author contributions . Use a ` Signed-off-by: ` trailer
4040 (` git commit --signoff ` ).
4141- Credit AI assistance with an ` Assisted-by: <tool>:<model> ` trailer, matching
4242 existing history.
@@ -126,66 +126,36 @@ Push-surface design (in `qcom-reusable-workflows`, planned):
126126 workflow input that any repo dev could flip off.
127127- Coverage boundary: this surface only reaches repos that CALL the reusable
128128 workflow. Repos that don't get PR-gate coverage only (no push scan) until the
129- GitHub App lands.
130-
131- ** Long-term:** a GitHub App replaces the push surface entirely (server-side scan on
132- push webhooks with its own credentials), covering fork PRs and repos that don't
133- call the reusable workflow — full control regardless of local workflow files.
129+ ** GitHub App** long-term replacement lands (server-side scan on push webhooks
130+ with its own credentials — covers fork PRs and non-adopting repos regardless of
131+ local workflow files).
134132
135133## PR gate: ONE ruleset rule, gate on job status
136134
137- ** Current approach (interim).** Enforce with a SINGLE ruleset rule:
138- ** "Require workflows to pass before merging"** , source repo
139- ` qualcomm/qcom-enterprise-workflows ` , workflow ` .github/workflows/zizmor-scan.yml ` .
140- The merge gate is the ** job's exit status** : the ` Scan and enforce (gate) ` step
141- runs zizmor in ` --format=github ` (annotations) mode, which PRESERVES zizmor's
142- severity exit codes (11–14), so the job fails when the highest finding is at or
143- above ` ZIZMOR_FAIL_SEVERITY ` (default ` high ` ).
144-
145- ** Rollout without blocking teams: Evaluate mode.** Set the ruleset to ** Evaluate**
146- (not Active) during rollout. For the "require workflows to pass" rule specifically,
147- Evaluate mode ** still runs the workflow** — so PR annotations and job summaries are
148- posted and developers see findings — but ** nothing is blocked** (neither merges nor
149- direct pushes). Flip to ** Active** to start blocking. This is the interim that
150- avoids the direct-push block impacting teams while findings are still surfaced.
151- ` zizmor-scan.yml ` lists ONLY ruleset-injected events (` pull_request ` , ` merge_group ` );
152- it has no ` push ` /` workflow_dispatch ` triggers (they would be no-ops in targets).
153- Verified: the enterprise ruleset triggers the workflow with only "Require workflows
154- to pass before merging" enabled.
135+ Enforce with a SINGLE ruleset rule: ** "Require workflows to pass before merging"** ,
136+ source repo ` qualcomm/qcom-enterprise-workflows ` , workflow
137+ ` .github/workflows/zizmor-scan.yml ` . (Verified: the ruleset triggers the workflow
138+ with only this rule enabled.) The workflow has two steps:
139+
140+ - ** ` Scan and enforce (gate) ` ** — the gate; always runs. ` annotations:true ` ,
141+ ` advanced-security:false ` , ` min-severity:<fail-severity> ` . Preserves zizmor's
142+ severity exit codes, so the job fails when the highest finding is ≥
143+ ` ZIZMOR_FAIL_SEVERITY ` (default ` high ` ). Identical on fork PRs, no-GHAS repos,
144+ and normal PRs — needs no analysis, GHAS license, or write token.
145+ - ** ` Upload results to code scanning (best-effort) ` ** — GHAS repos only (fork PRs
146+ INCLUDED). ` advanced-security:true ` (SARIF, exits 0) + ` continue-on-error:true ` ,
147+ so it is purely COSMETIC (populates the Security tab, never affects the gate).
148+ Skipped, not failed, on no-GHAS repos.
155149
156150** Why NOT "Require code scanning results".** That rule can only require a tool that
157- has ** already produced an analysis** for the repo — and nothing in the central
158- ruleset produces one (a ruleset can only inject on PR events, never ` on: push ` ). A
159- repo with no local zizmor workflow, not yet reached by the push-scan surface, has
160- no analysis, so the rule ** fails closed** and blocks every PR (observed: * "Waiting
161- for Code Scanning results — Code Scanning may not be configured for the target
162- branch"* ). Gating on job status needs no pre-existing analysis, no GHAS license,
163- and no write token, so it works identically on every repo. This mirrors ** Grafana's**
164- at-scale zizmor rollout, which also gates on the job exit code. (Note: fork PRs
165- CAN upload SARIF — GitHub's code-scanning endpoint accepts SARIF from the read-only
166- fork token on ` pull_request ` runs, verified empirically — so the fork token is NOT
167- a reason to avoid code-scanning results; the analysis-provenance problem above is.)
168-
169- ** What each part does in ` zizmor-scan.yml ` :**
170-
171- - ** ` Scan and enforce (gate) ` ** — always runs; the gate. Uses
172- ` advanced-security:false ` , ` annotations:true ` , ` min-severity:<fail-severity> ` .
173- Fails the job on findings ≥ threshold. Identical behavior on fork PRs, no-GHAS
174- repos, and normal PRs.
175- - ** ` Upload results to code scanning (best-effort) ` ** — GHAS-enabled repos only
176- (fork PRs INCLUDED). Uses ` advanced-security:true ` (SARIF, exits 0 on findings)
177- with ` continue-on-error:true ` , so it is purely COSMETIC: populates the Security
178- tab / full-severity history and can NEVER affect the gate. Skipped (not failed)
179- on no-GHAS repos.
180- - ** ` ZIZMOR_FAIL_SEVERITY ` ** — rollout lever. ` never ` = advisory (scan + annotate,
181- never block); ratchet ` high → medium → low ` to tighten. Onboard new fleets at
182- ` never ` first.
183-
184- ** Long-term direction:** a GitHub App + backend service to scan on push webhooks
185- with its own credentials and govern dismissals, covering repos that don't call the
186- reusable workflow. Once analysis is guaranteed for every repo, "require code
187- scanning results" becomes viable as the gate. The single-rule/job-status model
188- above is the interim bridge until that exists.
151+ has ** already produced an analysis** for the repo — and nothing central produces
152+ one (a ruleset injects only on PR events, never ` on: push ` ). A repo not yet reached
153+ by the push surface has no analysis, so the rule ** fails closed** and blocks every
154+ PR (* "Waiting for Code Scanning results…"* ). Job-status gating has no such
155+ dependency. This mirrors ** Grafana's** at-scale rollout. Note: this is NOT a
156+ fork-token problem — fork PRs CAN upload SARIF (GitHub's endpoint accepts the
157+ read-only fork token on ` pull_request ` runs, verified empirically). The blocker is
158+ analysis provenance, which only the push surface / GitHub App resolves.
189159
190160## Exceptions / governance direction
191161
0 commit comments