#!/bin/bash # Pre-commit secret scanner for itpp-infrastructure # Scans staged changes for credential patterns before allowing commit. # Blocks commits containing API keys, tokens, or passwords. set -euo pipefail RED='\033[0;31m' NC='\033[0m' # Patterns that indicate secrets PATTERNS=( # API key formats 'sk-[a-zA-Z0-9]{32,}' 'sk-litellm-[a-zA-Z0-9]{32,}' 'Bearer [a-zA-Z0-9_-]{20,}' 'x-api-key: [a-zA-Z0-9]{20,}' 'api_key.*=.*[a-zA-Z0-9_-]{20,}' 'api-key: [a-zA-Z0-9_-]{20,}' # SyncroMSP token patterns 'T[0-9a-f]{8}[a-zA-Z0-9_-]{24,}' # Generic secret patterns 'passwor[d][[:space:]]*=[[:space:]]*[^[:space:]]{8,}' 'secret[[:space:]]*=[[:space:]]*[^[:space:]]{16,}' 'token[[:space:]]*=[[:space:]]*[^[:space:]]{16,}' # AWS key patterns 'AKIA[0-9A-Z]{16}' 'aws_access_key_id[[:space:]]*=[[:space:]]*[A-Z0-9]{16,}' # Private key patterns '-----BEGIN (RSA|OPENSSH|EC) PRIVATE KEY-----' # JWT/stripe patterns 'eyJ[a-zA-Z0-9_-]{20,}\.[a-zA-Z0-9_-]{20,}' 'sk_live_[0-9a-zA-Z]{24,}' 'pk_live_[0-9a-zA-Z]{24,}' ) # Files to skip SKIP_GLOB="*.lock|*.png|*.jpg|*.gif|*.svg|*.ico|*.woff*|*.ttf|*.eot|*.min.js|*.min.css|*.map|package-lock.json|yarn.lock|pnpm-lock.yaml|go.sum|Cargo.lock|*.pb.go|*.gen.go|*.generated.*|.gitignore" FOUND_SECRET=0 CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM) if [ -z "$CHANGED_FILES" ]; then exit 0 fi # Create temp file with staged content STAGED_DIR=$(mktemp -d) trap "rm -rf $STAGED_DIR" EXIT for file in $CHANGED_FILES; do # Skip binary/lock files if echo "$file" | grep -qE "$SKIP_GLOB"; then continue fi # Get staged content mkdir -p "$(dirname "$STAGED_DIR/$file")" git show ":$file" > "$STAGED_DIR/$file" 2>/dev/null || continue for pattern in "${PATTERNS[@]}"; do if grep -qE "$pattern" "$STAGED_DIR/$file" 2>/dev/null; then if [ $FOUND_SECRET -eq 0 ]; then echo "" echo -e "${RED}╔══════════════════════════════════════════════╗${NC}" echo -e "${RED}║ SECRET DETECTED — COMMIT BLOCKED ║${NC}" echo -e "${RED}╚══════════════════════════════════════════════╝${NC}" echo "" fi FOUND_SECRET=1 echo -e "${RED}[BLOCKED]${NC} $file — matches pattern: $pattern" echo " → $(grep -nE "$pattern" "$STAGED_DIR/$file" | head -1 | cut -c1-120)" fi done done if [ $FOUND_SECRET -eq 1 ]; then echo "" echo -e "${RED}Commit aborted. Remove the secrets above and try again.${NC}" echo "If this is a false positive, add the file to SKIP_GLOB in .git/hooks/pre-commit" echo "or use: git commit --no-verify" exit 1 fi exit 0