From 5fcfe16bf94cea77889390fc51e9d0d4326a0dbb Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 4 Sep 2026 03:00:13 +0100 Subject: [PATCH] fix(secret-scanner): pin gen-1 baseline fetch to job.workflow_sha The reusable stages the estate gitleaks baseline by TWO paths, and only the second was ever pinned. gen 1 L161-188 UNGATED, always runs ref: main <- moving gen 2 L214-255 if: estate_baseline == true ref: job.workflow_sha `referenced` is true iff the consumer has a `.gitleaks.toml` that extends `.gitleaks-estate.toml`. The scan step then resolves CONFIG=".gitleaks-estate.toml" if [ -f .gitleaks.toml ]; then CONFIG=".gitleaks.toml"; fi so gen 1 is the ONLY step that stages a usable config for a consumer with no local `.gitleaks.toml` -- the large majority of the 400+. Whoever fixed the moving ref fixed gen 2 and presumably verified against a repo that DOES extend the baseline; the majority path kept re-deriving its allowlist from this repository's default branch on every run, no matter which SHA it pinned. This is one line of behaviour plus a comment recording why, and one hardening line (`persist-credentials: false`) bringing gen 1 into line with gen 2. SAFETY -- measured 2026-09-04, not assumed. `job.workflow_sha` resolves to a commit that CONTAINS the path that commit references, for all six SHAs where gen 1 has ever existed. Note gen 1's sparse-checkout path CHANGED over time, so each SHA was checked against the path IT references, not a hardcoded one: 3079bc12 2026-08-07 sparse=.gitleaks.toml present 86bad549 2026-08-07 sparse=.gitleaks.toml present c139238e 2026-08-07 sparse=config/gitleaks/estate-baseline.toml present 84d6fe98 2026-08-13 sparse=config/gitleaks/estate-baseline.toml present f2f8e679 2026-08-14 sparse=config/gitleaks/estate-baseline.toml present f451a2bb 2026-08-24 sparse=config/gitleaks/estate-baseline.toml present WHY `ref: main` IS WORSE THAN A MOVING PIN, and why the comment is long. The file gen 1 fetches has been RENAMED under it. Before 86bad549 the shared allowlist WAS `.gitleaks.toml` (148 lines, 16 rules); after it, that path is this repo's own 18-line dogfooding stub whose `[extend] path` points at `config/gitleaks/estate-baseline.toml` -- a path the consumer does not have, because gen 1 stages exactly one file. `ref: main` therefore fails as a CLIFF, not as drift. BLAST RADIUS OF THAT CLIFF IS ZERO TODAY, and this commit does not claim otherwise. 86bad549 was HEAD for 132 minutes and 3079bc12 for 4h15m, both on 2026-08-07; `gh search code` finds no consumer on either, and the six metadatastician repos are on 516bd724 (five) and bd0df9ea (cerro-torre, which predates gen 1 entirely and is fixed by metadatastician/cerro-torre#35). The cliff is recorded because it explains the severity of the general defect, not because anyone is standing on it. PROPAGATION IS ASYMMETRIC -- state this, do not round it off. The DEFECT propagates instantly, because gen 1 fetches from this repo's default branch at runtime. The FIX propagates only at pin-bump speed, because gen 1's `ref:` lives in the reusable YAML that consumers pin. The five repos on 516bd724 keep running `ref: main` until their next sweep. Correct wording for the record: "cured in standards; reaches consumers on the next sweep" -- never "the moving baseline is cured". Until that sweep, `config/gitleaks/estate-baseline.toml` on this branch remains live production config for every no-config consumer with no pin between them and it. #737 records exactly that in the file's own header. VERIFICATION -- a green run proves nothing here. The baseline blob is 1423f3e731283ee241cb18d20285b424438a9f4c at both 516bd724 and origin/main, and `config/gitleaks/estate-baseline.toml` has exactly one commit (86bad549), so before and after stage byte-identical content and any scan count is equal BY CONSTRUCTION. The only discriminator is the checkout log's `ref:` line changing from `main` to a SHA. This repo dogfoods the reusable, so its own run on this branch shows `ref: `. ruby YAML parse: 3 jobs, gitleaks job 9 steps actionlint: reports `property "workflow_sha" is not defined` at BOTH the new line 187 and the pre-existing line 258. Same diagnostic on unmodified main (line 235). actionlint's `job` context schema is {container, services, status}; GitHub does provide job.workflow_sha inside a reusable, verified on consumer run logs 2026-09-02. Not a regression, and standards CI does not lint this file. Self-merged under the standing --admin grant. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/secret-scanner-reusable.yml | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/secret-scanner-reusable.yml b/.github/workflows/secret-scanner-reusable.yml index 117fb7ed1..3a8d73b9d 100644 --- a/.github/workflows/secret-scanner-reusable.yml +++ b/.github/workflows/secret-scanner-reusable.yml @@ -158,15 +158,38 @@ jobs: # and inherit the whole baseline while adding only its own exemptions, so # a repo-specific blind spot stays local to the repo that justified it # instead of widening the allowlist for all 400+. + # + # THIS STEP IS UNGATED ON PURPOSE. It is the only thing that creates + # `.gitleaks-estate.toml` for a consumer with no `.gitleaks.toml` of its + # own — the large majority — and that is exactly the consumer whose + # CONFIG resolves to that file in the scan step below. Do not delete it + # as a duplicate of the gated "Estate baseline — is it referenced?" + # block further down; that block fires only for repos that DO have a + # local config, so removing this one leaves CONFIG naming a file nothing + # creates, across most of the estate. + # + # `ref` was `main` until 2026-09-04, and that was worse than a moving + # pin: the file this step fetches has been RENAMED under it. Before + # 86bad549 the shared allowlist WAS `.gitleaks.toml` (148 lines, 16 + # rules) and gen-1 sparse-checked-out that path; after the rename, + # `.gitleaks.toml` is standards' own 18-line dogfooding stub whose + # `[extend] path` points at `config/gitleaks/estate-baseline.toml` — a + # path the consumer does NOT have, because this step stages exactly one + # file. So every consumer pinned before the rename silently began + # staging a stub with a dangling `[extend]`. `job.workflow_sha` is the + # commit of THIS reusable, so a consumer now receives the baseline as it + # stood at the SHA it pins, and the path each SHA references exists at + # that SHA (verified for all six gen-1 SHAs, 2026-09-04). - name: Fetch estate gitleaks baseline uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: hyperpolymath/standards - ref: main + ref: ${{ job.workflow_sha }} path: .standards-gitleaks sparse-checkout: | config/gitleaks/estate-baseline.toml sparse-checkout-cone-mode: false + persist-credentials: false - name: Stage estate gitleaks baseline run: |