Skip to content

learn shell from AI #69

@zero2hj

Description

@zero2hj
#!/bin/bash

# Inspection Rule Execution Script
# This script executes inspection rules based on rule names and returns results in JSON format
# Usage: ./inspect-script.sh "rule1,rule2,rule3"

set -euo pipefail

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RESULTS_FILE="/tmp/inspect_results_$(date +%s).json"
YAML_FILE="${SCRIPT_DIR}/inspect.yaml"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Logging functions
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1" >&2
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1" >&2
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1" >&2
}

# Function to check if required tools are available
check_dependencies() {
    local missing_tools=()
    
    if ! command -v jq &> /dev/null; then
        missing_tools+=("jq")
    fi
    
    if ! command -v yq &> /dev/null; then
        missing_tools+=("yq")
    fi
    
    if [ ${#missing_tools[@]} -ne 0 ]; then
        log_error "Missing required tools: ${missing_tools[*]}"
        log_error "Please install them before running this script"
        exit 1
    fi
}

# Function to execute a single command and capture result
execute_command() {
    local rule_id="$1"
    local rule_name="$2"
    local command="$3"
    local category="$4"
    local description="$5"
    
    log_info "Executing rule: $rule_id ($rule_name)"
    log_info "Command: $command"
    
    local start_time=$(date +%s.%N)
    local temp_output=$(mktemp)
    local temp_error=$(mktemp)
    
    # Execute command and capture output and exit code
    set +e
    eval "$command" > "$temp_output" 2> "$temp_error"
    local exit_code=$?
    set -e
    
    local end_time=$(date +%s.%N)
    local duration=$(echo "$end_time - $start_time" | bc -l)
    local duration_ms=$(echo "$duration * 1000" | bc -l | cut -d. -f1)
    
    # Read output and error
    local output=$(cat "$temp_output")
    local error_output=$(cat "$temp_error")
    
    # Combine output and error if there's an error
    if [ $exit_code -ne 0 ] && [ -n "$error_output" ]; then
        output="$output\nError: $error_output"
    fi
    
    # Clean up temp files
    rm -f "$temp_output" "$temp_error"
    
    # Create result JSON
    local result=$(jq -n \
        --arg rule_id "$rule_id" \
        --arg rule_name "$rule_name" \
        --arg command "$command" \
        --arg category "$category" \
        --arg description "$description" \
        --argjson exit_code "$exit_code" \
        --arg output "$output" \
        --argjson success "$([ $exit_code -eq 0 ] && echo true || echo false)" \
        --argjson execution_time_ms "$duration_ms" \
        --arg timestamp "$(date -Iseconds)" \
        '{
            ruleId: $rule_id,
            ruleName: $rule_name,
            command: $command,
            category: $category,
            description: $description,
            exitCode: $exit_code,
            output: $output,
            success: $success,
            executionTimeMs: $execution_time_ms,
            timestamp: $timestamp
        }')
    
    echo "$result"
    
    # Log result
    if [ $exit_code -eq 0 ]; then
        log_info "Rule $rule_id completed successfully (${duration_ms}ms)"
    else
        log_error "Rule $rule_id failed with exit code $exit_code (${duration_ms}ms)"
    fi
}

# Function to get rule definition from YAML
get_rule_definition() {
    local rule_id="$1"
    
    if [ ! -f "$YAML_FILE" ]; then
        log_error "YAML file not found: $YAML_FILE"
        return 1
    fi
    
    # Extract rule definition using yq
    yq eval ".[] | select(.id == \"$rule_id\")" "$YAML_FILE"
}

# Function to execute rules based on rule names
execute_rules() {
    local rule_names="$1"
    local results=()
    
    # Parse comma-separated rule names
    IFS=',' read -ra RULES <<< "$rule_names"
    
    for rule_name in "${RULES[@]}"; do
        # Trim whitespace
        rule_name=$(echo "$rule_name" | xargs)
        
        if [ -z "$rule_name" ]; then
            continue
        fi
        
        log_info "Processing rule: $rule_name"
        
        # Get rule definition from YAML
        rule_def=$(get_rule_definition "$rule_name")
        
        if [ -z "$rule_def" ]; then
            log_warn "Rule not found: $rule_name"
            
            # Create error result
            error_result=$(jq -n \
                --arg rule_id "$rule_name" \
                --arg rule_name "$rule_name" \
                --arg command "" \
                --arg category "Error" \
                --arg description "Rule not found" \
                --argjson exit_code -1 \
                --arg output "Rule not found: $rule_name" \
                --argjson success false \
                --argjson execution_time_ms 0 \
                --arg timestamp "$(date -Iseconds)" \
                '{
                    ruleId: $rule_id,
                    ruleName: $rule_name,
                    command: $command,
                    category: $category,
                    description: $description,
                    exitCode: $exit_code,
                    output: $output,
                    success: $success,
                    executionTimeMs: $execution_time_ms,
                    timestamp: $timestamp
                }')
            
            results+=("$error_result")
            continue
        fi
        
        # Extract rule properties
        local rule_id=$(echo "$rule_def" | yq eval '.id' -)
        local name=$(echo "$rule_def" | yq eval '.name' -)
        local command=$(echo "$rule_def" | yq eval '.rule' -)
        local category=$(echo "$rule_def" | yq eval '.category' -)
        local description=$(echo "$rule_def" | yq eval '.reason' -)
        local type=$(echo "$rule_def" | yq eval '.type' -)
        
        # Check if it's a COMMAND type rule
        if [ "$type" != "COMMAND" ]; then
            log_warn "Rule $rule_name is not a COMMAND type rule, skipping"
            continue
        fi
        
        # Execute the command
        result=$(execute_command "$rule_id" "$name" "$command" "$category" "$description")
        results+=("$result")
    done
    
    # Create final JSON array
    printf '%s\n' "${results[@]}" | jq -s '.' | tee $RESULTS_FILE
}

# Main function
main() {
    if [ $# -eq 0 ]; then
        echo "Usage: $0 <rule-names> <result-file> <rule-file>"
        echo "Example: $0 \"docker-version,system-info,disk-usage\" /tmp/result0 inspect.yml "
        echo ""
        echo "Available rules:"

        if [ -f "$YAML_FILE" ]; then
            yq eval '.[].id' "$YAML_FILE" | sed 's/^/  - /'
        else
            echo "  (inspect.yaml not found)"
        fi
        exit 1
    fi
    local rule_names="$1"
    RESULTS_FILE="${2:-$RESULTS_FILE}" 
    YAML_FILE="${3:-$YAML_FILE}"

    log_info "Starting inspection rule execution"
    log_info "Rule names: $rule_names"
    
    # Check dependencies
    check_dependencies
    
    # Execute rules and output results
    execute_rules "$rule_names"
    
    log_info "Inspection completed"
}

# Run main function with all arguments
main "$@"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions