Files
AetherForge/server/internal/alerts/kev_notify.go
AetherForge 5fc601b564 feat: fleet ops, KEV scan, tunnels, beacon fallback, persistence
Extend owned-fleet control with scheduled tasks, audit log, file browser,
HTTPS beacon when WS drops, protocol tunnels, registry/autostart forge
options, KEV exposure in full sys check with Telegram alerts, and UI/tests.
2026-06-04 09:34:33 -07:00

57 lines
1.5 KiB
Go

package alerts
import (
"encoding/json"
"strconv"
"strings"
)
// kevExposurePayload mirrors agent KEVScanReport JSON.
type kevExposurePayload struct {
ExposedCount int `json:"exposed_count"`
CriticalCount int `json:"critical_count"`
LikelyCount int `json:"likely_count"`
RiskScore int `json:"risk_score"`
Summary string `json:"summary"`
Findings []struct {
CVE string `json:"cve"`
Name string `json:"name"`
Status string `json:"status"`
Severity string `json:"severity"`
Detail string `json:"detail"`
} `json:"findings"`
}
const EventKEVExposure = "kev_exposure"
// NotifyKEVFromSysCheck parses a full_sys_check message and sends Telegram if enabled.
func NotifyKEVFromSysCheck(n *Notifier, agentName, message string) {
if n == nil || strings.TrimSpace(message) == "" {
return
}
var report struct {
KEV *kevExposurePayload `json:"kev_exposure"`
}
if err := json.Unmarshal([]byte(message), &report); err != nil || report.KEV == nil {
return
}
k := report.KEV
if k.ExposedCount == 0 && k.CriticalCount == 0 {
return
}
s := n.settings()
if !s.Events.KEVExposure {
return
}
body := agentName + ": " + k.Summary
if body == agentName+": " {
body = agentName + ": KEV exposure indicators — exposed=" + strconv.Itoa(k.ExposedCount) + " critical=" + strconv.Itoa(k.CriticalCount)
}
for _, f := range k.Findings {
if f.Status == "exposed" && f.Severity == "critical" {
body += "\n• " + f.CVE + " " + f.Name
}
}
n.Emit(EventKEVExposure, "AetherForge KEV alert", body)
}