CI: a Lens's verdict and the secret scan's rules run from the base

Merged
DO
3d ago
+358-10

Closes #137, in the scope the Maintainer shrank it to on 2026-10-17. A change can no longer loosen the Lens that judges it in two places: the secret scan's rules and allowlist, and verify's verdict. In this repo no Lens input can come off the list, and decision 0023 says why.

What changes

  • Secret scan (.github/workflows/ci.yml):
    • A second checkout, with the same pinned actions/checkout and persist-credentials: false, puts the base in base/. That is pull_request.base.sha, or merge_group.base_sha, or github.sha on a push to main.
    • The run deletes the head's .gitleaksignore, then scans with --config base/.gitleaks.toml --gitleaks-ignore-path base/.gitleaksignore. A change cannot widen the allowlist it needs. A false positive takes two merges, a cost the Maintainer accepted.
    • The scan adds --log-opts="--full-history --all --diff-filter=tuxdb --text", which is gitleaks' default plus --text, so a head .gitattributes marking a file -diff cannot hide it.
    • It also adds --ignore-gitleaks-allow, so an inline gitleaks:allow in the head is not obeyed.
    • Each of these was proved with a local canary on gitleaks 8.30.1.
    • A new scan_problems() in check_workflows holds all of this, and EXEMPT has the new hash.
  • verify (.github/workflows/verify.yml, its example and the standard): the judging job's only checkout is the base, so it runs the base's tools/needs_passed.py. check_workflows requires one base checkout with persist-credentials: false. A workflow with a judging job may run on pull_request and merge_group only, so the base ref can never come out empty.
  • Decision 0023 records both changes. It also says why no lens_inputs entry comes off the list: here only Dependabot's pin updates use the exemption, and they touch the protected .github/. And it records ci.yml's further departure from the org's text.
  • Design: new trial P-37, what merge_group.base_sha is in a live event. GitHub documents it as the group's parent commit, and the queue history fits that.

Verified:

  • On a git archive export at b695e37, with gitleaks off PATH as in CI: make verify passes and python3 -m tools.mutants kills 404 of 404. check_decisions is clean.
  • The exact ci.yml scan, run locally against a full clone with the base under base/, scans 196 commits and finds no leaks. With the base's ignore file switched off, it reports exactly the four known fingerprints.

Reviewed by: a fresh-context Claude review and a security pass. They found that the scan had no rules at all, fixed first in #144. Also fixed: the .gitattributes and gitleaks:allow gaps, an empty base ref, and a quoted bash -c call.

AGY (Gemini 4 Argon) on 2c7d4ae: two majors and a minor, all real and fixed in 2dda6c5. scan_problems had read only the lines around the gitleaks call, and only the order of the two checkouts. It now holds the scan job to exactly four steps in order: the head's checkout, the base's checkout, the install, the scan. The scan step must be SCAN_RUN exactly, with no env, defaults, container or working-directory. The two untested branches now have tests and mutants. CodeRabbit's step-level if: false is refused by the same rule.

Muse Wonder (muse-wonder-1.0) on 2c7d4ae: its major, a shell function named gitleaks inside the scan step, is refused at 2dda6c5. Two gaps are left, and both are held today by ci.yml's hash and the model review: a stub binary written by the install step, and a downgraded checkout pin. Both are filed as #146.

CI's mutation shards on 2dda6c5: four mutants survived. They targeted code that read gitleaks calls by option, path or quotes, which became dead once the scan step had to equal SCAN_RUN. The code and its mutants are removed in b695e37. They had looked killed locally only because an unrelated test failed under load, which is filed as #147.

Follow-up: the judging job's env: could carry BASH_ENV or PYTHONPATH. The workflow file is the head's own, and .github/ changes need the model review (decision 0020).

šŸ¤– Generated with Claude Code

Summary by CodeRabbit

  • Security
    • Secret scanning now uses the pull-request or merge-queue base revision’s rules while scanning the submitted changes and their history. Inline gitleaks:allow annotations are ignored.
    • Required verification now evaluates the base revision, while checks and mutation testing continue to run against the submitted changes.
  • Documentation
    • Updated workflow guidance and architecture records to describe how base revisions are selected and evaluated in pull requests and merge queues.