mirror of
https://github.com/syntrex-lab/gomcp.git
synced 2026-04-26 04:46:22 +02:00
225 lines
5.4 KiB
Go
225 lines
5.4 KiB
Go
package guard
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func testPolicy() *Policy {
|
|
return &Policy{
|
|
Version: "1.0",
|
|
Mode: ModeAudit,
|
|
Processes: map[string]ProcessPolicy{
|
|
"soc-ingest": {
|
|
Description: "test ingest",
|
|
BlockedSyscalls: []string{"ptrace", "process_vm_readv"},
|
|
AllowedFiles: []string{"/var/lib/sentinel/data/*", "/tmp/*"},
|
|
BlockedFiles: []string{"/etc/shadow", "/root/*"},
|
|
AllowedNetwork: []string{"0.0.0.0:9750"},
|
|
MaxMemoryMB: 512,
|
|
},
|
|
"soc-correlate": {
|
|
Description: "test correlate — no network",
|
|
BlockedSyscalls: []string{"ptrace", "execve", "fork", "socket"},
|
|
AllowedFiles: []string{"/var/lib/sentinel/data/*"},
|
|
BlockedFiles: []string{"/etc/*", "/root/*"},
|
|
AllowedNetwork: []string{}, // NONE
|
|
MaxMemoryMB: 1024,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestCheckSyscall_Blocked(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckSyscall("soc-ingest", 1234, "ptrace")
|
|
if v == nil {
|
|
t.Fatal("expected violation for ptrace")
|
|
}
|
|
if v.Severity != "CRITICAL" {
|
|
t.Errorf("severity = %s, want CRITICAL", v.Severity)
|
|
}
|
|
if v.Action != "logged" {
|
|
t.Errorf("action = %s, want logged (audit mode)", v.Action)
|
|
}
|
|
}
|
|
|
|
func TestCheckSyscall_Allowed(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckSyscall("soc-ingest", 1234, "read")
|
|
if v != nil {
|
|
t.Errorf("unexpected violation for read: %+v", v)
|
|
}
|
|
}
|
|
|
|
func TestCheckSyscall_EnforceMode(t *testing.T) {
|
|
p := testPolicy()
|
|
p.Mode = ModeEnforce
|
|
g := New(p)
|
|
|
|
v := g.CheckSyscall("soc-correlate", 5678, "execve")
|
|
if v == nil {
|
|
t.Fatal("expected violation for execve")
|
|
}
|
|
if v.Action != "blocked" {
|
|
t.Errorf("action = %s, want blocked (enforce mode)", v.Action)
|
|
}
|
|
}
|
|
|
|
func TestCheckSyscall_UnknownProcess(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckSyscall("unknown-proc", 9999, "ptrace")
|
|
if v != nil {
|
|
t.Errorf("expected nil for unknown process, got %+v", v)
|
|
}
|
|
}
|
|
|
|
func TestCheckFileAccess_Blocked(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckFileAccess("soc-ingest", 1234, "/etc/shadow")
|
|
if v == nil {
|
|
t.Fatal("expected violation for /etc/shadow")
|
|
}
|
|
if v.Severity != "HIGH" {
|
|
t.Errorf("severity = %s, want HIGH", v.Severity)
|
|
}
|
|
}
|
|
|
|
func TestCheckFileAccess_Allowed(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckFileAccess("soc-ingest", 1234, "/var/lib/sentinel/data/soc.db")
|
|
if v != nil {
|
|
t.Errorf("unexpected violation for allowed path: %+v", v)
|
|
}
|
|
}
|
|
|
|
func TestCheckFileAccess_Unauthorized(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckFileAccess("soc-ingest", 1234, "/opt/something/secret")
|
|
if v == nil {
|
|
t.Fatal("expected violation for unauthorized path")
|
|
}
|
|
if v.Severity != "MEDIUM" {
|
|
t.Errorf("severity = %s, want MEDIUM", v.Severity)
|
|
}
|
|
}
|
|
|
|
func TestCheckNetwork_NoNetworkAllowed(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
// soc-correlate has AllowedNetwork: [] — no network at all.
|
|
v := g.CheckNetwork("soc-correlate", 5678, "8.8.8.8:443")
|
|
if v == nil {
|
|
t.Fatal("expected violation for network on correlate")
|
|
}
|
|
if v.Severity != "CRITICAL" {
|
|
t.Errorf("severity = %s, want CRITICAL", v.Severity)
|
|
}
|
|
}
|
|
|
|
func TestCheckMemory_Exceeded(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckMemory("soc-ingest", 1234, 600) // 600MB > 512MB limit
|
|
if v == nil {
|
|
t.Fatal("expected violation for memory exceeded")
|
|
}
|
|
if v.Severity != "HIGH" {
|
|
t.Errorf("severity = %s, want HIGH", v.Severity)
|
|
}
|
|
}
|
|
|
|
func TestCheckMemory_Within(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
v := g.CheckMemory("soc-ingest", 1234, 400) // 400MB < 512MB
|
|
if v != nil {
|
|
t.Errorf("unexpected violation for memory within limit: %+v", v)
|
|
}
|
|
}
|
|
|
|
func TestStats(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
g.CheckSyscall("soc-ingest", 1, "ptrace")
|
|
g.CheckSyscall("soc-ingest", 1, "process_vm_readv")
|
|
g.CheckFileAccess("soc-ingest", 1, "/etc/shadow")
|
|
|
|
stats := g.Stats()
|
|
if stats.Violations != 3 {
|
|
t.Errorf("violations = %d, want 3", stats.Violations)
|
|
}
|
|
if stats.ByProcess["soc-ingest"] != 3 {
|
|
t.Errorf("by_process[soc-ingest] = %d, want 3", stats.ByProcess["soc-ingest"])
|
|
}
|
|
if stats.ByType["syscall"] != 2 {
|
|
t.Errorf("by_type[syscall] = %d, want 2", stats.ByType["syscall"])
|
|
}
|
|
}
|
|
|
|
func TestSetMode(t *testing.T) {
|
|
g := New(testPolicy())
|
|
if g.CurrentMode() != ModeAudit {
|
|
t.Fatalf("initial mode = %s, want audit", g.CurrentMode())
|
|
}
|
|
|
|
g.SetMode(ModeEnforce)
|
|
if g.CurrentMode() != ModeEnforce {
|
|
t.Errorf("mode after set = %s, want enforce", g.CurrentMode())
|
|
}
|
|
}
|
|
|
|
func TestViolationHandler(t *testing.T) {
|
|
g := New(testPolicy())
|
|
|
|
var received []Violation
|
|
g.OnViolation(func(v Violation) {
|
|
received = append(received, v)
|
|
})
|
|
|
|
g.CheckSyscall("soc-ingest", 1, "ptrace")
|
|
|
|
if len(received) != 1 {
|
|
t.Fatalf("handler received %d violations, want 1", len(received))
|
|
}
|
|
if received[0].Type != "syscall" {
|
|
t.Errorf("type = %s, want syscall", received[0].Type)
|
|
}
|
|
}
|
|
|
|
func TestLoadPolicy(t *testing.T) {
|
|
// Write temp policy file.
|
|
content := `
|
|
version: "1.0"
|
|
mode: enforce
|
|
processes:
|
|
test-proc:
|
|
blocked_syscalls: [ptrace]
|
|
allowed_files: [/tmp/*]
|
|
`
|
|
tmpFile := t.TempDir() + "/test_policy.yaml"
|
|
if err := writeFile(tmpFile, content); err != nil {
|
|
t.Fatalf("write temp policy: %v", err)
|
|
}
|
|
|
|
policy, err := LoadPolicy(tmpFile)
|
|
if err != nil {
|
|
t.Fatalf("LoadPolicy: %v", err)
|
|
}
|
|
if policy.Mode != ModeEnforce {
|
|
t.Errorf("mode = %s, want enforce", policy.Mode)
|
|
}
|
|
if _, ok := policy.Processes["test-proc"]; !ok {
|
|
t.Error("expected test-proc in processes")
|
|
}
|
|
}
|
|
|
|
func writeFile(path, content string) error {
|
|
return os.WriteFile(path, []byte(content), 0644)
|
|
}
|