12 tests covering secret blocking (FORGEJO token, sk- key), PII blocking (phone, personal email), allowlist pass-throughs (.example files, ollama placeholder, safe source), and all commit-msg format cases.
121 lines
4.9 KiB
Bash
Executable file
121 lines
4.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# tests/test_hooks.sh — integration tests for circuitforge-hooks
|
|
# Requires: gitleaks installed, bash 4+
|
|
set -euo pipefail
|
|
|
|
HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/hooks"
|
|
PASS_COUNT=0
|
|
FAIL_COUNT=0
|
|
|
|
pass() { echo " PASS: $1"; PASS_COUNT=$((PASS_COUNT + 1)); }
|
|
fail() { echo " FAIL: $1"; FAIL_COUNT=$((FAIL_COUNT + 1)); }
|
|
|
|
# Create a temp git repo for realistic staged-content tests
|
|
setup_temp_repo() {
|
|
local dir
|
|
dir=$(mktemp -d)
|
|
git init "$dir" -q
|
|
git -C "$dir" config user.email "test@example.com"
|
|
git -C "$dir" config user.name "Test"
|
|
git -C "$dir" config core.hooksPath "$HOOKS_DIR"
|
|
echo "$dir"
|
|
}
|
|
|
|
echo ""
|
|
echo "=== pre-commit hook tests ==="
|
|
|
|
# Test 1: blocks live-format Forgejo token
|
|
echo "Test 1: blocks FORGEJO_API_TOKEN=<hex>"
|
|
REPO=$(setup_temp_repo)
|
|
echo 'FORGEJO_API_TOKEN=YOUR_FORGEJO_TOKEN_HERE' > "$REPO/test.env"
|
|
git -C "$REPO" add test.env
|
|
RESULT=$(cd "$REPO" && bash "$HOOKS_DIR/pre-commit" 2>&1; echo "EXIT:$?")
|
|
if echo "$RESULT" | grep -q "EXIT:1"; then pass "blocked FORGEJO_API_TOKEN"; else fail "should have blocked FORGEJO_API_TOKEN"; fi
|
|
rm -rf "$REPO"
|
|
|
|
# Test 2: blocks OpenAI-style sk- key
|
|
echo "Test 2: blocks sk-<key> pattern"
|
|
REPO=$(setup_temp_repo)
|
|
echo 'api_key = "sk-abcXYZ1234567890abcXYZ1234567890"' > "$REPO/config.py"
|
|
git -C "$REPO" add config.py
|
|
RESULT=$(cd "$REPO" && bash "$HOOKS_DIR/pre-commit" 2>&1; echo "EXIT:$?")
|
|
if echo "$RESULT" | grep -q "EXIT:1"; then pass "blocked sk- key"; else fail "should have blocked sk- key"; fi
|
|
rm -rf "$REPO"
|
|
|
|
# Test 3: blocks US phone number
|
|
echo "Test 3: blocks US phone number"
|
|
REPO=$(setup_temp_repo)
|
|
echo 'phone: "5107643155"' > "$REPO/config.yaml"
|
|
git -C "$REPO" add config.yaml
|
|
RESULT=$(cd "$REPO" && bash "$HOOKS_DIR/pre-commit" 2>&1; echo "EXIT:$?")
|
|
if echo "$RESULT" | grep -q "EXIT:1"; then pass "blocked phone number"; else fail "should have blocked phone number"; fi
|
|
rm -rf "$REPO"
|
|
|
|
# Test 4: blocks personal email in source
|
|
echo "Test 4: blocks personal gmail address in .py file"
|
|
REPO=$(setup_temp_repo)
|
|
echo 'DEFAULT_EMAIL = "someone@gmail.com"' > "$REPO/app.py"
|
|
git -C "$REPO" add app.py
|
|
RESULT=$(cd "$REPO" && bash "$HOOKS_DIR/pre-commit" 2>&1; echo "EXIT:$?")
|
|
if echo "$RESULT" | grep -q "EXIT:1"; then pass "blocked personal email"; else fail "should have blocked personal email"; fi
|
|
rm -rf "$REPO"
|
|
|
|
# Test 5: allows .example file with placeholders
|
|
echo "Test 5: allows .example file with placeholder values"
|
|
REPO=$(setup_temp_repo)
|
|
echo 'FORGEJO_API_TOKEN=your-forgejo-api-token-here' > "$REPO/config.env.example"
|
|
git -C "$REPO" add config.env.example
|
|
RESULT=$(cd "$REPO" && bash "$HOOKS_DIR/pre-commit" 2>&1; echo "EXIT:$?")
|
|
if echo "$RESULT" | grep -q "EXIT:0"; then pass "allowed .example placeholder"; else fail "should have allowed .example file"; fi
|
|
rm -rf "$REPO"
|
|
|
|
# Test 6: allows ollama api_key placeholder
|
|
echo "Test 6: allows api_key: ollama (known safe placeholder)"
|
|
REPO=$(setup_temp_repo)
|
|
printf 'backends:\n - api_key: ollama\n' > "$REPO/llm.yaml"
|
|
git -C "$REPO" add llm.yaml
|
|
RESULT=$(cd "$REPO" && bash "$HOOKS_DIR/pre-commit" 2>&1; echo "EXIT:$?")
|
|
if echo "$RESULT" | grep -q "EXIT:0"; then pass "allowed ollama api_key"; else fail "should have allowed ollama api_key"; fi
|
|
rm -rf "$REPO"
|
|
|
|
# Test 7: allows safe source file
|
|
echo "Test 7: allows normal Python import"
|
|
REPO=$(setup_temp_repo)
|
|
echo 'import streamlit as st' > "$REPO/app.py"
|
|
git -C "$REPO" add app.py
|
|
RESULT=$(cd "$REPO" && bash "$HOOKS_DIR/pre-commit" 2>&1; echo "EXIT:$?")
|
|
if echo "$RESULT" | grep -q "EXIT:0"; then pass "allowed safe file"; else fail "should have allowed safe file"; fi
|
|
rm -rf "$REPO"
|
|
|
|
echo ""
|
|
echo "=== commit-msg hook tests ==="
|
|
|
|
tmpfile=$(mktemp)
|
|
|
|
echo "Test 8: accepts feat: message"
|
|
echo "feat: add gitleaks scanning" > "$tmpfile"
|
|
if bash "$HOOKS_DIR/commit-msg" "$tmpfile" &>/dev/null; then pass "accepted feat:"; else fail "rejected valid feat:"; fi
|
|
|
|
echo "Test 9: accepts security: message (new type)"
|
|
echo "security: rotate leaked API token" > "$tmpfile"
|
|
if bash "$HOOKS_DIR/commit-msg" "$tmpfile" &>/dev/null; then pass "accepted security:"; else fail "rejected valid security:"; fi
|
|
|
|
echo "Test 10: accepts fix(scope): message"
|
|
echo "fix(wizard): handle missing user.yaml" > "$tmpfile"
|
|
if bash "$HOOKS_DIR/commit-msg" "$tmpfile" &>/dev/null; then pass "accepted fix(scope):"; else fail "rejected valid fix(scope):"; fi
|
|
|
|
echo "Test 11: rejects non-conventional message"
|
|
echo "updated the thing" > "$tmpfile"
|
|
if bash "$HOOKS_DIR/commit-msg" "$tmpfile" &>/dev/null; then fail "should have rejected"; else pass "rejected non-conventional"; fi
|
|
|
|
echo "Test 12: rejects empty message"
|
|
echo "" > "$tmpfile"
|
|
if bash "$HOOKS_DIR/commit-msg" "$tmpfile" &>/dev/null; then fail "should have rejected empty"; else pass "rejected empty message"; fi
|
|
|
|
rm -f "$tmpfile"
|
|
|
|
echo ""
|
|
echo "=== Results ==="
|
|
echo " Passed: $PASS_COUNT"
|
|
echo " Failed: $FAIL_COUNT"
|
|
[[ $FAIL_COUNT -eq 0 ]] && echo "All tests passed." || { echo "FAILURES detected."; exit 1; }
|