Skip to content

ROX-33339: Sensor support for refresh image cache TTL message#19837

Merged
clickboo merged 2 commits intomasterfrom
boo-sensor-refresh-invalidate-reprocessor
Apr 8, 2026
Merged

ROX-33339: Sensor support for refresh image cache TTL message#19837
clickboo merged 2 commits intomasterfrom
boo-sensor-refresh-invalidate-reprocessor

Conversation

@clickboo
Copy link
Copy Markdown
Contributor

@clickboo clickboo commented Apr 6, 2026

Description

Adds Sensor-side processing of RefreshImageCacheTTL messages from Central. When Central's reprocessor determines that an image's scan data has not changed, it sends RefreshImageCacheTTL instead of UpdatedImage. Sensor handles this by extending the TTL of the existing entry in its local image cache via a new Touch() method on expiringcache.Cache, avoiding unnecessary image data transfer, proto serialization and deserialization, and deployment re-evaluation.

Key changes:

  • New RefreshImageCacheTTL proto message in MsgToSensor carrying a batch of image keys
  • expiringcache.Cache.Touch(key) method that resets an entry's TTL without replacing its value
  • ProcessRefreshImageCacheTTL handler in Sensor's reprocessor that calls Touch for each image key
  • Event pipeline routing for the new message type
  • Extracted cacheKeyFromImageKey helper to deduplicate key-selection logic between ProcessInvalidateImageCache and ProcessRefreshImageCacheTTL

Note:
PR #19840 contains the logic to send RefreshImageCacheTTL.

User-facing documentation

Testing and quality

  • the change is production ready: the change is GA, or otherwise the functionality is gated by a feature flag
  • CI results are inspected

Automated testing

  • added unit tests
  • added e2e tests
  • added regression tests
  • added compatibility tests
  • modified existing tests

How I validated my change

Manually tested on full stack including #19840 and #19600 using the following:

  1. Live burst-test.sh script from ROX-33343: Automated suite for adm cntrl bench testing & profiling #19427 to generate admission controller review request load with image scanning.
  2. In parallel run a script to reassess all policies every 60 seconds in a loop to trigger short circuit reprocessing, while the burst script is running and generating admission controller load.
  3. Admission review requests pass/fail as expected, no observable latency increases or failures.

@clickboo
Copy link
Copy Markdown
Contributor Author

clickboo commented Apr 6, 2026

@openshift-ci
Copy link
Copy Markdown

openshift-ci bot commented Apr 6, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

sourcery-ai[bot]

This comment was marked as outdated.

@clickboo clickboo force-pushed the boo-sensor-refresh-invalidate-reprocessor branch from 9fc3225 to c15a13f Compare April 6, 2026 04:43
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 6, 2026

🚀 Build Images Ready

Images are ready for commit 39d15cc. To use with deploy scripts:

export MAIN_IMAGE_TAG=4.11.x-601-g39d15cc177

@clickboo clickboo force-pushed the boo-sensor-refresh-invalidate-reprocessor branch 2 times, most recently from 2b11784 to a5bd2d1 Compare April 6, 2026 05:14
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 6, 2026

Codecov Report

❌ Patch coverage is 86.00000% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.59%. Comparing base (7f56c20) to head (579f6be).
⚠️ Report is 26 commits behind head on master.

Files with missing lines Patch % Lines
central/image/service/service_impl.go 50.00% 2 Missing ⚠️
sensor/common/reprocessor/handler.go 91.66% 2 Missing ⚠️
...rabilityrequest/manager/requestmgr/manager_impl.go 66.66% 1 Missing ⚠️
...ommon/admissioncontroller/settings_manager_impl.go 0.00% 1 Missing ⚠️
sensor/kubernetes/eventpipeline/pipeline_impl.go 83.33% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #19837      +/-   ##
==========================================
- Coverage   49.60%   49.59%   -0.02%     
==========================================
  Files        2763     2766       +3     
  Lines      208331   208572     +241     
==========================================
+ Hits       103338   103435      +97     
- Misses      97327    97462     +135     
- Partials     7666     7675       +9     
Flag Coverage Δ
go-unit-tests 49.59% <86.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@clickboo clickboo force-pushed the boo-reprocessor-targeted-invalidation branch from 6211fa0 to 8e833aa Compare April 7, 2026 05:52
Base automatically changed from boo-reprocessor-targeted-invalidation to master April 7, 2026 09:27
@clickboo clickboo force-pushed the boo-sensor-refresh-invalidate-reprocessor branch from a5bd2d1 to de678cb Compare April 7, 2026 09:29
@clickboo clickboo force-pushed the boo-sensor-refresh-invalidate-reprocessor branch from de678cb to b1142f8 Compare April 7, 2026 09:54
@clickboo
Copy link
Copy Markdown
Contributor Author

clickboo commented Apr 7, 2026

/test all

@clickboo clickboo marked this pull request as ready for review April 7, 2026 11:32
@clickboo clickboo requested a review from a team as a code owner April 7, 2026 11:32
sourcery-ai[bot]

This comment was marked as outdated.

