pre-commit•4.62 kB
#!/bin/bash
# scripts/hooks/pre-commit - Pre-commit quality checks using Groq (primary) or Gemini (fallback)
#
# Installation: ln -s ../../scripts/hooks/pre-commit .git/hooks/pre-commit
#
# This hook checks:
# 1. Code complexity (blocks if >8, warns if >7)
# 2. Security vulnerabilities (blocks on any findings)
# 3. Basic code quality issues
#
# LLM Selection Priority:
# 1. Groq API (fast, simple API key auth, 200-300ms)
# 2. Gemini CLI (fallback, slower, browser OAuth)
# 3. Skip checks (if neither available)
set -e
# Colors for output
RED='\033[0;31m'
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
echo "Running pre-commit quality checks..."
echo ""
# Determine which LLM to use (Groq preferred, Gemini fallback)
LLM_CMD=""
LLM_NAME=""
# Get script directory for Groq wrapper
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# Check for Groq first (preferred - fast, no OAuth issues)
if [ -x "$SCRIPT_DIR/scripts/utils/groq" ] && [ -n "$GROQ_API_KEY" ]; then
LLM_CMD="$SCRIPT_DIR/scripts/utils/groq"
LLM_NAME="Groq"
echo -e "${GREEN}✓${NC} Using Groq API (fast mode)"
# Fall back to Gemini if available
elif command -v gemini &> /dev/null; then
LLM_CMD="gemini"
LLM_NAME="Gemini"
echo -e "${YELLOW}⚠️${NC} Using Gemini CLI (may require browser auth)"
# Skip checks if neither available
else
echo -e "${YELLOW}⚠️ No LLM available (Groq or Gemini), skipping quality checks${NC}"
echo "To enable automated quality gates:"
echo " - Install Groq: export GROQ_API_KEY=your-key (recommended)"
echo " - OR install Gemini CLI: npm install -g @google/generative-ai-cli"
exit 0
fi
echo ""
# Get staged Python files (store once for efficiency)
staged_files=$(git diff --cached --name-only --diff-filter=AM | grep '\.py$' || echo "")
if [ -z "$staged_files" ]; then
echo "No Python files staged, skipping checks"
exit 0
fi
echo "Checking staged files:"
echo "$staged_files"
echo ""
high_complexity=0
security_issues=0
while IFS= read -r file; do
if [ ! -f "$file" ]; then
continue
fi
echo "=== Checking: $file ==="
# Complexity check
echo "Checking complexity..."
complexity_result=$($LLM_CMD "Analyze code complexity. Rate each function 1-10. Report ONLY functions with score >7 in format: 'FunctionName: Score X'. Be concise. File:
$(cat "$file")" || echo "")
if echo "$complexity_result" | grep -qi "score [89]\|score 10"; then
echo -e "${RED}🔴 CRITICAL: Very high complexity detected${NC}"
echo "$complexity_result"
echo ""
echo "Functions with score >8 must be refactored before committing."
security_issues=1 # Block commit
elif echo "$complexity_result" | grep -qi "score 7"; then
echo -e "${YELLOW}⚠️ High complexity detected (score 7)${NC}"
echo "$complexity_result"
high_complexity=1
else
echo -e "${GREEN}✓${NC} Complexity OK"
fi
echo ""
# Security check
echo "Checking for security issues..."
security_result=$($LLM_CMD "Security scan. Check ONLY for: SQL injection (raw SQL), XSS (unescaped HTML), command injection (os.system, subprocess shell=True), hardcoded secrets.
IMPORTANT: Output format:
- If ANY vulnerability found, start response with: VULNERABILITY_DETECTED: [type]
- If NO vulnerabilities found, start response with: SECURITY_CLEAN
- Then provide details
File to scan:
$(cat "$file")" || echo "SECURITY_CLEAN")
# Check for machine-parseable vulnerability marker
if echo "$security_result" | grep -q "^VULNERABILITY_DETECTED:"; then
echo -e "${RED}🔴 SECURITY ISSUE DETECTED${NC}"
echo "$security_result"
echo ""
security_issues=1
else
echo -e "${GREEN}✓${NC} No security issues"
fi
echo ""
done <<< "$staged_files"
echo "=== Pre-commit Check Summary ==="
echo ""
if [ $security_issues -eq 1 ]; then
echo -e "${RED}❌ COMMIT BLOCKED${NC}"
echo ""
echo "Security issues or critical complexity detected."
echo "Please fix the issues above and try again."
echo ""
exit 1
fi
if [ $high_complexity -eq 1 ]; then
echo -e "${YELLOW}⚠️ HIGH COMPLEXITY WARNING${NC}"
echo ""
echo "Some functions have high complexity (score 7)."
echo "Consider refactoring to improve maintainability."
echo ""
echo -n "Continue with commit anyway? (y/n) "
read -r response
if [ "$response" != "y" ]; then
echo "Commit cancelled."
exit 1
fi
fi
echo -e "${GREEN}✅ Pre-commit checks passed${NC}"
echo ""
exit 0