New Packages: - secubox-cve-triage: AI-powered CVE analysis and vulnerability management - NVD API integration for CVE data - CrowdSec CVE alert correlation - LocalAI-powered impact analysis - Approval workflow for patch recommendations - Multi-source monitoring (opkg, LXC, Docker) - luci-app-cve-triage: Dashboard with alerts, pending queue, risk score - secubox-vortex-dns: Meshed multi-dynamic subdomain delegation - Master/slave hierarchical DNS delegation - Wildcard domain management - First Peek auto-registration - Gossip-based exposure config sync - Submastering for nested hierarchies Fixes: - Webmail 401 login: config.docker.inc.php was overriding IMAP host to ssl://mail.secubox.in:993 which Docker couldn't reach - Fixed mailctl webmail configure to use socat proxy (172.17.0.1:10143) Documentation: - Added LXC cgroup:mixed fix to FAQ-TROUBLESHOOTING.md - Updated CLAUDE.md to include FAQ consultation at startup Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
209 lines
5.4 KiB
Bash
209 lines
5.4 KiB
Bash
#!/bin/sh
|
|
# RPCD handler for CVE Triage
|
|
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
CONFIG="cve-triage"
|
|
STATE_DIR="/var/lib/cve-triage"
|
|
|
|
uci_get() { uci -q get "${CONFIG}.$1"; }
|
|
|
|
# JSON output helpers
|
|
json_output() {
|
|
local tmpfile="/tmp/cve_triage_output_$$.json"
|
|
cat > "$tmpfile"
|
|
cat "$tmpfile"
|
|
rm -f "$tmpfile"
|
|
}
|
|
|
|
case "$1" in
|
|
list)
|
|
cat <<'EOF'
|
|
{
|
|
"status": {},
|
|
"get_pending": {},
|
|
"get_alerts": {},
|
|
"get_recommendations": { "limit": 50 },
|
|
"get_summary": {},
|
|
"scan": {},
|
|
"analyze": { "cve": "string" },
|
|
"run": {},
|
|
"approve": { "id": "string" },
|
|
"reject": { "id": "string", "reason": "string" },
|
|
"approve_all": {},
|
|
"clear_pending": {},
|
|
"ack_alert": { "id": "string" }
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
call)
|
|
case "$2" in
|
|
status)
|
|
local enabled=$(uci_get main.enabled)
|
|
local interval=$(uci_get main.interval)
|
|
local localai_url=$(uci_get main.localai_url)
|
|
local min_severity=$(uci_get main.min_severity)
|
|
|
|
# Check LocalAI
|
|
local localai_status="offline"
|
|
wget -q -O /dev/null --timeout=2 "${localai_url:-http://127.0.0.1:8081}/v1/models" 2>/dev/null && localai_status="online"
|
|
|
|
# Count pending
|
|
local pending_count=0
|
|
[ -f "$STATE_DIR/pending_actions.json" ] && \
|
|
pending_count=$(jsonfilter -i "$STATE_DIR/pending_actions.json" -e '@[*]' 2>/dev/null | wc -l)
|
|
|
|
# Count alerts
|
|
local alert_count=0
|
|
[ -f "$STATE_DIR/alerts.json" ] && \
|
|
alert_count=$(jsonfilter -i "$STATE_DIR/alerts.json" -e '@[*]' 2>/dev/null | grep -c '"acknowledged":false')
|
|
|
|
# Last run
|
|
local last_run=""
|
|
[ -f "$STATE_DIR/last_run" ] && last_run=$(cat "$STATE_DIR/last_run")
|
|
|
|
# Package counts
|
|
local opkg_count=$(opkg list-installed 2>/dev/null | wc -l)
|
|
local lxc_count=$(ls -d /srv/lxc/*/ 2>/dev/null | wc -l)
|
|
local docker_count=$(docker ps -q 2>/dev/null | wc -l || echo 0)
|
|
|
|
cat <<EOF
|
|
{
|
|
"enabled": $([ "$enabled" = "1" ] && echo "true" || echo "false"),
|
|
"interval": ${interval:-3600},
|
|
"min_severity": "${min_severity:-high}",
|
|
"localai_status": "$localai_status",
|
|
"localai_url": "${localai_url:-http://127.0.0.1:8081}",
|
|
"pending_count": $pending_count,
|
|
"alert_count": $alert_count,
|
|
"last_run": "$last_run",
|
|
"packages": {
|
|
"opkg": $opkg_count,
|
|
"lxc": $lxc_count,
|
|
"docker": $docker_count
|
|
}
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
get_pending)
|
|
if [ -f "$STATE_DIR/pending_actions.json" ]; then
|
|
printf '{"pending":'
|
|
cat "$STATE_DIR/pending_actions.json"
|
|
printf '}'
|
|
else
|
|
echo '{"pending":[]}'
|
|
fi
|
|
;;
|
|
|
|
get_alerts)
|
|
if [ -f "$STATE_DIR/alerts.json" ]; then
|
|
printf '{"alerts":'
|
|
cat "$STATE_DIR/alerts.json"
|
|
printf '}'
|
|
else
|
|
echo '{"alerts":[]}'
|
|
fi
|
|
;;
|
|
|
|
get_recommendations)
|
|
read -r input
|
|
local limit=$(echo "$input" | jsonfilter -e '@.limit' 2>/dev/null)
|
|
limit="${limit:-50}"
|
|
|
|
if [ -f "$STATE_DIR/recommendations.json" ]; then
|
|
printf '{"recommendations":'
|
|
cat "$STATE_DIR/recommendations.json"
|
|
printf '}'
|
|
else
|
|
echo '{"recommendations":[]}'
|
|
fi
|
|
;;
|
|
|
|
get_summary)
|
|
if [ -f "$STATE_DIR/last_summary.json" ]; then
|
|
printf '{"summary":'
|
|
cat "$STATE_DIR/last_summary.json"
|
|
printf '}'
|
|
else
|
|
echo '{"summary":{"risk_score":0,"summary":"No analysis available"}}'
|
|
fi
|
|
;;
|
|
|
|
scan)
|
|
local output=$(/usr/bin/cve-triage scan 2>&1)
|
|
local pkg_count=$(opkg list-installed 2>/dev/null | wc -l)
|
|
echo "{\"success\":true,\"packages\":$pkg_count,\"output\":\"$(echo "$output" | sed 's/"/\\"/g' | tr '\n' ' ')\"}"
|
|
;;
|
|
|
|
analyze)
|
|
read -r input
|
|
local cve=$(echo "$input" | jsonfilter -e '@.cve' 2>/dev/null)
|
|
if [ -z "$cve" ]; then
|
|
echo '{"error":"CVE ID required"}'
|
|
else
|
|
local output=$(/usr/bin/cve-triage analyze "$cve" 2>&1)
|
|
echo "{\"cve\":\"$cve\",\"analysis\":\"$(echo "$output" | sed 's/"/\\"/g' | tr '\n' ' ')\"}"
|
|
fi
|
|
;;
|
|
|
|
run)
|
|
/usr/bin/cve-triage run >/dev/null 2>&1 &
|
|
echo '{"success":true,"message":"Triage cycle started in background"}'
|
|
;;
|
|
|
|
approve)
|
|
read -r input
|
|
local rec_id=$(echo "$input" | jsonfilter -e '@.id' 2>/dev/null)
|
|
if [ -z "$rec_id" ]; then
|
|
echo '{"error":"Recommendation ID required"}'
|
|
else
|
|
local output=$(/usr/bin/cve-triage approve "$rec_id" 2>&1)
|
|
echo "{\"success\":true,\"id\":\"$rec_id\",\"output\":\"$(echo "$output" | sed 's/"/\\"/g' | tr '\n' ' ')\"}"
|
|
fi
|
|
;;
|
|
|
|
reject)
|
|
read -r input
|
|
local rec_id=$(echo "$input" | jsonfilter -e '@.id' 2>/dev/null)
|
|
local reason=$(echo "$input" | jsonfilter -e '@.reason' 2>/dev/null)
|
|
if [ -z "$rec_id" ]; then
|
|
echo '{"error":"Recommendation ID required"}'
|
|
else
|
|
local output=$(/usr/bin/cve-triage reject "$rec_id" "$reason" 2>&1)
|
|
echo "{\"success\":true,\"id\":\"$rec_id\"}"
|
|
fi
|
|
;;
|
|
|
|
approve_all)
|
|
/usr/bin/cve-triage approve-all >/dev/null 2>&1
|
|
echo '{"success":true}'
|
|
;;
|
|
|
|
clear_pending)
|
|
/usr/bin/cve-triage clear-pending >/dev/null 2>&1
|
|
echo '{"success":true}'
|
|
;;
|
|
|
|
ack_alert)
|
|
read -r input
|
|
local alert_id=$(echo "$input" | jsonfilter -e '@.id' 2>/dev/null)
|
|
if [ -z "$alert_id" ]; then
|
|
echo '{"error":"Alert ID required"}'
|
|
else
|
|
# Update alert as acknowledged
|
|
if [ -f "$STATE_DIR/alerts.json" ]; then
|
|
sed -i "s/\"id\":\"$alert_id\",\\(.*\\)\"acknowledged\":false/\"id\":\"$alert_id\",\\1\"acknowledged\":true/" "$STATE_DIR/alerts.json"
|
|
fi
|
|
echo "{\"success\":true,\"id\":\"$alert_id\"}"
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
echo '{"error":"Unknown method"}'
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|