chore: deprecate old profiletypes in favor of containerprofiles - #864
Conversation
… -> ContainerProfile ConvertUserProfilesToContainerProfile produces the single user-defined ContainerProfile equivalent to a legacy user-authored ApplicationProfile + NetworkNeighborhood pair, reusing the existing projectUserProfiles merge onto an empty base. The differential oracle pins the migration contract at the enforcement level: for representative user-defined shapes (opens/exec argv wildcards, HTTP endpoints, egress/ingress + LabelSelector) the ProjectedContainerProfile from the legacy AP+NN overlay path equals the one from using the converted ContainerProfile as the base with no overlay. Behaviour-preserving by construction. Signed-off-by: entlein <einentlein@gmail.com>
…e authoritative base When the user-defined-profile pod label names a ContainerProfile carrying managed-by: User, the cache now uses it directly as the container's base profile (the migrated "new way"), instead of overlaying a legacy ApplicationProfile + NetworkNeighborhood pair. It falls back to the legacy AP+NN pair when no such CP exists, which still fires the existing deprecation signal. - add-time (tryPopulateEntry) and refresh (reconciler) both prefer the user CP, gated on the managed-by: User annotation so a learned CP at the same name is never mistaken for a user-defined one - UserCPRef/UserCPRV bookkeeping mirrors the legacy UserAPRV/UserNNRV RV tracking so the reconciler re-fetches and rebuilds only when the user CP changes Signed-off-by: entlein <einentlein@gmail.com>
Test_28 now creates one ContainerProfile (managed-by: User) carrying the merged exec/syscall + egress/selector surfaces, instead of a separate user-authored ApplicationProfile + NetworkNeighborhood pair — exercising the migrated read-path end to end. Assertions unchanged. Signed-off-by: entlein <einentlein@gmail.com>
…verlay The new path (converted CP as base, no overlay) is ~35% faster and allocates ~27% less than the legacy AP+NN overlay per projection, since it skips the two-object merge. Signed-off-by: entlein <einentlein@gmail.com>
Test_27 (opens R0002, both the regex and the curl-wildcard profile sites), Test_32 (R0040 argv wildcards), and Test_33 (opens wildcard anchoring — the previously-fixed one) now each create a single user-defined ContainerProfile (managed-by: User) carrying the merged exec/open/syscall (+ egress/selector for 32) surfaces, replacing the legacy ApplicationProfile + NetworkNeighborhood pair. Assertions unchanged. Test_28 was ported in an earlier commit. Signed-off-by: entlein <einentlein@gmail.com>
containsDynamicSegment recognised only the one-segment DynamicIdentifier
('⋯'), so a path-surface opens entry bearing the zero-or-more
WildcardIdentifier ('*') — e.g. '/etc/ssl/*' — was routed to Values as if it
were a literal. was_path_opened tolerates this (Values and Patterns are both
matched via CompareDynamic), but it is wrong for any consumer that treats
Values as exact membership, and it drops '*'-only entries a rule needs when
spec.All is false and no prefix/suffix matcher retains them. Recognise both
wildcard markers. Regression test pins '/etc/ssl/*' -> Patterns.
Pre-existing in upstream (identical containsDynamicSegment).
Signed-off-by: Entlein <eineintlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Test_33's anchoring subtests assert R0002 alerts, but the rule's file-access monitoring is opt-in (monitored prefixes incl. /etc/). Test_33 never applied r0002-files-access-enabled.yaml (Test_27 does via enableR0002ForTest), so R0002 never evaluated the opens and every 'expect alert' case silently passed as a no-alert — invisible because Test_33 had never run in CI. Enable it like Test_27. Verified on a live cluster: /etc/ssl/* correctly alerts on the bare parent /etc/ssl and stays silent on the child /etc/ssl/openssl.cnf. Signed-off-by: entlein <einentlein@gmail.com>
…tations A user-authored profile is authoritative and complete by definition — it should not carry the learning-lifecycle status/completion markers, nor a managed-by annotation. The pod's user-defined-profile label is what declares it user-authored (a signature, added by the signing tooling, is the integrity marker). - read-path/reconciler no longer gate on managed-by: the label-referenced CP is used as authoritative, and the entry State is forced to Completed+Full so the rule engine enforces it despite the absent completion annotation - the converter emits clean CPs (name + namespace + spec only) - fake client models an absent overlay-name fetch (drives the legacy fallback) Signed-off-by: entlein <einentlein@gmail.com>
…mple - Test_28 now loads its user-defined ContainerProfile from a real yaml (resources/containerprofile-user-defined-network.yaml) via a loader helper, so the fixture doubles as the copy-pasteable "how to author a user-defined profile" example. - The example — and all the test CPs — carry only name + spec: the nonsensical learning-lifecycle annotations (status/completion) and the managed-by marker are dropped (node-agent now treats a label-referenced CP as authoritative and forces the enforce-state itself). Signed-off-by: entlein <einentlein@gmail.com>
Migrate the network-wildcards NetworkNeighborhood fixtures into their user-authored ContainerProfile form so users can copy-paste them to author user-defined-profile allow-lists: - per-container spec.egress/ingress (NN's spec.containers[] collapses, one CP document per container; fixture 20 splits into two) - no lifecycle annotations — name only (namespace injected by tooling), matching the clean user-managed CP contract - teaching comments preserved verbatim from the NN fixtures Adds 00-fusioncore-homoglyph-attack.yaml: a pinned single-vendor allow-list and the look-alike (homoglyph) domains its exact-match dnsNames compare rejects (each fires R0005). All 21 documents strict-parse against v1beta1 ContainerProfile and carry zero annotations (verified). Signed-off-by: entlein <einentlein@gmail.com>
The component tests build their user-defined profiles inline as ContainerProfiles (Test_27/32/33) or load a CP yaml (Test_28); the legacy ApplicationProfile / NetworkNeighborhood fixtures they were derived from are no longer referenced by any Go test. Migrate the two CT-relevant ones to their user-authored CP form and delete the orphan: - exec-arg-wildcards-profile.yaml (AP curl-32-overlay) -> containerprofile-exec-arg-wildcards.yaml. CP form mirrors Test_32's inline CP exactly (same execs incl. busybox-symlink + literal-* entries, same syscalls, matchLabels app: curl-32). Demonstrates the exec-arg wildcard grammar for authoring. - known-network-neighborhood.yaml (NN fusioncore-network) -> containerprofile-fusioncore-network.yaml. Clean user-managed CP: name only, no managed-by / status / completion annotations. - user-profile.yaml: deleted. Zero references anywhere; its nginx/server exec surface matches no current test or deployment. Both new documents strict-parse against v1beta1 ContainerProfile and carry zero annotations (verified). CT compiles unchanged (go vet -tags component); no Go test referenced the deleted files. Signed-off-by: entlein <einentlein@gmail.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR migrates profile handling from legacy ApplicationProfile and NetworkNeighborhood overlays to authored ContainerProfiles. It updates cache refresh, CEL namespaces, storage and watcher APIs, metrics, component tests, and fixtures. ChangesContainerProfile cache and refresh
CEL and integration migration
Platform and test migration
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
pkg/objectcache/containerprofilecache/containerprofilecache.go (1)
380-458: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick winNon-terminal consolidated
cppermanently blocks an already-available authoritative user-defined CP.The terminal-status gate on the consolidated
cp(Lines 380-391) runs beforeuserDefinedCPis fetched (Lines 402-444) and before it replacescp(Lines 455-457). If a pod already has a non-terminal (still-learning) consolidated CP at the moment theuser-defined-profilelabel is added — the exact scenario this PR's migration enables for already-running workloads —tryPopulateEntryreturnsfalseforever, even though a ready, authoritativeuserDefinedCPexists. The pending-retry loop re-runs this same function on every tick, so it hits the same gate every time and never gets past it to checkuserDefinedCP.Fetch the overlay first and skip the gate once it resolves an authoritative profile:
🐛 Proposed fix
- // Only cache profiles whose status is terminal (Completed or TooLarge). - // Learning/ready profiles are still being written; caching them would let - // rules fire against incomplete data. TooLarge is terminal: the manager - // stopped collecting but the truncated data is still valid for detection. - // Return false so the synthetic-CP fallback below does not bypass the gate. - if cp != nil && !isTerminalCPStatus(cp.Annotations[helpersv1.StatusMetadataKey]) { - logger.L().Debug("tryPopulateEntry: CP status not terminal; keeping pending", - helpers.String("containerID", containerID), - helpers.String("namespace", ns), - helpers.String("status", cp.Annotations[helpersv1.StatusMetadataKey])) - return false - } - // Fetch user-authored legacy CRDs when the pod carries the - // UserDefinedProfileMetadataKey label. ... + // UserDefinedProfileMetadataKey label. Fetched before the terminal-status + // gate below so a non-terminal (still-learning) consolidated CP never + // blocks an already-available authoritative user-defined CP. var userAP *v1beta1.ApplicationProfile var userNN *v1beta1.NetworkNeighborhood var userDefinedCP *v1beta1.ContainerProfile overlayName, hasOverlay := container.K8s.PodLabels[helpersv1.UserDefinedProfileMetadataKey] if hasOverlay && overlayName != "" { ... (unchanged fetch logic) } + + // Only cache profiles whose status is terminal (Completed or TooLarge), + // unless an authoritative user-defined CP is already available. + if cp != nil && userDefinedCP == nil && !isTerminalCPStatus(cp.Annotations[helpersv1.StatusMetadataKey]) { + logger.L().Debug("tryPopulateEntry: CP status not terminal; keeping pending", + helpers.String("containerID", containerID), + helpers.String("namespace", ns), + helpers.String("status", cp.Annotations[helpersv1.StatusMetadataKey])) + return false + }The same ordering exists in
refreshOneEntry(reconciler.go Lines 301-332 run the terminal-check before the userDefinedCP re-fetch at Lines 406-427); worth the same fix there once addressed here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/objectcache/containerprofilecache/containerprofilecache.go` around lines 380 - 458, Reorder the user-defined profile lookup in tryPopulateEntry so userDefinedCP is fetched before the consolidated cp terminal-status gate. Allow processing to continue when an authoritative userDefinedCP is available, while retaining the existing gate for non-terminal cp without one. Apply the same ordering and bypass behavior in refreshOneEntry, preserving legacy fallback handling.tests/component_test.go (1)
2250-2261: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winRemove unneeded metadata labels from the user-defined container profile.
ApiGroupMetadataKey,ApiVersionMetadataKey, andRelated*metadata labels are not consulted when selecting/projecting a user-definedContainerProfile; the cache useskubescape.io/user-defined-profile. Strip these labels on the inline CP so the fixture matches the documented “name + spec” contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/component_test.go` around lines 2250 - 2261, Update the inline ContainerProfile fixture in the component test to remove ApiGroupMetadataKey, ApiVersionMetadataKey, and all Related* metadata labels, leaving only the metadata required by the documented name-and-spec contract and the cache’s kubescape.io/user-defined-profile label if applicable.
🧹 Nitpick comments (5)
pkg/objectcache/containerprofilecache/containerprofilecache_test.go (1)
221-256: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMissing regression coverage for a failed initial CP fetch.
This test only covers the happy path (successful
userCPfetch). Consider adding a case where the initialGetContainerProfilecall for the overlay name fails (e.g.cpErron that name) and a lateraddContainer/refresh succeeds — this is exactly the scenario whereUserCPRefbookkeeping needs to survive a failed first attempt (see the critical issue raised incontainerprofilecache.goLines 402-546).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/objectcache/containerprofilecache/containerprofilecache_test.go` around lines 221 - 256, Add regression coverage alongside TestOverlayPath_UserDefinedCP_NewWay for an initial user-defined ContainerProfile fetch failure: configure the fake client to return cpErr for the overlay name, call addContainer, then make the later fetch succeed and trigger addContainer or refresh. Assert the eventual projection succeeds and UserCPRef/UserCPRV are preserved, verifying the bookkeeping survives the failed first attempt.tests/resources/containerprofile-user-defined-network.yaml (1)
58-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRedundant deprecated singular fields (
dns,ipAddress) alongside their plural equivalents.This egress entry sets
dnsanddnsNamesto the same value, and uses singularipAddress— all legacy/deprecated forms per this PR's own08-deprecated-ipaddress.yamlfixture. As an authoring example for "the new way," consider keeping only the canonical plural fields to avoid ambiguity for authors copying this example.📝 Suggested fix
egress: - identifier: fusioncore-egress type: external - dns: fusioncore.ai. dnsNames: - fusioncore.ai. - ipAddress: 162.0.217.171 + ipAddresses: + - 162.0.217.171 ports:🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/resources/containerprofile-user-defined-network.yaml` around lines 58 - 68, Update the fusioncore-egress entry in the user-defined network fixture to remove the deprecated singular dns and ipAddress fields, retaining the canonical dnsNames and existing ports configuration.tests/component_test.go (1)
1653-1657: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStale doc comment: still describes
ApplicationProfile.The
deployWithProfilehelper now builds av1beta1.ContainerProfile(Lines 1661-1679), but the preceding doc comment still says "creates a user-defined ApplicationProfile." Update it to avoid misleading future readers.📝 Suggested fix
- // deployWithProfile creates a user-defined ApplicationProfile with the + // deployWithProfile creates a user-defined ContainerProfile with the // given Opens list, polls until it is retrievable from storage, then // deploys nginx with the kubescape.io/user-defined-profile label // pointing at it, and waits for the pod to be ready.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/component_test.go` around lines 1653 - 1657, Update the doc comment for the deployWithProfile helper to describe creation of a user-defined v1beta1.ContainerProfile instead of an ApplicationProfile, while preserving the existing description of its deployment and readiness behavior.tests/resources/containerprofile-fusioncore-network.yaml (1)
25-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUses deprecated singular
ipAddressin a "new way" authoring example.Elsewhere in this PR (
network-wildcards-cp/08-deprecated-ipaddress.yaml, README) the singularipAddressfield is documented as deprecated in favor of pluralipAddresses. Since this fixture's own comment frames it as the "new way" ContainerProfile authoring example, consider using the canonicalipAddresses: ["162.0.217.171"]form for consistency.📝 Suggested fix
dnsNames: - fusioncore.ai. - ipAddress: 162.0.217.171 + ipAddresses: + - 162.0.217.171 ports:🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/resources/containerprofile-fusioncore-network.yaml` around lines 25 - 34, Update the egress entry in the ContainerProfile example to replace the deprecated singular ipAddress field with the canonical ipAddresses field containing 162.0.217.171, while preserving the existing network rule and other fields.tests/resources/network-wildcards-cp/07-mixed-ip-list.yaml (1)
8-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAlign the fixture description with the actual matching path.
Because
*makes every valid IP match, this fixture cannot exercise list ordering or first-match behavior. Either remove those claims or use a mixed literal/CIDR case without*; keep this fixture focused on accepting mixed forms with the sentinel.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/resources/network-wildcards-cp/07-mixed-ip-list.yaml` around lines 8 - 13, Update the comments in the mixed IP list fixture to remove claims that it tests list ordering, loop ordering, or first-match short-circuiting, since the sentinel `*` matches every valid IP. Keep the description focused on accepting mixed literal/CIDR forms with the unconstrained sentinel.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/objectcache/containerprofilecache/containerprofilecache.go`:
- Around line 402-444: Record UserCPRef whenever a non-empty user-defined
profile label is present, even when the initial GetContainerProfile call fails,
so refreshOneEntry can retry it later. In rebuildEntryFromSources, clear
UserAPRef and UserNNRef when userDefinedCP becomes authoritative, preserving the
mutually exclusive reference invariant while retaining legacy refs only when no
user CP is available.
In `@tests/resources/network-wildcards-cp/13-dns-trailing-dot-normalisation.yaml`:
- Around line 5-10: Update the YAML fixture’s profile entries to match its
documented cases: replace the api.github.com entry with api.stripe.com if
testing both trailing-dot forms, and ensure the expectations in both referenced
sections consistently describe the actual profile-side hostname.
---
Outside diff comments:
In `@pkg/objectcache/containerprofilecache/containerprofilecache.go`:
- Around line 380-458: Reorder the user-defined profile lookup in
tryPopulateEntry so userDefinedCP is fetched before the consolidated cp
terminal-status gate. Allow processing to continue when an authoritative
userDefinedCP is available, while retaining the existing gate for non-terminal
cp without one. Apply the same ordering and bypass behavior in refreshOneEntry,
preserving legacy fallback handling.
In `@tests/component_test.go`:
- Around line 2250-2261: Update the inline ContainerProfile fixture in the
component test to remove ApiGroupMetadataKey, ApiVersionMetadataKey, and all
Related* metadata labels, leaving only the metadata required by the documented
name-and-spec contract and the cache’s kubescape.io/user-defined-profile label
if applicable.
---
Nitpick comments:
In `@pkg/objectcache/containerprofilecache/containerprofilecache_test.go`:
- Around line 221-256: Add regression coverage alongside
TestOverlayPath_UserDefinedCP_NewWay for an initial user-defined
ContainerProfile fetch failure: configure the fake client to return cpErr for
the overlay name, call addContainer, then make the later fetch succeed and
trigger addContainer or refresh. Assert the eventual projection succeeds and
UserCPRef/UserCPRV are preserved, verifying the bookkeeping survives the failed
first attempt.
In `@tests/component_test.go`:
- Around line 1653-1657: Update the doc comment for the deployWithProfile helper
to describe creation of a user-defined v1beta1.ContainerProfile instead of an
ApplicationProfile, while preserving the existing description of its deployment
and readiness behavior.
In `@tests/resources/containerprofile-fusioncore-network.yaml`:
- Around line 25-34: Update the egress entry in the ContainerProfile example to
replace the deprecated singular ipAddress field with the canonical ipAddresses
field containing 162.0.217.171, while preserving the existing network rule and
other fields.
In `@tests/resources/containerprofile-user-defined-network.yaml`:
- Around line 58-68: Update the fusioncore-egress entry in the user-defined
network fixture to remove the deprecated singular dns and ipAddress fields,
retaining the canonical dnsNames and existing ports configuration.
In `@tests/resources/network-wildcards-cp/07-mixed-ip-list.yaml`:
- Around line 8-13: Update the comments in the mixed IP list fixture to remove
claims that it tests list ordering, loop ordering, or first-match
short-circuiting, since the sentinel `*` matches every valid IP. Keep the
description focused on accepting mixed literal/CIDR forms with the unconstrained
sentinel.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4b7c84a9-bef1-4de2-8db4-3ffe8bc86801
📒 Files selected for processing (36)
pkg/objectcache/containerprofilecache/containerprofilecache.gopkg/objectcache/containerprofilecache/containerprofilecache_test.gopkg/objectcache/containerprofilecache/projection_apply.gopkg/objectcache/containerprofilecache/projection_wildcard_classification_test.gopkg/objectcache/containerprofilecache/reconciler.gopkg/objectcache/containerprofilecache/reconciler_test.gotests/component_test.gotests/resources/containerprofile-exec-arg-wildcards.yamltests/resources/containerprofile-fusioncore-network.yamltests/resources/containerprofile-user-defined-network.yamltests/resources/exec-arg-wildcards-profile.yamltests/resources/known-network-neighborhood.yamltests/resources/network-wildcards-cp/00-fusioncore-homoglyph-attack.yamltests/resources/network-wildcards-cp/01-literal-ipv4.yamltests/resources/network-wildcards-cp/02-literal-ipv6.yamltests/resources/network-wildcards-cp/03-cidr-ipv4.yamltests/resources/network-wildcards-cp/04-cidr-ipv6.yamltests/resources/network-wildcards-cp/05-any-ip-sentinel.yamltests/resources/network-wildcards-cp/06-any-as-cidr.yamltests/resources/network-wildcards-cp/07-mixed-ip-list.yamltests/resources/network-wildcards-cp/08-deprecated-ipaddress.yamltests/resources/network-wildcards-cp/09-dns-literal.yamltests/resources/network-wildcards-cp/10-dns-leading-wildcard.yamltests/resources/network-wildcards-cp/11-dns-mid-ellipsis.yamltests/resources/network-wildcards-cp/12-dns-trailing-star.yamltests/resources/network-wildcards-cp/13-dns-trailing-dot-normalisation.yamltests/resources/network-wildcards-cp/14-recursive-star-rejected.yamltests/resources/network-wildcards-cp/15-egress-and-ingress.yamltests/resources/network-wildcards-cp/16-egress-none.yamltests/resources/network-wildcards-cp/17-realistic-stripe-api.yamltests/resources/network-wildcards-cp/18-cluster-dns-via-mid-ellipsis.yamltests/resources/network-wildcards-cp/19-port-protocol-with-cidr.yamltests/resources/network-wildcards-cp/20-multi-container-mixed-wildcards.yamltests/resources/network-wildcards-cp/README.mdtests/resources/network-wildcards/README.mdtests/resources/user-profile.yaml
💤 Files with no reviewable changes (4)
- tests/resources/user-profile.yaml
- tests/resources/exec-arg-wildcards-profile.yaml
- tests/resources/network-wildcards/README.md
- tests/resources/known-network-neighborhood.yaml
… decommission them -step 1 of many -- I understand that this has a long tail of decommissions Signed-off-by: entlein <einentlein@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
pkg/objectcache/containerprofilecache/reconciler.go (2)
380-388: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winHandle
NotFoundas deletion rather than a transient error.Once
UserCPRVis set, every fetch error preserves the cached authoritative policy. Deleting the referenced CP therefore leaves its old policy enforced indefinitely instead of rebuilding from the learned CP. Return early only for non-NotFoundfailures; letNotFoundsetuserDefinedCPto nil so the RV mismatch triggers a rebuild.Proposed fix
- if userCPErr != nil && e.UserCPRV != "" { + if userCPErr != nil && e.UserCPRV != "" && !apierrors.IsNotFound(userCPErr) { logger.L().Debug("refreshOneEntry: user-defined CP fetch failed; keeping cached entry", helpers.String("containerID", id), helpers.String("name", e.UserCPRef.Name), helpers.Error(userCPErr)) return }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/objectcache/containerprofilecache/reconciler.go` around lines 380 - 388, Update the user-defined CP error handling in refreshOneEntry so cached policy is preserved only for non-NotFound fetch failures. Detect the NotFound condition before the early return, allow it to continue with userDefinedCP set to nil, and retain the existing return behavior for other errors so the RV mismatch triggers rebuilding.
369-379: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winValidate that the referenced CP is user-managed before adopting it.
The migration contract identifies this source as
managed-by: User, but this path accepts any same-name CP. A learned CP can bypass the terminal-status gate above and then be forced toCompleted/Fullin the rebuilt entry. Reject or ignore profiles withoutManagedByMetadataKey == ManagedByUserValue, with coverage for an invalid reference.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/objectcache/containerprofilecache/reconciler.go` around lines 369 - 379, Validate the ContainerProfile fetched in the UserCPRef refresh within the reconciler before adopting it. Only accept profiles whose ManagedByMetadataKey equals ManagedByUserValue; ignore or reject invalid references so learned profiles cannot bypass terminal-status handling. Add coverage for a referenced profile with invalid management metadata, while preserving transient fetch-error behavior.
🧹 Nitpick comments (1)
pkg/objectcache/containerprofilecache/containerprofilecache_test.go (1)
223-226: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert that the user CP is the effective policy.
These assertions only prove it was fetched and recorded. A regression could retain the learned/synthetic CP while copying
UserCPRef/RV and still pass. Assert a user-CP-specific projected value, or at minimumentry.State.Name == "override".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/objectcache/containerprofilecache/containerprofilecache_test.go` around lines 223 - 226, Strengthen the assertions in the user-defined CP test to verify the user CP is the effective policy, not merely recorded for refresh. After the existing UserCPRef checks, assert the projected profile contains a user-CP-specific value or, at minimum, that entry.State.Name equals "override"; keep the existing fetch and reference assertions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/resources/nnlint_test.go`:
- Around line 176-211: Update lintEndpoint to apply the existing dnsNameProblem
validation to the singular e.DNS value and validIPEntry validation to the
singular e.IPAddress value, in addition to the plural DNSNames and IPAddresses
loops. Emit the same R-NN-13 and R-NN-15 rules with contextual messages so
malformed deprecated fields are reported.
---
Outside diff comments:
In `@pkg/objectcache/containerprofilecache/reconciler.go`:
- Around line 380-388: Update the user-defined CP error handling in
refreshOneEntry so cached policy is preserved only for non-NotFound fetch
failures. Detect the NotFound condition before the early return, allow it to
continue with userDefinedCP set to nil, and retain the existing return behavior
for other errors so the RV mismatch triggers rebuilding.
- Around line 369-379: Validate the ContainerProfile fetched in the UserCPRef
refresh within the reconciler before adopting it. Only accept profiles whose
ManagedByMetadataKey equals ManagedByUserValue; ignore or reject invalid
references so learned profiles cannot bypass terminal-status handling. Add
coverage for a referenced profile with invalid management metadata, while
preserving transient fetch-error behavior.
---
Nitpick comments:
In `@pkg/objectcache/containerprofilecache/containerprofilecache_test.go`:
- Around line 223-226: Strengthen the assertions in the user-defined CP test to
verify the user CP is the effective policy, not merely recorded for refresh.
After the existing UserCPRef checks, assert the projected profile contains a
user-CP-specific value or, at minimum, that entry.State.Name equals "override";
keep the existing fetch and reference assertions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 394d9bb1-b653-454c-8c2e-9dd9ea0f41d9
📒 Files selected for processing (8)
pkg/objectcache/containerprofilecache/containerprofilecache.gopkg/objectcache/containerprofilecache/containerprofilecache_test.gopkg/objectcache/containerprofilecache/export_test.gopkg/objectcache/containerprofilecache/reconciler.gopkg/objectcache/containerprofilecache/reconciler_test.gopkg/objectcache/containerprofilecache/t8_overlay_refresh_test.gotests/resources/network-wildcards-cp/13-dns-trailing-dot-normalisation.yamltests/resources/nnlint_test.go
💤 Files with no reviewable changes (3)
- pkg/objectcache/containerprofilecache/t8_overlay_refresh_test.go
- pkg/objectcache/containerprofilecache/export_test.go
- pkg/objectcache/containerprofilecache/reconciler_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/resources/network-wildcards-cp/13-dns-trailing-dot-normalisation.yaml
- pkg/objectcache/containerprofilecache/containerprofilecache.go
| // the container stays pending; UserCPRef — recorded unconditionally below — | ||
| // drives the reconciler to retry the CP on every tick until it materialises. | ||
| var userDefinedCP *v1beta1.ContainerProfile | ||
| overlayName, hasOverlay := container.K8s.PodLabels[helpersv1.UserDefinedProfileMetadataKey] |
There was a problem hiding this comment.
Every container in the pod resolves the same overlayName and adopts the same CP — the binding is a pod label, but a ContainerProfile is per-container. A sidecar inherits the app container's allow-list and vice versa.
The legacy path handled this: projectUserProfiles(..., container.Runtime.ContainerName) selected the matching spec.containers[] entry across containers / initContainers / ephemeralContainers. Nothing replaces it.
We need either a naming convention the read path derives (<label-value>-<containerName>, falling back to the bare name for single-container pods) or a container selector inside the CP spec.
Worth settling before the storage PR locks the shape in — tests/resources/network-wildcards-cp/README.md already documents "one CP document per container", and fixture 20 emits nw-20-multi-container-frontend + nw-20-multi-container-sidecar, but nothing can currently bind either one to a specific container.
There was a problem hiding this comment.
Addressed. The read path now derives a per-container slug and only falls back to the bare name:
containerprofilecache.go:344perContainerName := overlayName + "-" + container.Runtime.ContainerName- fetched at
:347, and only if that 404s does it fall back to the bareoverlayName(:358).
So a sidecar resolves <overlay>-<sidecarName>, not the app container's CP. Covered end-to-end by TestUserDefinedCP_PerContainerBinding (containerprofilecache_test.go:399) — asserts each container resolves its own per-container CP — and TestUserDefinedCP_SingleContainerBareFallback for the fallback.
| // test is only that iteration stopped early. | ||
| } | ||
|
|
||
| // TestRefreshFastSkipWhenAllRVsMatch — delta #4. When CP RV and both overlay |
There was a problem hiding this comment.
We should migrate these tests to CPs rather than drop them. This hunk and the ones below remove every refresh-path overlay test (−274 here, −114 in t8_overlay_refresh_test.go), and nothing replaces them for the user-CP path — TestOverlayPath_UserDefinedCP_NewWay only covers the add path. That's why the entry.RV bug is green in CI.
The four worth restoring in CP form:
- fast-skip when the CP RV and
UserCPRVboth match (TestRefreshFastSkipWhenAllRVsMatch) - rebuild when only
UserCPRVchanges (TestRefreshRebuildsOnUserAPChange) - end-to-end: edit the authored CP in the fake, one
refreshAllEntries, assert the projection reflects the edit (TestT8_EndToEndRefreshUpdatesProjection) — this is the one that catches the freeze - user-defined CP present with no learned CP (
TestUserDefinedProfileOnly_NoBaseCP)
countingProfileClient.GetContainerProfile (:78) also ignores its name argument, so it can't distinguish base from authored CP — it needs the same name-matching treatment fakeProfileClient just got. And countingMetrics.legacyLoad (:129) is now unused after these deletions; unused/staticcheck will flag it.
There was a problem hiding this comment.
Addressed — migrated to CP form rather than dropped. The four you named now exist against the user-CP path:
- fast-skip when CP RV and UserCPRV both match →
TestRefreshUserCP_FastSkipWhenRVsMatch(containerprofilecache_test.go:595) - rebuild when only UserCPRV changes →
TestRefreshUserCP_RebuildWhenUserCPRVChanges(:634) - rebuild on learned-CP RV change →
TestRefreshRebuildsOnCPChange(reconciler_test.go:326) - the
entry.RVfreeze this exposed →TestRefreshReflectsAuthoredCPEdit_RVFreezeProof(containerprofilecache_test.go:512)
Plus TestRefreshPreservesEntryOnTransientUserCPError and TestRefreshUserCP_NoLearnedCP.
| } | ||
| if entry.UserNNRef == nil { | ||
| entry.UserNNRef = &namespacedName{Namespace: ns, Name: overlayName} | ||
| entry.UserCPRef = &namespacedName{Namespace: ns, Name: overlayName} |
There was a problem hiding this comment.
This forces Completed/Full without ever checking that the fetched CP is user-authored, or that it's finished. The isTerminalCPStatus gate at :375 — "Learning/ready profiles are still being written; caching them would let rules fire against incomplete data" — only guards the base CP fetched by the derived slug at :319. The label-referenced CP fetched at :391-407 gets no equivalent check, becomes the profile at :419-421, and has its real annotations overwritten here.
Tested on this branch: a CP carrying status: ready / completion: partial published at the label's name is cached as Status="completed" Completion="complete". Result is false positives — rules alert on everything legitimate that wasn't learned yet.
3f9299b's gate prevented exactly this; f2f730f removed it on the grounds that a signature is the real integrity marker, but "check signature logic" is still an open TODO, so nothing verifies anything today.
Suggest gating on the negative instead — a learned CP wears lifecycle annotations, an authored one doesn't. This belongs right after the fetch (~:407) or inside the if userDefinedCP != nil below, not at this line, where userDefinedCP may be nil:
if userDefinedCP != nil {
if _, learned := userDefinedCP.Annotations[helpersv1.StatusMetadataKey]; learned {
logger.L().Warning("user-defined-profile label resolves to a learned ContainerProfile; ignoring", ...)
userDefinedCP = nil
}
}That makes "authored profiles carry no annotations" self-enforcing without blocking on the signature work.
There was a problem hiding this comment.
Addressed. A label-referenced CP that is actually a learned profile is now rejected before it can be forced to Completed/Full:
containerprofilecache.go:386-394 — if the fetched user CP carries the status annotation (i.e. it is learned, not authored), it is dropped (userDefinedCP = nil) with a Warning. Only an authored CP (no lifecycle annotations) is adopted.
matthyx
left a comment
There was a problem hiding this comment.
Reviewed locally against main at fd5ed04. The direction is right — one unified user-authored CRD instead of the AP+NN pair is a real simplification, and the commit messages are unusually good at stating the contract each change pins. Two things block, and a couple of design questions are worth settling before this leaves draft.
Blockers
Authored ContainerProfile edits are never picked up. entry.RV ends up holding the authored CP's ResourceVersion, while entry.CPName points at the learned slug — which never exists, because learning is suppressed for user-defined containers. The permanent 404 then reads as a transient error and the entry is frozen for the container's lifetime. I verified this and the two-hunk fix is inline (:419, :466); after it, a refresh test goes red→green and the rest of the package is unchanged. It also fixes the learned+authored case, where the authored RV currently shadows the learned one.
Multi-container pods lose per-container separation. The binding is a pod label but a ContainerProfile is per-container, so every container in the pod adopts the same profile. The old path selected the right spec.containers[] entry by container name; nothing replaces it. Worth noting the PR's own network-wildcards-cp/README.md documents "one CP document per container", which the read path can't currently express — that gap should be closed before the storage PR locks the shape in.
Worth settling
- Nothing validates that the label-referenced CP is user-authored, and its state is force-set to
Completed/Full. A profile withstatus: ready/completion: partialat that name gets enforced as complete — I tested it. 3f9299b's gate prevented exactly this; f2f730f removed it on the grounds that a signature is the real integrity marker, but "check signature logic" is still open on your TODO list, so right now nothing verifies anything. Suggestion inline. - The upgrade path fails silently. A workload still on user-defined AP+NN gets no profile and no warning — just a
Debugline and a container pending forever. AWarning+ metric would make it visible; keeping the AP/NN read behind a deprecation flag for one release would make it safe. Your call which, but "couldn't find any active consumers" is a bet I'd rather not take silently on a security control. - The refresh-path tests were removed where the regressions landed (−274 in
reconciler_test.go, −114 int8_overlay_refresh_test.go), with nothing covering the user-CP path —TestOverlayPath_UserDefinedCP_NewWayonly exercises the add path. That's precisely why the RV bug above is green in CI.countingProfileClient.GetContainerProfilealso ignores itsnameargument, so no reconciler test can currently distinguish base from authored CP. Related:countingMetrics.legacyLoadis now unused and will likely tripunused.
The * classification fix looks right
Checked 903443d against storage: analyze_opens.go:97 uses the same Wildcard || Dynamic test, so this aligns node-agent with the producer, and compareSegmentsIndex only treats a whole segment * as a wildcard — so a path with an embedded literal * still matches literally and no allow-list is broadened. It applies to Execs and Endpoints too, not just Opens; harmless for Endpoints (both Values and Patterns go through CompareDynamic), but the new test only covers Opens — an Execs case would pin it.
The Test_33 R0002 fix (8c82261) is a good catch: a test that had never run in CI and was silently passing every "expect alert" case.
Nits with no anchorable hunk
reconciler.go:224still says "UserAPRV + UserNNRV all match";rebuildEntryFromSources' doc comment (:436-437) still describes the "label-referenced user overlay AP+NN" ladder pass that no longer exists.component_test.go:2343still refers toUserAPRef. Test_28'sconst overlayName = "curl-28-overlay"is now dead, and the comment above it still describes the AP+NN dual lookup — same innginx-user-defined-deployment.yaml:17-18.tests/resources/network-wildcards/README.mdwas deleted, but the NN fixtures it documented are still consumed bypkg/rulemanager/cel/libraries/networkneighborhood/fixtures_test.go:227— those are now undocumented.- No metric or log when an authored CP is adopted; the legacy path emitted overlay metrics, so the new path is a blind spot.
Verified
go build ./pkg/objectcache/..., go test ./pkg/objectcache/... ./tests/resources/, and go vet -tags component ./tests/... all pass on the branch. The two behavioural claims above (frozen entry, forced-complete state) were each confirmed with a purpose-written test run against this branch, then discarded.
| return false | ||
| } |
There was a problem hiding this comment.
This gate (from :375) runs against the learned CP and returns before the authored CP is fetched at :391. So if the label is added to a workload that already has a CP mid-learning, the authored profile is never adopted until that CP reaches a terminal status — even though it's meant to replace it outright. refreshOneEntry:326 has the same ordering.
Simplest fix: fetch the authored CP first and skip this gate entirely when one is present — the learned CP is discarded at :419-421 anyway.
There was a problem hiding this comment.
Reordered. The terminal-status gate now runs only when no authored CP will be used:
containerprofilecache.go:404 if userDefinedCP == nil && cp != nil && !isTerminalCPStatus(...). The authored CP is fetched first (:347/:358), so a mid-learning base CP no longer blocks adopting an authored profile that replaces it.
…storage etc Signed-off-by: entlein <einentlein@gmail.com>
…icontainer labels, tests not reviewed yet Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Co-authored-by: Matthias Bertschy <matthias.bertschy@gmail.com> Signed-off-by: Duck <70207455+entlein@users.noreply.github.com>
Component-test validation (live k3s)Ran the migration CT matrix on a live k3s cluster using the component-test chart pinned to freshly built node-agent + storage images, with CI-faithful config (short learning intervals, R0040 defined + enabled, R0002 self-enabled at runtime, alerts collected via Alertmanager).
Review feedback addressed:
|
| assert.Equal(t, 0, countR0001("app", "id"), | ||
| "id IS in the app section — R0001 in app means the wrong section was enforced") | ||
|
|
||
| // KNOWN LIMITATION — ephemeral container runtime tracing. The debug |
There was a problem hiding this comment.
AI: I thought you solved it, do you start these eph containers with sharedpid-ns or without?
Get a fresh PG and add a CT section on learning the eph/init section (no user-defined labels at all), then use the exact learned schema for the detection.
See above -> maybe there is still a bug in the identation of the whole yaml?
There was a problem hiding this comment.
Answered in a PR-level comment with the full evidence: ephemeral containers are neither learned nor alerted on. The learning manager skips them (ignoring ephemeral container, the guard from #579), while the rule manager still monitors them and then finds no profile (ContainerProfile not yet available ... -ephcon-... not found). Measured on k3s: no ContainerProfile for the eph container and 0 alerts on repeated exec ... -c ephcon -- id.
On the shared-PID-ns question: there is no shareProcessNamespace handling in the code either way. So no dedicated CT here yet — the fix is upstream (remove/relax the guard, or enforce the target container's profile), and the CT for eph learn+alert should follow that.
entlein
left a comment
There was a problem hiding this comment.
AI: please go through the CTs
- restore the learning tests (while keeping the detection tests)
- there are inconsistencies with the overall profile multi-container sections
- those may or may not be the reason why the debug containers dont alert.
…nce when ephermal continers are not being learnt anymore Signed-off-by: entlein <einentlein@gmail.com>
Ephemeral containers are neither learned nor alerted onOrigin. Introduced by PR #579 "Refactor profiles creation" (#579), merged 2025-07-10 (merge commit Behaviour (verified on k3s, kernel 6.1, this branch's images). The two subsystems disagree on ephemeral containers:
So an ephemeral container is watched for events but has no profile, and every profile-dependent rule (R0001, R0003, R0004, …) needs a completed profile to evaluate. Result, measured:
Net: a process run inside an injected/debug ephemeral container ( Fix size. Small on the code side — the rule path is already wired (it monitors the ephemeral container and looks up a
|
@matthyx : do you remember the rational behind excl ephemeral containers from learning/alerting? I d prefer we have this consistent -> either they are ignored (then they are not in the spec) or they get the full |
|
let's give them the full treatment, please |
… due to timeouts Signed-off-by: entlein <einentlein@gmail.com>
|
CT 27 is supposed to fail for this PR (that s the missing opens-gadget redis test) Suggest: follow-up PR that investigates time-out, wait, sleep and other asserts that are not 100% deterministic at the moment. |
Signed-off-by: entlein <einentlein@gmail.com>
|
@matthyx : if you have a second -> would you please kick off the CTs here on the PR so I can see, how much is failing here (our github workflows are not 100 percent identical). |
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
Signed-off-by: entlein <einentlein@gmail.com>
|
Overlay component tests are green on the current Run: https://github.com/k8sstormcenter/node-agent/actions/runs/32068856082
Coverage exercised this round includes: reconcile refresh handling of a deleted vs transiently-unavailable ContainerProfile (learned and authored), add/refresh parity on authored per-subtype resolution, ephemeral-container full treatment, per-subtype authored enforcement, and the grouped-document storage round-trip. We did a further pass over the change set and the storage counterpart and found nothing else outstanding. From our side this is ready for review, or to merge. |
… is set refreshOneEntry's transient-error guards for the learned CP and the authored (label-referenced) CP were gated on the entry already having a previously cached ResourceVersion (e.RV != "" / e.UserCPRV != ""). That gate meant a non-NotFound (transient) error on the *first-ever* fetch of either source fell through instead of returning early, discarding the "we don't actually know the true state" signal. Concretely, for the authored side: an entry can be UserCPRef != nil with UserCPRV == "" right after the overlay label is added, before the first successful authored-CP fetch. If a transient error hits that fetch while, in the same tick, the learned CP genuinely 404s, the function reached the cp == nil && userDefinedCP == nil branch and permanently evicted the entry (profile_deleted), even though the authored side only had a transient blip. This silently dropped enforcement for the container until the next Add event or pod restart. The symmetric case exists on the learned-CP side too: an entry built purely from an authored CP (learned CP never observed, e.RV == "") that hits a transient learned-CP error while the authored CP genuinely 404s in the same tick hit the same eviction path. Fix: drop the e.RV != "" / e.UserCPRV != "" conditions from both guards. A transient (non-NotFound) error on an attempted fetch now always keeps the cached entry as-is and retries next tick, regardless of whether that source had previously resolved successfully. Added TestRefresh_AuthoredCP_TransientErrorBeforeFirstFetchKeepsEntry and TestRefresh_LearnedCP_TransientErrorBeforeFirstFetchKeepsEntry, verified to fail against the pre-fix code and pass with the fix. Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
…drift (#900) Follow-up to #864, split from its review into two CI-hygiene fixes: - component-tests.yaml matrix: Test_12/Test_13 referenced stale function names (Test_12_MergingProfilesTest, Test_13_MergingNetworkNeighborhoodTest) that no longer exist after the #864 migration renamed them; go test -run silently matches nothing and exits 0, so these entries were reporting green while running zero test code. Updated to the current function names (Test_12_AuthoredMultiSubtypeProfile, Test_13_NaturalLearningLifecycle). Also added real, matrix-shaped test functions that existed in tests/component_test.go but were never wired into the matrix: Test_25, Test_28, Test_30, Test_33, Test_35, Test_43, Test_49. Test_09_FalsePositiveTest was deliberately left out: it carries its own t.Skip with "Also removed from the CI matrix" pending a storage write-serialization fix, so re-adding it would be a no-op at best. - tests/scripts/storage-tag.sh: it mirrors whatever storage image tag kubescape/helm-charts' main branch has pinned, which currently lags behind the github.com/kubescape/storage client library version pinned in this repo's go.mod (v0.0.303). The older server silently drops the grouped Containers/InitContainers/EphemeralContainers subtype fields the newer client writes, so Test_48_MultiSubtypeGroupedProfileDocument's round-trip would come back empty. The script now takes the max of the dynamically-fetched tag and this repo's go.mod-pinned floor (derived via `go list -m`), so CI doesn't silently regress again next time helm-charts lags. The durable fix is bumping helm-charts' own pin; that's a separate repo/PR. Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
#864 renamed the ap.*/nn.* CEL rule-library helper namespaces to cp.* with no backward-compatible aliases. Since CEL rules are loaded from CRDs at runtime (user-authored detection rules), any pre-existing rule still referencing ap.*/nn.* now fails to compile — and pkg/utils/cel.go silently disables the expression on a compile failure (logs a warning, no error surfaced), so affected rules just stop detecting anything. Register the same 14 ap.* and 6 nn.* helper functions (e.g. ap.was_executed, nn.is_domain_in_egress) alongside the existing cp.* namespace, wired to the exact same Go implementations via a shared funcSpecs table per library, so cp.* and its legacy alias can never drift apart. cel-go requires overload ids to be unique per environment, so the alias registers its own overload ids (ap_*/nn_*) rather than literally reusing cp.*'s FunctionOpt values — only the CEL-facing glue is duplicated, not the detection logic. These aliases are a deliberate transition/deprecation window, not a permanent API; both AP()/NN() and the CEL registration in cel.go are commented accordingly for removal once user rules have migrated to cp.*. Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com> Docs-exempt: internal CEL rule-library namespace change; #864 (the PR that introduced the cp.* rename this follows up on) made no docs/ changes either, and no doc in this repo documents the ap./nn./cp. helper namespaces. The change is self-documented via code comments on AP()/NN() and in this PR description. Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
…ty (#901) #864 renamed the ap.*/nn.* CEL rule-library helper namespaces to cp.* with no backward-compatible aliases. Since CEL rules are loaded from CRDs at runtime (user-authored detection rules), any pre-existing rule still referencing ap.*/nn.* now fails to compile — and pkg/utils/cel.go silently disables the expression on a compile failure (logs a warning, no error surfaced), so affected rules just stop detecting anything. Register the same 14 ap.* and 6 nn.* helper functions (e.g. ap.was_executed, nn.is_domain_in_egress) alongside the existing cp.* namespace, wired to the exact same Go implementations via a shared funcSpecs table per library, so cp.* and its legacy alias can never drift apart. cel-go requires overload ids to be unique per environment, so the alias registers its own overload ids (ap_*/nn_*) rather than literally reusing cp.*'s FunctionOpt values — only the CEL-facing glue is duplicated, not the detection logic. These aliases are a deliberate transition/deprecation window, not a permanent API; both AP()/NN() and the CEL registration in cel.go are commented accordingly for removal once user rules have migrated to cp.*. Docs-exempt: internal CEL rule-library namespace change; #864 (the PR that introduced the cp.* rename this follows up on) made no docs/ changes either, and no doc in this repo documents the ap./nn./cp. helper namespaces. The change is self-documented via code comments on AP()/NN() and in this PR description. Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
Overview
Migrating old AP/NN/ug- structure to exclusively be container profile, migrating also all tests.
Benchmarks were run : CPU flat, mem somewhat better
Additional Information
See the issue
Also see new documentation under kubescape.io
Should we keep the
migration support of the old wayor just completely switch instantly?-> Decided to switch completely
Behavior that changes with this PR
ephemeral containers and initcontainers are now recorded differently.
TODO
Comment before merging
Discussion on ephemeral containers