feat: add lookup cache for WhoCanAccess/WhatCanTargetAccess#367
Merged
feat: add lookup cache for WhoCanAccess/WhatCanTargetAccess#367
Conversation
Add TTL-based lookup cache for authorization lookup queries. Config (env vars): - AUTHZCACHE_LOOKUP_CACHE_ENABLED (default: true) - AUTHZCACHE_LOOKUP_CACHE_SIZE_PER_PROJECT (default: 10000) - AUTHZCACHE_LOOKUP_CACHE_TTL_IN_SECONDS (default: 60) - AUTHZCACHE_LOOKUP_CACHE_MAX_RESULT_SIZE (default: 1000) The lookup cache is invalidated: - On schema changes (full purge) - On relation mutations (full purge) - When TTL expires (per-entry) Large results (> max_result_size) are not cached to prevent memory issues.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a TTL-based lookup cache for authorization lookup queries (WhoCanAccess and WhatCanTargetAccess) with configurable settings and cache invalidation strategies.
Changes:
- Introduces a new lookup cache with TTL-based expiration for authorization queries
- Adds configuration parameters for cache size, TTL, and result size limits
- Implements cache invalidation on schema/relation changes
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/services/caches/projectauthzcache_mock.go | Adds mock methods for lookup cache operations |
| internal/services/caches/projectauthzcache.go | Implements lookup cache with TTL tracking and cache key generation |
| internal/services/authz_mock.go | Adds mock methods for WhoCanAccess and WhatCanTargetAccess |
| internal/services/authz.go | Integrates lookup cache into authorization service methods |
| internal/config/config.go | Adds configuration functions for lookup cache settings |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Instead of returning stale cached results directly, we now: 1. Get cached lookup results as 'candidates' (may be stale) 2. Verify each candidate using the Check cache (always fresh) 3. Filter out candidates that fail the check This ensures lookup results are always accurate while still benefiting from the lookup cache for the candidate superset. Also adds comprehensive tests for: - WhoCanAccess cache miss/hit with filtering - WhatCanTargetAccess cache miss/hit with filtering - Stale candidate filtering behavior
Skip malformed entries instead of leaving nil in the slice. Return cache miss if all entries are malformed.
When relations are added or deleted via UpdateCacheWithAddedRelations or UpdateCacheWithDeletedRelations, the lookup cache (WhoCanAccess/ WhatCanTargetAccess) must also be purged to prevent stale results. Previously, only the indirectRelationCache was purged, which could lead to incorrect lookup results until TTL expiration.
When remote polling detects relation changes (resources or targets modified), the lookup cache must also be purged to ensure new candidates are visible. Without this fix, new relations added remotely would not appear in WhoCanAccess/WhatCanTargetAccess results until TTL expiration.
Instead of purging the entire lookup cache on relation changes: - Direct relation added: Add target to existing WhoCanAccess/WhatCanTargetAccess cache entries (if present) - Direct relation deleted: Rely on candidate filtering (CheckRelation returns false for deleted relations) - Remote relation changes: Rely on candidate filtering This avoids invalidating all cached lookups when only specific entries are affected. Removed access is handled immediately via candidate filtering, while new access is visible immediately for direct relations added locally. Added comprehensive tests for direct/indirect relation removal filtering.
yosiharan
reviewed
Feb 12, 2026
Contributor
yosiharan
left a comment
There was a problem hiding this comment.
Great work, excited to see the results!
Just had a couple of suggestions to reduce code repetition, nothing critical, lmk what you think 🙏
Address CR feedback from yosiharan: - Remove redundant projectCache and mgmtSDK parameters from filter methods - Replace checkRelationsWithCache with direct calls to existing Check method - Delete duplicate checkRelationsWithCache method (~30 lines removed)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issues
Related to https://github.com/descope/etc/issues/13966
Description
Add lookup cache with Candidate Filtering for
WhoCanAccessandWhatCanTargetAccess.How It Works
This gives cache speed with real-time accuracy:
Cache Invalidation Strategy
Key insight: We don't purge the entire lookup cache on relation changes. Instead:
Configuration (env vars)
AUTHZCACHE_LOOKUP_CACHE_ENABLEDtrueAUTHZCACHE_LOOKUP_CACHE_SIZE_PER_PROJECT10000AUTHZCACHE_LOOKUP_CACHE_TTL_IN_SECONDS60AUTHZCACHE_LOOKUP_CACHE_MAX_RESULT_SIZE1000Benefits
Note
Defaults are conservative. After collecting Datadog metrics from authzservice (PR #1747), tune based on:
Must