92 lines
3.3 KiB
Go
92 lines
3.3 KiB
Go
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package enrich
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model"
|
|
)
|
|
|
|
func TestBuildAddsBoundedProcessRemotePathAndLineageContext(t *testing.T) {
|
|
result := Build([]model.Alert{{
|
|
SID: 100010, Signature: "reverse_shell", Key: "persist:/etc/cron.d/dropper",
|
|
Detail: "pid=42 peer=[8.8.8.8:4444] wrote /tmp/dropper (deleted)",
|
|
}}, []Process{{PID: 42, Comm: "bash", Exe: "/tmp/dropper (deleted)", PPID: 10, PPIDComm: "nginx"}}, []int{42, 10})
|
|
processes := result["processes"].([]map[string]any)
|
|
if len(processes) != 1 || processes[0]["exe"] != "/tmp/dropper" ||
|
|
processes[0]["package_owner"] != nil || processes[0]["exe_sha256"] != nil {
|
|
t.Fatalf("processes=%#v", processes)
|
|
}
|
|
chain := processes[0]["parent_chain"].([]map[string]any)
|
|
if len(chain) != 1 || chain[0]["pid"] != 10 || chain[0]["comm"] != "nginx" {
|
|
t.Fatalf("chain=%#v", chain)
|
|
}
|
|
remotes := result["remotes"].([]map[string]any)
|
|
if len(remotes) != 1 || remotes[0]["ip"] != "8.8.8.8" || remotes[0]["classification"] != "public" {
|
|
t.Fatalf("remotes=%#v", remotes)
|
|
}
|
|
files := result["files"].([]map[string]any)
|
|
if len(files) != 2 || files[0]["path"] != "/etc/cron.d/dropper" || files[1]["path"] != "/tmp/dropper" {
|
|
t.Fatalf("files=%#v", files)
|
|
}
|
|
lineage := result["lineage"].([]map[string]any)
|
|
if len(lineage) != 2 || lineage[0]["pid"] != 10 || lineage[0]["comm"] != "nginx" {
|
|
t.Fatalf("lineage=%#v", lineage)
|
|
}
|
|
}
|
|
|
|
func TestBuildClassifiesPrivateAndInvalidAddresses(t *testing.T) {
|
|
result := Build([]model.Alert{{Detail: "peers 10.1.2.3 and 999.1.2.3"}}, nil, nil)
|
|
remotes := result["remotes"].([]map[string]any)
|
|
if len(remotes) != 2 || remotes[0]["classification"] != "private" || remotes[1]["classification"] != "invalid" {
|
|
t.Fatalf("remotes=%#v", remotes)
|
|
}
|
|
}
|
|
|
|
func TestBuildCapsAttackerControlledIndicators(t *testing.T) {
|
|
alerts := make([]model.Alert, 300)
|
|
for index := range alerts {
|
|
alerts[index].Detail = "/tmp/path " + "1.2.3.4"
|
|
}
|
|
result := Build(alerts, nil, nil)
|
|
if len(result["remotes"].([]map[string]any)) > maxIndicators || len(result["files"].([]map[string]any)) > maxIndicators {
|
|
t.Fatal("indicator caps were not applied")
|
|
}
|
|
}
|
|
|
|
func TestCollectSlowAddsInjectedPackageOwnership(t *testing.T) {
|
|
directory := t.TempDir()
|
|
exe := filepath.Join(directory, "payload")
|
|
if err := os.WriteFile(exe, []byte("payload"), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result := CollectSlow([]Process{{PID: 42, Exe: exe}}, []string{exe}, func(path string) string {
|
|
if path == exe {
|
|
return "example-package 1.0-1"
|
|
}
|
|
return ""
|
|
})
|
|
if result.Processes[42]["package_owner"] != "example-package 1.0-1" ||
|
|
result.Files[exe]["package_owner"] != "example-package 1.0-1" {
|
|
t.Fatalf("result=%#v", result)
|
|
}
|
|
}
|
|
|
|
func TestIntegrityAnchorsAreTruthfulAndReadOnly(t *testing.T) {
|
|
directory := t.TempDir()
|
|
anchors := IntegrityAnchors(directory)
|
|
if anchors["fim_baseline"].(map[string]any)["status"] != "missing" ||
|
|
anchors["rootcheck"].(map[string]any)["enabled"] != false {
|
|
t.Fatalf("anchors=%#v", anchors)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(directory, "hash-chain.jsonl"), []byte("{}\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
anchors = IntegrityAnchors(directory)
|
|
if anchors["go_assurance"].(map[string]any)["status"] != "present" {
|
|
t.Fatalf("anchors=%#v", anchors)
|
|
}
|
|
}
|