Files
2025-12-26 13:38:04 +01:00

275 lines
12 KiB
Bash
Executable File

#!/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"