feat: deny-by-default retrieval authorization scoping - #96
Conversation
- Add retrieval/scope.py: RetrievalScope dataclass (principal_user_id,
role, publish_visibility), derive_scope(), assert_scope_match(),
visible_to() post-check, cache_scope_key() partition helper.
- Update memory/store.py: get_profile/get_chat_summary accept scope=
kwarg; cross-user and anonymous access is blocked and logged.
- Update semantic_cache.py: CacheEntry carries scope_key slot;
SemanticCache.get()/put() enforce partition match so per-user entries
never cross principals.
- Update main.py: _resolve_principal() reads X-User-Id header;
/chat and /chat/stream derive RetrievalScope, assert_scope_match
raises 403 on body user_id ≠ principal; all memory lookups use
_effective_user_id from scope; /memory/{user_id} GET+DELETE and
/user/{user_id}/chats enforce scope guard with 403; /chat/stream
outer exception handler re-raises HTTPException correctly.
- Add tests/test_retrieval_scope.py: 63 adversarial tests covering
scope construction, derive_scope, assert_scope_match, visible_to
post-check, cache partition isolation, memory store enforcement,
denied-retrieval logging (no PII leak), HTTP 403 integration tests,
and bypass-attempt matrix.
Closes Deen-Bridge#91
|
Important Review available on request
Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 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. Comment |
|
Strict review blocker: this branch conflicts with the base branch, and is failing. Please resolve both blockers. |
|
Strict review blocker: this branch conflicts with the base branch, and |
|
Strict review blocker: required checks are failing. Please fix the failures before requesting merge. |
|
@DavidAkere204 this PR has merge conflicts with the |
Add retrieval/scope.py: RetrievalScope dataclass (principal_user_id, role, publish_visibility), derive_scope(), assert_scope_match(), visible_to() post-check, cache_scope_key() partition helper.
Update memory/store.py: get_profile/get_chat_summary accept scope= kwarg; cross-user and anonymous access is blocked and logged.
Update semantic_cache.py: CacheEntry carries scope_key slot; SemanticCache.get()/put() enforce partition match so per-user entries never cross principals.
Update main.py: _resolve_principal() reads X-User-Id header; /chat and /chat/stream derive RetrievalScope, assert_scope_match raises 403 on body user_id ≠ principal; all memory lookups use _effective_user_id from scope; /memory/{user_id} GET+DELETE and /user/{user_id}/chats enforce scope guard with 403; /chat/stream outer exception handler re-raises HTTPException correctly.
Add tests/test_retrieval_scope.py: 63 adversarial tests covering scope construction, derive_scope, assert_scope_match, visible_to post-check, cache partition isolation, memory store enforcement, denied-retrieval logging (no PII leak), HTTP 403 integration tests, and bypass-attempt matrix.
Closes #91