feat: add gitleaks secret scanning setup and skill
- scripts/setup-gitleaks.sh — installs gitleaks v8.24.2, seeds .gitleaks.toml on first run, writes managed pre-commit hook block; re-run replaces block in place without disturbing other hook content - scripts/gitleaks.toml — base config template extending default ruleset - .gitleaks.toml — repo config with docs/research/ path allowlist (high-entropy terminal captures; v8.24.2 [allowlist] syntax) - tests/test-setup-gitleaks.sh — 6 behavior tests including stale-block replacement and idempotency - .agents/skills/gitleaks/ — cross-cutting skill covering install, update, allowlist tuning, scan modes, and real-finding remediation - .agents/evals/cross-cutting/gitleaks/eval.yaml — 7 trigger + 3 output tests including version-aware allowlist guidance case - docs/spec/overview.md — updated to reflect new tooling and skill Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
24
scripts/gitleaks.toml
Normal file
24
scripts/gitleaks.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
title = "gitleaks config"
|
||||
|
||||
[extend]
|
||||
# Extends the default ruleset built into gitleaks.
|
||||
# Remove useDefault and define [[rules]] from scratch if you want full control.
|
||||
useDefault = true
|
||||
|
||||
# Rules to disable from the default set — uncomment and add IDs for known false positives.
|
||||
# Run `gitleaks git -v` on your repo first to discover which rules fire.
|
||||
# disabledRules = ["generic-api-key"]
|
||||
|
||||
# Global allowlist — applies to all rules.
|
||||
# Note: uses [allowlist] (v8 syntax). v8.25.0+ uses [[allowlists]] (array of tables).
|
||||
# Add path regexes or stopwords to suppress known false positives.
|
||||
#
|
||||
# Example: ignore test fixtures
|
||||
# [allowlist]
|
||||
# description = "test fixtures"
|
||||
# paths = ['''tests/fixtures/.*''']
|
||||
#
|
||||
# Example: ignore a known false-positive secret value
|
||||
# [allowlist]
|
||||
# description = "placeholder values in docs"
|
||||
# stopwords = ["example", "placeholder", "changeme"]
|
||||
124
scripts/setup-gitleaks.sh
Executable file
124
scripts/setup-gitleaks.sh
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Sets up gitleaks as a git pre-commit hook in a target repository.
|
||||
# Usage: setup-gitleaks.sh [TARGET_REPO]
|
||||
# TARGET_REPO — path to the git repo to configure (default: current directory)
|
||||
# Idempotent: safe to re-run; always replaces the hook block with the current version.
|
||||
|
||||
GITLEAKS_VERSION="8.24.2"
|
||||
GITLEAKS_INSTALL_DIR="${GITLEAKS_INSTALL_DIR:-/usr/local/bin}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TARGET="${1:-$(pwd)}"
|
||||
HOOK_FILE="$TARGET/.git/hooks/pre-commit"
|
||||
CONFIG_SRC="$SCRIPT_DIR/gitleaks.toml"
|
||||
CONFIG_DEST="$TARGET/.gitleaks.toml"
|
||||
MARKER="# managed by setup-gitleaks.sh"
|
||||
END_MARKER="# end gitleaks"
|
||||
|
||||
# --- Install gitleaks if not present ---
|
||||
|
||||
install_gitleaks() {
|
||||
local os arch tarball url tmp_dir
|
||||
|
||||
case "$(uname -s)" in
|
||||
Linux) os="linux" ;;
|
||||
Darwin) os="darwin" ;;
|
||||
*)
|
||||
echo "Error: unsupported OS '$(uname -s)' — install gitleaks manually from https://github.com/gitleaks/gitleaks/releases" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64) arch="x64" ;;
|
||||
aarch64 | arm64) arch="arm64" ;;
|
||||
*)
|
||||
echo "Error: unsupported architecture '$(uname -m)' — install gitleaks manually from https://github.com/gitleaks/gitleaks/releases" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
tarball="gitleaks_${GITLEAKS_VERSION}_${os}_${arch}.tar.gz"
|
||||
url="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${tarball}"
|
||||
tmp_dir="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp_dir"' RETURN
|
||||
|
||||
echo "Installing gitleaks v${GITLEAKS_VERSION}..."
|
||||
curl -fsSL "$url" -o "$tmp_dir/$tarball"
|
||||
tar -xzf "$tmp_dir/$tarball" -C "$tmp_dir" gitleaks
|
||||
install -m 755 "$tmp_dir/gitleaks" "$GITLEAKS_INSTALL_DIR/gitleaks"
|
||||
echo "Installed: $GITLEAKS_INSTALL_DIR/gitleaks"
|
||||
}
|
||||
|
||||
if ! command -v gitleaks &>/dev/null; then
|
||||
install_gitleaks
|
||||
fi
|
||||
|
||||
# --- Validate ---
|
||||
|
||||
if [ ! -d "$TARGET/.git" ]; then
|
||||
echo "Error: $TARGET is not a git repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$CONFIG_SRC" ]; then
|
||||
echo "Error: config template not found at $CONFIG_SRC" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Deploy config ---
|
||||
|
||||
if [ -f "$CONFIG_DEST" ]; then
|
||||
echo "Skipped: $CONFIG_DEST already exists — edit it directly to customise rules."
|
||||
else
|
||||
cp "$CONFIG_SRC" "$CONFIG_DEST"
|
||||
echo "Wrote: $CONFIG_DEST"
|
||||
echo " Commit this file — it belongs in version control."
|
||||
fi
|
||||
|
||||
# --- Deploy hook ---
|
||||
|
||||
hook_block() {
|
||||
cat <<BLOCK
|
||||
|
||||
$MARKER
|
||||
if command -v gitleaks &>/dev/null; then
|
||||
gitleaks git --staged --redact -v
|
||||
else
|
||||
echo "Warning: gitleaks not installed — secret scan skipped (https://github.com/gitleaks/gitleaks/releases)" >&2
|
||||
fi
|
||||
$END_MARKER
|
||||
BLOCK
|
||||
}
|
||||
|
||||
write_hook() {
|
||||
local hook_file="$1"
|
||||
|
||||
if grep -qF "$MARKER" "$hook_file"; then
|
||||
# Remove old block (start marker through end marker inclusive) then append current version
|
||||
awk -v start="$MARKER" -v end="$END_MARKER" '
|
||||
$0 == start { skip=1; next }
|
||||
skip && $0 == end { skip=0; next }
|
||||
!skip { print }
|
||||
' "$hook_file" > "${hook_file}.tmp" && mv "${hook_file}.tmp" "$hook_file"
|
||||
hook_block >> "$hook_file"
|
||||
echo "Updated: $hook_file (gitleaks block replaced)"
|
||||
else
|
||||
hook_block >> "$hook_file"
|
||||
echo "Updated: $hook_file (gitleaks block appended to existing hook)"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -f "$HOOK_FILE" ]; then
|
||||
write_hook "$HOOK_FILE"
|
||||
else
|
||||
{ echo '#!/usr/bin/env bash'; echo 'set -euo pipefail'; hook_block; } > "$HOOK_FILE"
|
||||
chmod +x "$HOOK_FILE"
|
||||
echo "Created: $HOOK_FILE"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Done. Staged secrets will be scanned on every commit in $TARGET."
|
||||
echo "To skip on a single commit: SKIP=gitleaks git commit ..."
|
||||
Reference in New Issue
Block a user