Goal
Secret scanning of in-flight pushes is a core proxy capability. The specific tool that does the scanning is an implementation detail — different scanners have different trade-offs (detection recall, binary size, rule sets, performance) and operators should be able to choose.
Extract a SecretScanner interface from the current GitleaksRunner implementation so scanners are swappable without touching the hook/filter chain.
Contract
interface SecretScanner {
Optional<List<Finding>> scan(String diff, SecretScanConfig config);
Optional<List<Finding>> scanGit(Path repoDir, String commitFrom, String commitTo, SecretScanConfig config);
}
Both methods follow the existing fail-open contract: Optional.empty() means the scanner was unavailable or errored; Optional.of(list) means the scanner ran (list may be empty for a clean result).
Candidate implementations
| Scanner |
Binary size |
Notes |
| gitleaks (current) |
~21MB (8.30.1) |
Stable, well-known; grew significantly in recent releases |
| betterleaks |
~40MB (v1.1.2, down from 51MB) |
Higher recall (98.6% vs 70.4%), 4–5× faster; CLI subcommand structure differs from gitleaks — needs adapter work |
What needs doing
- Extract
SecretScanner interface from GitleaksRunner
- Rename
GitleaksRunner → GitleaksScanner implements SecretScanner
- Add
commit.secretScanning.engine config key (default: gitleaks)
- Wire selected implementation through
SecretScanConfig or a scanner factory
- When betterleaks CLI is stable enough: add
BetterleaksScanner implementation and verify the same tests pass
Notes on betterleaks CLI compatibility (needs verification before point 5)
detect --pipe → stdin subcommand (reads unified diff from stdin)
git --log-opts=<range> semantics need confirming
- Exit code for findings must be configurable to match our
FINDINGS_EXIT_CODE = 2 assumption
- Binary size is trending down; worth re-evaluating when it approaches gitleaks parity
Goal
Secret scanning of in-flight pushes is a core proxy capability. The specific tool that does the scanning is an implementation detail — different scanners have different trade-offs (detection recall, binary size, rule sets, performance) and operators should be able to choose.
Extract a
SecretScannerinterface from the currentGitleaksRunnerimplementation so scanners are swappable without touching the hook/filter chain.Contract
Both methods follow the existing fail-open contract:
Optional.empty()means the scanner was unavailable or errored;Optional.of(list)means the scanner ran (list may be empty for a clean result).Candidate implementations
What needs doing
SecretScannerinterface fromGitleaksRunnerGitleaksRunner→GitleaksScanner implements SecretScannercommit.secretScanning.engineconfig key (default:gitleaks)SecretScanConfigor a scanner factoryBetterleaksScannerimplementation and verify the same tests passNotes on betterleaks CLI compatibility (needs verification before point 5)
detect --pipe→stdinsubcommand (reads unified diff from stdin)git --log-opts=<range>semantics need confirmingFINDINGS_EXIT_CODE = 2assumption