- Pre-commit hook install/force/uninstall lifecycle - GitHub Actions workflow example with SARIF upload - External scanner import walkthrough (trufflehog, gitleaks) - Exit-code table for CI gating
5.7 KiB
KeyHunter CI/CD Integration
KeyHunter is designed to plug into developer workflows at three points: as a local pre-commit hook that blocks leaks before they land in git history, as a GitHub Actions step that uploads SARIF findings into the repository's Code Scanning tab, and as an import sink that consolidates results from other scanners (TruffleHog, Gitleaks) into one normalized database. This guide shows how to wire up each one.
Pre-commit Hook
The pre-commit hook scans only files that are staged for commit
(git diff --cached --name-only --diff-filter=ACMR), so it adds minimal latency to
local development while still catching fresh leaks before they leave the workstation.
Install
keyhunter hook install
This writes an executable shell script to .git/hooks/pre-commit in the current
repository. The script shells out to the keyhunter binary on your PATH and exits
non-zero if any findings are produced — which aborts the commit.
The command refuses to overwrite an existing pre-commit hook unless you pass
--force:
keyhunter hook install --force
With --force, the existing hook is backed up to
.git/hooks/pre-commit.bak.<unix-timestamp> before the new one is written. You can
restore it manually at any time.
Bypass a Single Commit
If you need to commit in an emergency and want to skip the hook for one commit only, use git's built-in bypass flag:
git commit --no-verify -m "hotfix: bypass scan"
No KeyHunter state is changed — the next commit will be scanned normally.
Uninstall
keyhunter hook uninstall
This removes .git/hooks/pre-commit. Any .bak.<timestamp> files created by
--force are left in place so you can restore previous hooks manually.
GitHub Actions (SARIF upload to Code Scanning)
KeyHunter emits SARIF 2.1.0 output (--output sarif), which GitHub's Code Scanning
service ingests directly. Once uploaded, findings appear in the repository's
Security tab, can be triaged, and can block pull requests via branch protection
rules.
Save the following as .github/workflows/keyhunter.yml:
name: KeyHunter
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install KeyHunter
run: |
curl -sSL https://github.com/salvacybersec/keyhunter/releases/latest/download/keyhunter_linux_amd64.tar.gz | tar -xz
sudo mv keyhunter /usr/local/bin/
- name: Scan repository
run: keyhunter scan . --output sarif > keyhunter.sarif
continue-on-error: true
- name: Upload SARIF to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: keyhunter.sarif
category: keyhunter
Why continue-on-error: true?
KeyHunter exits with code 1 when it finds keys (see Exit Codes below). Without
continue-on-error: true, GitHub Actions would mark the scan step as failed and skip
the upload step — meaning the findings would never reach the Security tab. Letting
the scan "fail" gracefully and then uploading the SARIF file gives you both the
annotated findings in Code Scanning and the option to enforce blocking via branch
protection rules on the Code Scanning check itself.
Why security-events: write?
GitHub requires the security-events: write permission on the job for
github/codeql-action/upload-sarif@v3 to post results into Code Scanning. The
default GITHUB_TOKEN has this permission available but it must be explicitly
requested at the job level when using fine-grained workflow permissions. fetch-depth: 0
ensures the full history is available so findings can be attributed to specific
commits.
Importing External Scanner Output
KeyHunter's import subcommand consolidates findings from other scanners into its
SQLite database. This is useful when you run multiple tools in CI and want a single
place to triage, verify, and track leaks over time.
TruffleHog (JSON)
trufflehog filesystem . --json > trufflehog.json
keyhunter import --format=trufflehog trufflehog.json
Gitleaks (JSON)
gitleaks detect -f json -r gitleaks.json
keyhunter import --format=gitleaks gitleaks.json
Gitleaks (CSV)
gitleaks detect -f csv -r gitleaks.csv
keyhunter import --format=gitleaks-csv gitleaks.csv
Idempotency
Every imported finding is hashed on (provider, masked_key, source) before insert.
Re-running the same import — for example, because a later CI step needs to consume
the results — will not create duplicate rows. The command prints a summary of the
form Imported N findings (M new, K duplicates) so you can confirm dedup worked.
Exit Codes
Both keyhunter scan and keyhunter import follow the same exit-code convention so
they compose predictably with CI runners and shell scripts:
| Code | Meaning | Typical CI usage |
|---|---|---|
0 |
Clean run — no findings | Step passes, pipeline continues |
1 |
Findings present | Mark the job as failed / upload SARIF anyway |
2 |
Runtime error (bad flags, I/O, parse fail) | Pipeline should stop; investigate logs |
For GitHub Actions SARIF uploads, use continue-on-error: true on the scan step so
that exit code 1 still lets the upload step run. For simple gating (e.g. a Makefile
target), keyhunter scan . && echo clean || echo findings distinguishes the three
states.