feat!: require explicit user on every tenant-data endpoint
Remove the implicit jpmschweitzer default tenant (DEFAULT_USER) from src/core/multi_tenancy.py and every endpoint and request model that inherited it (~40 endpoints across /query, /wiki, /vector, /graph, /ingest, /volatile, /documents, /stats, /rag). - Add validate_required_user() + RequiredUser pydantic type in multi_tenancy and a shared require_user FastAPI dependency (RequiredUserQuery) that rejects missing, empty, and whitespace-only users with 422, following the /maintenance/* pattern. - Wiki page create / smart-create / dossier request models now require user (no fallback in wiki_service). - /maintenance/cleanup/test-data derives the tenant from the page path instead of using the production tenant collection. - Wiki.js change listener skips changes when no tenant user can be derived from the notification email instead of defaulting to the production tenant. - Consolidation service internal helpers no longer default to the production tenant. - Tool catalog marks user as required with honest descriptions. - OpenAPI descriptions updated honestly; CHANGELOG notes that callers (tatlock, Scheduler ingest tasks) must now send explicit user. - Offline tests: 422 coverage for query/body endpoints, required-user validator tests; updated legacy tests that assumed a default tenant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -398,7 +398,7 @@ class ConsolidationService:
|
||||
query: str,
|
||||
web_results: List[Dict[str, Any]],
|
||||
keywords: List[str],
|
||||
user: str = "jpmschweitzer"
|
||||
user: str
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Analyze web results with Ollama for novel information.
|
||||
@@ -977,7 +977,7 @@ JSON:"""
|
||||
query: str,
|
||||
web_results: List[Dict[str, Any]],
|
||||
keywords: List[str],
|
||||
user: str = "jpmschweitzer"
|
||||
user: str
|
||||
) -> MemoryRoutingResult:
|
||||
"""
|
||||
Unified classification of web results for memory routing.
|
||||
|
||||
@@ -103,8 +103,17 @@ class WikiChangeListener:
|
||||
}
|
||||
event = event_map.get(operation, 'page.update')
|
||||
|
||||
# Extract user from email
|
||||
user = user_email.split('@')[0] if '@' in user_email else 'jpmschweitzer'
|
||||
# Extract user from email. There is NO default tenant: if no user
|
||||
# can be derived from the notification, skip processing instead of
|
||||
# attributing the change to an arbitrary tenant.
|
||||
if '@' in user_email and user_email.split('@')[0].strip():
|
||||
user = user_email.split('@')[0].strip()
|
||||
else:
|
||||
logger.warning(
|
||||
f"Skipping page {page_id} change: cannot derive tenant user "
|
||||
f"from notification email {user_email!r}"
|
||||
)
|
||||
return
|
||||
|
||||
# Process the change
|
||||
await self._process_page_change(
|
||||
|
||||
@@ -12,7 +12,7 @@ from typing import List, Optional, Dict, Any
|
||||
import logging
|
||||
|
||||
from src.clients.wikijs_client import WikiJSClient
|
||||
from src.core.multi_tenancy import get_wikijs_namespace, validate_user_id, DEFAULT_USER
|
||||
from src.core.multi_tenancy import get_wikijs_namespace, validate_user_id
|
||||
from src.models.wiki import (
|
||||
WikiPage, WikiPageSummary, WikiPageList,
|
||||
WikiPageCreate, WikiPageUpdate,
|
||||
@@ -184,7 +184,7 @@ class WikiService:
|
||||
Raises:
|
||||
ValueError: If creation fails
|
||||
"""
|
||||
user = page_data.user or DEFAULT_USER
|
||||
user = page_data.user
|
||||
|
||||
# Ensure path is in user's namespace
|
||||
full_path = self._ensure_user_path(page_data.path, user)
|
||||
|
||||
Reference in New Issue
Block a user