diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index 5fadda02c3..64dbf7ec76 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -34,10 +34,20 @@ jobs: | tar -xz gitleaks sudo mv gitleaks /usr/local/bin/gitleaks - - name: Run gitleaks (all our branch commits, excluding submodule history) + # ONE-TIME AUDIT, not for merge: until #2389, PR scans covered 0 commits, + # so commits that live only on a branch or a PR head were never scanned. + # This run scans every remote head plus every refs/pull/*/head. It prints + # commit, file and rule only, never the value. + - name: Fetch every pull-request head + run: git fetch -q origin '+refs/pull/*/head:refs/remotes/pr/*' + + - name: Audit gitleaks over every remote head and PR head run: | - # Scan the full history of our branches (not --all, which includes - # submodule git objects from _external/clawdbot). - # ~500 commits, ~15s. Catches historical leaks in our own code. - gitleaks detect --source . --config .gitleaks.toml --redact -v \ - --log-opts="--branches --remotes=origin/main --remotes=origin/v1.0.x" + echo "refs: $(git for-each-ref refs/remotes | wc -l)" + echo "commits: $(git rev-list --remotes | wc -l)" + gitleaks detect --source . --config .gitleaks.toml --redact \ + --report-format json --report-path /tmp/audit.json \ + --log-opts="--remotes" || true + echo "findings: $(jq length /tmp/audit.json)" + jq -r '.[] | "\(.Commit[0:12]) \(.File) \(.RuleID)"' /tmp/audit.json | sort -u + test "$(jq length /tmp/audit.json)" = 0 diff --git a/.gitleaks.toml b/.gitleaks.toml index 80b8f7ffe9..967a926260 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -17,6 +17,11 @@ regexes = [ # (shared on the landing page, README, and Discord). Tests pin it as the # REACT_APP_COMMUNITY_INVITE_TOKEN fixture; it is not a secret. '''7b91255f18ae3c0ae3721707a6613731''', + # A fake ChatGPT JWT in agentProvisionerServiceK8s.test.js (#2213): the + # base64 of {"alg":"RS256"} followed by the literal ".jwt", no payload and no + # signature. generic-api-key matched it, and main's Secret Scan was red on + # every push from 2026-10-16. The exact literal only, so a real token still fails. + '''eyJhbGciOiJSUzI1NiJ9\.jwt''', ] paths = [