feat(authz): data-plane allowlist helper + INSUFFICIENT_SCOPE code (Stage 1 收口)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1445043649
2026-06-28 21:19:32 +08:00
parent 1b7d8217dd
commit 2d982c3f0b
3 changed files with 76 additions and 0 deletions
+1
View File
@@ -22,6 +22,7 @@ class AuthErrorCode(StrEnum):
NOT_AUTHENTICATED = "not_authenticated"
SYSTEM_ALREADY_INITIALIZED = "system_already_initialized"
WORKSPACE_REQUIRED = "workspace_required"
INSUFFICIENT_SCOPE = "insufficient_scope"
class TokenError(StrEnum):
+22
View File
@@ -55,6 +55,28 @@ def _is_public(path: str) -> bool:
return any(path.startswith(prefix) for prefix in _PUBLIC_PATH_PREFIXES)
# Data-plane / SDK route prefixes a service principal (API key) may reach.
# Everything else (global control plane: models/mcp/memory/skills/channels/
# agents, plus management/auth endpoints) is denied by default for API keys.
# NOTE: nginx rewrites /api/langgraph/(.*) -> /api/$1 before the gateway, so
# AuthMiddleware never sees /api/langgraph; the SDK surface arrives as
# /api/threads, /api/runs, /api/assistants. assistants.search()/get() is
# required for langgraph-sdk client init, so /api/assistants is allowed.
_DATAPLANE_PREFIXES: tuple[str, ...] = (
"/api/threads",
"/api/v1/threads",
"/api/runs",
"/api/v1/runs",
"/api/assistants",
)
def _is_dataplane_path(path: str) -> bool:
"""True if an API key request may reach this path. Reusable by a future
Pattern B service-token branch."""
return any(path.startswith(prefix) for prefix in _DATAPLANE_PREFIXES)
class AuthMiddleware(BaseHTTPMiddleware):
"""Strict auth gate: reject requests without a valid session.