@clickboo clickboo force-pushed the boo-sensor-refresh-invalidate-reprocessor branch from b1142f8 to f71c251 Compare April 7, 2026 12:00
@clickboo
Copy link
Copy Markdown
Contributor Author

clickboo commented Apr 7, 2026

/test ocp-4-12-qa-e2e-tests

Copy link
Copy Markdown
Contributor

@dcaravel dcaravel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks OK, however something to consider regarding Sensor cache + failed scans.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

The changes introduce a new image cache TTL refresh feature for sensors by extracting ImageKey to a top-level protobuf message, adding a RefreshImageCacheTTL command, implementing a Touch method on the expiring cache interface, and integrating the refresh pipeline throughout the sensor event handling system.

Changes

Cohort / File(s) Summary
Protobuf Message Definitions
proto/internalapi/central/sensor_iservice.proto, proto/internalapi/sensor/admission_control.proto
Extracted ImageKey to a new top-level message with fields image_id, image_full_name, image_id_v2. Updated InvalidateImageCache to reference the new top-level ImageKey. Added new RefreshImageCacheTTL message and new oneof field in MsgToSensor to enable Central to send cache refresh commands.
Image Key Type Migration
central/image/service/service_impl.go, central/image/service/service_impl_test.go, central/vulnmgmt/vulnerabilityrequest/manager/requestmgr/manager_impl.go, sensor/common/admissioncontroller/settings_manager.go, sensor/common/admissioncontroller/settings_manager_impl.go, sensor/common/admissioncontroller/mocks/settings_manager.go, sensor/admission-control/manager/manager_impl_test.go
Migrated cache invalidation payloads from *central.InvalidateImageCache_ImageKey to *central.ImageKey across service implementations, interfaces, and test fixtures while preserving field assignments.
Expiring Cache Touch Feature
pkg/expiringcache/cache.go, pkg/expiringcache/cache_test.go, pkg/expiringcache/mocks/cache.go
Added new Touch(key K) bool method to the Cache interface that refreshes an existing entry's TTL without modifying its value. Implemented the method with lock-safe cleanup, key existence checks, and re-insertion for TTL reset. Added comprehensive unit tests and mock support.
Cache TTL Refresh Handler
sensor/common/reprocessor/handler.go, sensor/common/reprocessor/handler_test.go, sensor/common/reprocessor/mocks/handler.go
Added new ProcessRefreshImageCacheTTL(*central.RefreshImageCacheTTL) error method to the Handler interface and implementation. Refactored image-key-to-cache-key resolution into shared cacheKeyFromImageKey helper to determine cache keys using FlattenImageData precedence. Replaced separate flatten/non-flatten tests with table-driven test suite.
Event Pipeline Integration
sensor/kubernetes/eventpipeline/pipeline_impl.go, sensor/kubernetes/eventpipeline/pipeline_test.go
Updated eventPipeline.Accepts to recognize RefreshImageCacheTTL messages. Added routing in ProcessMessage to delegate RefreshImageCacheTTL commands to new processRefreshImageCacheTTL handler method. Added test case validating end-to-end message handling.

Sequence Diagram(s)

sequenceDiagram
    participant Central
    participant Pipeline as Event Pipeline
    participant Reprocessor
    participant Cache as Expiring Cache

    Central->>Pipeline: RefreshImageCacheTTL(image_keys=[...])
    activate Pipeline
    
    Pipeline->>Pipeline: Accepts(msg) validates message type
    Pipeline->>Pipeline: ProcessMessage routes to handler
    Pipeline->>Reprocessor: ProcessRefreshImageCacheTTL(req)
    
    activate Reprocessor
    loop For each image_key in req
        Reprocessor->>Reprocessor: cacheKeyFromImageKey(imageKey)
        Reprocessor->>Cache: Touch(resolvedKey)
        activate Cache
        Cache->>Cache: Lock cache
        Cache->>Cache: cleanNoLock() prune expired
        Cache->>Cache: Lookup key exists?
        alt Key exists
            Cache->>Cache: Remove and re-add value
            Cache-->>Reprocessor: true (TTL refreshed)
        else Key not found
            Cache-->>Reprocessor: false (key absent)
        end
        deactivate Cache
    end
    Reprocessor-->>Pipeline: error or nil
    deactivate Reprocessor
    
    Pipeline-->>Central: Acknowledge/respond
    deactivate Pipeline
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding Sensor-side support for a new RefreshImageCacheTTL message type.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the change rationale, key modifications, testing approach, and validation methodology.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 boo-sensor-refresh-invalidate-reprocessor

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
sensor/common/reprocessor/handler_test.go (1)

32-43: This test doesn't currently prove the TTL was refreshed.

Because newTestCache hardcodes a real one-hour cache and the assertions run immediately after ProcessRefreshImageCacheTTL, this would still pass for a no-op. Consider using a controllable clock or a very short TTL and asserting that refreshed keys survive past the original expiry while untouched keys do not.

