mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 17:24:12 +00:00
Monitors porwoll.de and blogwoman.de for stale builds caused by Plesk Git's silent deploy failures (code pulled but build never ran). - Compares source file timestamps vs .next/BUILD_ID mtime - HTTP health checks via public URLs - --alert flag for CMS monitoring API integration - Runs as cron job every 30 minutes on sv-payload Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
162 lines
4.2 KiB
Bash
Executable file
162 lines
4.2 KiB
Bash
Executable file
#!/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$'
|
|
'db-direct\.sh$' # Uses get_password() function for secure password input
|
|
'setup-tenants/setup\.sh$' # Uses environment variables, not hardcoded secrets
|
|
'check-production-deploys\.sh$' # References env var name CRON_SECRET, not actual secret
|
|
)
|
|
|
|
# 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
|