#!/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 "Failed to change directory to $PROJECT_ROOT" exit 1 } # shellcheck source=scripts/install-tools.sh source "$SCRIPT_DIR/install-tools.sh" echo "🔒 Starting comprehensive security scan for gibidify..." check_dependencies # 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 revive with comprehensive linting run_security_lint() { print_status "Running comprehensive code quality linting with revive..." if revive -config revive.toml -set_exit_status ./...; then print_success "Revive linting passed" else print_error "Revive 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|no-color\.org|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 +002 -not -path "./.git/*" | grep -q .; then print_warning "World-writable files found:" find . -type f -perm +002 -not -path "./.git/*" || true perm_issues=true fi # Check for executable files that shouldn't be if find . -type f -name "*.go" -perm +111 | grep -q .; then print_warning "Executable Go files found (should not be executable):" find . -type f -name "*.go" -perm +111 || 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" <