Skip to content

feat(objectcache): carry a content checksum for conditional container-profile fetches - #941

Open
matthyx wants to merge 1 commit into
mainfrom
container-profile-checksum-step4a
Open

feat(objectcache): carry a content checksum for conditional container-profile fetches#941
matthyx wants to merge 1 commit into
mainfrom
container-profile-checksum-step4a

Conversation

@matthyx

@matthyx matthyx commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Overview

Lands the client half of "conditional container-profile fetch" (step 4a of 5 in
armosec/shared-designs-and-docs#201,
status: proposed). The container-profile cache reconciler can now present the
content checksum of the profile it already holds, and treat a server's
"unchanged" reply as "keep the cached entry, skip the rebuild" — instead of
today's behavior, which fetches the full body every tick and only decides
after the object is on the wire whether a rebuild is needed.

This PR is DORMANT. No in-tree ProfileClient implementer returns the new
sentinel, so no conditional fetch has been or can be observed here. Green
tests prove the contract compiles and existing behavior is byte-for-byte
unchanged — nothing more. The companion kubescape/backend PR (kubescape/backend#62)
adds the server-side contract; a private downstream adapter (not part of this
org, not this PR) is what will eventually make node-agent actually send the
checksum in production.

Design constraint

storage.ProfileClient.GetContainerProfile(ctx, namespace, name) has a second
implementer in this repo (pkg/storage/v1, the in-cluster CRD/aggregated-API
backend), which has no concept of a remote checksum. This PR does not
change that interface's signature — pkg/storage/v1/, storage_mock.go, and
the interface definition are byte-for-byte untouched (git diff --stat is
empty). The checksum crosses the boundary out-of-band instead: a context.Context
key on the request side, a sentinel error plus an ObjectMeta annotation on
the response side.

Changes

  • pkg/storage/checksum.go (new): WithKnownChecksum/KnownChecksumFromContext
    over an unexported context key; ErrProfileUnchanged; the exported
    ContainerProfileChecksumAnnotationKey (backend.kubescape.io/container-profile-checksum,
    matching feat(storageclient): add conditional container-profile fetch contract backend#62's key exactly — pinned by a dedicated
    cross-repo equality test in the downstream adapter).
  • CachedContainerProfile gains a Checksum field, populated at both
    places a cache entry is constructed (rebuildEntryFromSources and
    buildEntry/tryPopulateEntry — missing the second site would have made
    the optimization silently inert for every profile that never changes, i.e.
    exactly the population it targets).
  • refreshOneEntry's guard for attaching a checksum to the learned-CP fetch
    requires: no authored-CP override in play, the projection spec hash
    unchanged, a known checksum available, and the entry's learned status is
    already terminal (Completed+Full) — that last conjunct exists because a
    lifecycle-only change (e.g. completion status flipping) doesn't change the
    content checksum, and this cache's State feeds real alerting logic
    downstream, so a conditional fetch is only requested once nothing about the
    entry can still move.
  • The user-authored-CP fetch (a separate call in the same function) never
    receives a checksum and is completely unaffected.
  • docs/features/container-profile-conditional-fetch-contract.md (new):
    documents this repo's half of the cross-repo contract for future
    maintainers and upstream reviewers.

Testing

  • 17 new tests in pkg/objectcache/containerprofilecache/reconciler_checksum_test.go,
    covering: both construction sites (including that the adopted entry stores
    the learned CP's checksum, not the authored CP's), every guard conjunct
    individually, per-call-site isolation (the authored-CP fetch never sees a
    checksum even in the same tick), the sentinel keeping the cache entry
    pointer-identical with no rebuild, and the terminal-state guard walking all
    three phases (declined while partial → completion flip reaches the cache →
    shortcut engages once terminal).
  • go test ./pkg/objectcache/containerprofilecache/... -race green.
  • go test ./pkg/objectcache/... -run Golden green — no projection-golden
    churn from the new annotation.
  • Every pre-existing test in this package passes unmodified — no assertion
    edits, no new skips.
  • go build ./... — confirms the in-cluster Storage implementer still
    satisfies ProfileClient with zero changes on this PR's part.

Related

Step 4a of 5 in the conditional container-profile fetch plan.
Companion PR: kubescape/backend#62 (step 2, proto contract).

🤖 Generated with Claude Code

https://claude.ai/code/session_01HnqMRD3r2kGYUBTxMHM5vi

AI-skills: oh-my-claudecode:plan,oh-my-claudecode:team | cmds: /oh-my-claudecode:deep-interview

Summary by CodeRabbit

  • New Features

    • Added conditional fetching for unchanged container profiles, allowing compatible sources to avoid retransmitting identical profile data.
    • Container profile checksums are now stored and reused during eligible refreshes.
    • Added handling to retain cached profiles when the source confirms that content is unchanged.
  • Documentation

    • Added documentation describing the conditional-fetch contract, checksum behavior, and refresh conditions.

…-profile fetches

Lands the client half of the conditional container-profile fetch contract. It
is DORMANT: no in-tree ProfileClient implementer returns the sentinel, so no
conditional fetch has been or can be observed here, and there is no behavior or
byte-savings change. Green tests prove the contract compiles and that existing
behavior is unchanged — nothing more.

pkg/storage gains the shared vocabulary, deliberately out-of-band so
ProfileClient's signature is byte-identical and its checksum-unaware in-cluster
implementer changes by zero lines: a context key (WithKnownChecksum /
KnownChecksumFromContext) for the request, and ErrProfileUnchanged plus
ContainerProfileChecksumAnnotationKey for the response. The annotation key is a
string contract shared with an out-of-tree implementer and fails silently, not
loudly, if the two sides ever disagree.

CachedContainerProfile gains Checksum, populated at BOTH construction sites.
buildEntry matters as much as rebuildEntryFromSources: a profile that never
changes is built once and thereafter always fast-skips, so populating only the
rebuild path would leave the validator empty forever and make the optimization
silently inert for exactly the steady-state population it targets. On the
adoption path the value is corrected post-call from the pre-repoint learned CP,
mirroring the existing entry.RV = learnedRV fix, so the validator always
describes the object CPName points at.

refreshOneEntry offers the validator only under a five-conjunct guard — no
authored CP ref, no recorded authored RV, unchanged spec hash, a non-empty
stored checksum, and a cached state that has already reached Completed+Full.
The last conjunct is load-bearing: the lifecycle annotations sit outside the
content checksum, so a profile finishing its learning period presents an
unchanged checksum, and without it the entry would answer "unchanged" on that
tick and on every later one — freezing entry.State permanently. That state is
not internal bookkeeping; rulemanager gates HasFinalApplicationProfile on
Completed+Full and stamps FailOnProfile from it, so a frozen state would keep
alerting a finished profile as partial forever. Unlike the RV staleness below,
that staleness would never self-correct.

The validator is attached per call, never to the shared context, so the
authored-CP fetch can never receive the learned CP's checksum. The projection
spec is snapshotted once above the fetch and reused, which moves detection of a
spec swap landing mid-fetch to the next tick; that is self-healing.

One accepted, tested divergence remains: a checksum match proves content
identity, not ResourceVersion identity, so on the sentinel path e.RV may lag a
metadata-only write until the next unconditional fetch. That one is bounded and
self-correcting, which is why it is accepted where the state freeze is not.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HnqMRD3r2kGYUBTxMHM5vi
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
@matthyx matthyx added the ai-assisted Created through Armosec AI tooling (armosec-shared-rules plugin) label Sep 2, 2026
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 6ff12dc1-e347-4db0-a96d-ae2376187549

📥 Commits

Reviewing files that changed from the base of the PR and between 4956ea2 and 6bd3ddc.

📒 Files selected for processing (5)
  • docs/features/container-profile-conditional-fetch-contract.md
  • pkg/objectcache/containerprofilecache/containerprofilecache.go
  • pkg/objectcache/containerprofilecache/reconciler.go
  • pkg/objectcache/containerprofilecache/reconciler_checksum_test.go
  • pkg/storage/checksum.go

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds a checksum contract for conditional container-profile fetches. The cache stores the learned profile checksum, refresh logic sends it under defined conditions, and unchanged responses preserve the cached entry. Tests cover the contract and refresh behavior. Documentation describes the protocol.

Changes

Container profile conditional fetch

Layer / File(s) Summary
Checksum contract
pkg/storage/checksum.go, docs/features/container-profile-conditional-fetch-contract.md
Defines the checksum annotation key, ErrProfileUnchanged, and context helpers. Documents request and response semantics.
Cache checksum tracking
pkg/objectcache/containerprofilecache/containerprofilecache.go, pkg/objectcache/containerprofilecache/reconciler.go
Stores the learned profile checksum and preserves it when an authored profile is adopted.
Conditional refresh flow
pkg/objectcache/containerprofilecache/reconciler.go, docs/features/container-profile-conditional-fetch-contract.md
Uses one spec-hash snapshot and applies the five-part guard before attaching a checksum. Handles ErrProfileUnchanged before not-found checks and stores refreshed checksums.
Checksum behavior validation
pkg/objectcache/containerprofilecache/reconciler_checksum_test.go
Tests checksum storage, guard conditions, per-call context handling, sentinel behavior, RV staleness, rebuilds, and context helper round-tripping.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to 6bd3d

The cache can now skip rebuilding when profile content is unchanged, but a status-only transition could leave lifecycle metadata stale and affect downstream rule or alert decisions once a checksum-aware client is deployed. The PR is mergeable with explicit owner awareness and follow-up before activating the downstream integration.

Sequence Diagram(s)

sequenceDiagram
  participant CacheReconciler
  participant ProfileClient
  participant ContainerProfileCache
  CacheReconciler->>ProfileClient: Fetch learned profile with known checksum
  ProfileClient-->>CacheReconciler: ErrProfileUnchanged when checksum matches
  CacheReconciler->>ContainerProfileCache: Keep existing entry without rebuild
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: carrying content checksums for conditional container-profile fetches.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 26 functions across 4 files. (1 skipped: 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 26 functions across 4 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch container-profile-checksum-step4a

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Performance Benchmark Results

Node-Agent Resource Usage
Metric BEFORE AFTER Delta
Avg CPU (cores) 0.142 0.146 +2.4%
Peak CPU (cores) 0.148 0.151 +1.9%
Peak CPU p95 (cores) 0.146 0.151 +3.3%
Avg Memory (MiB) 375.259 312.899 -16.6%
Peak Memory (MiB) 377.656 321.211 -14.9%
Dedup Effectiveness

No data available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted Created through Armosec AI tooling (armosec-shared-rules plugin)

Projects

Status: WIP

Development

Successfully merging this pull request may close these issues.

1 participant