Skip to content

Comments

feat: add in-memory LRU+TTL cache for validation results#1933

Open
nissessenap wants to merge 5 commits intosigstore:mainfrom
nissessenap:cache_impl
Open

feat: add in-memory LRU+TTL cache for validation results#1933
nissessenap wants to merge 5 commits intosigstore:mainfrom
nissessenap:cache_impl

Conversation

@nissessenap
Copy link

@nissessenap nissessenap commented Feb 16, 2026

Summary

  • Implement ResultCache interface with an LRU+TTL cache using hashicorp/golang-lru/v2/expirable, opt-in via --enable-cache CLI flag
  • Fix cache key mismatch bug: ref.Name() in Set vs ref.String() in Get caused the cache to never hit — both now use ref.String()
  • Move cache.Set call from validatePolicies into ValidatePolicy so caching is self-contained regardless of call path (previously it was in the goroutine caller, using ref.Name() which strips the digest)
  • Only successful validations (PolicyResult non-nil) are cached; failed validations are skipped to allow immediate retries after signing

Closes #647, closes #1887

Details

New files:

  • pkg/webhook/lrucache.goLRUCache struct wrapping expirable.LRU[string, *CacheResult]
  • pkg/webhook/lrucache_test.go — 8 unit tests (set/get, miss, skip errors, partial success, TTL expiry, eviction, key isolation, resourceVersion invalidation)

Modified files:

  • pkg/webhook/validator.go — Fix ref.Name()ref.String() bug, move cache.Set into ValidatePolicy (was in validatePolicies goroutine)
  • pkg/webhook/validator_test.go — 4 integration tests (cache hit, skip errors, partial success, no-cache default)
  • cmd/webhook/main.go — Add --enable-cache, --cache-size, --cache-ttl flags; inject cache into validating webhook context
  • go.mod — Promote hashicorp/golang-lru/v2 from indirect to direct dependency

CLI flags (all opt-in, cache disabled by default):

Flag Default Description
--enable-cache false Enable in-memory LRU cache
--cache-size 1024 Max cache entries
--cache-ttl 1h TTL for cached results

Test plan

  • Unit tests pass: go test ./pkg/webhook/... -run TestLRUCache
  • Integration tests pass: go test ./pkg/webhook/... -run TestValidatePolicyCache
  • Full test suite passes: go test $(go list ./... | grep -v third_party/)
  • Build succeeds: go build ./cmd/webhook/...
  • Flag help shows new flags: --enable-cache, --cache-size, --cache-ttl
  • Deploy to test cluster with --enable-cache and verify repeated admissions use cache
  • Verify without --enable-cache behavior is identical to before

🤖 Generated with Claude Code

@nissessenap nissessenap marked this pull request as draft February 16, 2026 12:28
@nissessenap
Copy link
Author

nissessenap commented Feb 16, 2026

I need to perform some validation, of this before changing over from draft.

I will also create a PR that builds on this which implements some basic metrics make the cach visaiable, but that is a sperate PR since it's the first time we use custom metrics in this repo, but I wanted to showcase that I was working on the issues with this PR at least.

nissessenap and others added 5 commits February 16, 2026 20:07
Add tests for the upcoming LRU+TTL cache implementation (sigstore#647).
Unit tests cover set/get, TTL expiry, eviction, key isolation,
error skipping, and resource version invalidation. Integration
tests verify ValidatePolicy cache hit/miss behavior.

All tests currently fail to compile (NewLRUCache undefined),
confirming the TDD Red phase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Edvin Norling <edvin.norling@kognic.com>
Add LRUCache implementing ResultCache using hashicorp/golang-lru/v2
expirable. Only successful validations (PolicyResult non-nil) are
cached; failed validations are skipped to allow immediate retries.

Fix cache key mismatch bug: ref.Name() in Set vs ref.String() in Get
caused cache to never hit. Both now use ref.String().

Move cache Set into ValidatePolicy so caching is self-contained
regardless of call path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Edvin Norling <edvin.norling@kognic.com>
Wire the LRU+TTL cache into the validating webhook via --enable-cache,
--cache-size, and --cache-ttl flags. Cache is off by default and only
injected into the validating admission controller context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Edvin Norling <edvin.norling@kognic.com>
- Copy CacheResult.Errors slice in LRUCache.Set to prevent callers from
  mutating cached entries through the shared backing array
- Update copyright year to 2026 on new files (lrucache.go, lrucache_test.go)
- Extract cacheTestFixtures helper to reduce boilerplate in cache
  integration tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Edvin Norling <edvin.norling@kognic.com>
    Move cache observability into LRUCache.Get() so the implementation
    owns its own logging

Signed-off-by: Edvin Norling <edvin.norling@kognic.com>
@nissessenap nissessenap marked this pull request as ready for review February 16, 2026 20:42
@nissessenap
Copy link
Author

I have ran this locally and it seams to works as intended.
I haven't added any e2e, since it's rather hard to test without any metrics, I don't just want todo some kubectl logs command to verify if the cachce has hit or not.

I removed third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru in one commit, but saw on my local PR that it made a CI fail.

I hope you think this is a sufisant start to get this PR merged and we can build uppon it to create two seperate PR

  • add metrics
  • add e2e coverage for caching

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for Caching Validation Results Implement a simple in-mem cache (with opt-in).

1 participant