Spaces:
Runtime error
Runtime error
File size: 3,921 Bytes
dc1b199 32c4506 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 d611f45 dc1b199 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | """Tenant isolation acceptance tests.
These are the hard-gating acceptance tests that must pass before any PR is merged:
- Ingest a document under tenant_A and another under tenant_B.
- Searching as tenant_A must NEVER return chunks that belong to tenant_B.
- Searching as tenant_B must NEVER return chunks that belong to tenant_A.
The vector store under test is a LangChain FAISS instance with an empty
on-disk path (from conftest). Documents carry ``tenant_id`` and ``chunk_id`` metadata.
"""
from __future__ import annotations
from langchain_core.documents import Document
def _make_docs(tenant_id: str, doc_id: str, n: int = 3) -> list[Document]:
"""Build ``n`` LangChain Documents for ``tenant_id``."""
return [
Document(
page_content=f"FIXTURE {tenant_id} document chunk number {i}.",
metadata={
"tenant_id": tenant_id,
"doc_id": doc_id,
"chunk_id": f"c-{tenant_id}-{i}",
},
)
for i in range(n)
]
def _index_docs(vs: object, docs: list[Document]) -> None:
"""Add documents to the vector store using the LangChain API."""
vs.add_documents(docs)
def test_tenant_a_results_only_contain_tenant_a_chunks(
in_memory_vs: object,
) -> None:
"""tenant_A search must not return any chunk from tenant_B.
This is a hard acceptance criterion — any failure here means tenant data
isolation is broken and the PR must not be merged.
"""
_index_docs(in_memory_vs, _make_docs("tenant_A", "doc-a"))
_index_docs(in_memory_vs, _make_docs("tenant_B", "doc-b"))
results = in_memory_vs.search("FIXTURE tenant_A document chunk", tenant_id="tenant_A", k=20)
assert len(results) > 0, "tenant_A should have matching results"
for r in results:
assert r.tenant_id == "tenant_A", (
f"Cross-tenant leak: got tenant_id='{r.tenant_id}' "
f"(chunk_id='{r.chunk_id}') in tenant_A query"
)
def test_tenant_b_results_only_contain_tenant_b_chunks(
in_memory_vs: object,
) -> None:
"""tenant_B search must not return any chunk from tenant_A."""
_index_docs(in_memory_vs, _make_docs("tenant_A", "doc-a"))
_index_docs(in_memory_vs, _make_docs("tenant_B", "doc-b"))
results = in_memory_vs.search("FIXTURE tenant_B document chunk", tenant_id="tenant_B", k=20)
assert len(results) > 0, "tenant_B should have matching results"
for r in results:
assert r.tenant_id == "tenant_B", (
f"Cross-tenant leak: got tenant_id='{r.tenant_id}' "
f"(chunk_id='{r.chunk_id}') in tenant_B query"
)
def test_unknown_tenant_returns_empty_results(
in_memory_vs: object,
) -> None:
"""A tenant with no ingested data should receive an empty result set."""
_index_docs(in_memory_vs, _make_docs("tenant_A", "doc-a"))
results = in_memory_vs.search("some query", tenant_id="tenant_UNKNOWN", k=10)
assert results == [], (
f"Expected empty results for unknown tenant, got {len(results)} results"
)
def test_count_is_per_tenant(
in_memory_vs: object,
) -> None:
"""count() should return the correct per-tenant chunk count."""
docs_a = _make_docs("tenant_A", "doc-a", n=3)
docs_b = _make_docs("tenant_B", "doc-b", n=2)
_index_docs(in_memory_vs, docs_a)
_index_docs(in_memory_vs, docs_b)
count_a = in_memory_vs.count("tenant_A")
count_b = in_memory_vs.count("tenant_B")
assert count_a == len(docs_a)
assert count_b == len(docs_b)
def test_delete_document_removes_chunks(
in_memory_vs: object,
) -> None:
"""delete_document should remove all chunks for that doc_id."""
docs_a = _make_docs("tenant_A", "doc-a", n=3)
_index_docs(in_memory_vs, docs_a)
assert in_memory_vs.count("tenant_A") == len(docs_a)
in_memory_vs.delete_document("doc-a")
assert in_memory_vs.count("tenant_A") == 0
|