From 366b4111be0009fe7a43f7d82ba92c233c9f3f8f Mon Sep 17 00:00:00 2001 From: Yakir Oren Date: Thu, 22 Jan 2026 16:07:02 +0200 Subject: [PATCH 1/3] header parsing and early return in ruleAppliesToContext Signed-off-by: Yakir Oren --- pkg/containerwatcher/v2/tracers/httpparse.go | 55 +++++++++++++------- pkg/rulemanager/cel/cel.go | 11 ++-- pkg/rulemanager/rulepolicy.go | 15 +++--- pkg/utils/labels.go | 19 ++----- 4 files changed, 53 insertions(+), 47 deletions(-) diff --git a/pkg/containerwatcher/v2/tracers/httpparse.go b/pkg/containerwatcher/v2/tracers/httpparse.go index 5602912471..ed80e6fb38 100644 --- a/pkg/containerwatcher/v2/tracers/httpparse.go +++ b/pkg/containerwatcher/v2/tracers/httpparse.go @@ -78,43 +78,58 @@ func GetPacketDirection(syscall string) (consts.NetworkDirection, error) { } func ParseHttpRequest(data []byte) (*http.Request, error) { - bufReader := bufio.NewReader(bytes.NewReader(data)) + // Find header/body boundary + headerEnd := bytes.Index(data, []byte("\r\n\r\n")) + if headerEnd == -1 { + headerEnd = bytes.Index(data, []byte("\n\n")) + if headerEnd == -1 { + return fallbackReadRequest(data) + } + headerEnd += 2 + } else { + headerEnd += 4 + } + // Parse headers only + bufReader := bufio.NewReader(bytes.NewReader(data[:headerEnd])) req, err := http.ReadRequest(bufReader) if err != nil { return fallbackReadRequest(data) } - body, err := io.ReadAll(req.Body) - if err != nil { - return nil, err - } - - req.Body.Close() - - req.Body = io.NopCloser(bytes.NewReader(body)) + // Set body directly without re-reading + bodyData := data[headerEnd:] + req.ContentLength = int64(len(bodyData)) + req.Body = io.NopCloser(bytes.NewReader(bodyData)) return req, nil } func ParseHttpResponse(data []byte, req *http.Request) (*http.Response, error) { - resp, err := readResponse(data, req) - if err != nil { - resp, err = fallbackReadResponse(data, req) - if err != nil { - return nil, err + // Find header/body boundary + headerEnd := bytes.Index(data, []byte("\r\n\r\n")) + if headerEnd == -1 { + headerEnd = bytes.Index(data, []byte("\n\n")) + if headerEnd == -1 { + return fallbackReadResponse(data, req) } + headerEnd += 2 + } else { + headerEnd += 4 } - body, err := io.ReadAll(resp.Body) - if err != nil && err != io.ErrUnexpectedEOF { - return nil, err + // Parse headers only + bufReader := bufio.NewReader(bytes.NewReader(data[:headerEnd])) + resp, err := http.ReadResponse(bufReader, req) + if err != nil { + return fallbackReadResponse(data, req) } + // Set body directly without re-reading + bodyData := data[headerEnd:] resp.Body.Close() - - resp.Body = io.NopCloser(bytes.NewReader(body)) - resp.ContentLength = int64(len(body)) + resp.Body = io.NopCloser(bytes.NewReader(bodyData)) + resp.ContentLength = int64(len(bodyData)) resp.TransferEncoding = nil resp.Header.Del("Transfer-Encoding") resp.Header.Del("Content-Length") diff --git a/pkg/rulemanager/cel/cel.go b/pkg/rulemanager/cel/cel.go index 36a5ed1708..7cc507d980 100644 --- a/pkg/rulemanager/cel/cel.go +++ b/pkg/rulemanager/cel/cel.go @@ -68,7 +68,7 @@ func NewCEL(objectCache objectcache.ObjectCache, cfg config.Config) (*CEL, error } c.evalContextPool.New = func() interface{} { - return make(map[string]any, 1) + return make(map[string]any, 2) } return c, nil @@ -117,8 +117,11 @@ func (c *CEL) getOrCreateProgram(expression string) (cel.Program, error) { } func (c *CEL) EvaluateRule(event *events.EnrichedEvent, expressions []typesv1.RuleExpression) (bool, error) { + obj, _ := xcel.NewObject(event.Event.(utils.CelEvent)) // FIXME put safety check here + eventType := event.Event.GetEventType() + input := map[string]any{"event": obj, "eventType": string(eventType)} + for _, expression := range expressions { - eventType := event.Event.GetEventType() if expression.EventType != eventType { continue } @@ -127,9 +130,7 @@ func (c *CEL) EvaluateRule(event *events.EnrichedEvent, expressions []typesv1.Ru if err != nil { return false, err } - - obj, _ := xcel.NewObject(event.Event.(utils.CelEvent)) // FIXME put safety check here - out, _, err := program.Eval(map[string]any{"event": obj, "eventType": string(eventType)}) + out, _, err := program.Eval(input) if err != nil { return false, err } diff --git a/pkg/rulemanager/rulepolicy.go b/pkg/rulemanager/rulepolicy.go index eef804a449..4ef1092b39 100644 --- a/pkg/rulemanager/rulepolicy.go +++ b/pkg/rulemanager/rulepolicy.go @@ -43,17 +43,20 @@ func RuleAppliesToContext(rule *typesv1.Rule, contextInfo contextdetection.Conte currentContext = contextInfo.Context() } - var contextTags []string + var hasContextTags bool for _, tag := range rule.Tags { if ctx, found := strings.CutPrefix(tag, "context:"); found { - contextTags = append(contextTags, ctx) + hasContextTags = true + if ctx == string(currentContext) { + return true + } } } - if len(contextTags) > 0 { - return slices.Contains(contextTags, string(currentContext)) + // No context specified in tags: default to kubernetes only (backward compatible) + if !hasContextTags { + return currentContext == contextdetection.Kubernetes } - // No context specified in tags: default to kubernetes only (backward compatible) - return currentContext == contextdetection.Kubernetes + return false } diff --git a/pkg/utils/labels.go b/pkg/utils/labels.go index acccdfd91c..ab4c9ac704 100644 --- a/pkg/utils/labels.go +++ b/pkg/utils/labels.go @@ -8,35 +8,22 @@ import ( ) func parseStringToMap(s string) map[string]string { - result := make(map[string]string) - - // 1. Split the string by the comma delimiter to get key-value pairs pairs := strings.Split(s, ",") + result := make(map[string]string, len(pairs)/2) for _, pair := range pairs { - // Trim any leading/trailing whitespace from the pair pair = strings.TrimSpace(pair) if pair == "" { - continue // Skip empty pairs that could result from multiple commas + continue } - // 2. Split each pair by the equals sign delimiter. - // We use SplitN(pair, "=", 2) to ensure that only the first - // equals sign is treated as the delimiter, allowing values to - // contain equals signs (though not the case in the example). parts := strings.SplitN(pair, "=", 2) - if len(parts) != 2 { - // Handle malformed pairs (e.g., "key" or "key=value=extra") logger.L().Debug("Malformed key-value pair", helpers.String("pair", pair)) continue } - // Trim whitespace from key and value and add to the map - key := strings.TrimSpace(parts[0]) - value := strings.TrimSpace(parts[1]) - - result[key] = value + result[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) } return result From b9b663de89896663a78417298ecd91870530e846 Mon Sep 17 00:00:00 2001 From: Yakir Oren Date: Sun, 25 Jan 2026 08:59:56 +0200 Subject: [PATCH 2/3] remove redundant call to getRuleExpressions Signed-off-by: Yakir Oren --- pkg/rulemanager/rule_manager.go | 8 ++++---- pkg/rulemanager/rulepolicy.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/rulemanager/rule_manager.go b/pkg/rulemanager/rule_manager.go index 408631e5a5..9c3de0de13 100644 --- a/pkg/rulemanager/rule_manager.go +++ b/pkg/rulemanager/rule_manager.go @@ -204,10 +204,10 @@ func (rm *RuleManager) ReportEnrichedEvent(enrichedEvent *events.EnrichedEvent) continue } - ruleExpressions := rm.getRuleExpressions(rule, eventType) - if len(ruleExpressions) == 0 { - continue - } + //ruleExpressions := rm.getRuleExpressions(rule, eventType) + //if len(ruleExpressions) == 0 { + // continue + //} if rule.SupportPolicy && rm.validateRulePolicy(rule, enrichedEvent.Event, enrichedEvent.ContainerID) { continue diff --git a/pkg/rulemanager/rulepolicy.go b/pkg/rulemanager/rulepolicy.go index 4ef1092b39..9a58943b00 100644 --- a/pkg/rulemanager/rulepolicy.go +++ b/pkg/rulemanager/rulepolicy.go @@ -46,10 +46,10 @@ func RuleAppliesToContext(rule *typesv1.Rule, contextInfo contextdetection.Conte var hasContextTags bool for _, tag := range rule.Tags { if ctx, found := strings.CutPrefix(tag, "context:"); found { - hasContextTags = true if ctx == string(currentContext) { return true } + hasContextTags = true } } From 2e826b34cec65d6fcafa6732c2759fc57c755e32 Mon Sep 17 00:00:00 2001 From: Yakir Oren Date: Sun, 25 Jan 2026 15:51:24 +0200 Subject: [PATCH 3/3] remove pod label and update deps Signed-off-by: Yakir Oren --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/cloudmetadata/metadata.go | 2 +- pkg/rulemanager/rule_manager.go | 8 ++++---- pkg/rulemanager/ruleadapters/adapters/common.go | 4 +++- pkg/rulemanager/ruleadapters/adapters/pool.go | 2 +- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 684ea733fc..40b41a800d 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.4.0 github.com/anchore/syft v1.32.0 github.com/aquilax/truncate v1.0.0 - github.com/armosec/armoapi-go v0.0.663 + github.com/armosec/armoapi-go v0.0.667 github.com/armosec/utils-k8s-go v0.0.35 github.com/cenkalti/backoff v2.2.1+incompatible github.com/cenkalti/backoff/v4 v4.3.0 @@ -33,7 +33,7 @@ require ( github.com/joncrlsn/dque v0.0.0-20241024143830-7723fd131a64 github.com/kubescape/backend v0.0.25 github.com/kubescape/go-logger v0.0.24 - github.com/kubescape/k8s-interface v0.0.200 + github.com/kubescape/k8s-interface v0.0.202 github.com/kubescape/storage v0.0.221 github.com/kubescape/workerpool v0.0.0-20250526074519-0e4a4e7f44cf github.com/moby/sys/mountinfo v0.7.2 diff --git a/go.sum b/go.sum index 4249ce6e70..73feed110b 100644 --- a/go.sum +++ b/go.sum @@ -761,8 +761,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/armosec/armoapi-go v0.0.663 h1:Ht8eBIY8y3VbFhtvfzdwjMsgiVX7K3dURp6qfBwz8Jo= -github.com/armosec/armoapi-go v0.0.663/go.mod h1:9jAH0g8ZsryhiBDd/aNMX4+n10bGwTx/doWCyyjSxts= +github.com/armosec/armoapi-go v0.0.667 h1:LrFowKvthnL676Gx+hjhvqP4pQ2+CjykFO9SdIYDc/c= +github.com/armosec/armoapi-go v0.0.667/go.mod h1:9jAH0g8ZsryhiBDd/aNMX4+n10bGwTx/doWCyyjSxts= github.com/armosec/gojay v1.2.17 h1:VSkLBQzD1c2V+FMtlGFKqWXNsdNvIKygTKJI9ysY8eM= github.com/armosec/gojay v1.2.17/go.mod h1:vuvX3DlY0nbVrJ0qCklSS733AWMoQboq3cFyuQW9ybc= github.com/armosec/utils-go v0.0.58 h1:g9RnRkxZAmzTfPe2ruMo2OXSYLwVSegQSkSavOfmaIE= @@ -1469,8 +1469,8 @@ github.com/kubescape/backend v0.0.25 h1:PLESA7KGJskebR5hiSqPeJ1cPQ8Ra+4yNYXKyIej github.com/kubescape/backend v0.0.25/go.mod h1:FpazfN+c3Ucuvv4jZYCnk99moSBRNMVIxl5aWCZAEBo= github.com/kubescape/go-logger v0.0.24 h1:JRNlblY16Ty7hD6MSYNPvWYDxNzVAufsDDX/sZJayL0= github.com/kubescape/go-logger v0.0.24/go.mod h1:sMPVCr3VpW/e+SeMaXig5kClGvmZbDXN8YktUeNU4nY= -github.com/kubescape/k8s-interface v0.0.200 h1:Ff64dlDigg8dDYJuaeLFFjfTCHQNC1SStWNECWFRCYE= -github.com/kubescape/k8s-interface v0.0.200/go.mod h1:j9snZbH+RxOaa1yG/bWgTClj90q7To0rGgQepxy4b+k= +github.com/kubescape/k8s-interface v0.0.202 h1:yu9x+07crFQAgrBatFFU2WuuxMJfHUMHVuCzuHE9Q4M= +github.com/kubescape/k8s-interface v0.0.202/go.mod h1:d4NVhL81bVXe8yEXlkT4ZHrt3iEppEIN39b8N1oXm5s= github.com/kubescape/storage v0.0.221 h1:HLWnNokkKgKo9ka/p797fFQdsbzKxSXT5/RpUWrKWzI= github.com/kubescape/storage v0.0.221/go.mod h1:L/fF3teor8cUj80TVujqy9E1rKsf+Dox2hZtkS1vjOU= github.com/kubescape/workerpool v0.0.0-20250526074519-0e4a4e7f44cf h1:hI0jVwrB6fT4GJWvuUjzObfci1CUknrZdRHfnRVtKM0= diff --git a/pkg/cloudmetadata/metadata.go b/pkg/cloudmetadata/metadata.go index c752632a95..1171f3b80c 100644 --- a/pkg/cloudmetadata/metadata.go +++ b/pkg/cloudmetadata/metadata.go @@ -39,7 +39,7 @@ func GetCloudMetadata(ctx context.Context, client *k8sinterface.KubernetesApi, n } func enrichCloudMetadataForAWS(ctx context.Context, client *k8sinterface.KubernetesApi, cMetadata *apitypes.CloudMetadata) { - if cMetadata == nil || cMetadata.Provider != k8sInterfaceCloudMetadata.ProviderAWS || cMetadata.AccountID != "" { + if cMetadata == nil || cMetadata.Provider != apitypes.ProviderAws || cMetadata.AccountID != "" { return } diff --git a/pkg/rulemanager/rule_manager.go b/pkg/rulemanager/rule_manager.go index 9c3de0de13..408631e5a5 100644 --- a/pkg/rulemanager/rule_manager.go +++ b/pkg/rulemanager/rule_manager.go @@ -204,10 +204,10 @@ func (rm *RuleManager) ReportEnrichedEvent(enrichedEvent *events.EnrichedEvent) continue } - //ruleExpressions := rm.getRuleExpressions(rule, eventType) - //if len(ruleExpressions) == 0 { - // continue - //} + ruleExpressions := rm.getRuleExpressions(rule, eventType) + if len(ruleExpressions) == 0 { + continue + } if rule.SupportPolicy && rm.validateRulePolicy(rule, enrichedEvent.Event, enrichedEvent.ContainerID) { continue diff --git a/pkg/rulemanager/ruleadapters/adapters/common.go b/pkg/rulemanager/ruleadapters/adapters/common.go index 4d22228212..e485d28a79 100644 --- a/pkg/rulemanager/ruleadapters/adapters/common.go +++ b/pkg/rulemanager/ruleadapters/adapters/common.go @@ -23,7 +23,9 @@ func ConvertToMap(e utils.EnrichEvent) map[string]interface{} { //k8s["node"] = e.K8s.Node k8s["namespace"] = e.GetNamespace() k8s["podName"] = e.GetPod() - k8s["podLabels"] = e.GetPodLabels() + + //k8s["podLabels"] = e.GetPodLabels() + k8s["containerName"] = e.GetContainer() k8s["hostNetwork"] = e.GetHostNetwork() diff --git a/pkg/rulemanager/ruleadapters/adapters/pool.go b/pkg/rulemanager/ruleadapters/adapters/pool.go index 778cf46e5a..8d2200d0b4 100644 --- a/pkg/rulemanager/ruleadapters/adapters/pool.go +++ b/pkg/rulemanager/ruleadapters/adapters/pool.go @@ -7,7 +7,7 @@ import "sync" // for the number of keys in your event maps. var mapPool = sync.Pool{ New: func() interface{} { - return make(map[string]interface{}, 32) + return make(map[string]interface{}, 5) }, }