#!/bin/bash # # Secret Detection Pre-Commit Hook # # Dieses Skript prüft staged Dateien auf potenzielle Secrets. # Installation: ln -sf ../../scripts/detect-secrets.sh .git/hooks/pre-commit # set -e # Farben für Output RED='\033[0;31m' YELLOW='\033[1;33m' GREEN='\033[0;32m' NC='\033[0m' # No Color echo -e "${GREEN}🔍 Checking for secrets in staged files...${NC}" # Patterns für potenzielle Secrets PATTERNS=( # API Keys und Tokens 'api[_-]?key\s*[:=]\s*["\x27][a-zA-Z0-9_-]{20,}["\x27]' 'token\s*[:=]\s*["\x27][a-zA-Z0-9_-]{20,}["\x27]' # AWS 'AKIA[0-9A-Z]{16}' 'aws[_-]?secret[_-]?access[_-]?key' # Private Keys '-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----' # Passwörter in Code 'password\s*[:=]\s*["\x27][^"\x27]{8,}["\x27]' 'passwd\s*[:=]\s*["\x27][^"\x27]{8,}["\x27]' # SMTP Credentials 'smtp[_-]?pass(word)?\s*[:=]\s*["\x27][^"\x27]+["\x27]' # Database URLs mit Passwörtern '(postgres|mysql|mongodb)://[^:]+:[^@]+@' # JWT Tokens (vollständige) 'eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}' # Generic Secrets 'secret\s*[:=]\s*["\x27][^"\x27]{16,}["\x27]' # Slack Webhooks 'hooks\.slack\.com/services/T[A-Z0-9]{8}/B[A-Z0-9]{8}/[a-zA-Z0-9]{24}' # Discord Webhooks 'discord(app)?\.com/api/webhooks/[0-9]+/[a-zA-Z0-9_-]+' # GitHub Tokens 'ghp_[a-zA-Z0-9]{36}' 'gho_[a-zA-Z0-9]{36}' 'ghu_[a-zA-Z0-9]{36}' 'ghs_[a-zA-Z0-9]{36}' # SendGrid 'SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}' # Stripe 'sk_(live|test)_[a-zA-Z0-9]{24,}' 'pk_(live|test)_[a-zA-Z0-9]{24,}' ) # Dateien die ignoriert werden sollen IGNORE_FILES=( '\.min\.js$' '\.min\.css$' 'package-lock\.json$' 'pnpm-lock\.yaml$' 'yarn\.lock$' '\.md$' '\.txt$' 'detect-secrets\.sh$' '\.example$' '\.sample$' '\.spec\.ts$' # Test files may contain example secrets for testing '\.test\.ts$' ) # Pfade die ignoriert werden sollen IGNORE_PATHS=( 'node_modules/' 'dist/' '.next/' 'coverage/' '.git/' ) # Prüfe ob wir in einem Git-Repository sind if ! git rev-parse --git-dir > /dev/null 2>&1; then echo -e "${RED}Error: Not a git repository${NC}" exit 1 fi # Hole staged Dateien STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM) if [ -z "$STAGED_FILES" ]; then echo -e "${GREEN}✅ No staged files to check${NC}" exit 0 fi FOUND_SECRETS=0 for file in $STAGED_FILES; do # Überspringe wenn Datei nicht existiert [ ! -f "$file" ] && continue # Überspringe ignorierte Pfade skip=false for ignore_path in "${IGNORE_PATHS[@]}"; do if [[ "$file" == *"$ignore_path"* ]]; then skip=true break fi done [ "$skip" = true ] && continue # Überspringe ignorierte Dateitypen for ignore_file in "${IGNORE_FILES[@]}"; do if [[ "$file" =~ $ignore_file ]]; then skip=true break fi done [ "$skip" = true ] && continue # Prüfe jedes Pattern for pattern in "${PATTERNS[@]}"; do # Hole nur die staged Version der Datei matches=$(git show ":$file" 2>/dev/null | grep -niE "$pattern" 2>/dev/null || true) if [ -n "$matches" ]; then echo -e "${RED}⚠️ Potential secret found in: $file${NC}" echo -e "${YELLOW}Pattern: $pattern${NC}" echo "$matches" | head -5 echo "" FOUND_SECRETS=$((FOUND_SECRETS + 1)) fi done done if [ $FOUND_SECRETS -gt 0 ]; then echo -e "${RED}❌ Found $FOUND_SECRETS potential secret(s)!${NC}" echo "" echo "If these are false positives, you can:" echo " 1. Add the file to IGNORE_FILES in scripts/detect-secrets.sh" echo " 2. Use 'git commit --no-verify' to skip this check (not recommended)" echo " 3. Move secrets to environment variables or .env files" echo "" exit 1 fi echo -e "${GREEN}✅ No secrets found in staged files${NC}" exit 0