Commit 3e4bd4c
authored
feat(governance): add secret-scanner-reusable.yml — propagate shell-secrets to 281 repos (#190)
## Summary
Extends the reusable-workflow pattern from #168 / #174 / #187 to
**secret-scanner.yml**. Same shape as #187 (no per-call inputs except
`runs-on`; caller uses `secrets: inherit`).
### Why secret-scanner is the next foundational reusable
Estate drift survey (`gh api /search/code` paginated against
`org:hyperpolymath`, blob-SHA grouped over **all 281 deployments**):
| Metric | Value |
|---|---|
| Total deployments | **281** |
| Unique blob SHAs | **54** |
| Structural drift | **19%** (top 4 SHAs cover 69%, top 6 cover 79%) |
| Feature variance | **near-zero** — all sampled variants carry the same
3 jobs (trufflehog + gitleaks + rust-secrets) at 75-81 lines |
| True drift source | action-SHA pin churn + whitespace |
The 100-sample drift estimate (55%) initially ranked secret-scanner
third behind mirror; the full pagination reveals the actual figure is
19%. The variance was a sampling artefact.
### Security debt this PR force-fixes
The `shell-secrets` job was added to the canonical 2026-05-21 (commit
`080c394`) in direct response to the **live Cloudflare API token leak**
via `avow-protocol/deploy-repos.sh` (commit `5f2f8b2`) — a leak that
both `trufflehog --only-verified` and default `gitleaks` missed.
Of 16 estate `secret-scanner.yml` blobs sampled across the top +
long-tail SHAs, **0 carry the `shell-secrets` job**.
The post-incident guardrail intended to catch the *next* such leak has
propagated to nothing. Consolidating the workflow behind this reusable
means the wrapper sweep that follows this PR force-promotes
`shell-secrets` to all 281 repos in one batch.
### Design
- **No per-call inputs other than `runs-on`** — each job self-conditions
internally:
- `rust-secrets` exits early on no `Cargo.toml` (safe on every repo)
- `shell-secrets` no-ops without `.sh`/`.bash` files
- `trufflehog` + `gitleaks` always-on (intended)
- **`secrets: inherit` required at the call site** — so the inner
`secrets.GITHUB_TOKEN` reference in the `gitleaks-action` step resolves.
Without `inherit` it falls back to anonymous mode (rate-limited; misses
some PRs).
- **Caller keeps `on:` + `concurrency:`** — so the read-only
cancel-superseded guardrail stays in the wrapper.
- SPDX header, top-level `permissions: contents: read`, all actions
SHA-pinned — passes the `workflow-lint` job in
`governance-reusable.yml`.
### Caller wrapper shape (post-merge)
```yaml
# SPDX-License-Identifier: PMPL-1.0-or-later
name: Secret Scanner
on:
pull_request:
push:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
scan:
uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@<sha>
secrets: inherit
```
~12 lines per repo, replacing ~75-116 lines.
### Rollout plan
**NOT started in this PR — owner-gated, same as #187 / #174 sweeps.**
| Wave | Repos | Action |
|---|---|---|
| 1: bulk-mechanical | ~275 | Canonical 3-job match. Fan-out
single-commit wrapper PR per repo, pinned to this PR HEAD; rebase to
merged-main SHA before batch firing. |
| 2: slim variants | ~6 | Repos with 2-job (missing `rust-secrets`) or
1-job (`trufflehog` only) older copies. Standardize-up safely since the
missing job self-skips on non-applicable repos. |
Total expected sweep: ~281 PRs (well above the 82-PR rust-ci precedent —
recommend batching by wave; user gates each wave start).
### Pattern hardening
- Same `workflow_call` shape as #168 / #174 / #187 — no new
infrastructure.
- Independent of #174 (`rust-ci-reusable.yml`), #180
(`apply-baseline.sh` glob fix), and #187 (`mirror-reusable.yml`) — no
file conflicts; lands in any order.
🤖 Generated with [Claude Code](https://claude.com/claude-code)1 parent e6b2884 commit 3e4bd4c
1 file changed
Lines changed: 159 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
0 commit comments