Aggregate user-managed (ug- prefix) profiles into the consolidated ContainerProfile
- Dominant language
- Go
- Stars
- 4
- Forks
- 22
- Avg merge
- 20h 43m
- Merged PRs (30d)
- 33
Description
## Context
The node-agent's unified `ContainerProfileCache` (see [kubescape/node-agent#788](https://github.com/kubescape/node-agent/pull/788)) is CP-direct: it reads the consolidated `ContainerProfile` at the stable `GetSlug(false)` name as the single source of truth. The storage server already aggregates the per-tick time-series `ContainerProfile` writes (named `-`) into a consolidated CP at the `` name — that part works well.
What it does NOT aggregate is the **user-managed** profiles published at the `"ug-" + workloadSlug` well-known name. These are authored by humans (either directly or via the kubescape UI) and carry the annotation:
```yaml
kubescape.io/managed-by: User
```
The legacy `ApplicationProfileCache.handleUserManagedProfile` auto-discovered these via the annotation + `ug-` prefix and merged them into the workload's cached profile (see [legacy source, deleted in the migration PR](https://github.com/kubescape/node-agent/blob/900e72bd/pkg/objectcache/applicationprofilecache/applicationprofilecache.go#L269-L351)).
## Current state in the new cache
As a short-term fix in PR #788, the node-agent fetches `ug-` AP and NN on every `addContainer` and on every reconciler refresh tick, then projects them on top of the consolidated CP. This works but:
- Adds 2 RPCs per container per refresh tick (on top of the 1 CP GET).
- Duplicates the merge logic between node-agent and (eventually) storage.
- Splits the \"CP-direct\" principle: the CP isn't actually authoritative because the cache still has to go fetch user-managed profiles separately.
- Every agent on every node does the merge independently; server-side aggregation would do it once.
## Proposal
When the storage server consolidates time-series `ContainerProfile` writes into the stable-named CP (via `ContainerProfileProcessor.consolidateKeyTimeSeries`), **also merge the matching user-managed profile** (`ug-` if it exists) into the output.
Matching rules should mirror what `handleUserManagedProfile` did:
- Workload slug: `instanceID.GetSlug(true)` (no container name).
- Per-container: find the matching `ApplicationProfileContainer` / `NetworkNeighborhoodContainer` by `Name` across `.Spec.Containers + .Spec.InitContainers + .Spec.EphemeralContainers` and merge its fields into the consolidated CP's flat spec.
- Completion / Status annotations come from the base CP; user-managed data is additive.
The merge math already exists in node-agent's [projection.go](https://github.com/kubescape/node-agent/blob/cp-cache/pkg/objectcache/containerprofilecache/projection.go) (ported from the legacy `performMerge` / `mergeNetworkNeighbors`) — the same logic needs to live in storage instead.
## Acceptance
- A consolidated `ContainerProfile` at `` reflects data from both the time-series writes AND any user-managed `ug-` AP/NN, merged per-container.
- Re-consolidation fires whenever either source changes (so user edits to `ug-` propagate).
- Once this is in place, node-agent can drop its client-side `ug-` fetch and the corresponding refresh path (see [deviation doc](https://github.com/kubescape/node-agent/blob/cp-cache/.omc/plans/containerprofile-cache-deviations-from-consensus.md) \"Path A.2\").
## Related
- node-agent PR: https://github.com/kubescape/node-agent/pull/788
- Plan doc: `.omc/plans/containerprofile-cache-unification-consensus.md` in the node-agent PR
- Current cache-side implementation: `pkg/objectcache/containerprofilecache/containerprofilecache.go` `tryPopulateEntry` (look for \"user-managed\" comments)
## Non-goals
- User-defined profiles referenced by pod label (`kubescape.io/profile: `). Those stay cache-side because the name is arbitrary and chosen per-pod; they are not \"well-known\".
Contributor guide
Research direction
Start at ContainerProfileProcessor.consolidateKeyTimeSeries and trace how stable-named ContainerProfiles are built from time-series writes. Compare the merge behavior in node-agent's projection.go and the legacy handleUserManagedProfile path, then identify the storage events needed when either source changes. Done means the consolidated profile includes matching ug- data per container and reconsolidates after user-managed edits.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100