diff --git a/go.mod b/go.mod index 1752e3c..da5963b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.0 toolchain go1.24.5 require ( + github.com/google/cel-go v0.23.2 github.com/goradd/maps v1.0.0 github.com/inspektor-gadget/inspektor-gadget v0.41.0 github.com/kubescape/node-agent v0.0.0-00010101000000-000000000000 @@ -54,6 +55,7 @@ require ( github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/containers/common v0.63.0 // indirect github.com/coreos/go-oidc/v3 v3.14.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/crewjam/rfc5424 v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -61,7 +63,7 @@ require ( github.com/dghubble/trie v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v28.2.1+incompatible // indirect - github.com/docker/docker v28.2.1+incompatible // indirect + github.com/docker/docker v28.3.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.3 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect @@ -90,10 +92,10 @@ require ( github.com/go-openapi/swag v0.23.1 // indirect github.com/go-openapi/validate v0.24.0 // indirect github.com/go-viper/mapstructure/v2 v2.3.0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect - github.com/google/cel-go v0.23.2 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-containerregistry v0.20.3 // indirect @@ -241,6 +243,6 @@ replace github.com/vishvananda/netns => github.com/inspektor-gadget/netns v0.0.5 replace github.com/mholt/archiver/v3 v3.5.1 => github.com/anchore/archiver/v3 v3.5.2 -replace github.com/inspektor-gadget/inspektor-gadget => github.com/amirmalka/inspektor-gadget v0.39.1-0.20250511132413-c7a2a761237a +replace github.com/inspektor-gadget/inspektor-gadget => github.com/amirmalka/inspektor-gadget v0.40.1-0.20250814111737-3a58864c8d86 -replace github.com/kubescape/node-agent => github.com/kubescape/node-agent v0.2.362-0.20250807102617-1ef40266db3b +replace github.com/kubescape/node-agent => github.com/kubescape/node-agent v0.2.375-0.20250818082235-0ba8a1de9cfa diff --git a/go.sum b/go.sum index a523333..756c8d7 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/amirmalka/inspektor-gadget v0.39.1-0.20250511132413-c7a2a761237a h1:2vLghsSw+mIAiMElWRn64YqLFo6L3hFPWXh1EQe4dhc= -github.com/amirmalka/inspektor-gadget v0.39.1-0.20250511132413-c7a2a761237a/go.mod h1:4XWD/ylSvywkRlIv01nl3QAAS9VhObi5Pha2pAbednA= +github.com/amirmalka/inspektor-gadget v0.40.1-0.20250814111737-3a58864c8d86 h1:cLzA/pqfFQdzmI9hnR2W5gMUUMPiP3MXS/bwTFNz6wo= +github.com/amirmalka/inspektor-gadget v0.40.1-0.20250814111737-3a58864c8d86/go.mod h1:W6tNNRa3QDFdrknnOnavk+HD8FI/XUGY6tY6PSonhAk= github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837 h1:bIG3WsfosZsJ5LMC7PB9J/ekFM3a0j0ZEDvN3ID6GTI= github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837/go.mod h1:tRQVKkjYeejrh9AdM0s1esbwtMU7rdHAHSQWkv4qskE= github.com/anchore/fangs v0.0.0-20250402135612-96e29e45f3fe h1:qv/xxpjF5RdKPqZjx8RM0aBi3HUCAO0DhRBMs2xhY1I= @@ -193,6 +193,8 @@ github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmr github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/crewjam/rfc5424 v0.1.0 h1:MSeXJm22oKovLzWj44AHwaItjIMUMugYGkEzfa831H8= @@ -212,8 +214,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v28.2.1+incompatible h1:AYyTcuwvhl9dXdyCiXlOGXiIqSNYzTmaDNpxIISPGsM= github.com/docker/cli v28.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v28.2.1+incompatible h1:aTSWVTDStpHbnRu0xBcGoJEjRf5EQKt6nik6Vif8sWw= -github.com/docker/docker v28.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= +github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -317,6 +319,8 @@ github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncV github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= @@ -516,8 +520,8 @@ github.com/kubescape/go-logger v0.0.24 h1:JRNlblY16Ty7hD6MSYNPvWYDxNzVAufsDDX/sZ github.com/kubescape/go-logger v0.0.24/go.mod h1:sMPVCr3VpW/e+SeMaXig5kClGvmZbDXN8YktUeNU4nY= github.com/kubescape/k8s-interface v0.0.198 h1:U7PNTyS9ZE9ZkSrLMclLO7Sz4grf/2CLbmpVT6Hc0nU= github.com/kubescape/k8s-interface v0.0.198/go.mod h1:j9snZbH+RxOaa1yG/bWgTClj90q7To0rGgQepxy4b+k= -github.com/kubescape/node-agent v0.2.362-0.20250807102617-1ef40266db3b h1:JJHMDdHBNMhfYMJNBaz6yNjAHURnPmEjWoZnZoCSmaw= -github.com/kubescape/node-agent v0.2.362-0.20250807102617-1ef40266db3b/go.mod h1:XrjR9qQGV0ElDjYXlBdmIdBKf+XjWdlAgXv6r4or8kk= +github.com/kubescape/node-agent v0.2.375-0.20250818082235-0ba8a1de9cfa h1:J/sF/XKvKb2nAikos64GwGcRo9jbmAcd5LmN6T1U46Q= +github.com/kubescape/node-agent v0.2.375-0.20250818082235-0ba8a1de9cfa/go.mod h1:U5/d1gjSu0u42H1CzkTl4C3lG7SvPHjUDrbu6DNGVhs= github.com/kubescape/storage v0.0.200 h1:gLCPiAPxDii03Jo326Ye0qx1cXOAz6KH+A9B0WuL1CE= github.com/kubescape/storage v0.0.200/go.mod h1:uv4LMQjcTYIn7bgyMFGc0UBZ3gxdl7MNixPSjALP08E= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= @@ -683,8 +687,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a h1:w3tdWGKbLGBPtR/8/oO74W6hmz0qE5q0z9aqSAewaaM= +github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:S8kfXMp+yh77OxPD4fdM6YUknrZpQxLhvxzS4gDHENY= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= diff --git a/pkg/cmd/cost_analyzer.go b/pkg/cmd/cost_analyzer.go new file mode 100644 index 0000000..3f4e94f --- /dev/null +++ b/pkg/cmd/cost_analyzer.go @@ -0,0 +1,205 @@ +package main + +import ( + "fmt" + "log" + "os" + "path/filepath" + "strings" + + "github.com/google/cel-go/cel" + "github.com/google/cel-go/checker" + "github.com/google/cel-go/ext" + "github.com/goradd/maps" + "gopkg.in/yaml.v3" + + // Mock dependencies for library initialization + "github.com/kubescape/node-agent/pkg/config" + "github.com/kubescape/node-agent/pkg/objectcache" + objectcachev1 "github.com/kubescape/node-agent/pkg/objectcache/v1" + + // Import the actual agent libraries + "github.com/kubescape/node-agent/pkg/rulemanager/cel/libraries" + "github.com/kubescape/node-agent/pkg/rulemanager/cel/libraries/applicationprofile" + "github.com/kubescape/node-agent/pkg/rulemanager/cel/libraries/k8s" + "github.com/kubescape/node-agent/pkg/rulemanager/cel/libraries/net" + "github.com/kubescape/node-agent/pkg/rulemanager/cel/libraries/networkneighborhood" + "github.com/kubescape/node-agent/pkg/rulemanager/cel/libraries/parse" + "github.com/kubescape/node-agent/pkg/rulemanager/cel/libraries/process" + typesv1 "github.com/kubescape/node-agent/pkg/rulemanager/types/v1" +) + +// ===================================================================================== +// 1. YAML Parsing Structs +// ===================================================================================== + +type Rules struct { + Spec typesv1.RulesSpec `yaml:"spec"` +} + +// ===================================================================================== +// 2. Composite Cost Estimator +// This combines all individual library estimators into one. +// ===================================================================================== + +type CompositeCostEstimator struct { + estimators []checker.CostEstimator +} + +func NewCompositeCostEstimator(estimators ...checker.CostEstimator) checker.CostEstimator { + var nonNilEstimators []checker.CostEstimator + for _, e := range estimators { + if e != nil { + nonNilEstimators = append(nonNilEstimators, e) + } + } + return &CompositeCostEstimator{estimators: nonNilEstimators} +} + +func (c *CompositeCostEstimator) EstimateCallCost(function, overloadID string, target *checker.AstNode, args []checker.AstNode) *checker.CallEstimate { + for _, e := range c.estimators { + if estimate := e.EstimateCallCost(function, overloadID, target, args); estimate != nil { + return estimate + } + } + return nil +} + +func (c *CompositeCostEstimator) EstimateSize(element checker.AstNode) *checker.SizeEstimate { + for _, e := range c.estimators { + if estimate := e.EstimateSize(element); estimate != nil { + return estimate + } + } + return nil +} + +// ===================================================================================== +// 3. Main Application Logic +// ===================================================================================== + +// createAnalyzerEnvAndEstimator initializes a CEL environment using the real agent libraries +// and constructs a composite cost estimator from them. +func createAnalyzerEnvAndEstimator() (*cel.Env, checker.CostEstimator, error) { + // Create mock dependencies required by the library constructors + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + cfg := config.Config{} + + // Instantiate all of the agent's real libraries + allLibraries := []libraries.Library{ + applicationprofile.New(objCache, cfg), + k8s.New(objCache.K8sObjectCache(), cfg), + networkneighborhood.New(objCache, cfg), + parse.New(cfg), + net.New(cfg), + process.New(cfg), + } + + var envOptions []cel.EnvOption + var costEstimators []checker.CostEstimator + + // Collect EnvOptions and CostEstimators from each library + for _, lib := range allLibraries { + envOptions = append(envOptions, cel.Lib(lib)) + if estimator := lib.CostEstimator(); estimator != nil { + costEstimators = append(costEstimators, estimator) + } + } + + compositeEstimator := NewCompositeCostEstimator(costEstimators...) + + // Add standard variables and extensions + envOptions = append(envOptions, + cel.Variable("event", cel.AnyType), + ext.Strings(), + ) + + env, err := cel.NewEnv(envOptions...) + return env, compositeEstimator, err +} + +func main() { + rulesPath := "pkg/rules" + if len(os.Args) > 1 { + rulesPath = os.Args[1] + } + + fmt.Printf("Analyzing CEL rule costs in: %s\n", rulesPath) + fmt.Println("--------------------------------------------------") + + // Create the fully-featured CEL Environment and the estimator + env, estimator, err := createAnalyzerEnvAndEstimator() + if err != nil { + log.Fatalf("Failed to create CEL environment: %v", err) + } + + // Walk the directory to find all rule files. + err = filepath.Walk(rulesPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() && (strings.HasSuffix(info.Name(), ".yaml") || strings.HasSuffix(info.Name(), ".yml")) { + processRuleFile(path, env, estimator) + } + return nil + }) + + if err != nil { + log.Fatalf("Error walking the path %q: %v\n", rulesPath, err) + } +} + +// processRuleFile reads a YAML file, extracts the CEL expression, and estimates its cost. +func processRuleFile(filePath string, env *cel.Env, estimator checker.CostEstimator) { + yamlFile, err := os.ReadFile(filePath) + if err != nil { + log.Printf("WARN: Failed to read file %s: %v", filePath, err) + return + } + + var rules Rules + err = yaml.Unmarshal(yamlFile, &rules) + if err != nil { + log.Printf("WARN: Failed to unmarshal YAML for %s: %v", filePath, err) + return + } + + if len(rules.Spec.Rules) == 0 { + return // Not a rule file, skip silently. + } + + rule := rules.Spec.Rules[0] + if len(rule.Expressions.RuleExpression) == 0 { + fmt.Printf("Rule: %s\n", rule.Name) + fmt.Printf(" Path: %s\n", filePath) + fmt.Printf(" Cost: [No rule_expression found]\n\n") + return + } + + expression := rule.Expressions.RuleExpression[0].Expression + + // Compile the expression to get an AST. + ast, issues := env.Compile(expression) + if issues != nil && issues.Err() != nil { + fmt.Printf("Rule: %s\n", rule.Name) + fmt.Printf(" Path: %s\n", filePath) + fmt.Printf(" ERROR compiling expression: %v\n\n", issues.Err()) + return + } + + // Estimate the cost of the compiled AST using our composite estimator. + cost, err := env.EstimateCost(ast, estimator) + if err != nil { + fmt.Printf("Rule: %s\n", rule.Name) + fmt.Printf(" Path: %s\n", filePath) + fmt.Printf(" ERROR estimating cost: %v\n\n", err) + return + } + + // Print the final result. + fmt.Printf("Rule: %s\n", rule.Name) + fmt.Printf(" Path: %s\n", filePath) + fmt.Printf(" Cost: [Min: %d, Max: %d]\n\n", cost.Min, cost.Max) +} diff --git a/pkg/rules/r0001-unexpected-process-launched/rule_test.go b/pkg/rules/r0001-unexpected-process-launched/rule_test.go index b7a3b6e..65bd186 100644 --- a/pkg/rules/r0001-unexpected-process-launched/rule_test.go +++ b/pkg/rules/r0001-unexpected-process-launched/rule_test.go @@ -140,3 +140,92 @@ func TestR0001UnexpectedProcessLaunched(t *testing.T) { t.Fatalf("Rule evaluation should have failed") } } + +// BenchmarkR0001CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0001CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-process-launched.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a process exec event + e := &events.ExecEvent{ + Event: tracerexectype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test-process", + Pcomm: "test-process", + ExePath: "/usr/bin/test-process", + Args: []string{"test-process", "arg1"}, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.ExecveEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.ExecveEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0002-unexpected-file-access/rule_test.go b/pkg/rules/r0002-unexpected-file-access/rule_test.go index f1ae31b..39d5a85 100644 --- a/pkg/rules/r0002-unexpected-file-access/rule_test.go +++ b/pkg/rules/r0002-unexpected-file-access/rule_test.go @@ -139,3 +139,92 @@ func TestR0002UnexpectedFileAccess(t *testing.T) { t.Fatalf("Rule evaluation should have failed") } } + +// BenchmarkR0002CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0002CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-file-access.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a file access event + e := &events.OpenEvent{ + Event: traceropentype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test", + Path: "/etc/test", + FullPath: "/etc/test", + Flags: []string{"O_RDONLY"}, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.OpenEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.OpenEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0003-unexpected-system-call/rule_test.go b/pkg/rules/r0003-unexpected-system-call/rule_test.go index 914eb2a..319f591 100644 --- a/pkg/rules/r0003-unexpected-system-call/rule_test.go +++ b/pkg/rules/r0003-unexpected-system-call/rule_test.go @@ -131,3 +131,88 @@ func TestR0003UnexpectedSystemCall(t *testing.T) { t.Fatalf("Rule evaluation should have failed") } } + +// BenchmarkR0003CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0003CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-system-call.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a syscall event + e := &types.SyscallEvent{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "test", + SyscallName: "test_syscall", + Pid: 1234, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.SyscallEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.SyscallEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0004-unexpected-capability-used/rule_test.go b/pkg/rules/r0004-unexpected-capability-used/rule_test.go index 58900c7..4f80410 100644 --- a/pkg/rules/r0004-unexpected-capability-used/rule_test.go +++ b/pkg/rules/r0004-unexpected-capability-used/rule_test.go @@ -135,3 +135,89 @@ func TestR0004UnexpectedCapabilityUsed(t *testing.T) { t.Fatalf("Rule evaluation should have failed") } } + +// BenchmarkR0004CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0004CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-capability-used.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a capabilities event + e := &tracercapabilitiestype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "test", + CapName: "test_cap", + Syscall: "test_syscall", + Pid: 1234, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.CapabilitiesEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.CapabilitiesEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0005-unexpected-domain-request/rule_test.go b/pkg/rules/r0005-unexpected-domain-request/rule_test.go index 8499d0f..811b572 100644 --- a/pkg/rules/r0005-unexpected-domain-request/rule_test.go +++ b/pkg/rules/r0005-unexpected-domain-request/rule_test.go @@ -150,3 +150,252 @@ func TestR0005UnexpectedDomainRequest(t *testing.T) { t.Fatalf("Rule evaluation should have failed for in-cluster communication") } } + +// BenchmarkR0005CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0005CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-domain-request.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a DNS event + e := &tracerdnstype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test-process", + DNSName: "test.com", + Qr: tracerdnstype.DNSPktTypeQuery, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.DnsEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.DnsEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} + +// BenchmarkR0005CompleteEventProcessing benchmarks the complete event processing cost +// This gives you the real "cost" of processing one event through the entire pipeline +func BenchmarkR0005CompleteEventProcessing(b *testing.B) { + // Load rule once outside the loop to simulate production scenario + ruleSpec, err := common.LoadRuleFromYAML("unexpected-domain-request.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create CEL engine once outside the loop (like in production) + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.DnsEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark - each iteration represents processing one complete event + for i := 0; i < b.N; i++ { + // Create a new event for each iteration (simulates real event processing) + e := &tracerdnstype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test-process", + DNSName: "test.com", + Qr: tracerdnstype.DNSPktTypeQuery, + } + + // Convert event to map (this is part of the real cost) + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Evaluate the rule (main cost) + _, err := celEngine.EvaluateRule(eventMap, utils.DnsEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Evaluate message and unique ID (part of complete event processing) + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} + +// BenchmarkR0005SingleRuleEvaluation benchmarks just the rule evaluation cost +// This isolates the CEL evaluation performance from other overhead +func BenchmarkR0005SingleRuleEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-domain-request.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.DnsEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + e := &tracerdnstype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test-process", + DNSName: "test.com", + Qr: tracerdnstype.DNSPktTypeQuery, + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + b.ResetTimer() + + // Only measure the rule evaluation itself + for i := 0; i < b.N; i++ { + _, err := celEngine.EvaluateRule(eventMap, utils.DnsEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + } +} diff --git a/pkg/rules/r0006-unexpected-service-account-token-access/rule_test.go b/pkg/rules/r0006-unexpected-service-account-token-access/rule_test.go index b250803..a3d90be 100644 --- a/pkg/rules/r0006-unexpected-service-account-token-access/rule_test.go +++ b/pkg/rules/r0006-unexpected-service-account-token-access/rule_test.go @@ -317,3 +317,90 @@ func TestR0006WithTimestampPaths(t *testing.T) { }) } } + +// BenchmarkR0006CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0006CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-service-account-token-access.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an open event for service account token access + e := &traceropentype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "kubectl", + Path: "/var/run/secrets/kubernetes.io/serviceaccount/token", + FullPath: "/var/run/secrets/kubernetes.io/serviceaccount/token", + Flags: []string{"O_RDONLY"}, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.OpenEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.OpenEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0007-kubernetes-client-executed/rule_test.go b/pkg/rules/r0007-kubernetes-client-executed/rule_test.go index ee75d35..7a95639 100644 --- a/pkg/rules/r0007-kubernetes-client-executed/rule_test.go +++ b/pkg/rules/r0007-kubernetes-client-executed/rule_test.go @@ -228,3 +228,91 @@ func TestR0007KubernetesClientExecutedNetwork(t *testing.T) { t.Fatalf("Rule evaluation should have failed") } } + +// BenchmarkR0007CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0007CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("kubernetes-client-executed.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an exec event for kubectl + e := &events.ExecEvent{ + Event: tracerexectype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "kubectl", + ExePath: "/usr/bin/kubectl", + Args: []string{"kubectl", "get", "pods"}, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.ExecveEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.ExecveEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0008-read-environment-variables-procfs/rule_test.go b/pkg/rules/r0008-read-environment-variables-procfs/rule_test.go index c807183..e86d77e 100644 --- a/pkg/rules/r0008-read-environment-variables-procfs/rule_test.go +++ b/pkg/rules/r0008-read-environment-variables-procfs/rule_test.go @@ -334,3 +334,90 @@ func TestR0008VariousProcFSPaths(t *testing.T) { }) } } + +// BenchmarkR0008CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0008CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("read-environment-variables-procfs.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an open event for proc environ access + e := &traceropentype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "cat", + Path: "/proc/self/environ", + FullPath: "/proc/self/environ", + Flags: []string{"O_RDONLY"}, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.OpenEventType) + if !ok { + b.Fatalf("Failed to get event adapter: %v", err) + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.OpenEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0009-ebpf-program-load/rule_test.go b/pkg/rules/r0009-ebpf-program-load/rule_test.go index b6b42e1..43bb64c 100644 --- a/pkg/rules/r0009-ebpf-program-load/rule_test.go +++ b/pkg/rules/r0009-ebpf-program-load/rule_test.go @@ -149,3 +149,88 @@ func TestR0009EbpfProgramLoad(t *testing.T) { t.Fatalf("Rule evaluation should have failed for non-bpf syscall") } } + +// BenchmarkR0009CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0009CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("ebpf-program-load.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a syscall event with bpf syscall + e := &types.SyscallEvent{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test-process", + SyscallName: "bpf", + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.SyscallEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.SyscallEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0010-unexpected-sensitive-file-access/rule_test.go b/pkg/rules/r0010-unexpected-sensitive-file-access/rule_test.go index d5b4c1a..1e75b4e 100644 --- a/pkg/rules/r0010-unexpected-sensitive-file-access/rule_test.go +++ b/pkg/rules/r0010-unexpected-sensitive-file-access/rule_test.go @@ -160,3 +160,90 @@ func TestR0010UnexpectedSensitiveFileAccess(t *testing.T) { t.Fatalf("Rule evaluation should have failed for non-sensitive file") } } + +// BenchmarkR0010CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0010CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-sensitive-file-access.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an open event for sensitive file access + e := &traceropentype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test-process", + Path: "/etc/shadow", + FullPath: "/etc/shadow", + Flags: []string{"O_RDONLY"}, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.OpenEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.OpenEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r0011-unexpected-egress-network-traffic/rule_test.go b/pkg/rules/r0011-unexpected-egress-network-traffic/rule_test.go index 45d7ad4..d1467c5 100644 --- a/pkg/rules/r0011-unexpected-egress-network-traffic/rule_test.go +++ b/pkg/rules/r0011-unexpected-egress-network-traffic/rule_test.go @@ -215,3 +215,91 @@ func TestR0011UnexpectedEgressNetworkTraffic(t *testing.T) { t.Fatalf("Rule evaluation failed - should have detected unexpected egress traffic with UDP") } } + +// BenchmarkR0011CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR0011CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-egress-network-traffic.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a network event for egress traffic + e := &tracernetworktype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + PktType: "OUTGOING", + Proto: "TCP", + Port: 80, + DstEndpoint: eventtypes.L3Endpoint{ + Addr: "8.8.8.8", + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.NetworkEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.NetworkEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1000-exec-from-malicious-source/rule_test.go b/pkg/rules/r1000-exec-from-malicious-source/rule_test.go index e5f50c2..3ea9bfc 100644 --- a/pkg/rules/r1000-exec-from-malicious-source/rule_test.go +++ b/pkg/rules/r1000-exec-from-malicious-source/rule_test.go @@ -315,3 +315,92 @@ func TestR1000MaliciousPathVariants(t *testing.T) { }) } } + +// BenchmarkR1000CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1000CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("exec-from-malicious-source.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an exec event for malicious source + e := &events.ExecEvent{ + Event: tracerexectype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "malicious", + ExePath: "/dev/shm/malicious", + Cwd: "/", + Args: []string{"/dev/shm/malicious"}, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.ExecveEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.ExecveEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1001-exec-binary-not-in-base-image/rule_test.go b/pkg/rules/r1001-exec-binary-not-in-base-image/rule_test.go index 5ca6747..1b15282 100644 --- a/pkg/rules/r1001-exec-binary-not-in-base-image/rule_test.go +++ b/pkg/rules/r1001-exec-binary-not-in-base-image/rule_test.go @@ -322,3 +322,92 @@ func TestR1001UpperLayerVariants(t *testing.T) { }) } } + +// BenchmarkR1001CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1001CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("exec-binary-not-in-base-image.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an exec event for binary not in base image + e := &events.ExecEvent{ + Event: tracerexectype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test-process", + ExePath: "/tmp/test", + Pcomm: "bash", + UpperLayer: true, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.ExecveEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.ExecveEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1002-kernel-module-load/rule_test.go b/pkg/rules/r1002-kernel-module-load/rule_test.go index aebc336..e83bff4 100644 --- a/pkg/rules/r1002-kernel-module-load/rule_test.go +++ b/pkg/rules/r1002-kernel-module-load/rule_test.go @@ -153,3 +153,72 @@ func TestR1002KernelModuleLoad(t *testing.T) { }) } } + +// BenchmarkR1002CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1002CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("kernel-module-load.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a syscall event for kernel module load + e := createTestSyscallEvent("test", "container123", "test-process", "init_module", uint32(1234)) + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.SyscallEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.SyscallEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1003-malicious-ssh-connection/rule_test.go b/pkg/rules/r1003-malicious-ssh-connection/rule_test.go index 9d3d4bb..2dd1720 100644 --- a/pkg/rules/r1003-malicious-ssh-connection/rule_test.go +++ b/pkg/rules/r1003-malicious-ssh-connection/rule_test.go @@ -281,3 +281,89 @@ func TestR1003MaliciousSSHConnection(t *testing.T) { t.Fatalf("Rule evaluation failed - should have detected malicious SSH connection with different process name") } } + +// BenchmarkR1003CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1003CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("malicious-ssh-connection.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an SSH event for malicious connection + e := &tracersshtype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "ssh", + DstIP: "1.1.1.1", + DstPort: 1234, + SrcPort: 33333, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.SSHEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.SSHEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1004-exec-from-mount/rule_test.go b/pkg/rules/r1004-exec-from-mount/rule_test.go index 4e67b5a..a14ea55 100644 --- a/pkg/rules/r1004-exec-from-mount/rule_test.go +++ b/pkg/rules/r1004-exec-from-mount/rule_test.go @@ -273,3 +273,91 @@ func TestR1004ExecFromMount(t *testing.T) { t.Fatalf("Rule evaluation should have failed for exec from system path") } } + +// BenchmarkR1004CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1004CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("exec-from-mount.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an exec event for execution from mount + e := &events.ExecEvent{ + Event: tracerexectype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "test", + ExePath: "/var/test1/test", + Args: []string{"/var/test1/test", "arg1"}, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.ExecveEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.ExecveEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1005-fileless-execution/rule_test.go b/pkg/rules/r1005-fileless-execution/rule_test.go index 4d47317..725cb33 100644 --- a/pkg/rules/r1005-fileless-execution/rule_test.go +++ b/pkg/rules/r1005-fileless-execution/rule_test.go @@ -269,3 +269,91 @@ func TestR1005FilelessExecution(t *testing.T) { t.Fatalf("Rule evaluation failed - should have detected fileless execution with different fd number") } } + +// BenchmarkR1005CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1005CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("fileless-execution.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an exec event for fileless execution + e := &events.ExecEvent{ + Event: tracerexectype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Pid: 1234, + Comm: "/proc/1234/fd/5", + ExePath: "/proc/1234/fd/5", + Args: []string{"/proc/1234/fd/5"}, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.ExecveEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.ExecveEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1006-unshare-syscall/rule_test.go b/pkg/rules/r1006-unshare-syscall/rule_test.go index accd5e4..a71854e 100644 --- a/pkg/rules/r1006-unshare-syscall/rule_test.go +++ b/pkg/rules/r1006-unshare-syscall/rule_test.go @@ -149,3 +149,88 @@ func TestR1006UnshareSyscall(t *testing.T) { t.Fatalf("Rule evaluation should have failed for non-unshare syscall") } } + +// BenchmarkR1006CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1006CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unshare-syscall.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a syscall event for unshare + e := &types.SyscallEvent{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "test", + SyscallName: "unshare", + Pid: 1234, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.SyscallEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.SyscallEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1007-xmr-crypto-mining/rule_test.go b/pkg/rules/r1007-xmr-crypto-mining/rule_test.go index 5876cee..119af77 100644 --- a/pkg/rules/r1007-xmr-crypto-mining/rule_test.go +++ b/pkg/rules/r1007-xmr-crypto-mining/rule_test.go @@ -196,3 +196,95 @@ func TestR1007XMRCryptoMining(t *testing.T) { t.Fatalf("Rule evaluation failed - should have detected XMR crypto mining with different UID/GID") } } + +// BenchmarkR1007CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1007CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("xmr-crypto-mining.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a RandomX event for crypto mining detection + e := &tracerrandomxtype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + PodName: "test-pod", + Namespace: "test-namespace", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test-container", + ContainerName: "test", + }, + }, + }, + Comm: "xmrig", + ExePath: "/usr/bin/xmrig", + Pid: 1234, + Uid: 1000, + Gid: 1000, + PPid: 1, + UpperLayer: true, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test-container", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.RandomXEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.RandomXEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1008-crypto-mining-domain-communication/rule_test.go b/pkg/rules/r1008-crypto-mining-domain-communication/rule_test.go index baead65..ae7a009 100644 --- a/pkg/rules/r1008-crypto-mining-domain-communication/rule_test.go +++ b/pkg/rules/r1008-crypto-mining-domain-communication/rule_test.go @@ -219,3 +219,97 @@ func TestR1008CryptoMiningDomainCommunication(t *testing.T) { t.Fatalf("Rule evaluation failed - should have detected crypto mining domain with different process") } } + +// BenchmarkR1008CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1008CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("crypto-mining-domain-communication.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a DNS event for crypto mining domain communication + e := &tracerdnstype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + PodName: "test-pod", + Namespace: "test-namespace", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test-container", + ContainerName: "test", + }, + }, + }, + DNSName: "xmr.gntl.uk.", + Comm: "xmrig", + Exepath: "/usr/bin/xmrig", + Pid: 1234, + Uid: 1000, + Gid: 1000, + Ppid: 1, + Pcomm: "bash", + Cwd: "/tmp", + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test-container", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.DnsEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.DnsEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1009-crypto-mining-related-port/rule_test.go b/pkg/rules/r1009-crypto-mining-related-port/rule_test.go index e8e8533..71616e2 100644 --- a/pkg/rules/r1009-crypto-mining-related-port/rule_test.go +++ b/pkg/rules/r1009-crypto-mining-related-port/rule_test.go @@ -255,3 +255,92 @@ func TestR1009CryptoMiningRelatedPort(t *testing.T) { t.Fatalf("Rule evaluation failed - should have detected crypto mining port communication to non-whitelisted address") } } + +// BenchmarkR1009CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1009CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("crypto-mining-related-port.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a network event for crypto mining port + e := &tracernetworktype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "xmrig", + Port: 3333, + Proto: "TCP", + PktType: "OUTGOING", + DstEndpoint: eventtypes.L3Endpoint{ + Addr: "1.1.1.1", + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.NetworkEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.NetworkEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1010-symlink-created-over-sensitive-file/rule_test.go b/pkg/rules/r1010-symlink-created-over-sensitive-file/rule_test.go index ce2a894..e3d58e7 100644 --- a/pkg/rules/r1010-symlink-created-over-sensitive-file/rule_test.go +++ b/pkg/rules/r1010-symlink-created-over-sensitive-file/rule_test.go @@ -153,3 +153,87 @@ func TestR1010SymlinkCreatedOverSensitiveFile(t *testing.T) { t.Fatalf("Rule evaluation should have failed") } } + +// BenchmarkR1010CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1010CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("symlink-created-over-sensitive-file.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a symlink event for sensitive file + e := &tracersymlinktype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + OldPath: "/etc/shadow", + NewPath: "/etc/abc", + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.SymlinkEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.SymlinkEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1011-ld-preload-hook/rule_test.go b/pkg/rules/r1011-ld-preload-hook/rule_test.go index 57d924e..ea3ef31 100644 --- a/pkg/rules/r1011-ld-preload-hook/rule_test.go +++ b/pkg/rules/r1011-ld-preload-hook/rule_test.go @@ -211,3 +211,90 @@ func TestR1011LdPreloadHook(t *testing.T) { t.Fatalf("Rule policy validation should return true for whitelisted process") } } + +// BenchmarkR1011CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1011CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("ld-preload-hook.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an open event for ld.so.preload + e := &events.OpenEvent{ + Event: traceropentype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "test", + FullPath: "/etc/ld.so.preload", + FlagsRaw: 1, + }, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.OpenEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.OpenEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1012-hardlink-created-over-sensitive-file/rule_test.go b/pkg/rules/r1012-hardlink-created-over-sensitive-file/rule_test.go index 2bf41e6..0c8e66e 100644 --- a/pkg/rules/r1012-hardlink-created-over-sensitive-file/rule_test.go +++ b/pkg/rules/r1012-hardlink-created-over-sensitive-file/rule_test.go @@ -202,3 +202,88 @@ func TestR1012HardlinkCreatedOverSensitiveFile(t *testing.T) { t.Fatalf("Rule policy validation should return true for whitelisted process") } } + +// BenchmarkR1012CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1012CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("hardlink-created-over-sensitive-file.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a hardlink event for sensitive file + e := &tracerhardlinktype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "test", + OldPath: "/etc/shadow", + NewPath: "/etc/abc", + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.HardlinkEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.HardlinkEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1015-malicious-ptrace-usage/rule_test.go b/pkg/rules/r1015-malicious-ptrace-usage/rule_test.go index d6783bf..12d6d8e 100644 --- a/pkg/rules/r1015-malicious-ptrace-usage/rule_test.go +++ b/pkg/rules/r1015-malicious-ptrace-usage/rule_test.go @@ -179,3 +179,88 @@ func TestR1015MaliciousPtraceUsage(t *testing.T) { t.Fatalf("Rule evaluation should always return true for ptrace events even for unknown processes") } } + +// BenchmarkR1015CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1015CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("malicious-ptrace-usage.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create a ptrace event for malicious usage + e := &tracerptracetype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "malicious_process", + Request: PTRACE_POKEDATA, + Pid: 1234, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.PtraceEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.PtraceEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +} diff --git a/pkg/rules/r1030-unexpected-io_uring-operation/rule_test.go b/pkg/rules/r1030-unexpected-io_uring-operation/rule_test.go index d96ee18..db93d1b 100644 --- a/pkg/rules/r1030-unexpected-io_uring-operation/rule_test.go +++ b/pkg/rules/r1030-unexpected-io_uring-operation/rule_test.go @@ -157,3 +157,88 @@ func TestR1030UnexpectedIouringOperation(t *testing.T) { t.Fatalf("Rule policy validation should return true for whitelisted process") } } + +// BenchmarkR1030CELEvaluation benchmarks the CEL rule evaluation performance +func BenchmarkR1030CELEvaluation(b *testing.B) { + ruleSpec, err := common.LoadRuleFromYAML("unexpected-io_uring-operation.yaml") + if err != nil { + b.Fatalf("Failed to load rule: %v", err) + } + + // Create an io_uring event for unexpected operation + e := &traceriouringtype.Event{ + Event: eventtypes.Event{ + CommonData: eventtypes.CommonData{ + K8s: eventtypes.K8sMetadata{ + BasicK8sMetadata: eventtypes.BasicK8sMetadata{ + ContainerName: "test", + }, + }, + Runtime: eventtypes.BasicRuntimeMetadata{ + ContainerID: "test", + }, + }, + }, + Comm: "test-process", + Opcode: 1, + Flags: 0x0, + } + + objCache := &objectcachev1.RuleObjectCacheMock{ + ContainerIDToSharedData: maps.NewSafeMap[string, *objectcache.WatchedContainerData](), + } + + objCache.SetSharedContainerData("test", &objectcache.WatchedContainerData{ + ContainerType: objectcache.Container, + ContainerInfos: map[objectcache.ContainerType][]objectcache.ContainerInfo{ + objectcache.Container: { + { + Name: "test", + }, + }, + }, + }) + + celEngine, err := celengine.NewCEL(objCache, config.Config{ + CelConfigCache: cache.FunctionCacheConfig{ + MaxSize: 1000, + TTL: 1 * time.Microsecond, + }, + }) + if err != nil { + b.Fatalf("Failed to create CEL engine: %v", err) + } + + adapterFactory := ruleadapters.NewEventRuleAdapterFactory() + adapter, ok := adapterFactory.GetAdapter(utils.IoUringEventType) + if !ok { + b.Fatalf("Failed to get event adapter") + } + + eventMap := adapter.ToMap(&events.EnrichedEvent{ + Event: e, + }) + + // Reset timer to exclude setup time + b.ResetTimer() + + // Run the benchmark + for i := 0; i < b.N; i++ { + // Benchmark CEL rule evaluation + _, err := celEngine.EvaluateRule(eventMap, utils.IoUringEventType, ruleSpec.Rules[0].Expressions.RuleExpression) + if err != nil { + b.Fatalf("Failed to evaluate rule: %v", err) + } + + // Also benchmark message and unique ID expressions + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.Message) + if err != nil { + b.Fatalf("Failed to evaluate message: %v", err) + } + + _, err = celEngine.EvaluateExpression(eventMap, ruleSpec.Rules[0].Expressions.UniqueID) + if err != nil { + b.Fatalf("Failed to evaluate unique id: %v", err) + } + } +}