diff --git a/src/tenantq/search.py b/src/tenantq/search.py index 9a51c6a..5923be5 100644 --- a/src/tenantq/search.py +++ b/src/tenantq/search.py @@ -44,6 +44,12 @@ def build_filter( created_before: Optional[int] = None, ) -> models.Filter: """Build a tenant-scoped filter, optionally narrowed by metadata.""" + if tenant_id is None or not str(tenant_id).strip(): + raise ValueError( + "tenant_id is required: request was not scoped to a tenant " + "(empty or whitespace-only tenant_id)" + ) + tenant_id = str(tenant_id).strip() must: List[models.FieldCondition] = [ models.FieldCondition(key=TENANT_FIELD, match=models.MatchValue(value=tenant_id)) ] diff --git a/tests/test_search.py b/tests/test_search.py index 8a936f8..7e7ebc6 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -66,3 +66,16 @@ def test_search_accepts_query_with_internal_spaces(ingested, settings, embedder) limit=5, ) assert len(hits) > 0 + + +@pytest.mark.parametrize("bad", ["", " ", "\t"]) +def test_build_filter_rejects_empty_tenant_id(bad): + from tenantq.search import build_filter + with pytest.raises(ValueError, match="not scoped"): + build_filter(bad) + + +def test_build_filter_accepts_tenant_with_internal_spaces(): + from tenantq.search import build_filter + f = build_filter("acme corp") + assert f.must