#!/usr/bin/env bash

#########################################################################################
#### security-group-auditor.sh — Audit AWS Security Groups for risky configs         ####
#### Finds 0.0.0.0/0 rules, dangerous ports, all-port rules, unused groups           ####
#### Requires: bash 4+, aws CLI, jq                                                 ####
####                                                                                 ####
#### Author: Phil Connor                                                             ####
#### Contact: contact@mylinux.work                                                   ####
#### License: MIT                                                                    ####
#### Version 1.01                                                                    ####
####                                                                                 ####
#### Usage:                                                                          ####
####   ./security-group-auditor.sh --full                                            ####
####                                                                                 ####
#### See --help for all options.                                                     ####
#########################################################################################

set -euo pipefail

# ── Colors (pre-initialized) ─────────────────────────────────────────
RED="" GREEN="" YELLOW="" BLUE="" CYAN="" BOLD="" DIM="" RESET=""

setup_colors() {
    if [[ "${COLOR:-auto}" == "never" ]]; then
        return
    fi
    if [[ "${COLOR:-auto}" == "always" ]] || [[ -t 1 ]]; then
        RED='\033[0;31m'
        GREEN='\033[0;32m'
        YELLOW='\033[0;33m'
        BLUE='\033[0;34m'
        CYAN='\033[0;36m'
        BOLD='\033[1m'
        DIM='\033[2m'
        RESET='\033[0m'
    fi
}

# ── Logging ───────────────────────────────────────────────────────────
log()     { echo -e "${BLUE}[INFO]${RESET} $*"; }
warn()    { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
err()     { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
die()     { err "$*"; exit 1; }

# ── Severity counters ────────────────────────────────────────────────
TOTAL_CRIT=0
TOTAL_WARN=0
TOTAL_INFO=0
TOTAL_OK=0

flag_crit() { ((TOTAL_CRIT++)) || true; }
flag_warn() { ((TOTAL_WARN++)) || true; }
flag_info() { ((TOTAL_INFO++)) || true; }
flag_ok()   { ((TOTAL_OK++)) || true; }

# ── Defaults ──────────────────────────────────────────────────────────
RUN_MODE=""
DANGEROUS_PORTS="${DANGEROUS_PORTS:-22,3389,3306,5432,1433,6379,27017,9200,8080,8443}"
VERBOSE="${VERBOSE:-false}"
COLOR="${COLOR:-auto}"
AWS_REGION=""
VPC_ID=""

# ── State ─────────────────────────────────────────────────────────────
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
START_TIME=""

# ── Dependency and credential checks ────────────────────────────────
check_deps() {
    command -v aws &>/dev/null || die "aws CLI is required (install: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)"
    command -v jq &>/dev/null || die "jq is required"
}

check_credentials() {
    local identity
    identity=$(aws_cmd sts get-caller-identity --output json 2>/dev/null) \
        || die "No valid AWS credentials — run 'aws configure' or set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY"

    local account arn
    account=$(echo "$identity" | jq -r '.Account')
    arn=$(echo "$identity" | jq -r '.Arn')

    verbose "Account: ${account}"
    verbose "ARN:     ${arn}"

    local region
    region=$(aws_cmd configure get region 2>/dev/null || true)
    if [[ -z "$AWS_REGION" && -z "$region" ]]; then
        die "No region set — use --region or 'aws configure set region REGION' or set AWS_DEFAULT_REGION"
    fi

    log "Account: ${account}"
    log "Region:  ${AWS_REGION:-$region}"
}

# ── aws wrapper ──────────────────────────────────────────────────────
aws_cmd() {
    local args=("$@")
    if [[ -n "$AWS_REGION" ]]; then
        args+=(--region "$AWS_REGION")
    fi
    verbose "aws ${args[*]}"
    aws "${args[@]}"
}

# ── Port-to-service mapping ─────────────────────────────────────────
port_to_service() {
    local port="$1"
    case "$port" in
        22)    echo "SSH" ;;
        80)    echo "HTTP" ;;
        443)   echo "HTTPS" ;;
        3306)  echo "MySQL" ;;
        5432)  echo "PostgreSQL" ;;
        1433)  echo "MSSQL" ;;
        3389)  echo "RDP" ;;
        6379)  echo "Redis" ;;
        27017) echo "MongoDB" ;;
        9200)  echo "Elasticsearch" ;;
        8080)  echo "HTTP-Alt" ;;
        8443)  echo "HTTPS-Alt" ;;
        53)    echo "DNS" ;;
        25)    echo "SMTP" ;;
        5900)  echo "VNC" ;;
        11211) echo "Memcached" ;;
        2379)  echo "etcd" ;;
        9090)  echo "Prometheus" ;;
        *)     echo "" ;;
    esac
}

