// SPDX-License-Identifier: GPL-3.0-or-later package incident import ( "os" "path/filepath" "testing" "time" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/correlation" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model" ) func TestRecordAlertGroupsLineageAndPersistsCorrelation(t *testing.T) { directory := t.TempDir() store, err := New(directory, true, 1800, 8) if err != nil { t.Fatal(err) } firstTime := time.Unix(1000, 0).UTC() first, err := store.RecordAlert("alert-1.log", model.Alert{ SID: 100003, Severity: "HIGH", Signature: "exec_rule.web-rce", PIDs: []int{4242}, }, map[int]bool{4242: true, 999: true}, firstTime, "host-a", "") if err != nil { t.Fatal(err) } second, err := store.RecordAlert("alert-2.log", model.Alert{ SID: 100067, Severity: "HIGH", Signature: "host_rule.suspicious-egress", PIDs: []int{4243}, }, map[int]bool{4243: true, 999: true}, firstTime.Add(50*time.Second), "host-a", "") if err != nil { t.Fatal(err) } if first == "" || second != first { t.Fatalf("incident ids first=%q second=%q", first, second) } index, err := LoadIndex(directory) if err != nil { t.Fatal(err) } item := index[first] if len(index) != 1 || item == nil || item.Schema != Schema || item.AlertCount != 2 || item.Severity != "CRITICAL" || len(item.Snapshots) != 2 || len(item.Correlations) != 1 || item.Correlations[0].SID != correlation.SIDMultiStageIntrusion { t.Fatalf("index=%#v", index) } if info, err := os.Stat(filepath.Join(directory, IndexName)); err != nil || info.Mode().Perm() != 0o600 { t.Fatalf("incident index mode info=%v err=%v", info, err) } } func TestPreferredIncidentMakesSnapshotAppendIdempotent(t *testing.T) { store, err := New(t.TempDir(), true, 1800, 8) if err != nil { t.Fatal(err) } when := time.Unix(1000, 0).UTC() id, err := store.RecordAlert("alert-1.log", model.Alert{ SID: 1, Severity: "HIGH", Signature: "one", PIDs: []int{10}, }, map[int]bool{10: true}, when, "host-a", "") if err != nil { t.Fatal(err) } if _, err := store.RecordAlert("alert-1.log", model.Alert{ SID: 2, Severity: "CRITICAL", Signature: "two", PIDs: []int{20}, }, map[int]bool{20: true}, when.Add(500*time.Millisecond), "host-a", id); err != nil { t.Fatal(err) } index, _ := LoadIndex(store.Dir) item := index[id] if len(item.Snapshots) != 1 || item.AlertCount != 2 || len(item.PIDs) != 2 || item.Severity != "CRITICAL" { t.Fatalf("incident=%#v", item) } } func TestDisabledStoreDoesNotWriteIndex(t *testing.T) { directory := t.TempDir() store, err := New(directory, false, 1800, 8) if err != nil { t.Fatal(err) } id, err := store.RecordAlert("alert.log", model.Alert{SID: 1, Severity: "HIGH", Signature: "test"}, nil, time.Now(), "host-a", "") if err != nil || id != "" { t.Fatalf("id=%q err=%v", id, err) } if _, err := os.Stat(filepath.Join(directory, IndexName)); !os.IsNotExist(err) { t.Fatalf("disabled index exists: %v", err) } }