#!/usr/bin/env bash
# audit_security.sh — Security posture assessment for macOS (read-only)
# Output: JSON lines to stdout, one per finding
set -euo pipefail

json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | tr '\n' ' '; }

json_finding() {
  local severity="$1" finding action details
  finding=$(json_escape "$2")
  action=$(json_escape "$3")
  details=$(json_escape "$4")
  printf '{"module":"security","severity":"%s","finding":"%s","action":"%s","details":"%s"}\n' \
    "$severity" "$finding" "$action" "$details"
}

# --- SIP (System Integrity Protection) ---
sip_status=$(csrutil status 2>/dev/null || echo "unknown")
if echo "$sip_status" | grep -q "enabled"; then
  json_finding "info" "SIP enabled" "none" ""
elif echo "$sip_status" | grep -q "disabled"; then
  json_finding "critical" "SIP is disabled" "report" "System Integrity Protection should be enabled"
else
  json_finding "warning" "SIP status unknown" "report" "$sip_status"
fi

# --- Gatekeeper ---
gatekeeper_status=$(spctl --status 2>/dev/null || echo "unknown")
if echo "$gatekeeper_status" | grep -q "assessments enabled"; then
  json_finding "info" "Gatekeeper enabled" "none" ""
elif echo "$gatekeeper_status" | grep -q "assessments disabled"; then
  json_finding "critical" "Gatekeeper is disabled" "report" "Enable via: sudo spctl --master-enable"
else
  json_finding "warning" "Gatekeeper status unknown" "report" "$gatekeeper_status"
fi

# --- Firewall ---
fw_tool="/usr/libexec/ApplicationFirewall/socketfilterfw"
if [ -x "$fw_tool" ]; then
  fw_status=$("$fw_tool" --getglobalstate 2>/dev/null || echo "unknown")
  if echo "$fw_status" | grep -qi "enabled"; then
    json_finding "info" "Firewall enabled" "none" ""
  else
    json_finding "critical" "Firewall is disabled" "report" "Enable in System Settings > Network > Firewall"
  fi
else
  # Fallback to defaults
  fw_default=$(defaults read /Library/Preferences/com.apple.alf globalstate 2>/dev/null || echo "unknown")
  case "$fw_default" in
    0) json_finding "critical" "Firewall is disabled" "report" "Enable in System Settings > Network > Firewall" ;;
    1|2) json_finding "info" "Firewall enabled" "none" "" ;;
    *) json_finding "warning" "Firewall status unknown" "report" "" ;;
  esac
fi

# --- FileVault ---
fv_status=$(fdesetup status 2>/dev/null || echo "unknown")
if echo "$fv_status" | grep -q "FileVault is On"; then
  json_finding "info" "FileVault enabled (disk encryption)" "none" ""
elif echo "$fv_status" | grep -q "FileVault is Off"; then
  json_finding "critical" "FileVault is off (disk not encrypted)" "report" "Enable in System Settings > Privacy and Security > FileVault"
else
  json_finding "warning" "FileVault status unknown" "report" "$fv_status"
fi

# --- Open listening ports ---
listening_ports=$(lsof -iTCP -sTCP:LISTEN -nP 2>/dev/null | tail -n +2 || echo "")
port_count=$(echo "$listening_ports" | grep -c . 2>/dev/null || echo 0)

if [ "$port_count" -gt 0 ]; then
  # Extract unique port/process combos
  port_summary=$(echo "$listening_ports" | awk '{print $1":"$9}' | sort -u | head -10 | tr '\n' ', ' | sed 's/,$//')
  json_finding "info" "${port_count} listening TCP connections" "review" "$port_summary"
fi

# --- SSH config ---
ssh_config="/etc/ssh/sshd_config"
if [ -f "$ssh_config" ]; then
  # Check password auth
  if grep -qi "^PasswordAuthentication yes" "$ssh_config" 2>/dev/null; then
    json_finding "warning" "SSH password authentication enabled" "report" "Consider key-based auth only"
  fi
  # Check root login
  if grep -qi "^PermitRootLogin yes" "$ssh_config" 2>/dev/null; then
    json_finding "warning" "SSH root login permitted" "report" "Consider disabling root SSH login"
  fi
fi

# --- Remote login ---
remote_login=$(systemsetup -getremotelogin 2>/dev/null || echo "unknown")
if echo "$remote_login" | grep -qi "on"; then
  json_finding "info" "Remote Login (SSH) is enabled" "review" "Disable if not needed: System Settings > General > Sharing"
fi

# --- Remote management ---
remote_mgmt=$(defaults read /Library/Preferences/com.apple.RemoteManagement ARD_AllLocalUsers 2>/dev/null || echo "not configured")
if [ "$remote_mgmt" = "1" ]; then
  json_finding "warning" "Remote Management enabled for all users" "review" "Check System Settings > General > Sharing"
fi

# --- Software updates ---
# Just check if updates are available (this can be slow, so we time-limit it)
# macOS lacks GNU timeout — use perl alarm as a portable alternative
update_check=$(perl -e 'alarm 30; exec @ARGV' -- softwareupdate -l 2>&1 || echo "timeout or error")
if echo "$update_check" | grep -q "No new software available"; then
  json_finding "info" "macOS software is up to date" "none" ""
elif echo "$update_check" | grep -q "timeout or error"; then
  json_finding "info" "Software update check timed out" "none" "Run softwareupdate -l manually"
else
  update_count=$(echo "$update_check" | grep -c "^\*" 2>/dev/null || echo 0)
  json_finding "warning" "${update_count} software update(s) available" "softwareupdate" "Run: softwareupdate -l for details"
fi

# --- Screen lock ---
screen_lock_delay=$(defaults -currentHost read com.apple.screensaver idleTime 2>/dev/null || echo "not set")
ask_password=$(defaults read com.apple.screensaver askForPassword 2>/dev/null || echo "unknown")

if [ "$ask_password" = "0" ]; then
  json_finding "warning" "Screen lock password not required" "report" "Enable in System Settings > Lock Screen"
elif [ "$screen_lock_delay" != "not set" ] && [ "$screen_lock_delay" -gt 300 ] 2>/dev/null; then
  json_finding "info" "Screen lock delay: ${screen_lock_delay}s (consider reducing)" "report" ""
fi
