#!/bin/bash # Installation script for Git hooks in Hastebin # This script sets up pre-commit hooks (tests + security scan) and pre-push hooks (unused code + security scan) # # Usage: # ./install-git-hooks.sh [--force] # # Options: # --force Overwrite existing hooks without prompting (backs up existing hooks) # Without this flag, fails if hooks already exist set -e # Parse arguments FORCE_MODE=false while [[ $# -gt 0 ]]; do case $1 in --force) FORCE_MODE=true shift ;; *) echo "Unknown option: $1" echo "Usage: $0 [--force]" exit 1 ;; esac done # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Get the repository root REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)") HOOKS_DIR="$REPO_ROOT/.git/hooks" PRE_COMMIT_HOOK="$HOOKS_DIR/pre-commit" PRE_PUSH_HOOK="$HOOKS_DIR/pre-push" SCRIPT_DIR="$REPO_ROOT/scripts" echo -e "${BLUE}Installing Git hooks for Hastebin${NC}" echo "" # Check if we're in a git repository if [ ! -d "$REPO_ROOT/.git" ]; then echo -e "${RED}Error: Not a git repository${NC}" exit 1 fi # Create hooks directory if it doesn't exist mkdir -p "$HOOKS_DIR" # Function to handle existing hook handle_existing_hook() { local hook_path="$1" local hook_name="$2" if [ -f "$hook_path" ]; then if [ "$FORCE_MODE" = true ]; then # Backup existing hook with timestamp mv "$hook_path" "$hook_path.backup.$(date +%Y%m%d_%H%M%S)" echo -e "${YELLOW}Backed up existing $hook_name hook${NC}" else echo -e "${RED}Error: $hook_name hook already exists at $hook_path${NC}" echo -e "${YELLOW}Use --force to overwrite (will backup existing hook)${NC}" exit 1 fi fi } # Check for existing hooks handle_existing_hook "$PRE_COMMIT_HOOK" "pre-commit" handle_existing_hook "$PRE_PUSH_HOOK" "pre-push" # --- Create the pre-commit hook --- cat > "$PRE_COMMIT_HOOK" << 'HOOK_EOF' #!/bin/bash # Git pre-commit hook for Hastebin # Runs tests and security scans before allowing commits set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color echo -e "${YELLOW}Running pre-commit checks...${NC}" echo "" # Get the repository root REPO_ROOT=$(git rev-parse --show-toplevel) cd "$REPO_ROOT" # Check required dependencies MISSING_DEPS=0 if ! command -v docker &> /dev/null; then echo -e "${RED}Docker not found - required for security scanning${NC}" MISSING_DEPS=1 fi if ! command -v trivy &> /dev/null; then echo -e "${RED}Trivy not found - required for security scanning${NC}" echo " Install: brew install trivy" MISSING_DEPS=1 fi if [ $MISSING_DEPS -ne 0 ]; then echo -e "${RED}Missing required dependencies. Commit aborted.${NC}" exit 1 fi # Check if node_modules exists, if not, install dependencies if [ ! -d "node_modules" ]; then echo -e "${YELLOW}Installing dependencies...${NC}" npm ci fi # Run the core tests (faster than full test suite) echo -e "${YELLOW}[1/2] Running core tests...${NC}" if npm run test:core; then echo -e "${GREEN}Core tests passed${NC}" else echo -e "${RED}Core tests failed. Commit aborted.${NC}" echo -e "${YELLOW}To skip this check, use: git commit --no-verify${NC}" exit 1 fi # Clean up test artifacts if [ -d "test-data" ]; then rm -rf test-data fi # Run Trivy security scan echo "" echo -e "${YELLOW}[2/2] Running security scan (Trivy image scan)...${NC}" if "$REPO_ROOT/scripts/scan-trivy-image.sh"; then echo -e "${GREEN}Security scan passed${NC}" else echo -e "${RED}Security scan found vulnerabilities. Commit aborted.${NC}" echo -e "${YELLOW}To skip this check, use: git commit --no-verify${NC}" exit 1 fi echo "" echo -e "${GREEN}Pre-commit checks passed${NC}" exit 0 HOOK_EOF chmod +x "$PRE_COMMIT_HOOK" echo -e "${GREEN}Pre-commit hook installed${NC}" # --- Create the pre-push hook --- cat > "$PRE_PUSH_HOOK" << 'HOOK_EOF' #!/bin/bash # Git pre-push hook for Hastebin # Scans for unused code/dependencies and runs security scan before pushing set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color echo -e "${YELLOW}Running pre-push checks...${NC}" echo "" # Get the repository root REPO_ROOT=$(git rev-parse --show-toplevel) cd "$REPO_ROOT" # Check required dependencies MISSING_DEPS=0 if ! command -v docker &> /dev/null; then echo -e "${RED}Docker not found - required for security scanning${NC}" MISSING_DEPS=1 fi if ! command -v trivy &> /dev/null; then echo -e "${RED}Trivy not found - required for security scanning${NC}" echo " Install: brew install trivy" MISSING_DEPS=1 fi if [ $MISSING_DEPS -ne 0 ]; then echo -e "${RED}Missing required dependencies. Push aborted.${NC}" exit 1 fi # Check if node_modules exists, if not, install dependencies if [ ! -d "node_modules" ]; then echo -e "${YELLOW}Installing dependencies...${NC}" npm ci fi # Scan for unused code/dependencies SCAN_FAILED=0 echo -e "${YELLOW}[1/3] Scanning for unused files/exports/dependencies (knip)...${NC}" if npx --yes knip 2>/dev/null; then echo -e "${GREEN}knip passed${NC}" else echo -e "${RED}knip found unused code${NC}" SCAN_FAILED=1 fi echo "" echo -e "${YELLOW}[2/3] Scanning for unused npm dependencies (depcheck)...${NC}" if npx --yes depcheck 2>/dev/null; then echo -e "${GREEN}depcheck passed${NC}" else echo -e "${RED}depcheck found issues${NC}" SCAN_FAILED=1 fi if [ $SCAN_FAILED -ne 0 ]; then echo -e "${RED}Unused code/dependencies detected. Push aborted.${NC}" echo -e "${YELLOW}To skip this check, use: git push --no-verify${NC}" exit 1 fi # Run Trivy security scan echo "" echo -e "${YELLOW}[3/3] Running security scan (Trivy image scan)...${NC}" if "$REPO_ROOT/scripts/scan-trivy-image.sh"; then echo -e "${GREEN}Security scan passed${NC}" else echo -e "${RED}Security scan found vulnerabilities. Push aborted.${NC}" echo -e "${YELLOW}To skip this check, use: git push --no-verify${NC}" exit 1 fi echo "" echo -e "${GREEN}Pre-push checks passed${NC}" exit 0 HOOK_EOF chmod +x "$PRE_PUSH_HOOK" echo -e "${GREEN}Pre-push hook installed${NC}" echo "" echo -e "${BLUE}Hooks installed:${NC}" echo -e "${BLUE} - pre-commit: core tests + Trivy security scan${NC}" echo -e "${BLUE} - pre-push: knip + depcheck + Trivy security scan${NC}" echo -e "${YELLOW}To skip hooks, use: git commit --no-verify / git push --no-verify${NC}" echo "" # Check if dependencies are installed if [ ! -d "$REPO_ROOT/node_modules" ]; then echo -e "${YELLOW}Dependencies not found. Installing...${NC}" cd "$REPO_ROOT" npm ci echo -e "${GREEN}Dependencies installed${NC}" fi echo -e "${GREEN}Git hooks installation complete!${NC}"