Also applies to: 125-191

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sensor/common/reprocessor/handler_test.go` around lines 32 - 43, The test
never verifies TTL refresh because newTestCache() creates a fixed 1-hour cache
and assertions run immediately; change the tests to use a controllable/short TTL
and advance time to observe expiry. Modify newTestCache to accept a TTL (or a
clock) parameter and construct the expiring cache with that TTL (or pass a mock
clock), then in the tests that call ProcessRefreshImageCacheTTL (and the block
around lines 125-191) create the cache with a very short TTL (e.g., 10–50ms) or
a fake clock, call ProcessRefreshImageCacheTTL, advance the clock (or sleep)
past the original TTL for non-refreshed keys, and assert refreshed keys still
exist while untouched keys have expired; refer to newTestCache and
ProcessRefreshImageCacheTTL to locate the changes.
sensor/common/reprocessor/handler.go (1)

95-97: Align empty-key handling with refresh path.

On Line 96, invalidation appends keys unconditionally, while the refresh handler skips empty keys. Filtering here too improves behavioral consistency and avoids acting on empty cache keys.

Suggested change
 		keysToDelete := make([]cache.Key, 0, len(req.GetImageKeys()))
 		for _, image := range req.GetImageKeys() {
-			keysToDelete = append(keysToDelete, cacheKeyFromImageKey(image))
+			if key := cacheKeyFromImageKey(image); key != "" {
+				keysToDelete = append(keysToDelete, key)
+			}
 		}
 		h.imageCache.Remove(keysToDelete...)

As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sensor/common/reprocessor/handler.go` around lines 95 - 97, The invalidation
loop appends cache keys unconditionally; align it with the refresh path by
skipping empty keys — call cacheKeyFromImageKey(image) and only append to
keysToDelete when the returned cache key is non-empty (i.e., if cacheKey == ""
continue). Update the loop that iterates req.GetImageKeys() so it filters out
empty cache keys before appending to keysToDelete.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@sensor/common/reprocessor/handler_test.go`:
- Around line 32-43: The test never verifies TTL refresh because newTestCache()
creates a fixed 1-hour cache and assertions run immediately; change the tests to
use a controllable/short TTL and advance time to observe expiry. Modify
newTestCache to accept a TTL (or a clock) parameter and construct the expiring
cache with that TTL (or pass a mock clock), then in the tests that call
ProcessRefreshImageCacheTTL (and the block around lines 125-191) create the
cache with a very short TTL (e.g., 10–50ms) or a fake clock, call
ProcessRefreshImageCacheTTL, advance the clock (or sleep) past the original TTL
for non-refreshed keys, and assert refreshed keys still exist while untouched
keys have expired; refer to newTestCache and ProcessRefreshImageCacheTTL to
locate the changes.

In `@sensor/common/reprocessor/handler.go`:
- Around line 95-97: The invalidation loop appends cache keys unconditionally;
align it with the refresh path by skipping empty keys — call
cacheKeyFromImageKey(image) and only append to keysToDelete when the returned
cache key is non-empty (i.e., if cacheKey == "" continue). Update the loop that
iterates req.GetImageKeys() so it filters out empty cache keys before appending
to keysToDelete.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: d331c9e9-1efa-420d-8a79-026e0d7fa5fc

📥 Commits

Reviewing files that changed from the base of the PR and between b2a85fc and 579f6be.

⛔ Files ignored due to path filters (4)
  • generated/internalapi/central/sensor_iservice.pb.go is excluded by !**/*.pb.go, !**/generated/**
  • generated/internalapi/central/sensor_iservice_vtproto.pb.go is excluded by !**/*.pb.go, !**/generated/**
  • generated/internalapi/sensor/admission_control.pb.go is excluded by !**/*.pb.go, !**/generated/**
  • generated/internalapi/sensor/admission_control_vtproto.pb.go is excluded by !**/*.pb.go, !**/generated/**
📒 Files selected for processing (17)
  • central/image/service/service_impl.go
  • central/image/service/service_impl_test.go
  • central/vulnmgmt/vulnerabilityrequest/manager/requestmgr/manager_impl.go
  • pkg/expiringcache/cache.go
  • pkg/expiringcache/cache_test.go
  • pkg/expiringcache/mocks/cache.go
  • proto/internalapi/central/sensor_iservice.proto
  • proto/internalapi/sensor/admission_control.proto
  • sensor/admission-control/manager/manager_impl_test.go
  • sensor/common/admissioncontroller/mocks/settings_manager.go
  • sensor/common/admissioncontroller/settings_manager.go
  • sensor/common/admissioncontroller/settings_manager_impl.go
  • sensor/common/reprocessor/handler.go
  • sensor/common/reprocessor/handler_test.go
  • sensor/common/reprocessor/mocks/handler.go
  • sensor/kubernetes/eventpipeline/pipeline_impl.go
  • sensor/kubernetes/eventpipeline/pipeline_test.go

@clickboo
Copy link
Copy Markdown
Contributor Author

clickboo commented Apr 8, 2026

/test ocp-4-21-qa-e2e-tests

@clickboo clickboo merged commit 39d15cc into master Apr 8, 2026
122 checks passed
@clickboo clickboo deleted the boo-sensor-refresh-invalidate-reprocessor branch April 8, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants