#!/usr/bin/env bash
set -Eeuo pipefail

TASK="REDIS01_Q131_PARENT_TRAVERSE_ACL_REPAIR_AND_RESUME"
EXPECTED_HOST="sqjcredis01"
EXPECTED_IP="10.2.203.112"
V3_SCRIPT="/root/redis01-q131-selinux-label-repair-and-verify-v3.sh"
V3_SCRIPT_SHA256="214b361c44609d8de19b191c156d72486fdeede30cbe59691cf4e682f407f990"
DIAG_AUDIT="/var/backups/zhct-q131-runtime-diagnosis/q131-runtime-diagnosis-20260805T054659Z/operator.log"
DIAG_AUDIT_SHA256="81a8c9a971cc9b5c7ede0e1ceb010dddeca9ceefb6784ef42e822517dd5b7156"
RUN_ID="q131-parent-acl-repair-$(date -u +%Y%m%dT%H%M%SZ)"
EVIDENCE_DIR="/var/backups/zhct-q131-parent-acl-repair/${RUN_ID}"
AUDIT_LOG="${EVIDENCE_DIR}/operator.log"

timestamp() { date '+%Y-%m-%dT%H:%M:%S%z'; }

if test "${1:-}" = "--static-validate"; then
  echo "Q131_PARENT_TRAVERSE_ACL_REPAIR_STATIC_VALIDATE=PASS"
  echo "TARGET_HOST=${EXPECTED_HOST}"
  echo "TARGET_IP=${EXPECTED_IP}"
  echo "REPAIR=/etc named ACL user:redis:--x plus /etc/redis root:redis:750"
  echo "RUNTIME_VALIDATION=V3_REAL_SERVICE_START_AND_Q131_VERIFY"
  echo "AUXILIARY_UNITS=DISABLED_INACTIVE"
  echo "Q132=LOCKED_NOT_EXECUTED"
  exit 0
fi

printf 'BEGIN|%s|%s\n' "$TASK" "$(timestamp)"

fail_before_write() {
  echo "ERROR: $*"
  printf 'END|%s|RC=1|PERSISTENT_WRITE=ZERO\n' "$TASK"
  exit 1
}

test "$(id -u)" -eq 0 || fail_before_write "root is required"
actual_host="$(hostname -s)"
test "$actual_host" = "$EXPECTED_HOST" ||
  fail_before_write "hostname mismatch: actual=${actual_host} expected=${EXPECTED_HOST}"
ip -4 -o addr show scope global | awk '{print $4}' | cut -d/ -f1 |
  grep -Fxq "$EXPECTED_IP" || fail_before_write "expected IPv4 is absent: ${EXPECTED_IP}"
echo "Q131_PARENT_ACL_REPAIR_TARGET_IDENTITY=PASS|host=${actual_host}|ip=${EXPECTED_IP}"

for command_name in sha256sum systemctl ss stat setfacl getfacl chgrp chmod; do
  command -v "$command_name" >/dev/null 2>&1 || fail_before_write "missing command: ${command_name}"
done
test -f "$V3_SCRIPT" && test ! -L "$V3_SCRIPT" || fail_before_write "v3 engine is absent or unsafe"
printf '%s  %s\n' "$V3_SCRIPT_SHA256" "$V3_SCRIPT" | sha256sum -c - ||
  fail_before_write "v3 engine checksum mismatch"
test -f "$DIAG_AUDIT" && test ! -L "$DIAG_AUDIT" || fail_before_write "runtime audit absent or unsafe"
printf '%s  %s\n' "$DIAG_AUDIT_SHA256" "$DIAG_AUDIT" | sha256sum -c - ||
  fail_before_write "runtime audit checksum mismatch"
grep -Fq 'META|目录|drwxr-x---|750|root:root|12288|/etc' "$DIAG_AUDIT" ||
  fail_before_write "locked /etc metadata evidence is absent"
grep -Fq "Fatal error, can't open config file '/etc/redis/redis7.conf': Permission denied" "$DIAG_AUDIT" ||
  fail_before_write "permission-denied runtime evidence is absent"
grep -Fxq '<no matches>' "$DIAG_AUDIT" || fail_before_write "expected no-AVC evidence is absent"

test "$(stat -c '%U:%G:%a' /etc)" = "root:root:750" || fail_before_write "unexpected /etc metadata"
test -d /etc/redis && test ! -L /etc/redis || fail_before_write "/etc/redis absent or unsafe"
test "$(stat -c '%U:%G:%a' /etc/redis)" = "root:root:750" || fail_before_write "unexpected /etc/redis metadata"
if getfacl -cp /etc | grep -q '^user:redis:'; then
  fail_before_write "pre-existing redis ACL on /etc requires separate review"
fi
for config in /etc/redis/redis5.conf /etc/redis/redis7.conf; do
  test -f "$config" && test ! -L "$config" || fail_before_write "config absent or unsafe: ${config}"
  test "$(stat -c '%U:%G:%a' "$config")" = "root:redis:640" || fail_before_write "config metadata mismatch: ${config}"
done
for unit in redis5.service redis7.service sentinel5.service sentinel7.service orchestrator.service; do
  test "$(systemctl is-enabled "$unit" 2>/dev/null || true)" = "disabled" ||
    fail_before_write "safe quiet state requires disabled unit: ${unit}"
  test "$(systemctl is-active "$unit" 2>/dev/null || true)" = "inactive" ||
    fail_before_write "safe quiet state requires inactive unit: ${unit}"
done
if ss -lntupH | grep -E ':(6379|6387|26379|26387|3000|10008)([[:space:]]|$)' >/dev/null; then
  fail_before_write "target listener exists before repair"
fi
echo "Q131_PARENT_ACL_REPAIR_PREWRITE_GATE=PASS"

install -d -o root -g root -m 0700 "$EVIDENCE_DIR"
exec 3>&1 4>&2
exec >"$AUDIT_LOG" 2>&1

mutation_started=0
success=0
acl_added=0

rollback_dac() {
  set +e
  systemctl disable --now redis5.service redis7.service sentinel5.service sentinel7.service orchestrator.service
  systemctl reset-failed redis5.service redis7.service
  chgrp root /etc/redis
  chmod 0750 /etc/redis
  if test "$acl_added" -eq 1; then setfacl -x u:redis /etc; fi
  echo "Q131_PARENT_ACL_REPAIR_ROLLBACK=ACL_REMOVED_ROOT_ROOT_0750_SAFE_QUIET"
  set -e
}

finalize() {
  local rc=$?
  trap - EXIT
  if test "$rc" -ne 0 && test "$mutation_started" -eq 1 && test "$success" -eq 0; then rollback_dac; fi
  marker="$(test "$rc" -eq 0 && printf PASS_ROLE_ACTIVATED_LOCAL_ONLY || printf FAIL_ROLLED_BACK_SAFE_QUIET)"
  printf 'Q131_PARENT_TRAVERSE_ACL_REPAIR_AND_RESUME=%s\n' "$marker"
  printf 'END|%s|RC=%s|AUDIT_LOG=%s\n' "$TASK" "$rc" "$AUDIT_LOG"
  printf 'Q131_PARENT_TRAVERSE_ACL_REPAIR_AND_RESUME=%s\n' "$marker" >&3
  printf 'END|%s|RC=%s|AUDIT_LOG=%s\n' "$TASK" "$rc" "$AUDIT_LOG" >&3
}
trap finalize EXIT

echo "AUDIT_BEGIN|${TASK}|$(timestamp)"
echo "RUN_ID=${RUN_ID}"
echo "PRE_ETC_METADATA=$(stat -c '%U:%G:%a' /etc)"
echo "PRE_REDIS_DIR_METADATA=$(stat -c '%U:%G:%a' /etc/redis)"
mutation_started=1
setfacl -m u:redis:--x /etc
acl_added=1
getfacl -cp /etc | grep -Fxq 'user:redis:--x'
echo "Q131_ETC_REDIS_TRAVERSE_ACL=PASS|permission=--x|content=NOT_LISTED"
chgrp redis /etc/redis
chmod 0750 /etc/redis
test "$(stat -c '%U:%G:%a' /etc/redis)" = "root:redis:750"
echo "Q131_REDIS_CONFIG_DIR_METADATA=PASS|metadata=root:redis:750"

set +e
"$V3_SCRIPT"
v3_rc=$?
set -e
echo "Q131_V3_ENGINE_RC=${v3_rc}"
test "$v3_rc" -eq 0

success=1
echo "Q131_PARENT_TRAVERSE_ACL_REPAIR_AND_RESUME=PASS_ROLE_ACTIVATED_LOCAL_ONLY"
echo "Q132=LOCKED_NOT_EXECUTED"
echo "SENTINEL_HA=NOT_CONFIGURED"
echo "VIP=DISABLED"
echo "SECRET_VALUES=NOT_OUTPUT_NOT_HASHED"
