feat(go): persist Python-compatible incidents
This commit is contained in:
parent
f85c2e831a
commit
538d1d954a
13 changed files with 555 additions and 46 deletions
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -69,6 +70,60 @@ func TestCaptureEventWritesCompatiblePairAndMergesSameSecond(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCaptureEventLinksMergedSnapshotToOneIncident(t *testing.T) {
|
||||
store, err := New(t.TempDir(), "/unused", 10, 30)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := store.ConfigureIncidents(true, 1800, 8); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parents := map[int]int{42: 7, 7: 1, 99: 1}
|
||||
store.ParentOf = func(pid int) int { return parents[pid] }
|
||||
store.Collect = func(pid int) ProcessDetail {
|
||||
return ProcessDetail{PID: pid, PPID: parents[pid], FDs: map[string]string{}}
|
||||
}
|
||||
first := alertEvent("2026-07-22T10:11:12.100-07:00", model.Alert{
|
||||
SID: 100003, Severity: "HIGH", Signature: "exec_rule.web-rce", Classtype: "execution", Key: "one", Detail: "first", PIDs: []int{42},
|
||||
})
|
||||
second := alertEvent("2026-07-22T10:11:12.900-07:00", model.Alert{
|
||||
SID: 100067, Severity: "HIGH", Signature: "host_rule.suspicious-egress", Classtype: "c2", Key: "two", Detail: "second", PIDs: []int{99},
|
||||
})
|
||||
if _, err := store.CaptureEvent(first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := store.CaptureEvent(second); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(store.Dir, "alert-20260722-101112.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var report Report
|
||||
if err := json.Unmarshal(raw, &report); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if report.IncidentID == nil || *report.IncidentID == "" {
|
||||
t.Fatalf("missing incident id: %#v", report)
|
||||
}
|
||||
indexRaw, err := os.ReadFile(filepath.Join(store.Dir, "incidents.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var index map[string]map[string]any
|
||||
if err := json.Unmarshal(indexRaw, &index); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
item := index[*report.IncidentID]
|
||||
if item["schema"] != "enodia.incident.v1" || item["alert_count"] != float64(2) || len(item["snapshots"].([]any)) != 1 {
|
||||
t.Fatalf("incident=%#v", item)
|
||||
}
|
||||
textRaw, err := os.ReadFile(filepath.Join(store.Dir, "alert-20260722-101112.log"))
|
||||
if err != nil || !strings.Contains(string(textRaw), "Incident: "+*report.IncidentID) {
|
||||
t.Fatalf("text incident missing err=%v text=%q", err, textRaw)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetentionPrunesCountAndAgeAsPairs(t *testing.T) {
|
||||
store, err := New(t.TempDir(), "/unused", 2, 1)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue