// SPDX-License-Identifier: GPL-3.0-or-later package agent import ( "context" "testing" "time" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/config" "codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model" ) func TestRunOnceEmitsAlertAndStatusEnvelopes(t *testing.T) { agent := New(config.Default(), func() (model.State, error) { return model.State{Processes: []model.Process{ {PID: 42, Comm: "dropper", Exe: "/tmp/dropper (deleted)"}, }}, nil }) agent.Host = func() (string, error) { return "host-a", nil } agent.Now = func() time.Time { return time.Date(2026, 7, 10, 0, 0, 0, 0, time.FixedZone("PDT", -7*3600)) } var events []map[string]any err := agent.Run(context.Background(), true, func(event map[string]any) error { events = append(events, event) return nil }) if err != nil { t.Fatal(err) } if len(events) != 2 || events[0]["event_type"] != "alert" || events[1]["event_type"] != "status" { t.Fatalf("unexpected events: %#v", events) } alert := events[0]["alert"].(model.Alert) if alert.SID != 100012 || alert.Detail != "pid=42 comm=dropper exe=[/tmp/dropper (deleted)]" { t.Fatalf("unexpected alert payload: %#v", alert) } } func TestDisabledDetectorEmitsStatusOnly(t *testing.T) { cfg := config.Default() cfg.Detectors = map[string]bool{} agent := New(cfg, func() (model.State, error) { return model.State{Processes: []model.Process{{PID: 42, Exe: "/tmp/x (deleted)"}}}, nil }) events, err := agent.Sweep() if err != nil { t.Fatal(err) } if len(events) != 1 || events[0]["event_type"] != "status" { t.Fatalf("unexpected events: %#v", events) } } func TestSweepPreservesPythonDetectorOrder(t *testing.T) { agent := New(config.Default(), func() (model.State, error) { return model.State{ LDPreload: "/tmp/global.so", Processes: []model.Process{{ PID: 42, Comm: "dropper", Exe: "/tmp/dropper (deleted)", FDTargets: map[string]string{"4": "/etc/shadow", "7": "/dev/input/event3"}, }}, }, nil }) events, err := agent.Sweep() if err != nil { t.Fatal(err) } want := []string{"ld_preload", "deleted_exe", "input_snooper", "credential_access"} if len(events) != len(want)+1 { t.Fatalf("unexpected events: %#v", events) } for index, signature := range want { alert := events[index]["alert"].(model.Alert) if alert.Signature != signature { t.Fatalf("event %d: got %s, want %s", index, alert.Signature, signature) } } }