#!/usr/bin/env bash
set -Eeuo pipefail
set +x
umask 077

readonly LABEL=REDIS01_Q200_FIREWALLD_DBUS_DIAGNOSIS_V2
readonly EXPECTED_HOST=sqjcredis01
readonly EXPECTED_IP=10.2.203.112
readonly SOURCE_IP=10.2.203.113
readonly FAILED_SCRIPT=/root/redis01-q200-allow-redis02-replication-ports.sh
readonly FAILED_SCRIPT_SHA256=601dfc85a2ad6a1c1181b7eb43fc3e8a37b8e5f24a5ca275ce8817f97110684a
RUN_ID="q200-firewalld-dbus-diagnosis-$(date -u +%Y%m%dT%H%M%SZ)"
AUDIT_DIR="/var/backups/zhct-q200-firewalld-dbus-diagnosis/${RUN_ID}"
AUDIT_LOG="${AUDIT_DIR}/operator.log"

finish() {
    local rc=$?
    set +e
    printf '%s\n' \
        "$([[ "$rc" -eq 0 ]] && printf 'Q200_FIREWALLD_DBUS_DIAGNOSIS=PASS_READ_ONLY' || printf 'Q200_FIREWALLD_DBUS_DIAGNOSIS=FAIL_STOP')" \
        'SERVICE_MUTATION=ZERO' \
        'FIREWALL_MUTATION=ZERO' \
        'REDIS_MUTATION=ZERO' \
        "END|${LABEL}|RC=${rc}|AUDIT_LOG=${AUDIT_LOG}"
    exit "$rc"
}
trap finish EXIT

printf 'BEGIN|%s|%s\n' "$LABEL" "$(date '+%Y-%m-%dT%H:%M:%S%z')"
[[ $# -eq 0 && $(id -u) -eq 0 ]]
actual_host=$(hostname -s)
[[ "$actual_host" == "$EXPECTED_HOST" ]]
ip -o -4 addr show scope global | awk '{split($4,a,"/"); print a[1]}' | grep -Fxq "$EXPECTED_IP"
printf 'Q200_FIREWALLD_DBUS_TARGET_IDENTITY=PASS|host=%s|ip=%s\n' "$actual_host" "$EXPECTED_IP"
for command_name in systemctl firewall-cmd timeout journalctl ps ss stat install tee; do command -v "$command_name" >/dev/null; done
[[ -f "$FAILED_SCRIPT" && ! -L "$FAILED_SCRIPT" ]]
printf '%s  %s\n' "$FAILED_SCRIPT_SHA256" "$FAILED_SCRIPT" | sha256sum -c -
for unit in redis5.service redis7.service; do [[ "$(systemctl is-active "$unit" 2>/dev/null || true)" == active ]]; done
for unit in sentinel5.service sentinel7.service orchestrator.service; do [[ "$(systemctl is-active "$unit" 2>/dev/null || true)" == inactive ]]; done
printf 'Q200_PREVIOUS_FAILURE_BOUNDARY=ACCEPTED_FROM_COMPLETE_BEGIN_END_RC36_ZERO_MUTATION_RECEIPT\n'

install -d -o root -g root -m 0700 "$AUDIT_DIR"
exec > >(tee -a "$AUDIT_LOG") 2>&1
printf 'AUDIT_BEGIN|%s|%s\n' "$LABEL" "$(date '+%Y-%m-%dT%H:%M:%S%z')"

printf '%s\n' '=== SERVICE STATE ==='
for unit in dbus.service dbus.socket firewalld.service; do
    printf 'UNIT|%s|enabled=%s|active=%s|failed=%s\n' "$unit" \
        "$(systemctl is-enabled "$unit" 2>/dev/null || true)" \
        "$(systemctl is-active "$unit" 2>/dev/null || true)" \
        "$(systemctl is-failed "$unit" 2>/dev/null || true)"
    systemctl show "$unit" -p LoadState -p ActiveState -p SubState -p MainPID -p ExecMainStatus -p Result --no-pager 2>&1 || true
done

printf '%s\n' '=== PROCESS / SOCKET STATE ==='
ps -eo pid=,ppid=,stat=,etime=,comm=,args= | grep -E '[d]bus-daemon|[f]irewalld' || true
for path in /run/dbus/system_bus_socket /var/run/dbus/system_bus_socket; do
    if [[ -e "$path" || -L "$path" ]]; then stat -c 'BUS_SOCKET|%F|%A|%U:%G|%n' "$path"; else printf 'BUS_SOCKET|ABSENT|%s\n' "$path"; fi
done
ss -xlpn | grep -E 'dbus|firewalld' || true

printf '%s\n' '=== BOUNDED FIREWALL-CMD READS ==='
firewall_reads_ok=1
default_zone=''
active_zones=''
for query in '--state' '--get-default-zone' '--get-active-zones'; do
    set +e
    output=$(timeout 8 firewall-cmd $query 2>&1)
    rc=$?
    set -e
    printf 'FIREWALL_CMD|query=%s|rc=%s\n%s\n' "$query" "$rc" "$output"
    [[ "$rc" -eq 0 ]] || firewall_reads_ok=0
    [[ "$query" == --get-default-zone && "$rc" -eq 0 ]] && default_zone=$output
    [[ "$query" == --get-active-zones && "$rc" -eq 0 ]] && active_zones=$output
done

printf '%s\n' '=== ZONE / REDIS PORT POLICY ==='
iface=$(ip -o -4 addr show scope global | awk -v ip="$EXPECTED_IP" '{split($4,a,"/"); if(a[1]==ip){print $2; exit}}')
zone=''
if [[ "$firewall_reads_ok" -eq 1 ]]; then
    set +e
    zone=$(timeout 8 firewall-cmd --get-zone-of-interface="$iface" 2>/dev/null)
    zone_rc=$?
    set -e
    if [[ "$zone_rc" -ne 0 || -z "$zone" || "$zone" == no\ zone ]]; then zone=$default_zone; fi
fi
printf 'ZONE|interface=%s|zone=%s|reads_ok=%s\n' "$iface" "${zone:-UNRESOLVED}" "$firewall_reads_ok"
local_endpoint_ok=1
for port in 6379 6387; do
    if ss -lntH "sport = :${port}" | grep -q .; then
        printf 'LOCAL_ENDPOINT|port=%s|PASS_LISTENING\n' "$port"
    else
        printf 'LOCAL_ENDPOINT|port=%s|FAIL_NOT_LISTENING\n' "$port"
        local_endpoint_ok=0
    fi
done
matching_rule_count=0
if [[ "$firewall_reads_ok" -eq 1 && -n "$zone" ]]; then
    set +e
    ports_output=$(timeout 8 firewall-cmd --zone="$zone" --list-ports 2>&1); ports_rc=$?
    rules_output=$(timeout 8 firewall-cmd --zone="$zone" --list-rich-rules 2>&1); rules_rc=$?
    set -e
    printf 'ZONE_PORTS|rc=%s|%s\n' "$ports_rc" "$ports_output"
    printf 'ZONE_RICH_RULES|rc=%s\n%s\n' "$rules_rc" "$rules_output"
    [[ "$ports_rc" -eq 0 && "$rules_rc" -eq 0 ]] || firewall_reads_ok=0
    for port in 6379 6387; do
        if grep -F "$SOURCE_IP" <<<"$rules_output" | grep -Eq "port port=\"?${port}\"?|port=\"?${port}\"?"; then
            printf 'SOURCE_RULE|source=%s|port=%s|PRESENT\n' "$SOURCE_IP" "$port"
            matching_rule_count=$((matching_rule_count + 1))
        else
            printf 'SOURCE_RULE|source=%s|port=%s|ABSENT\n' "$SOURCE_IP" "$port"
        fi
    done
fi

printf '%s\n' '=== RECENT DBUS / FIREWALLD JOURNAL ==='
journalctl -u dbus.service -u firewalld.service --since '2026-08-06 10:30:00' --no-pager -n 160 2>&1 || true

printf '%s\n' '=== REDIS ROLE STATE ==='
for unit in redis5.service redis7.service sentinel5.service sentinel7.service orchestrator.service; do
    printf 'UNIT|%s|enabled=%s|active=%s\n' "$unit" \
        "$(systemctl is-enabled "$unit" 2>/dev/null || true)" \
        "$(systemctl is-active "$unit" 2>/dev/null || true)"
done
if [[ "$local_endpoint_ok" -ne 1 ]]; then
    printf 'ROOT_CAUSE=REDIS01_LOCAL_ENDPOINT_NOT_LISTENING\n'
    printf 'REMEDIATION_DECISION=AUTOMATIC_MINIMAL_REPAIR_ELIGIBLE|scope=REDIS01_LOCAL_ENDPOINT\n'
elif [[ "$firewall_reads_ok" -ne 1 ]]; then
    printf 'ROOT_CAUSE=REDIS01_LOCAL_FIREWALLD_DBUS_CONTROL_PLANE_UNHEALTHY\n'
    printf 'REMEDIATION_DECISION=AUTOMATIC_MINIMAL_REPAIR_ELIGIBLE|scope=FIREWALLD_CONTROL_PLANE_THEN_SOURCE_RULE\n'
elif [[ "$matching_rule_count" -lt 2 ]]; then
    printf 'ROOT_CAUSE=REDIS01_LOCAL_FIREWALL_MISSING_REDIS02_SOURCE_RULES\n'
    printf 'REMEDIATION_DECISION=AUTOMATIC_MINIMAL_REPAIR_ELIGIBLE|scope=SOURCE_10.2.203.113_TCP_6379_6387\n'
else
    printf 'ROOT_CAUSE=OUTSIDE_REDIS01_LOCAL_ENDPOINT_AND_DECLARED_FIREWALL_RULES\n'
    printf 'REMEDIATION_DECISION=EXTERNAL_NETWORK_ADMIN_REQUIRED|matrix=10.2.203.113_to_10.2.203.112_tcp_6379_6387\n'
fi
