Skip to content

ci: canary-test the secret scanner, and actually run tests/ - #530

Merged
hyperpolymath merged 3 commits into
mainfrom
ci/secret-scanner-canary-and-self-test
Jul 27, 2026
Merged

ci: canary-test the secret scanner, and actually run tests/#530
hyperpolymath merged 3 commits into
mainfrom
ci/secret-scanner-canary-and-self-test

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Phase 3 (preventive) of the secret-scanner programme. Two gaps, one shape.

1. The secret scanner had no canary

Every defect found in the 201-repo sweep was invisible in CI, because a gate that cannot fail is indistinguishable from a gate that passes:

Defect Consequence
continue-on-error: true on gitleaks scan found a live Cloudflare Global API Key in a PUBLIC repo and reported success anyway — for months, across ~200 repos
rust-secrets grepped ./src only Cargo workspaces keep code in crates/*/src; grep exits 2 on a missing dir and the if read that as clean. 8 of 64 Rust repos (12.5%) never scanned at all
const.*KEY.*= missed static AUTH_KEY found only because a canary planted 5 secrets and the job reported 4

tests/test_secret_scanner_canary.sh plants known secrets and asserts the scanner still trips — 9 assertions:

PASS  5 planted secrets in ./src -> BLOCKS
PASS  all 5 planted secrets reported (not just the first)
PASS  secret in crates/*/src -> BLOCKS after cutoff (no root ./src)
PASS  secret in crates/*/src -> advisory before cutoff
PASS  advisory run reports the finding and never claims a clean pass
PASS  env::var / URL / lookup / path / comment / pragma -> ALLOWED
PASS  literal secret + later env::var mention -> STILL BLOCKS
PASS  malformed cutoff -> REFUSES TO RUN
PASS  no Cargo.toml -> skips cleanly

Note assertion 2 counts findings rather than checking the exit code. The static AUTH_KEY defect passed an exit-code assertion — exit 1 only proves ≥1 was found, not that all were.

It extracts the step body from secret-scanner-reusable.yml at run time and executes it. Not a copy: a copy silently drifts from what ships, which is how these defects survived review.

Mutation tested

A canary that cannot fail would be the very thing it guards against. Reintroducing each historical defect kills it:

Mutant Result
./src-only scan ✓ killed
drop static from the KEY pattern ✓ killed
make the job unable to fail ✓ killed
over-broad env::var exemption ✓ killed
disarm the date guard ✓ killed

5/5.

2. tests/ was wired into no workflow

tests/test_check_trusted_base.sh has existed for some time and never executed in CI — the same shape a third time: a test that never runs looks exactly like a test that passes.

self-test.yml runs every tests/*.sh, so adding a test is now sufficient to have it enforced. Fail-closed: empty discovery fails the job rather than reporting a vacuous pass.

Also: registry regeneration

7 stale source_hash entries accumulated from #522/#525 plus these new files.

⚠️ This is the fourth registry-drift repair today. The drift keeps reaching main because Registry + topology in sync is not a required status check, while a phantom Dependabot context forces --admin on every merge — which bypasses all protection including the check that correctly failed on the PR. That ruleset fix is owner-only and tracked separately; without it this repair will be needed again.

Verified

  • both test files pass locally (2/2)
  • canary 9/9 against the shipping reusable
  • 5/5 mutants killed
  • scripts/build-registry.sh --check exits 0

🤖 Generated with Claude Code

hyperpolymath and others added 3 commits July 27, 2026 13:49
Phase 3 (preventive) of the secret-scanner programme. Two gaps, one shape.

1. THE SECRET SCANNER HAD NO CANARY. Every defect found in the 201-repo sweep
   was invisible in CI, because a gate that cannot fail is indistinguishable
   from a gate that passes:

     * `continue-on-error: true` on gitleaks — the scan found a live Cloudflare
       Global API Key in a PUBLIC repo and reported success anyway, for months,
       across ~200 repos.
     * `rust-secrets` grepped `./src` only. A Cargo workspace keeps code in
       crates/*/src, so grep exited 2 on a missing directory and the enclosing
       `if` read that as "clean" — 8 of 64 Rust repos (12.5%) were never
       scanned at all.
     * `const.*KEY.*=` never matched `static AUTH_KEY: &str = "…"`. That was
       found ONLY because a canary planted 5 secrets and the job reported 4.
       No amount of reading the regex would have shown it.

   `tests/test_secret_scanner_canary.sh` plants known secrets and asserts the
   scanner still trips: 9 assertions covering detection (with a COUNT, not just
   an exit code — the `static` defect passed an exit-code check), workspace
   layout, correct-code exemptions, exemption over-breadth, the self-flipping
   cutoff, and the malformed-cutoff refusal.

   It extracts the step body from secret-scanner-reusable.yml at run time and
   executes it. NOT a copy — a copy silently drifts from what ships, which is
   how these defects survived review in the first place.

   MUTATION TESTED. Reintroducing each historical defect kills the canary:
     src-only (F-10) ✓   no-static (F-11) ✓   cannot-fail (F-08) ✓
     over-broad env exemption ✓   disarmed date guard ✓        5/5 killed.
   A canary that cannot fail would be the very thing it guards against.

2. tests/ WAS WIRED INTO NO WORKFLOW. `test_check_trusted_base.sh` has existed
   for some time and never executed in CI — same shape again: a test that never
   runs looks exactly like a test that passes. `self-test.yml` runs every
   tests/*.sh, so adding a test is now sufficient to have it enforced. It is
   fail-closed: empty discovery fails the job rather than reporting a vacuous
   pass.

Also regenerates REGISTRY.a2ml — 7 stale source_hash entries accumulated from
#522/#525 plus these new files. This is the fourth registry-drift repair today;
the drift keeps reaching main because `Registry + topology in sync` is not a
required status check while a phantom `Dependabot` context forces --admin on
every merge. That ruleset fix is owner-only and tracked separately; without it
this repair will be needed again.

Verified: both test files pass locally (2/2); canary 9/9 against the shipping
reusable; 5/5 mutants killed; `build-registry.sh --check` exits 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hyperpolymath
hyperpolymath merged commit 0311aa1 into main Jul 27, 2026
18 of 19 checks passed
@hyperpolymath
hyperpolymath deleted the ci/secret-scanner-canary-and-self-test branch July 27, 2026 13:04
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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