- 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
162 lines
5.7 KiB
Markdown
162 lines
5.7 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
git commit --no-verify -m "hotfix: bypass scan"
|
|
```
|
|
|
|
No KeyHunter state is changed — the next commit will be scanned normally.
|
|
|
|
### Uninstall
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```yaml
|
|
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)
|
|
|
|
```bash
|
|
trufflehog filesystem . --json > trufflehog.json
|
|
keyhunter import --format=trufflehog trufflehog.json
|
|
```
|
|
|
|
### Gitleaks (JSON)
|
|
|
|
```bash
|
|
gitleaks detect -f json -r gitleaks.json
|
|
keyhunter import --format=gitleaks gitleaks.json
|
|
```
|
|
|
|
### Gitleaks (CSV)
|
|
|
|
```bash
|
|
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.
|