- 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>
152 lines
4.5 KiB
Bash
Executable File
152 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
SCRIPT="$REPO_ROOT/scripts/setup-gitleaks.sh"
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
|
fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
|
|
|
# Fake gitleaks binary — prevents the install step from running during tests
|
|
FAKE_BIN="$(mktemp -d)"
|
|
trap 'rm -rf "$FAKE_BIN"' EXIT
|
|
printf '#!/bin/sh\necho "gitleaks fake"\n' > "$FAKE_BIN/gitleaks"
|
|
chmod +x "$FAKE_BIN/gitleaks"
|
|
export PATH="$FAKE_BIN:$PATH"
|
|
|
|
# Helper: create an isolated git repo in a temp dir
|
|
make_repo() {
|
|
local dir
|
|
dir="$(mktemp -d)"
|
|
git -C "$dir" init -q
|
|
echo "$dir"
|
|
}
|
|
|
|
# Helper: run setup script against a target repo; capture output; always return exit code
|
|
run_setup() {
|
|
local target="$1"
|
|
bash "$SCRIPT" "$target" 2>&1
|
|
}
|
|
|
|
# --- 1. Rejects non-git directory ---
|
|
echo ""
|
|
echo "--- rejects non-git directory ---"
|
|
NON_GIT="$(mktemp -d)"
|
|
trap 'rm -rf "$NON_GIT"' EXIT
|
|
if bash "$SCRIPT" "$NON_GIT" >/dev/null 2>&1; then
|
|
fail "exited 0 for non-git directory — expected exit 1"
|
|
else
|
|
pass "exits non-zero for non-git directory"
|
|
fi
|
|
|
|
# --- 2. Config deployed ---
|
|
echo ""
|
|
echo "--- config deployed to target repo ---"
|
|
REPO="$(make_repo)"
|
|
trap 'rm -rf "$REPO"' EXIT
|
|
run_setup "$REPO" > /dev/null
|
|
if [ -f "$REPO/.gitleaks.toml" ]; then
|
|
pass ".gitleaks.toml created in target repo"
|
|
else
|
|
fail ".gitleaks.toml missing from target repo"
|
|
fi
|
|
if diff -q "$REPO_ROOT/scripts/gitleaks.toml" "$REPO/.gitleaks.toml" > /dev/null 2>&1; then
|
|
pass ".gitleaks.toml matches the template"
|
|
else
|
|
fail ".gitleaks.toml content differs from template"
|
|
fi
|
|
|
|
# --- 3. Hook created from scratch ---
|
|
echo ""
|
|
echo "--- hook created when none exists ---"
|
|
REPO2="$(make_repo)"
|
|
trap 'rm -rf "$REPO2"' EXIT
|
|
run_setup "$REPO2" > /dev/null
|
|
HOOK="$REPO2/.git/hooks/pre-commit"
|
|
if [ -f "$HOOK" ]; then
|
|
pass "pre-commit hook created"
|
|
else
|
|
fail "pre-commit hook not created"
|
|
fi
|
|
if [ -x "$HOOK" ]; then
|
|
pass "pre-commit hook is executable"
|
|
else
|
|
fail "pre-commit hook is not executable"
|
|
fi
|
|
if head -1 "$HOOK" | grep -q "^#!"; then
|
|
pass "pre-commit hook has a shebang"
|
|
else
|
|
fail "pre-commit hook missing shebang"
|
|
fi
|
|
if grep -q "gitleaks git --staged" "$HOOK"; then
|
|
pass "pre-commit hook contains gitleaks command"
|
|
else
|
|
fail "pre-commit hook missing gitleaks command"
|
|
fi
|
|
if grep -q "# managed by setup-gitleaks.sh" "$HOOK"; then
|
|
pass "pre-commit hook contains idempotency marker"
|
|
else
|
|
fail "pre-commit hook missing idempotency marker"
|
|
fi
|
|
|
|
# --- 4. Appends to existing hook; existing content retained ---
|
|
echo ""
|
|
echo "--- appends to existing hook; prior content retained ---"
|
|
REPO3="$(make_repo)"
|
|
trap 'rm -rf "$REPO3"' EXIT
|
|
HOOK3="$REPO3/.git/hooks/pre-commit"
|
|
printf '#!/usr/bin/env bash\nnpm test\n' > "$HOOK3"
|
|
chmod +x "$HOOK3"
|
|
run_setup "$REPO3" > /dev/null
|
|
if grep -q "npm test" "$HOOK3"; then
|
|
pass "existing hook content retained after append"
|
|
else
|
|
fail "existing hook content lost after append"
|
|
fi
|
|
if grep -q "gitleaks git --staged" "$HOOK3"; then
|
|
pass "gitleaks block appended to existing hook"
|
|
else
|
|
fail "gitleaks block missing after append"
|
|
fi
|
|
|
|
# --- 5. Second run replaces stale block; existing content still retained ---
|
|
echo ""
|
|
echo "--- second run replaces stale block; existing content still retained ---"
|
|
# Corrupt the gitleaks block to simulate stale content from an older version
|
|
sed -i 's/gitleaks git --staged/gitleaks protect --staged/' "$HOOK3"
|
|
run_setup "$REPO3" > /dev/null
|
|
if grep -q "npm test" "$HOOK3"; then
|
|
pass "existing content retained after block replacement"
|
|
else
|
|
fail "existing content lost after block replacement"
|
|
fi
|
|
marker_count="$(grep -c "# managed by setup-gitleaks.sh" "$HOOK3")"
|
|
if [ "$marker_count" -eq 1 ]; then
|
|
pass "gitleaks block appears exactly once after second run"
|
|
else
|
|
fail "gitleaks block duplicated — found $marker_count occurrences of marker"
|
|
fi
|
|
if grep -q "gitleaks git --staged" "$HOOK3"; then
|
|
pass "stale gitleaks command replaced with current command"
|
|
else
|
|
fail "stale gitleaks command not replaced — block was skipped, not updated"
|
|
fi
|
|
|
|
# --- 6. Third run still idempotent ---
|
|
echo ""
|
|
echo "--- repeated runs stay idempotent ---"
|
|
run_setup "$REPO3" > /dev/null
|
|
run_setup "$REPO3" > /dev/null
|
|
marker_count="$(grep -c "# managed by setup-gitleaks.sh" "$HOOK3")"
|
|
if [ "$marker_count" -eq 1 ]; then
|
|
pass "gitleaks block still appears exactly once after four total runs"
|
|
else
|
|
fail "gitleaks block duplicated — found $marker_count occurrences after four runs"
|
|
fi
|
|
|
|
echo ""
|
|
echo "Results: $PASS passed, $FAIL failed"
|
|
[[ $FAIL -eq 0 ]]
|