refactor: convert mac-optimizer from raw skill to proper plugin
Restructured 92-mac-optimizer from a CLAUDE.md-based skill into a full Claude Code plugin with .claude-plugin/plugin.json, 6 slash commands (/mac-doctor, /mac-packages, /mac-environment, /mac-security, /mac-cleanup, /mac-resources), and auto-trigger SKILL.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
122
custom-skills/92-mac-optimizer/skills/mac-optimizer/scripts/audit_security.sh
Executable file
122
custom-skills/92-mac-optimizer/skills/mac-optimizer/scripts/audit_security.sh
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user