Operator: GSA / cloud.gov | License: CC0 (Public Domain)
Caulking installs global Git hooks that run gitleaks so you don't accidentally commit or push secrets.
It's intentionally boring:
- deterministic install
- predictable XDG layout
- explicit verify/audit
- minimal moving parts
If you want fancy, you're in the wrong repo. If you want "it works the same every time," welcome.
After install, Git will use a global hooks directory:
- Hooks live at:
~/.config/git/hooks/pre-commit(scans staged changes)pre-push(scans the pushed range)
- Git is configured to use this globally (done by
make install):git config --global core.hooksPath ~/.config/git/hooks
Caulking also writes a global gitleaks config:
~/.config/gitleaks/config.toml
Important: the global config must extend defaults, or you've built security theater:
[extend]
useDefault = trueCaulking prevents two categories of leaks:
Gitleaks scans staged content for patterns matching:
- AWS access keys and secrets
- GitHub/GitLab tokens
- Private keys (RSA, DSA, ECDSA, Ed25519)
- API keys and bearer tokens
- Database connection strings
- And 100+ other secret patterns
See the gitleaks rule list for details.
Caulking blocks commits containing high-risk file types regardless of content:
- Private keys:
.pem,.key,.p12,.pfx,.jks - SSH keys:
id_rsa,id_ed25519,id_ecdsa,ssh_host_*_key - Credentials:
.env,.envrc,.netrc,.git-credentials - Cloud configs:
.aws/credentials,.kube/config,.docker/config.json - Terraform state:
.tfstate,.tfvars
This denylist cannot be bypassed via allowlist. If you need to commit a .pem file, you are doing something wrong.
Required:
git(configured with user.name and user.email)bash4.0+gitleaksv8.21.0+
Optional (but useful):
brew(macOS install helper)prekorpre-commit(only needed if you want to run repo lint/format hooks viamake lint)
macOS (Homebrew):
brew install gitleaksIf gitleaks is missing during make install, Caulking will attempt to install it via Homebrew automatically.
Linux (manual):
# Download latest release (adjust version and arch as needed)
GITLEAKS_VERSION=8.30.1
ARCH=x64 # or arm64 for ARM systems
curl -sSfL -o /tmp/gitleaks.tar.gz \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_${ARCH}.tar.gz"
sudo tar xzf /tmp/gitleaks.tar.gz -C /usr/local/bin gitleaks
rm /tmp/gitleaks.tar.gz
# Verify installation
gitleaks versionLinux (package managers):
# Arch Linux (AUR)
yay -S gitleaks
# NixOS
nix-env -iA nixpkgs.gitleaksFor other distributions, see the gitleaks releases page.
git clone https://github.com/cloud-gov/caulking.git
cd caulking
make install
make verifyIf make verify passes, you'll see an audit box confirming all checks passed with a verification ID for compliance records.
If make verify fails, it will tell you what is broken and how to fix it. The output is not lyrical, but it is correct.
Once installed, you don't "run" Caulking.
You just work:
git commit -m "..."
git pushIf you stage or push something that looks like a secret, gitleaks blocks it. That is the whole point.
If you stage a secret, the commit will fail with output showing:
- The matched rule (e.g.,
aws-access-token) - The file and line number
- A snippet of the matched content
The commit does not proceed. Fix the issue before continuing.
False positives happen. The correct fix is to teach the scanner, not to train yourself to ignore warnings.
Add a file named .gitleaks.repo.toml at the root of your repository:
title = "Repo allowlist"
[extend]
useDefault = true
[allowlist]
description = "Allow known-safe patterns for this repo"
regexes = [
# Example: fake test secret used in fixtures
"FAKE_TEST_SECRET_12345",
]
paths = [
# Example: allow generated artifacts or fixtures
"fixtures/.*",
]This is the right default for:
- test fixtures
- fake credentials
- intentionally embedded example tokens
- generated files you do not control
It keeps the global policy strict while allowing local exceptions where they make sense.
The global gitleaks config lives at:
~/.config/gitleaks/config.toml
It contains a small allowlist section:
[allowlist]
regexes = [
"(?i)example(_|-)?key",
"(?i)dummy(_|-)?secret",
]Only put patterns here that are:
- universally safe across all repos you work in
- genuinely non-secret examples
If you find yourself wanting to add lots of entries here, you are probably doing the wrong thing. Move them into a per-repo allowlist instead.
If you need to bypass gitleaks for a single operation:
SKIP=gitleaks git commit -m "..."
SKIP=gitleaks git pushThis bypasses gitleaks pattern scanning only. The filename denylist cannot be bypassed.
This is an escape hatch, not a workflow. If you use it often, your rules are wrong and you should fix them.
This repo includes a local .pre-commit-config.yaml for formatting and linting itself.
make lintUses:
prekif available- otherwise
pre-commit
If neither is installed, it fails loudly. This is deliberate.
Verify proves that enforcement actually works:
make verifyThe verify output includes a verification ID (e.g., caulk-20260429-221622-bb9a4a92) with user, host, platform, and timestamp for audit documentation.
For a quick status check:
make statusThis shows whether hooks are installed and gitleaks is working, without running the full functional test suite.
Audit is intentionally boring and currently aliases verify:
make auditIf you want pretty dashboards, write one. This tool is about not leaking secrets.
Caulking follows the XDG Base Directory Specification. All files go under ~/.config/:
Hooks:
~/.config/git/hooks/pre-commit~/.config/git/hooks/pre-push
Gitleaks config:
~/.config/gitleaks/config.toml
State:
~/.config/caulking/previous_hookspath
This exists solely to restore your previous core.hooksPath on uninstall. It is not a feature. It is housekeeping.
Pull the latest version and reinstall:
cd caulking
git pull
make install
make verifyCaulking does not have automatic updates. You are responsible for keeping it current.
git config --global --get core.hooksPath
ls -la ~/.config/git/hooksIf that path is wrong or the files aren’t executable, your hooks won’t run. This is not subtle.
chmod +x install.sh uninstall.sh verify.sh hooks/*.sh scripts/*.sh tests/*.shThen rerun:
make installIf a repo sets a local core.hooksPath, it can override the global one.
Check a tree of repos with:
./check_repos.sh <root_dir> check_hooks_pathThis scans all git repositories under <root_dir> and reports any that set a local core.hooksPath. Fix the offenders. Don't normalize bypassing guardrails.
Caulking requires a POSIX shell. On Windows, use WSL (Windows Subsystem for Linux). Native Windows (Git Bash, PowerShell) is not supported.
make uninstallThis:
- removes installed hook scripts
- restores your previous
core.hooksPathif recorded - leaves your global gitleaks config in place (on purpose)
If you want to fully nuke state, you can remove the XDG directories yourself. That is your call.
Do not report security issues in public GitHub issues.
Follow SECURITY.md and cloud.gov’s security.txt.
This project is public domain (CC0). See LICENSE.md.