Repository navigation
Per-request tenant isolation, filters and tenant-scoped files - #72
Merged
Merged
Conversation
… validation - Implemented integration tests for tenant isolation in the API, ensuring that users with the same ID in different organizations cannot access each other's threads, states, and messages. - Added unit tests to validate client filters on extra columns of non-table types, enforcing that only `is_null` is supported for these filters. - Created tests for the `ThreadOwnershipResolver` to verify caching behavior and correct handling of tenant values. - Enhanced the authorization backend to ensure proper isolation scope handling and to validate that unauthorized access is correctly denied.
- Updated `OwnershipAuthorizationBackend` to include user context in the `evict` method, allowing for more granular control over ownership checks during thread deletions. - Introduced `_identity_values` method to standardize the retrieval of user identity values, ensuring consistency in ownership checks. - Enhanced `ThreadOwnershipResolver` to handle tenant columns more effectively, including a new `evict` method that accommodates both user IDs and tenant values. - Implemented a mechanism to log and raise errors when cache eviction fails, improving visibility into potential issues with ownership cache management. - Added a new configuration option `store_allow_tenant_mismatch` to allow for flexibility in tenant column checks during store initialization. - Developed regression tests to validate the new behavior, ensuring that tenant column checks and cache eviction logic function as intended.
- Introduced tenant value tracking during file uploads, ensuring files are scoped by both user ID and tenant columns. - Added tenant validation in MediaService methods to enforce access control based on tenant values. - Updated ensure_can_access and related methods to check tenant values alongside user ownership. - Enhanced upload_file to raise MissingTenantError when tenant values are not provided. - Created integration tests to verify tenant isolation behavior, ensuring users from different tenants cannot access each other's files. - Updated unit tests to accommodate changes in method signatures and ensure correct behavior with tenant values.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
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.
Summary
Wires the new core multi-tenant storage into the API:
user_idand/or tenant columns such asorg_id).filters.Also fixes several isolation edge cases found in review.
Depends on the core PR (PgVectorStore, tenant columns,
sql_filter,aget_thread_scope,Isolation). Merge core first.Why
Core can now isolate threads and memories by developer-declared tenant columns. The API has to:
The same
user_idin two orgs must behave as two identities on every route.What changed
Isolation scope per request
AuthorizationBackend.isolation_scope(user)is called on every request. Its result is stamped asconfig["user"]["authz"]through corebuild_authz.isolation_scope(self)still work. The method's signature decides how it is called; there is no retry onTypeError."owner":user_idplus every tenant column."none": no filter.["org_id"]for an org admin.RoleBasedAuthorizationBackend(isolation=...)with a typo refuses to boot.isolation_scopenow means"owner"; before, it meant"none".Thread ownership
OwnershipAuthorizationBackendallows a thread only when the thread's values (aget_thread_scope) equal the caller's on every picked column. The caller's values come only from the authenticated user.user_idin another tenant cannot take over a just-deleted thread id.cleanup_failed: ["cache"].Filters
GET /v1/threads?filters=<JSON>:validate_filtersbefore any database work.user_id, unknown operators and bad JSON all answer 422.POST /v1/store/search,/memories/forgetand/memories/listvalidate theirfiltersthe same way when the store has a filter schema. Qdrant keeps its old behaviour.Tenant-scoped files
/info,/url, deleteGET /v1/filesgraph://media/orfile_idreference (invoke, stream, WS, AG-UI,PUT state,POST messages)link_threadsConfig and loader
storekey in10xgraph.json. A mismatch with the checkpointer refuses to boot underMODE=production.store_allow_tenant_mismatch, also in the config editor.pathnow accepts a top-level module:auth_app:Cls,auth_app.py:Cls,pkg.mod:Clsandpkg/mod.py:Cls. A missing module still raises.Other fixes
POST /v1/store/search:retrieval_strategyanddistance_metricdefault toNone(use the store's settings). They were forced tosimilarity/cosine, which broke a text-only or HYBRIDPgVectorStore, and a Qdrant store using another distance.client_thread_idsdocs are fixed.Breaking changes
RoleBasedAuthorizationBackend. It used to become"none"or"owner"silently.isolation_scopeis now isolated per owner, not shared.RoleBasedAuthorizationBackend(isolation="none")now lets any authenticated user reach an existing thread, matching what storage already did under"none".jsonb) allow onlyis_null.Testing
user_idisolated on every route family (threads, state, messages, invoke, stream, store, files)config.user,config.org_idandconfig.authzignoredPgCheckpointerandPgVectorStoreusingorg_idand two orgs sharing usersam: 33 of 33 checks pass, covering threads, state, messages, invoke, delete, forged config, filters, memories and files.Release note
Bump the core dependency, currently
10xgraph>=1.0.0rc4,<2.0, to the core release that ships this feature. The new imports are guarded, so an older core does not crash, but tenant isolation and filters need the new one.Related
filtersandFilterstypes.store_allow_tenant_mismatch.