# ── Check if port is in dangerous list ───────────────────────────────
is_dangerous_port() {
    local port="$1"
    local IFS=','
    for dp in $DANGEROUS_PORTS; do
        if [[ "$port" == "$dp" ]]; then
            return 0
        fi
    done
    return 1
}

# ── Check if dangerous port falls in a from-to range ────────────────
port_in_range() {
    local port="$1" from="$2" to="$3"
    [[ "$port" -ge "$from" && "$port" -le "$to" ]]
}

# ── Fetch security groups ───────────────────────────────────────────
fetch_sgs() {
    local args=(ec2 describe-security-groups --output json)
    if [[ -n "$VPC_ID" ]]; then
        args+=(--filters "Name=vpc-id,Values=${VPC_ID}")
    fi
    aws_cmd "${args[@]}" 2>/dev/null | jq '.SecurityGroups'
}

# ── Fetch ENI attachments (SG IDs in use) ────────────────────────────
fetch_attached_sg_ids() {
    aws_cmd ec2 describe-network-interfaces --output json \
        --query 'NetworkInterfaces[].Groups[].GroupId' 2>/dev/null | jq -r '.[]' | sort -u
}

# ══════════════════════════════════════════════════════════════════════
#                       OPEN PORTS AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_open_ports() {
    log "Auditing security groups for dangerous open ports..."
    log "Dangerous ports: ${DANGEROUS_PORTS}"
    echo ""

    printf "  %-24s %-14s %-14s %-8s %-12s %-18s %s\n" \
        "SG_NAME" "SG_ID" "VPC" "PROTO" "PORT" "SOURCE" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..105})"

    local sgs_json
    sgs_json=$(fetch_sgs)

    echo "$sgs_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r sg; do
        local sg_name sg_id vpc_id
        sg_name=$(echo "$sg" | jq -r '.GroupName')
        sg_id=$(echo "$sg" | jq -r '.GroupId')
        vpc_id=$(echo "$sg" | jq -r '.VpcId // "none"')

        echo "$sg" | jq -c '.IpPermissions[]? // empty' 2>/dev/null | while IFS= read -r perm; do
            local protocol from_port to_port
            protocol=$(echo "$perm" | jq -r '.IpProtocol')
            from_port=$(echo "$perm" | jq -r '.FromPort // -1')
            to_port=$(echo "$perm" | jq -r '.ToPort // -1')

            # Check for 0.0.0.0/0 or ::/0
            local has_open="false"
            local source_cidr=""
            while IFS= read -r cidr; do
                if [[ "$cidr" == "0.0.0.0/0" || "$cidr" == "::/0" ]]; then
                    has_open="true"
                    source_cidr="$cidr"
                    break
                fi
            done < <(echo "$perm" | jq -r '(.IpRanges[].CidrIp // empty), (.Ipv6Ranges[].CidrIpv6 // empty)' 2>/dev/null)

            [[ "$has_open" != "true" ]] && continue

            # Protocol -1 means all traffic
            if [[ "$protocol" == "-1" ]]; then
                printf "  %-24s %-14s %-14s %-8s %-12s %-18s %b%s%b\n" \
                    "${sg_name:0:23}" "$sg_id" "${vpc_id:0:13}" "all" "all" \
                    "$source_cidr" "$RED" "CRITICAL" "$RESET"
                flag_crit
                continue
            fi

            # No port range (e.g. icmp) — skip dangerous port check
            if [[ "$from_port" == "-1" && "$to_port" == "-1" && "$protocol" != "-1" ]]; then
                verbose "SG ${sg_id}: ${protocol} rule without port range — skipping port check"
                continue
            fi

            # Check if any dangerous port is in the from-to range
            local IFS=','
            for dp in $DANGEROUS_PORTS; do
                if port_in_range "$dp" "$from_port" "$to_port"; then
                    local svc severity color
                    svc=$(port_to_service "$dp")
                    if [[ "$dp" == "80" || "$dp" == "443" ]]; then
                        severity="INFO"; color="$CYAN"; flag_info
                    else
                        severity="CRITICAL"; color="$RED"; flag_crit
                    fi
                    local port_display="$dp"
                    [[ -n "$svc" ]] && port_display="${dp} (${svc})"
                    printf "  %-24s %-14s %-14s %-8s %-12s %-18s %b%s%b\n" \
                        "${sg_name:0:23}" "$sg_id" "${vpc_id:0:13}" "$protocol" \
                        "$port_display" "$source_cidr" "$color" "$severity" "$RESET"
                fi
            done
        done
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       PERMISSIVE RULES AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_permissive() {
    log "Auditing overly permissive security groups..."
    echo ""

    printf "  %-24s %-14s %-14s %-18s %s\n" \
        "SG_NAME" "SG_ID" "VPC" "SOURCE" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..85})"

    local sgs_json
    sgs_json=$(fetch_sgs)

    echo "$sgs_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r sg; do
        local sg_name sg_id vpc_id
        sg_name=$(echo "$sg" | jq -r '.GroupName')
        sg_id=$(echo "$sg" | jq -r '.GroupId')
        vpc_id=$(echo "$sg" | jq -r '.VpcId // "none"')

        echo "$sg" | jq -c '.IpPermissions[]? // empty' 2>/dev/null | while IFS= read -r perm; do
            local protocol
            protocol=$(echo "$perm" | jq -r '.IpProtocol')

            [[ "$protocol" != "-1" ]] && continue

            local source_cidr=""
            while IFS= read -r cidr; do
                if [[ "$cidr" == "0.0.0.0/0" || "$cidr" == "::/0" ]]; then
                    source_cidr="$cidr"
                    break
                fi
            done < <(echo "$perm" | jq -r '(.IpRanges[].CidrIp // empty), (.Ipv6Ranges[].CidrIpv6 // empty)' 2>/dev/null)

            [[ -z "$source_cidr" ]] && continue

            printf "  %-24s %-14s %-14s %-18s %b%s%b\n" \
                "${sg_name:0:23}" "$sg_id" "${vpc_id:0:13}" \
                "$source_cidr" "$RED" "CRITICAL" "$RESET"
            flag_crit
        done
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       EGRESS AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_egress() {
    log "Auditing egress security group rules..."
    echo ""

    printf "  %-24s %-14s %-14s %-18s %s\n" \
        "SG_NAME" "SG_ID" "VPC" "DESTINATION" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..85})"

    local sgs_json
    sgs_json=$(fetch_sgs)

    echo "$sgs_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r sg; do
        local sg_name sg_id vpc_id
        sg_name=$(echo "$sg" | jq -r '.GroupName')
        sg_id=$(echo "$sg" | jq -r '.GroupId')
        vpc_id=$(echo "$sg" | jq -r '.VpcId // "none"')

        echo "$sg" | jq -c '.IpPermissionsEgress[]? // empty' 2>/dev/null | while IFS= read -r perm; do
            local protocol
            protocol=$(echo "$perm" | jq -r '.IpProtocol')

            [[ "$protocol" != "-1" ]] && continue

            local dest_cidr=""
            while IFS= read -r cidr; do
                if [[ "$cidr" == "0.0.0.0/0" || "$cidr" == "::/0" ]]; then
                    dest_cidr="$cidr"
                    break
                fi
            done < <(echo "$perm" | jq -r '(.IpRanges[].CidrIp // empty), (.Ipv6Ranges[].CidrIpv6 // empty)' 2>/dev/null)

            [[ -z "$dest_cidr" ]] && continue

            printf "  %-24s %-14s %-14s %-18s %b%s%b\n" \
                "${sg_name:0:23}" "$sg_id" "${vpc_id:0:13}" \
                "$dest_cidr" "$YELLOW" "WARN" "$RESET"
            flag_warn
        done
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       UNUSED GROUPS AUDIT
# ══════════════════════════════════════════════════════════════════════
audit_unused() {
    log "Checking for unused security groups..."
    echo ""

    printf "  %-24s %-14s %-14s %-14s %s\n" \
        "SG_NAME" "SG_ID" "VPC" "ATTACHED_ENIS" "SEVERITY"
    printf "  %s\n" "$(printf '%.0s─' {1..85})"

    local sgs_json attached_ids
    sgs_json=$(fetch_sgs)
    attached_ids=$(fetch_attached_sg_ids)

    echo "$sgs_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r sg; do
        local sg_name sg_id vpc_id
        sg_name=$(echo "$sg" | jq -r '.GroupName')
        sg_id=$(echo "$sg" | jq -r '.GroupId')
        vpc_id=$(echo "$sg" | jq -r '.VpcId // "none"')

        # Skip default SG — can't be deleted
        if [[ "$sg_name" == "default" ]]; then
            verbose "Skipping default SG ${sg_id} (cannot be deleted)"
            flag_ok
            continue
        fi

        if echo "$attached_ids" | grep -qx "$sg_id"; then
            verbose "SG ${sg_id} (${sg_name}): attached to ENI(s)"
            flag_ok
        else
            printf "  %-24s %-14s %-14s %-14s %b%s%b\n" \
                "${sg_name:0:23}" "$sg_id" "${vpc_id:0:13}" \
                "0" "$YELLOW" "WARN — unused" "$RESET"
            flag_warn
        fi
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       LIST ALL RULES
# ══════════════════════════════════════════════════════════════════════
list_rules() {
    log "Listing all security group rules..."
    echo ""

    printf "  %-24s %-14s %-14s %-10s %-8s %-12s %-18s\n" \
        "SG_NAME" "SG_ID" "VPC" "DIR" "PROTO" "PORTS" "SOURCE/DEST"
    printf "  %s\n" "$(printf '%.0s─' {1..105})"

    local sgs_json
    sgs_json=$(fetch_sgs)

    echo "$sgs_json" | jq -c '.[]' 2>/dev/null | while IFS= read -r sg; do
        local sg_name sg_id vpc_id
        sg_name=$(echo "$sg" | jq -r '.GroupName')
        sg_id=$(echo "$sg" | jq -r '.GroupId')
        vpc_id=$(echo "$sg" | jq -r '.VpcId // "none"')

        # Ingress rules
        echo "$sg" | jq -c '.IpPermissions[]? // empty' 2>/dev/null | while IFS= read -r perm; do
            local protocol from_port to_port port_str cidr_list
            protocol=$(echo "$perm" | jq -r '.IpProtocol')
            from_port=$(echo "$perm" | jq -r '.FromPort // -1')
            to_port=$(echo "$perm" | jq -r '.ToPort // -1')

            if [[ "$protocol" == "-1" ]]; then
                port_str="all"
                protocol="all"
            elif [[ "$from_port" == "$to_port" ]]; then
                port_str="$from_port"
            else
                port_str="${from_port}-${to_port}"
            fi

            cidr_list=$(echo "$perm" | jq -r '(.IpRanges[0].CidrIp // .Ipv6Ranges[0].CidrIpv6 // .UserIdGroupPairs[0].GroupId // "any")' 2>/dev/null)

            printf "  %-24s %-14s %-14s %b%-10s%b %-8s %-12s %-18s\n" \
                "${sg_name:0:23}" "$sg_id" "${vpc_id:0:13}" "$CYAN" "INGRESS" "$RESET" \
                "$protocol" "${port_str:0:11}" "${cidr_list:0:17}"
        done

        # Egress rules
        echo "$sg" | jq -c '.IpPermissionsEgress[]? // empty' 2>/dev/null | while IFS= read -r perm; do
            local protocol from_port to_port port_str cidr_list
            protocol=$(echo "$perm" | jq -r '.IpProtocol')
            from_port=$(echo "$perm" | jq -r '.FromPort // -1')
            to_port=$(echo "$perm" | jq -r '.ToPort // -1')

            if [[ "$protocol" == "-1" ]]; then
                port_str="all"
                protocol="all"
            elif [[ "$from_port" == "$to_port" ]]; then
                port_str="$from_port"
            else
                port_str="${from_port}-${to_port}"
            fi

            cidr_list=$(echo "$perm" | jq -r '(.IpRanges[0].CidrIp // .Ipv6Ranges[0].CidrIpv6 // .UserIdGroupPairs[0].GroupId // "any")' 2>/dev/null)

            printf "  %-24s %-14s %-14s %b%-10s%b %-8s %-12s %-18s\n" \
                "${sg_name:0:23}" "$sg_id" "${vpc_id:0:13}" "$YELLOW" "EGRESS" "$RESET" \
                "$protocol" "${port_str:0:11}" "${cidr_list:0:17}"
        done
    done

    echo ""
}

# ══════════════════════════════════════════════════════════════════════
#                       SUMMARY
# ══════════════════════════════════════════════════════════════════════
print_summary() {
    local elapsed
    elapsed=$(( $(date +%s) - START_TIME ))

    echo ""
    echo "  ══════════════════════════════════════════"
    echo "  Security Group Audit Summary"
    echo "  ══════════════════════════════════════════"
    printf "  %-20s %b%d%b\n" "CRITICAL:" "$RED" "$TOTAL_CRIT" "$RESET"
    printf "  %-20s %b%d%b\n" "WARN:" "$YELLOW" "$TOTAL_WARN" "$RESET"
    printf "  %-20s %b%d%b\n" "INFO:" "$CYAN" "$TOTAL_INFO" "$RESET"
    printf "  %-20s %b%d%b\n" "OK:" "$GREEN" "$TOTAL_OK" "$RESET"
    echo "  ──────────────────────────────────────────"
    printf "  Completed in %ds\n" "$elapsed"
    echo ""

    if [[ "$TOTAL_CRIT" -gt 0 ]]; then
        echo -e "  ${RED}${BOLD}Action required:${RESET} ${TOTAL_CRIT} critical finding(s)"
        echo ""
        echo "  Top recommendations:"
        echo "    • Close 0.0.0.0/0 rules on SSH (22), RDP (3389), and database ports"
        echo "    • Replace all-traffic (-1) rules with specific port/protocol pairs"
        echo "    • Use VPC endpoints or NAT gateways instead of public access"
        echo "    • Delete unused security groups to reduce attack surface"
        echo ""
    elif [[ "$TOTAL_WARN" -gt 0 ]]; then
        echo -e "  ${YELLOW}Review recommended:${RESET} ${TOTAL_WARN} warning(s)"
        echo ""
        echo "  Suggestions:"
        echo "    • Review unused security groups for deletion"
        echo "    • Restrict overly broad egress rules"
        echo "    • Use security group references instead of CIDR blocks where possible"
        echo ""
    else
        echo -e "  ${GREEN}All checks passed${RESET}"
        echo ""
    fi
}

# ══════════════════════════════════════════════════════════════════════
#                       USAGE
# ══════════════════════════════════════════════════════════════════════
show_help() {
    cat <<EOF
${BOLD}${SCRIPT_NAME}${RESET} — AWS Security Group Auditor

Audit AWS EC2 Security Groups for risky configurations
via the AWS CLI. Read-only — never modifies security groups.

${BOLD}MODES${RESET}
  --full              Run all audits
  --open-ports        Find dangerous ports open to 0.0.0.0/0
  --permissive        Find all-traffic rules open to the internet
  --unused            Find security groups not attached to any ENI
  --egress            Audit wide egress rules
  --rules             List all security group rules

${BOLD}OPTIONS${RESET}
  --region REGION     AWS region (overrides AWS_DEFAULT_REGION)
  --vpc VPC_ID        Limit to specific VPC (vpc-xxx)
  --ports PORTS       Override dangerous ports (comma-separated)
  --verbose           Debug output
  --no-color          Disable colored output
  --help              Show this help message

${BOLD}ENVIRONMENT VARIABLES${RESET}
  DANGEROUS_PORTS      Comma-separated ports to flag (default: 22,3389,...)
  VERBOSE              Enable verbose output (true/false)
  COLOR                Color mode: auto, always, never
  AWS_DEFAULT_REGION   Default AWS region

${BOLD}EXAMPLES${RESET}
  # Full audit
  ${SCRIPT_NAME} --full

  # Check open ports only
  ${SCRIPT_NAME} --open-ports

  # Audit a specific region
  ${SCRIPT_NAME} --full --region us-east-1

  # Filter by VPC
  ${SCRIPT_NAME} --open-ports --vpc vpc-0abc123def456

  # Custom dangerous ports
  ${SCRIPT_NAME} --open-ports --ports "22,3389,5432,6379"

  # List all security group rules
  ${SCRIPT_NAME} --rules

${BOLD}EXIT CODES${RESET}
  0   All checks passed
  1   Warnings found (review recommended)
  2   Critical findings (action required)
EOF
}

# ══════════════════════════════════════════════════════════════════════
#                       PARSE ARGS
# ══════════════════════════════════════════════════════════════════════
parse_args() {
    local modes=()

    while [[ $# -gt 0 ]]; do
        case "$1" in
            --full)
                modes=(open-ports permissive unused egress)
                shift ;;
            --open-ports)
                modes+=(open-ports); shift ;;
            --permissive)
                modes+=(permissive); shift ;;
            --unused)
                modes+=(unused); shift ;;
            --egress)
                modes+=(egress); shift ;;
            --rules)
                modes+=(rules); shift ;;
            --region)
                AWS_REGION="${2:?--region requires a value}"; shift 2 ;;
            --vpc)
                VPC_ID="${2:?--vpc requires a value}"; shift 2 ;;
            --ports)
                DANGEROUS_PORTS="${2:?--ports requires a value}"; shift 2 ;;
            --verbose)
                VERBOSE="true"; shift ;;
            --no-color)
                COLOR="never"; shift ;;
            --help|-h)
                setup_colors; show_help; exit 0 ;;
            *)
                die "Unknown option: $1 (see --help)" ;;
        esac
    done

    if [[ ${#modes[@]} -eq 0 ]]; then
        err "No audit mode specified"
        echo "Run ${SCRIPT_NAME} --help for usage" >&2
        exit 1
    fi

    RUN_MODE="${modes[*]}"
}

# ══════════════════════════════════════════════════════════════════════
#                       MAIN
# ══════════════════════════════════════════════════════════════════════
main() {
    parse_args "$@"
    setup_colors
    check_deps
    check_credentials

    START_TIME=$(date +%s)

    echo ""
    echo -e "${BOLD}AWS Security Group Auditor${RESET}"
    echo -e "Region:  ${AWS_REGION:-$(aws configure get region 2>/dev/null || echo 'default')}"
    echo -e "Mode:    ${RUN_MODE}"
    if [[ -n "$VPC_ID" ]]; then
        echo -e "VPC:     ${VPC_ID}"
    fi
    echo -e "Time:    $(date -u +%Y-%m-%dT%H:%M:%SZ)"
    echo ""

    for mode in $RUN_MODE; do
        case "$mode" in
            open-ports)  audit_open_ports ;;
            permissive)  audit_permissive ;;
            unused)      audit_unused ;;
            egress)      audit_egress ;;
            rules)       list_rules ;;
        esac
    done

    print_summary

    if [[ "$TOTAL_CRIT" -gt 0 ]]; then
        exit 2
    elif [[ "$TOTAL_WARN" -gt 0 ]]; then
        exit 1
    fi
    exit 0
}

main "$@"
