ci(security): gate the secrets scan on a reviewed baseline - #2351
Conversation
Every finding is identified by sha256(detector|path|raw), truncated to 16 hex. The hash carries no commit id, so an entry survives a rebase; it is a hash rather than the tuple because the third field is the secret itself. Findings whose fingerprint is listed in .github/trufflehog-allowlist.txt are known false positives and do not fail the run; anything else does, in the blocking job. Accepting a new one means adding a line with a reason in the pull request that introduces it, so the claim is reviewed like any other diff. The three jobs now share one script instead of three inline heredocs, and it reads both the Git and the Github source metadata shapes. Refs #2301 Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
📝 WalkthroughWalkthroughChangesThe PR adds a shared TruffleHog JSONL gate, a reviewed fingerprint allowlist, and workflow integration. Pull-request scans block on new findings. Full-history and GitHub API scans report findings without blocking. TruffleHog scanning and reporting
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant TruffleHog
participant Workflow
participant trufflehog_gate.py
participant Allowlist
participant GitHubSummary
TruffleHog->>Workflow: Produce JSONL findings
Workflow->>trufflehog_gate.py: Run scan gate
trufflehog_gate.py->>Allowlist: Load fingerprints
trufflehog_gate.py->>GitHubSummary: Append redacted summary
trufflehog_gate.py->>Workflow: Return block or report status
Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/scripts/trufflehog_gate.py:
- Around line 50-54: Update the final gate decision in the summary logic to
return nonzero when mode is block and unparsable is greater than zero, even when
no parsed finding is new. Preserve the existing success behavior for non-block
modes and block runs with zero unparsable output, using the existing unparsable
counter.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6ff9a766-1cd5-42bc-aa5f-f4daeb481a04
📒 Files selected for processing (3)
.github/scripts/trufflehog_gate.py.github/trufflehog-allowlist.txt.github/workflows/trufflehog.yml
Fixes a problem found by CodeRabbit on this pull request: an empty result was reported as a pass even when a line failed to parse. A truncated stream drops every finding after the break, so in the blocking job that is not a pass. Only unparsable lines count. Records that parse but carry no detector are ordinary scanner output and stay silent. Refs #2301 Signed-off-by: Gregory Gogin <grigoriy.gogin@constructor.tech>
Refs #2301.
The secrets gate cannot tell a credential from ordinary code. A scan of every ref returns 272 findings across 9 detectors and not one is a credential — test function names, fixture values, UUIDs, constant names,
CHANGE_MEplaceholders, prose in a document. The 69 markedverifiedare all Lob, whose sandbox accepts anytest_-prefixed string, so a Python test name comes back confirmed. Disabling those detectors is not available to us: Jira, GitLab, HubSpot and Atlassian cover services Insight integrates with, andURIandSQLServercover the connection-string shapes that a real leak takes.This adds a reviewed baseline instead — the mechanism
detect-secretsand gitleaks both use, implemented here because TruffleHog has no equivalent (trufflesecurity/trufflehog#2687, open since 2024).How it works
What the scanner emits. TruffleHog returns no verdict. It writes one JSON object per finding to stdout, which the workflow redirects to a file. Each record carries the detector that matched, the matched value in
Raw, whether the vendor's API confirmed it, and the location underSourceMetadata.Data.Git— or under.Github, with alinkinstead of afile, when the source is the GitHub API. Deciding whether any of that should fail a build has always been our code's job; until now that code was three copies of a heredoc inlined in the YAML.Fingerprint. Each finding is named by
sha256(detector | path | raw), truncated to 16 hex characters.sha256keeps the value out of a file that lives in a public repository.Allowlist.
.github/trufflehog-allowlist.txt, one line per accepted finding:The script reads only the first field. The detector, path and reason are for the reviewer, who can check the claim without running a scanner. A missing file is not an error — the baseline is then empty and the gate behaves as it did before. Seeded with the 120 fingerprints that the current 272 findings reduce to.
The run. Findings are split into those whose fingerprint is listed and those that are not. The step summary reports the known ones as a count and the new ones as a table — detector, verified, commit, path, fingerprint.
Rawnever reaches the summary, the log or an artifact. The blocking job exits non-zero when the table is non-empty; the two nightly jobs report and always exit zero.secrets (diff)secrets (full history)secrets (GitHub API)What this means for a pull request author
Nothing, in about thirteen of every fourteen pull requests. The 272 findings already in the repository are seeded into the baseline and never surface again, and the nightly jobs never fail anything, so the only findings an author ever sees are ones their own diff introduced.
When the check does go red, the run summary names the finding. From there:
.github/trufflehog-allowlist.txtin the same pull request, copying the fingerprint from the table and writing the reason. Push; the check clears.The reviewer then sees that line in the diff, next to the code that produced it, and can judge the claim. That is the property
--exclude-detectorscannot offer: there the same decision is made once, silently, and applies to the whole repository forever.Expected frequency. 120 distinct false positives accumulated over the repository's 5.7 months, or roughly 21 a month, against 285 pull requests merged in the last 30 days — about one pull request in fourteen. They are not evenly spread: 55 are test function names and 32 are e2e metric fixtures, so the cost falls on people writing Python tests and metric expectations, not on everyone.
What does not change
No detector is disabled. A live Jira, GitLab or HubSpot token produces a fingerprint that is not in the file, which makes it new, which fails the build. The scan arguments, the result kinds and the redaction rules are untouched.
Test plan
No new secrets. 272 known finding(s) matched the allowlist.src/backend/config.rs: exit 1, and the table lists that finding alone, with its fingerprintreportmode on the same corpus: exit 0blockexits 1 withScan output was incomplete: 1 unparsable line(s)…,reportstill exits 0, and the intact corpus still exits 0python -m py_compileon the script; YAML parses; the three jobs keep their step orderactionlint .github/workflows/trufflehog.yml— exit 0secrets (diff)green on this pull requestsecrets (full history)reports 272 known and 0 newFollow-up
Once this lands, the
# trufflehog:ignoreadded to.github/workflows/ghcr-cleanup.ymlin #2308 can go: that finding belongs in the allowlist like the rest.Summary by CodeRabbit
New Features
Bug Fixes