diff --git a/README.md b/README.md index f9a78045a..f21a6a52b 100644 --- a/README.md +++ b/README.md @@ -348,7 +348,7 @@ spec: | Helper | v1 Behaviour | Note | |--------|-------------|------| -| `wasExecutedWithArgs(containerID, path, args)` | Equivalent to `wasExecuted(containerID, path)` — the `args` list is validated for type correctness but is **not** matched against the recorded argument list. Any execution of the given path returns `true` regardless of its arguments. | Full per-argument matching (`ExecArgsByPath`) will be added in a future version. | +| `wasExecutedWithArgs(containerID, path, args)` | Matches the `(path, args)` pair against the profile's exec entries. Argument matching is wildcard-aware: `*` zero-or-more and `⋯` exactly-one tokens are honoured per the v0.0.2 argv vocabulary. | Per-argument matching via the `ExecsByPath` composite-key surface (see `projection_apply.go`). | For the full list of rules, see the [Kubescape documentation](https://kubescape.io/docs/). diff --git a/pkg/objectcache/containerprofilecache/projection_trie.go b/pkg/objectcache/containerprofilecache/projection_trie.go index e4c3a793e..d7db14cd6 100644 --- a/pkg/objectcache/containerprofilecache/projection_trie.go +++ b/pkg/objectcache/containerprofilecache/projection_trie.go @@ -2,9 +2,11 @@ package containerprofilecache import "strings" -// trie implements a simple byte-level prefix trie for O(n) prefix matching -// where n is the length of the query string. Used by FieldSpec for prefix and -// suffix (reversed-insertion) matching. +// trie implements a simple rune-keyed prefix trie for O(n) prefix matching +// where n is the number of runes in the query string. Used by FieldSpec for +// prefix and suffix (reversed-insertion) matching. The children map is keyed +// by rune so multi-byte UTF-8 codepoints (e.g. `⋯`) are treated as a single +// step rather than as their byte sequence. type trie struct { children map[rune]*trie terminal bool // true if this node marks the end of an inserted pattern diff --git a/pkg/rulemanager/cel/libraries/cache/function_cache.go b/pkg/rulemanager/cel/libraries/cache/function_cache.go index 1990f0dac..448ac705e 100644 --- a/pkg/rulemanager/cel/libraries/cache/function_cache.go +++ b/pkg/rulemanager/cel/libraries/cache/function_cache.go @@ -112,8 +112,11 @@ func HashForContainerProfile(oc objectcache.ObjectCache) func([]ref.Val) string func (fc *FunctionCache) WithCache(fn CelFunction, functionName string, extraKeyFn ...func([]ref.Val) string) CelFunction { return func(values ...ref.Val) ref.Val { key := fc.generateCacheKey(functionName, values...) - for _, fn := range extraKeyFn { - key += "|" + fn(values) + for _, keyFn := range extraKeyFn { + if keyFn == nil { + continue + } + key += "|" + keyFn(values) } if cached, found := fc.cache.Get(key); found { diff --git a/pkg/rulemanager/profilehelper/profilehelper.go b/pkg/rulemanager/profilehelper/profilehelper.go index a5a768875..929cdd740 100644 --- a/pkg/rulemanager/profilehelper/profilehelper.go +++ b/pkg/rulemanager/profilehelper/profilehelper.go @@ -10,6 +10,9 @@ import ( // GetProjectedContainerProfile returns the ProjectedContainerProfile for a containerID plus its // SyncChecksum annotation value. func GetProjectedContainerProfile(objectCache objectcache.ObjectCache, containerID string) (*objectcache.ProjectedContainerProfile, string, error) { + if objectCache == nil { + return nil, "", errors.New("no object cache available") + } cpc := objectCache.ContainerProfileCache() if cpc == nil { return nil, "", errors.New("no container profile cache available") diff --git a/tests/resources/network-wildcards/README.md b/tests/resources/network-wildcards/README.md index 305e8f914..bc16e092e 100644 --- a/tests/resources/network-wildcards/README.md +++ b/tests/resources/network-wildcards/README.md @@ -11,11 +11,11 @@ directly; users learning the syntax can copy-paste them as authoritative examples. **Note on `14-recursive-star-rejected.yaml`:** this fixture is intentionally -**rejected at admission** — it carries `dnsNames: ["**"]` to demonstrate -that the recursive-wildcard token is invalid v0.0.2 syntax. Don't `kubectl -apply` it; the apiserver will return a 400. The runtime matcher also -defends by silently dropping it on read, so a broken admission layer -won't accidentally let it through. +**rejected at admission** — it carries `dnsNames: ["**.example.com."]` to +exercise the recursive-`**` token in a realistic position and demonstrate +that it is invalid v0.0.2 syntax. Don't `kubectl apply` it; the apiserver +will return a 400. The runtime matcher also defends by silently dropping +it on read, so a broken admission layer won't accidentally let it through. ## Wildcard token vocabulary (matches paths + argv vocabulary) @@ -71,7 +71,7 @@ the `(observedIP, observedDNS) → expected match result` triples that ## Migration note -Producers writing v0.0.2-conformant SBoBs SHOULD use `ipAddresses` (plural). +Producers writing v0.0.2-conformant SBOBs SHOULD use `ipAddresses` (plural). The singular `ipAddress` is retained ONLY for back-compat with v0.0.1-era profiles; producers MUST NOT populate both on the same entry (the apiserver admission strategy rejects this).