From e4a71bb0de903722b5aa3f08cc0e0fe404f74e7b Mon Sep 17 00:00:00 2001 From: salvacybersec Date: Sun, 5 Apr 2026 23:58:31 +0300 Subject: [PATCH] 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 --- docs/CI-CD.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 docs/CI-CD.md diff --git a/docs/CI-CD.md b/docs/CI-CD.md new file mode 100644 index 0000000..f410b08 --- /dev/null +++ b/docs/CI-CD.md @@ -0,0 +1,161 @@ +# 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.` 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.` 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.