#!/bin/bash set -euo pipefail # Security Scanning Script for gibidify # This script runs comprehensive security checks locally and in CI SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$PROJECT_ROOT" echo "🔒 Starting comprehensive security scan for gibidify..." # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Function to print status print_status() { echo -e "${BLUE}[INFO]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARN]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } # Check if required tools are installed check_dependencies() { print_status "Checking security scanning dependencies..." local missing_tools=() if ! command -v go &>/dev/null; then missing_tools+=("go") fi if ! command -v golangci-lint &>/dev/null; then print_warning "golangci-lint not found, installing..." go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest fi if ! command -v gosec &>/dev/null; then print_warning "gosec not found, installing..." go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest fi if ! command -v govulncheck &>/dev/null; then print_warning "govulncheck not found, installing..." go install golang.org/x/vuln/cmd/govulncheck@latest fi if ! command -v checkmake &>/dev/null; then print_warning "checkmake not found, installing..." go install github.com/mrtazz/checkmake/cmd/checkmake@latest fi if ! command -v shfmt &>/dev/null; then print_warning "shfmt not found, installing..." go install mvdan.cc/sh/v3/cmd/shfmt@latest fi if ! command -v yamllint &>/dev/null; then print_warning "yamllint not found, installing..." go install github.com/excilsploft/yamllint@latest fi if [ ${#missing_tools[@]} -ne 0 ]; then print_error "Missing required tools: ${missing_tools[*]}" print_error "Please install the missing tools and try again." exit 1 fi print_success "All dependencies are available" } # Run gosec security scanner run_gosec() { print_status "Running gosec security scanner..." if gosec -fmt=json -out=gosec-report.json -stdout -verbose=text ./...; then print_success "gosec scan completed successfully" else print_error "gosec found security issues!" if [ -f "gosec-report.json" ]; then echo "Detailed report saved to gosec-report.json" fi return 1 fi } # Run vulnerability check run_govulncheck() { print_status "Running govulncheck for dependency vulnerabilities..." if govulncheck -json ./... >govulncheck-report.json 2>&1; then print_success "No known vulnerabilities found in dependencies" else if grep -q '"finding"' govulncheck-report.json 2>/dev/null; then print_error "Vulnerabilities found in dependencies!" echo "Detailed report saved to govulncheck-report.json" return 1 else print_success "No vulnerabilities found" fi fi } # Run enhanced golangci-lint with security focus run_security_lint() { print_status "Running security-focused linting..." local security_linters="gosec,gocritic,bodyclose,rowserrcheck,misspell,unconvert,unparam,unused,errcheck,ineffassign,staticcheck" if golangci-lint run --enable="$security_linters" --timeout=5m; then print_success "Security linting passed" else print_error "Security linting found issues!" return 1 fi } # Check for potential secrets check_secrets() { print_status "Scanning for potential secrets and sensitive data..." local secrets_found=false # Common secret patterns local patterns=( "password\s*[:=]\s*['\"][^'\"]{3,}['\"]" "secret\s*[:=]\s*['\"][^'\"]{3,}['\"]" "key\s*[:=]\s*['\"][^'\"]{8,}['\"]" "token\s*[:=]\s*['\"][^'\"]{8,}['\"]" "api_?key\s*[:=]\s*['\"][^'\"]{8,}['\"]" "aws_?access_?key" "aws_?secret" "AKIA[0-9A-Z]{16}" # AWS Access Key pattern "github_?token" "private_?key" ) for pattern in "${patterns[@]}"; do if grep -r -i -E "$pattern" --include="*.go" . 2>/dev/null; then print_warning "Potential secret pattern found: $pattern" secrets_found=true fi done # Check git history for secrets (last 10 commits) if git log --oneline -10 | grep -i -E "(password|secret|key|token)" >/dev/null 2>&1; then print_warning "Potential secrets mentioned in recent commit messages" secrets_found=true fi if [ "$secrets_found" = true ]; then print_warning "Potential secrets detected. Please review manually." return 1 else print_success "No obvious secrets detected" fi } # Check for hardcoded network addresses check_hardcoded_addresses() { print_status "Checking for hardcoded network addresses..." local addresses_found=false # Look for IP addresses (excluding common safe ones) if grep -r -E "([0-9]{1,3}\.){3}[0-9]{1,3}" --include="*.go" . | grep -v -E "(127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.255|localhost)" >/dev/null 2>&1; then print_warning "Hardcoded IP addresses found:" grep -r -E "([0-9]{1,3}\.){3}[0-9]{1,3}" --include="*.go" . | grep -v -E "(127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.255|localhost)" || true addresses_found=true fi # Look for URLs (excluding documentation examples) if grep -r -E "https?://[^/\s]+" --include="*.go" . | grep -v -E "(example\.com|localhost|127\.0\.0\.1|\$\{)" >/dev/null 2>&1; then print_warning "Hardcoded URLs found:" grep -r -E "https?://[^/\s]+" --include="*.go" . | grep -v -E "(example\.com|localhost|127\.0\.0\.1|\$\{)" || true addresses_found=true fi if [ "$addresses_found" = true ]; then print_warning "Hardcoded network addresses detected. Please review." return 1 else print_success "No hardcoded network addresses found" fi } # Check Docker security (if Dockerfile exists) check_docker_security() { if [ -f "Dockerfile" ]; then print_status "Checking Docker security..." # Basic Dockerfile security checks local docker_issues=false if grep -q "^USER root" Dockerfile; then print_warning "Dockerfile runs as root user" docker_issues=true fi if ! grep -q "^USER " Dockerfile; then print_warning "Dockerfile doesn't specify a non-root user" docker_issues=true fi if grep -q "RUN.*wget\|RUN.*curl" Dockerfile && ! grep -q "rm.*wget\|rm.*curl" Dockerfile; then print_warning "Dockerfile may leave curl/wget installed" docker_issues=true fi if [ "$docker_issues" = true ]; then print_warning "Docker security issues detected" return 1 else print_success "Docker security check passed" fi else print_status "No Dockerfile found, skipping Docker security check" fi } # Check file permissions check_file_permissions() { print_status "Checking file permissions..." local perm_issues=false # Check for overly permissive files if find . -type f -perm /o+w -not -path "./.git/*" | grep -q .; then print_warning "World-writable files found:" find . -type f -perm /o+w -not -path "./.git/*" || true perm_issues=true fi # Check for executable files that shouldn't be if find . -type f -name "*.go" -perm /a+x | grep -q .; then print_warning "Executable Go files found (should not be executable):" find . -type f -name "*.go" -perm /a+x || true perm_issues=true fi if [ "$perm_issues" = true ]; then print_warning "File permission issues detected" return 1 else print_success "File permissions check passed" fi } # Check Makefile with checkmake check_makefile() { if [ -f "Makefile" ]; then print_status "Checking Makefile with checkmake..." if checkmake --config=.checkmake Makefile; then print_success "Makefile check passed" else print_error "Makefile issues detected!" return 1 fi else print_status "No Makefile found, skipping checkmake" fi } # Check shell scripts with shfmt check_shell_scripts() { print_status "Checking shell script formatting..." if find . -name "*.sh" -type f | head -1 | grep -q .; then if shfmt -d .; then print_success "Shell script formatting check passed" else print_error "Shell script formatting issues detected!" return 1 fi else print_status "No shell scripts found, skipping shfmt check" fi } # Check YAML files check_yaml_files() { print_status "Checking YAML files..." if find . -name "*.yml" -o -name "*.yaml" -type f | head -1 | grep -q .; then if yamllint -c .yamllint .; then print_success "YAML files check passed" else print_error "YAML file issues detected!" return 1 fi else print_status "No YAML files found, skipping yamllint check" fi } # Generate security report generate_report() { print_status "Generating security scan report..." local report_file="security-report.md" cat >"$report_file" <