Files
keyhunter/docs/CI-CD.md
salvacybersec e4a71bb0de docs(07-06): add CI/CD integration guide
- 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
2026-04-05 23:58:31 +03:00

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.