#!/usr/bin/env bash # Audit Besu Configuration Files # Compares running node configs to templates, identifies configuration drift set -euo pipefail # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # Script directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # Output format OUTPUT_FORMAT="${1:-human}" REPORT_FILE="${2:-besu-config-audit-$(date +%Y%m%d_%H%M%S).json}" log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # Track audit results TOTAL_CONFIGS=0 MATCHING_CONFIGS=0 DRIFT_DETECTED=0 DRIFT_FILES=() # Template files TEMPLATE_VALIDATOR="$PROJECT_ROOT/smom-dbis-138-proxmox/templates/besu-configs/config-validator.toml" TEMPLATE_SENTRY="$PROJECT_ROOT/smom-dbis-138-proxmox/templates/besu-configs/config-sentry.toml" TEMPLATE_RPC_CORE="$PROJECT_ROOT/smom-dbis-138-proxmox/templates/besu-configs/config-rpc-core.toml" TEMPLATE_RPC="$PROJECT_ROOT/smom-dbis-138-proxmox/templates/besu-configs/config-rpc.toml" # Function to normalize config for comparison (remove comments, blank lines) normalize_config() { local file="$1" if [ ! -f "$file" ]; then echo "" return 1 fi # Remove comments, blank lines, normalize whitespace grep -v '^#' "$file" | grep -v '^[[:space:]]*$' | sed 's/[[:space:]]*=[[:space:]]*/=/' | sort } # Function to compare two config files compare_configs() { local file1="$1" local file2="$2" local node_type="$3" local normalized1=$(normalize_config "$file1") local normalized2=$(normalize_config "$file2") # Compare normalized configs local diff_result=$(diff <(echo "$normalized1") <(echo "$normalized2") || true) if [ -z "$diff_result" ]; then return 0 # Match else echo "$diff_result" return 1 # Drift detected fi } # Function to detect node type from filename detect_node_type() { local file="$1" local basename=$(basename "$file") if [[ "$basename" == *"validator"* ]]; then echo "validator" elif [[ "$basename" == *"sentry"* ]]; then echo "sentry" elif [[ "$basename" == *"rpc-core"* ]] || [[ "$basename" == *"rpc.toml"* ]]; then echo "rpc-core" elif [[ "$basename" == *"rpc"* ]]; then echo "rpc" else echo "unknown" fi } # Function to get template for node type get_template() { local node_type="$1" case "$node_type" in validator) echo "$TEMPLATE_VALIDATOR" ;; sentry) echo "$TEMPLATE_SENTRY" ;; rpc-core) echo "$TEMPLATE_RPC_CORE" ;; rpc) echo "$TEMPLATE_RPC" ;; *) echo "" ;; esac } # Function to audit a config file audit_config_file() { local file="$1" local node_type=$(detect_node_type "$file") local template=$(get_template "$node_type") TOTAL_CONFIGS=$((TOTAL_CONFIGS + 1)) if [ "$OUTPUT_FORMAT" == "human" ]; then echo "" log_info "Auditing: $file (type: $node_type)" fi if [ ! -f "$file" ]; then log_error " File not found: $file" DRIFT_DETECTED=$((DRIFT_DETECTED + 1)) DRIFT_FILES+=("$file: FILE_NOT_FOUND") return 1 fi if [ -z "$template" ] || [ ! -f "$template" ]; then log_warn " No template found for node type: $node_type (skipping comparison)" return 0 fi # Compare with template local diff_result=$(compare_configs "$file" "$template" "$node_type") if [ $? -eq 0 ]; then MATCHING_CONFIGS=$((MATCHING_CONFIGS + 1)) if [ "$OUTPUT_FORMAT" == "human" ]; then log_success " Matches template" fi return 0 else DRIFT_DETECTED=$((DRIFT_DETECTED + 1)) DRIFT_FILES+=("$file: DRIFT_DETECTED") if [ "$OUTPUT_FORMAT" == "human" ]; then log_warn " Configuration drift detected" echo " Differences from template:" echo "$diff_result" | head -20 | sed 's/^/ /' if [ $(echo "$diff_result" | wc -l) -gt 20 ]; then echo " ... (showing first 20 differences)" fi fi return 1 fi } # Function to check configuration version/status check_config_version() { local file="$1" local version="" # Check for version comment or metadata if grep -q "#.*version\|#.*Version\|#.*VERSION" "$file" 2>/dev/null; then version=$(grep -i "#.*version" "$file" | head -1 | sed 's/.*version[^0-9]*\([0-9.]*\).*/\1/') fi # Check modification time local mod_time=$(stat -c %y "$file" 2>/dev/null || stat -f %Sm "$file" 2>/dev/null || echo "") echo "$version|$mod_time" } # Main execution if [ "$OUTPUT_FORMAT" == "human" ]; then echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║ BESU CONFIGURATION AUDIT ║${NC}" echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}" echo "" log_info "Auditing configuration files against templates..." fi # Config files to audit CONFIG_FILES=( "$PROJECT_ROOT/smom-dbis-138/config/config-validator.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-core.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-public.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-perm.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-thirdweb.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-4.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-putu-1.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-putu-8a.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-luis-1.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-rpc-luis-8a.toml" "$PROJECT_ROOT/smom-dbis-138/config/config-member.toml" ) # Audit each file for file in "${CONFIG_FILES[@]}"; do audit_config_file "$file" done # Summary if [ "$OUTPUT_FORMAT" == "human" ]; then echo "" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}Audit Summary${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" echo "Total configs audited: $TOTAL_CONFIGS" echo "Matching templates: $MATCHING_CONFIGS" echo "Drift detected: $DRIFT_DETECTED" echo "" if [ $DRIFT_DETECTED -eq 0 ]; then log_success "All configuration files match templates!" exit 0 else log_warn "Configuration drift detected in some files" echo "" echo "Files with drift:" for drift in "${DRIFT_FILES[@]}"; do echo " - $drift" done exit 1 fi else # JSON output for automation { echo "{" echo " \"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"," echo " \"total\": $TOTAL_CONFIGS," echo " \"matching\": $MATCHING_CONFIGS," echo " \"drift_detected\": $DRIFT_DETECTED," echo " \"drift_files\": [" for i in "${!DRIFT_FILES[@]}"; do echo -n " \"${DRIFT_FILES[$i]//\"/\\\"}\"" if [ $i -lt $((${#DRIFT_FILES[@]} - 1)) ]; then echo "," else echo "" fi done echo " ]," echo " \"success\": $([ $DRIFT_DETECTED -eq 0 ] && echo "true" || echo "false")" echo "}" } > "$REPORT_FILE" 2>/dev/null || echo "Failed to write report" echo "Audit report written to: $REPORT_FILE" exit $([ $DRIFT_DETECTED -eq 0 ] && echo 0 || echo 1) fi