#!/bin/bash # ============================================================================= # GO BACKEND AUDIT SCRIPT # Comprehensive analysis of Go microservices # ============================================================================= set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" BACKEND_DIR="$PROJECT_ROOT/backend/functions" OUTPUT_DIR="$PROJECT_ROOT/audit-reports/go-audit" TIMESTAMP=$(date +%Y%m%d-%H%M%S) # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' echo -e "${BLUE}========================================${NC}" echo -e "${BLUE} GO BACKEND COMPREHENSIVE AUDIT${NC}" echo -e "${BLUE}========================================${NC}" echo "" mkdir -p "$OUTPUT_DIR" # ============================================================================= # 1. STATIC ANALYSIS WITH go vet # ============================================================================= echo -e "${YELLOW}[1/10] Running go vet (static analysis)...${NC}" GO_VET_OUTPUT="$OUTPUT_DIR/go-vet-$TIMESTAMP.txt" echo "# Go Vet Results - $TIMESTAMP" > "$GO_VET_OUTPUT" echo "" >> "$GO_VET_OUTPUT" for service_dir in "$BACKEND_DIR"/*/; do service_name=$(basename "$service_dir") if [ -f "$service_dir/go.mod" ]; then echo "Analyzing: $service_name" >> "$GO_VET_OUTPUT" echo "---" >> "$GO_VET_OUTPUT" (cd "$service_dir" && go vet ./... 2>&1) >> "$GO_VET_OUTPUT" || true echo "" >> "$GO_VET_OUTPUT" fi done echo -e "${GREEN} Output: $GO_VET_OUTPUT${NC}" # ============================================================================= # 2. STATICCHECK (if available) # ============================================================================= echo -e "${YELLOW}[2/10] Running staticcheck (advanced static analysis)...${NC}" STATICCHECK_OUTPUT="$OUTPUT_DIR/staticcheck-$TIMESTAMP.txt" echo "# Staticcheck Results - $TIMESTAMP" > "$STATICCHECK_OUTPUT" if command -v staticcheck &> /dev/null; then for service_dir in "$BACKEND_DIR"/*/; do service_name=$(basename "$service_dir") if [ -f "$service_dir/go.mod" ]; then echo "Analyzing: $service_name" >> "$STATICCHECK_OUTPUT" echo "---" >> "$STATICCHECK_OUTPUT" (cd "$service_dir" && staticcheck ./... 2>&1) >> "$STATICCHECK_OUTPUT" || true echo "" >> "$STATICCHECK_OUTPUT" fi done echo -e "${GREEN} Output: $STATICCHECK_OUTPUT${NC}" else echo "staticcheck not installed. Install with: go install honnef.co/go/tools/cmd/staticcheck@latest" >> "$STATICCHECK_OUTPUT" echo -e "${RED} staticcheck not installed${NC}" fi # ============================================================================= # 3. GOLANGCI-LINT (if available) # ============================================================================= echo -e "${YELLOW}[3/10] Running golangci-lint (comprehensive linting)...${NC}" GOLINT_OUTPUT="$OUTPUT_DIR/golangci-lint-$TIMESTAMP.txt" echo "# GolangCI-Lint Results - $TIMESTAMP" > "$GOLINT_OUTPUT" if command -v golangci-lint &> /dev/null; then for service_dir in "$BACKEND_DIR"/*/; do service_name=$(basename "$service_dir") if [ -f "$service_dir/go.mod" ]; then echo "Analyzing: $service_name" >> "$GOLINT_OUTPUT" echo "---" >> "$GOLINT_OUTPUT" (cd "$service_dir" && golangci-lint run --enable-all --disable=gci,wrapcheck,exhaustruct,depguard 2>&1) >> "$GOLINT_OUTPUT" || true echo "" >> "$GOLINT_OUTPUT" fi done echo -e "${GREEN} Output: $GOLINT_OUTPUT${NC}" else echo "golangci-lint not installed. Install from: https://golangci-lint.run/usage/install/" >> "$GOLINT_OUTPUT" echo -e "${RED} golangci-lint not installed${NC}" fi # ============================================================================= # 4. GOSEC (Security Scanner) # ============================================================================= echo -e "${YELLOW}[4/10] Running gosec (security scanner)...${NC}" GOSEC_OUTPUT="$OUTPUT_DIR/gosec-$TIMESTAMP.txt" GOSEC_JSON="$OUTPUT_DIR/gosec-$TIMESTAMP.json" echo "# GoSec Security Scan Results - $TIMESTAMP" > "$GOSEC_OUTPUT" if command -v gosec &> /dev/null; then for service_dir in "$BACKEND_DIR"/*/; do service_name=$(basename "$service_dir") if [ -f "$service_dir/go.mod" ]; then echo "Analyzing: $service_name" >> "$GOSEC_OUTPUT" echo "---" >> "$GOSEC_OUTPUT" (cd "$service_dir" && gosec -fmt=text ./... 2>&1) >> "$GOSEC_OUTPUT" || true echo "" >> "$GOSEC_OUTPUT" fi done echo -e "${GREEN} Output: $GOSEC_OUTPUT${NC}" else echo "gosec not installed. Install with: go install github.com/securego/gosec/v2/cmd/gosec@latest" >> "$GOSEC_OUTPUT" echo -e "${RED} gosec not installed${NC}" fi # ============================================================================= # 5. DEPENDENCY AUDIT # ============================================================================= echo -e "${YELLOW}[5/10] Auditing dependencies...${NC}" DEP_OUTPUT="$OUTPUT_DIR/dependencies-$TIMESTAMP.txt" echo "# Dependency Audit Results - $TIMESTAMP" > "$DEP_OUTPUT" for service_dir in "$BACKEND_DIR"/*/; do service_name=$(basename "$service_dir") if [ -f "$service_dir/go.mod" ]; then echo "=== $service_name ===" >> "$DEP_OUTPUT" echo "" >> "$DEP_OUTPUT" echo "Direct Dependencies:" >> "$DEP_OUTPUT" (cd "$service_dir" && go list -m all 2>&1) >> "$DEP_OUTPUT" || true echo "" >> "$DEP_OUTPUT" echo "Outdated Dependencies:" >> "$DEP_OUTPUT" (cd "$service_dir" && go list -u -m all 2>&1 | grep '\[' ) >> "$DEP_OUTPUT" || echo "None found" >> "$DEP_OUTPUT" echo "" >> "$DEP_OUTPUT" # Check for known vulnerabilities echo "Vulnerability Check (govulncheck):" >> "$DEP_OUTPUT" if command -v govulncheck &> /dev/null; then (cd "$service_dir" && govulncheck ./... 2>&1) >> "$DEP_OUTPUT" || true else echo "govulncheck not installed. Install with: go install golang.org/x/vuln/cmd/govulncheck@latest" >> "$DEP_OUTPUT" fi echo "" >> "$DEP_OUTPUT" fi done echo -e "${GREEN} Output: $DEP_OUTPUT${NC}" # ============================================================================= # 6. CODE COMPLEXITY ANALYSIS # ============================================================================= echo -e "${YELLOW}[6/10] Analyzing code complexity...${NC}" COMPLEXITY_OUTPUT="$OUTPUT_DIR/complexity-$TIMESTAMP.txt" echo "# Code Complexity Analysis - $TIMESTAMP" > "$COMPLEXITY_OUTPUT" if command -v gocyclo &> /dev/null; then echo "Cyclomatic Complexity (threshold > 10):" >> "$COMPLEXITY_OUTPUT" echo "---" >> "$COMPLEXITY_OUTPUT" gocyclo -over 10 "$BACKEND_DIR" 2>&1 >> "$COMPLEXITY_OUTPUT" || true echo "" >> "$COMPLEXITY_OUTPUT" echo "All Functions by Complexity:" >> "$COMPLEXITY_OUTPUT" echo "---" >> "$COMPLEXITY_OUTPUT" gocyclo -top 50 "$BACKEND_DIR" 2>&1 >> "$COMPLEXITY_OUTPUT" || true echo -e "${GREEN} Output: $COMPLEXITY_OUTPUT${NC}" else echo "gocyclo not installed. Install with: go install github.com/fzipp/gocyclo/cmd/gocyclo@latest" >> "$COMPLEXITY_OUTPUT" echo -e "${RED} gocyclo not installed${NC}" fi # ============================================================================= # 7. DEAD CODE DETECTION # ============================================================================= echo -e "${YELLOW}[7/10] Detecting dead code...${NC}" DEADCODE_OUTPUT="$OUTPUT_DIR/deadcode-$TIMESTAMP.txt" echo "# Dead Code Detection - $TIMESTAMP" > "$DEADCODE_OUTPUT" if command -v deadcode &> /dev/null; then for service_dir in "$BACKEND_DIR"/*/; do service_name=$(basename "$service_dir") if [ -f "$service_dir/go.mod" ]; then echo "=== $service_name ===" >> "$DEADCODE_OUTPUT" (cd "$service_dir" && deadcode ./... 2>&1) >> "$DEADCODE_OUTPUT" || true echo "" >> "$DEADCODE_OUTPUT" fi done echo -e "${GREEN} Output: $DEADCODE_OUTPUT${NC}" else echo "deadcode not installed. Install with: go install golang.org/x/tools/cmd/deadcode@latest" >> "$DEADCODE_OUTPUT" echo -e "${RED} deadcode not installed${NC}" fi # ============================================================================= # 8. ERROR HANDLING AUDIT # ============================================================================= echo -e "${YELLOW}[8/10] Auditing error handling patterns...${NC}" ERROR_OUTPUT="$OUTPUT_DIR/error-handling-$TIMESTAMP.txt" echo "# Error Handling Audit - $TIMESTAMP" > "$ERROR_OUTPUT" echo "== Potentially Ignored Errors ==" >> "$ERROR_OUTPUT" grep -rn "_ = " "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$ERROR_OUTPUT" || echo "None found" >> "$ERROR_OUTPUT" echo "" >> "$ERROR_OUTPUT" echo "== Bare error returns (missing context) ==" >> "$ERROR_OUTPUT" grep -rn "return err$" "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$ERROR_OUTPUT" || echo "None found" >> "$ERROR_OUTPUT" echo "" >> "$ERROR_OUTPUT" echo "== Panic usage ==" >> "$ERROR_OUTPUT" grep -rn "panic(" "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$ERROR_OUTPUT" || echo "None found" >> "$ERROR_OUTPUT" echo "" >> "$ERROR_OUTPUT" echo "== log.Fatal usage (prevents defer) ==" >> "$ERROR_OUTPUT" grep -rn "log.Fatal" "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$ERROR_OUTPUT" || echo "None found" >> "$ERROR_OUTPUT" echo -e "${GREEN} Output: $ERROR_OUTPUT${NC}" # ============================================================================= # 9. HARDCODED SECRETS SCAN # ============================================================================= echo -e "${YELLOW}[9/10] Scanning for hardcoded secrets...${NC}" SECRETS_OUTPUT="$OUTPUT_DIR/secrets-scan-$TIMESTAMP.txt" echo "# Hardcoded Secrets Scan - $TIMESTAMP" > "$SECRETS_OUTPUT" echo "== Potential Hardcoded Passwords ==" >> "$SECRETS_OUTPUT" grep -rniE "(password|passwd|pwd)\s*[:=]\s*['\"][^'\"]+['\"]" "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$SECRETS_OUTPUT" || echo "None found" >> "$SECRETS_OUTPUT" echo "" >> "$SECRETS_OUTPUT" echo "== Potential API Keys ==" >> "$SECRETS_OUTPUT" grep -rniE "(api[_-]?key|apikey|secret[_-]?key)\s*[:=]\s*['\"][^'\"]+['\"]" "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$SECRETS_OUTPUT" || echo "None found" >> "$SECRETS_OUTPUT" echo "" >> "$SECRETS_OUTPUT" echo "== Potential Tokens ==" >> "$SECRETS_OUTPUT" grep -rniE "(token|bearer|jwt)\s*[:=]\s*['\"][^'\"]+['\"]" "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$SECRETS_OUTPUT" || echo "None found" >> "$SECRETS_OUTPUT" echo "" >> "$SECRETS_OUTPUT" echo "== Base64 Encoded Strings (potential secrets) ==" >> "$SECRETS_OUTPUT" grep -rnoE "['\"][A-Za-z0-9+/]{40,}={0,2}['\"]" "$BACKEND_DIR" --include="*.go" 2>/dev/null >> "$SECRETS_OUTPUT" || echo "None found" >> "$SECRETS_OUTPUT" echo -e "${GREEN} Output: $SECRETS_OUTPUT${NC}" # ============================================================================= # 10. TEST COVERAGE # ============================================================================= echo -e "${YELLOW}[10/10] Generating test coverage report...${NC}" COVERAGE_OUTPUT="$OUTPUT_DIR/coverage-$TIMESTAMP.txt" COVERAGE_HTML="$OUTPUT_DIR/coverage-$TIMESTAMP.html" echo "# Test Coverage Report - $TIMESTAMP" > "$COVERAGE_OUTPUT" for service_dir in "$BACKEND_DIR"/*/; do service_name=$(basename "$service_dir") if [ -f "$service_dir/go.mod" ]; then echo "=== $service_name ===" >> "$COVERAGE_OUTPUT" (cd "$service_dir" && go test -coverprofile=coverage.out ./... 2>&1) >> "$COVERAGE_OUTPUT" || true if [ -f "$service_dir/coverage.out" ]; then (cd "$service_dir" && go tool cover -func=coverage.out 2>&1) >> "$COVERAGE_OUTPUT" || true rm "$service_dir/coverage.out" fi echo "" >> "$COVERAGE_OUTPUT" fi done echo -e "${GREEN} Output: $COVERAGE_OUTPUT${NC}" # ============================================================================= # SUMMARY # ============================================================================= echo "" echo -e "${BLUE}========================================${NC}" echo -e "${BLUE} GO AUDIT COMPLETE${NC}" echo -e "${BLUE}========================================${NC}" echo "" echo -e "Reports generated in: ${GREEN}$OUTPUT_DIR${NC}" echo "" echo "Files generated:" ls -la "$OUTPUT_DIR"/*$TIMESTAMP* 2>/dev/null || echo "No files generated"