Stove-pipe RAG retrieval to prevent cross-tenant leakage (#40) #41

Merged
westfarn merged 1 commits from fix/rag-tenant-stove-pipe-40 into master 2026-08-01 12:35:01 -07:00
Owner

Summary

  • Closes #40
  • Aligns chat/RAG with the abc_worker stove-pipe pattern (b13cec8): immutable ChatCompanyScope per turn, conversation ownership validation, fail-closed Chroma filters
  • Prefer ASGI/JWT identity over client email; never bind identity from conversation_id alone
  • Close ConversationDetailView IDOR (prompts only for request.user)

Changes

  • New services/chat_tenant_scope.py with frozen ChatCompanyScope + ownership checks
  • WebSocket consumers (consumers.py / consumers_graph.py) validate scope before get_messages / RAG
  • search_documents requires a workspace (no more filter: None over the shared collection)
  • Ingest writes company_id metadata (retrieval still keys on workspace_id for back-compat)
  • Legacy get_retriever always applies a workspace filter

Test plan

  • manage.py test chat_backend.tests.test_chat_tenant_scope chat_backend.tests.test_consumers chat_backend.tests.test_services_rag chat_backend.tests.test_views_conversations
  • Manual: user A cannot stream RAG context from user B conversation_id
  • Manual: RAG still returns own-company docs after deploy (existing vectors with workspace_id only)
  • Follow-up: FE can send JWT token/access on WS payloads for stronger identity binding
## Summary - Closes [#40](https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/40) - Aligns chat/RAG with the abc_worker stove-pipe pattern ([b13cec8](https://git.aimloperations.com/GIS/abc_worker/commit/b13cec88f9730289f245b66b95aa11ee33cb4e8e)): immutable `ChatCompanyScope` per turn, conversation ownership validation, fail-closed Chroma filters - Prefer ASGI/JWT identity over client email; never bind identity from `conversation_id` alone - Close `ConversationDetailView` IDOR (prompts only for `request.user`) ## Changes - New `services/chat_tenant_scope.py` with frozen `ChatCompanyScope` + ownership checks - WebSocket consumers (`consumers.py` / `consumers_graph.py`) validate scope before `get_messages` / RAG - `search_documents` requires a workspace (no more `filter: None` over the shared collection) - Ingest writes `company_id` metadata (retrieval still keys on `workspace_id` for back-compat) - Legacy `get_retriever` always applies a workspace filter ## Test plan - [x] `manage.py test chat_backend.tests.test_chat_tenant_scope chat_backend.tests.test_consumers chat_backend.tests.test_services_rag chat_backend.tests.test_views_conversations` - [ ] Manual: user A cannot stream RAG context from user B `conversation_id` - [ ] Manual: RAG still returns own-company docs after deploy (existing vectors with `workspace_id` only) - [ ] Follow-up: FE can send JWT `token`/`access` on WS payloads for stronger identity binding
westfarn added 1 commit 2026-08-01 12:31:23 -07:00
Stove-pipe RAG retrieval behind ChatCompanyScope (#40).
CI / test (pull_request) Successful in 10s
Unit Tests / test (pull_request) Successful in 9s
7fae0175cf
Validate conversation ownership before workspace resolution, fail closed
when Chroma filters are missing, and close ConversationDetailView IDOR so
tenants cannot pull another company's document chunks.
westfarn merged commit 2e9e95e16c into master 2026-08-01 12:35:01 -07:00
westfarn deleted branch fix/rag-tenant-stove-pipe-40 2026-08-01 12:35:01 -07:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ai_ml_operations/chat_backend#41