Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -54,14 +55,15 @@ 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
github.com/deckarep/golang-set/v2 v2.7.0 // indirect
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
20 changes: 12 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand All @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
205 changes: 205 additions & 0 deletions pkg/cmd/cost_analyzer.go
Original file line number Diff line number Diff line change
@@ -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)
}
Loading