feat(go): advance validation sidecar toward production

This commit is contained in:
Luna 2026-07-22 01:52:19 -07:00
parent 6a06eba255
commit f85c2e831a
No known key found for this signature in database
92 changed files with 8881 additions and 91 deletions

View file

@ -7,8 +7,10 @@ import (
"testing"
"time"
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/baseline"
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/config"
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model"
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/schema"
)
func intPointer(value int) *int { return &value }
@ -40,6 +42,66 @@ func TestRunOnceEmitsAlertAndStatusEnvelopes(t *testing.T) {
}
}
func TestRunAttachesLiveBaselineLifecycle(t *testing.T) {
cfg := config.Default()
cfg.LogDir = t.TempDir()
cfg.BaselineGrace = 0
calls := 0
capture := func() (model.State, error) {
calls++
port := "0.0.0.0:22"
comm := "sshd"
if calls > 1 {
port = "0.0.0.0:31337"
comm = "nc"
}
pid := 42
return model.State{Sockets: []model.Socket{{
State: "LISTEN", Local: port, Comm: comm, PID: &pid, Kind: "tcp",
}}}, nil
}
runner := New(cfg, capture)
runner.Lifecycle = baseline.New(cfg, func() []string { return []string{} })
runner.Host = func() (string, error) { return "host-a", nil }
runner.Now = func() time.Time {
return time.Date(2026, 7, 20, 12, 0, 0, 0, time.UTC)
}
var events []map[string]any
if err := runner.Run(context.Background(), true, func(event map[string]any) error {
events = append(events, event)
return nil
}); err != nil {
t.Fatal(err)
}
if calls != 2 || len(events) != 2 {
t.Fatalf("unexpected lifecycle result: calls=%d events=%#v", calls, events)
}
alert := events[0]["alert"].(model.Alert)
if alert.Signature != "new_listener" || alert.Key != "lis:31337/nc" {
t.Fatalf("unexpected alert: %#v", alert)
}
}
func TestInitializeIsIdempotent(t *testing.T) {
cfg := config.Default()
cfg.LogDir = t.TempDir()
calls := 0
runner := New(cfg, func() (model.State, error) {
calls++
return model.State{}, nil
})
runner.Lifecycle = baseline.New(cfg, func() []string { return nil })
if err := runner.Initialize(); err != nil {
t.Fatal(err)
}
if err := runner.Initialize(); err != nil {
t.Fatal(err)
}
if calls != 1 {
t.Fatalf("initial capture count=%d, want 1", calls)
}
}
func TestDisabledDetectorEmitsStatusOnly(t *testing.T) {
cfg := config.Default()
cfg.Detectors = map[string]bool{}
@ -55,6 +117,68 @@ func TestDisabledDetectorEmitsStatusOnly(t *testing.T) {
}
}
func TestSweepAppliesPerKeyCooldown(t *testing.T) {
cfg := config.Default()
cfg.Cooldown = 60 * time.Second
runner := New(cfg, func() (model.State, error) {
return model.State{Processes: []model.Process{{
PID: 42, Comm: "dropper", Exe: "/tmp/dropper (deleted)",
}}}, nil
})
now := time.Date(2026, 7, 20, 12, 0, 0, 0, time.UTC)
runner.Now = func() time.Time { return now }
first, err := runner.Sweep()
if err != nil {
t.Fatal(err)
}
now = now.Add(30 * time.Second)
second, err := runner.Sweep()
if err != nil {
t.Fatal(err)
}
now = now.Add(31 * time.Second)
third, err := runner.Sweep()
if err != nil {
t.Fatal(err)
}
if len(first) != 2 || len(second) != 1 || len(third) != 2 {
t.Fatalf("cooldown output mismatch: %d %d %d", len(first), len(second), len(third))
}
}
func TestAsyncAlertsShareCooldownAndStatusReportsProbeState(t *testing.T) {
cfg := config.Default()
cfg.Cooldown = time.Minute
runner := New(cfg, func() (model.State, error) { return model.State{}, nil })
runner.Host = func() (string, error) { return "host-a", nil }
now := time.Date(2026, 7, 20, 12, 0, 0, 0, time.UTC)
runner.Now = func() time.Time { return now }
runner.SetExecProbeStatus("enabled")
runner.SetSyscallProbeStatus("disabled (test)")
alert := model.Alert{SID: 100001, Key: "exec:100001:42"}
first, err := runner.AlertEvents([]model.Alert{alert})
if err != nil {
t.Fatal(err)
}
now = now.Add(30 * time.Second)
second, err := runner.AlertEvents([]model.Alert{alert})
if err != nil {
t.Fatal(err)
}
sweep, err := runner.Sweep()
if err != nil {
t.Fatal(err)
}
status := sweep[0]["status"].(schema.Status)
if len(first) != 1 || len(second) != 0 {
t.Fatalf("async cooldown mismatch: first=%d second=%d", len(first), len(second))
}
if status.EBPF != "enabled" || status.EBPFExec != "enabled" || status.EBPFSyscall != "disabled (test)" {
t.Fatalf("unexpected probe status: %#v", status)
}
}
func TestSweepPreservesPythonDetectorOrder(t *testing.T) {
agent := New(config.Default(), func() (model.State, error) {
return model.State{