Initial public ModelForge release

This commit is contained in:
Jens
2026-09-01 21:30:16 +02:00
commit 7082ab955a
490 changed files with 104252 additions and 0 deletions
@@ -0,0 +1,208 @@
from __future__ import annotations
import hmac
import re
from dataclasses import dataclass
from enum import StrEnum
from typing import Annotated
from fastapi import Depends, Header, HTTPException, Request
from modelforge_api.settings import Settings, get_settings
class PrincipalRole(StrEnum):
"""Closed operator-console roles, ordered from read-only to security administration."""
VIEWER = "viewer"
OPERATOR = "operator"
ADMIN = "admin"
class AccessBoundary(StrEnum):
"""Mutually exclusive request authentication boundaries.
The control-plane boundary is deliberately the default. New endpoints therefore fail closed
behind the human operator credential until their narrower machine/public policy is explicitly
recorded here and in the route inventory tests.
"""
PUBLIC = "public"
SINGLE_USE_ENROLLMENT = "single_use_enrollment"
NODE = "node"
CAPABILITY_CLIENT = "capability_client"
CONTROL_PLANE = "control_plane"
_PUBLIC_REQUESTS = {
("GET", "/"),
("GET", "/api/v1/health/live"),
("GET", "/api/v1/health/ready"),
("GET", "/api/v1/version"),
}
_INTERACTIVE_API_PATHS = {"/docs", "/docs/oauth2-redirect", "/redoc", "/openapi.json"}
_NODE_REQUESTS = {
("POST", "/api/v1/agent/heartbeat"),
("PUT", "/api/v1/agent/inventory"),
("PUT", "/api/v1/agent/telemetry"),
("GET", "/api/v1/agent/artifact-jobs/next"),
("POST", "/api/v1/agent/artifact-jobs/{job_id}/progress"),
("POST", "/api/v1/agent/artifact-jobs/{job_id}/complete"),
("POST", "/api/v1/agent/artifact-jobs/{job_id}/fail"),
("GET", "/api/v1/agent/runtime-probes/next"),
("POST", "/api/v1/agent/runtime-probes/{probe_id}/progress"),
("POST", "/api/v1/agent/runtime-probes/{probe_id}/complete"),
("POST", "/api/v1/agent/runtime-probes/{probe_id}/fail"),
("GET", "/api/v1/agent/serving-jobs/next"),
("POST", "/api/v1/agent/serving-jobs/{job_id}/complete"),
("POST", "/api/v1/agent/serving-jobs/{job_id}/fail"),
("POST", "/api/v1/agent/serving-state"),
}
_NODE_PARAMETERIZED_REQUESTS = (
("POST", re.compile(r"^/api/v1/agent/artifact-jobs/[^/]+/(?:progress|complete|fail)$")),
("POST", re.compile(r"^/api/v1/agent/runtime-probes/[^/]+/(?:progress|complete|fail)$")),
("POST", re.compile(r"^/api/v1/agent/serving-jobs/[^/]+/(?:complete|fail)$")),
)
_CAPABILITY_REQUIREMENTS = {
("POST", "/api/v1/capabilities/rag.embedding@1/invoke"): "rag.embedding@1",
("POST", "/api/v1/capabilities/rag.reranking@1/invoke"): "rag.reranking@1",
("POST", "/api/v1/capabilities/document.ocr@1/invoke"): "document.ocr@1",
("POST", "/api/v1/capabilities/vision.embedding@1/invoke"): "vision.embedding@1",
("POST", "/api/v1/capabilities/speech.transcription@1/invoke"): "speech.transcription@1",
("POST", "/api/v1/capability-experiments/{route_key}/invoke"): "rag.embedding@1",
("POST", "/v1/embeddings"): "rag.embedding@1",
}
_CAPABILITY_CLIENT_REQUESTS = set(_CAPABILITY_REQUIREMENTS)
_CAPABILITY_EXPERIMENT_REQUEST = re.compile(r"^/api/v1/capability-experiments/[^/]+/invoke$")
def access_boundary_for_request(
method: str,
path: str,
) -> AccessBoundary:
"""Classify an HTTP request without reading its body or accepting credential aliases."""
normalized_method = method.upper()
if (normalized_method, path) in _PUBLIC_REQUESTS:
return AccessBoundary.PUBLIC
if path in _INTERACTIVE_API_PATHS:
# These routes exist only when the FastAPI app is explicitly constructed for development.
# In test/production they must reach routing unauthenticated so the disabled surface is a
# genuine 404 rather than an operator-auth challenge that reveals a hidden endpoint.
return AccessBoundary.PUBLIC
if normalized_method == "POST" and path == "/api/v1/agent/enroll":
return AccessBoundary.SINGLE_USE_ENROLLMENT
if (normalized_method, path) in _NODE_REQUESTS or any(
normalized_method == rule_method and pattern.fullmatch(path)
for rule_method, pattern in _NODE_PARAMETERIZED_REQUESTS
):
return AccessBoundary.NODE
if (normalized_method, path) in _CAPABILITY_CLIENT_REQUESTS or (
normalized_method == "POST" and _CAPABILITY_EXPERIMENT_REQUEST.fullmatch(path)
):
return AccessBoundary.CAPABILITY_CLIENT
return AccessBoundary.CONTROL_PLANE
def required_capability_for_request(method: str, path: str) -> str | None:
"""Return the exact capability scope for a registered project-facing route."""
normalized_method = method.upper()
requirement = _CAPABILITY_REQUIREMENTS.get((normalized_method, path))
if requirement is not None:
return requirement
if normalized_method == "POST" and _CAPABILITY_EXPERIMENT_REQUEST.fullmatch(path):
return "rag.embedding@1"
return None
def request_body_limit_bytes(settings: Settings, boundary: AccessBoundary) -> int:
"""Select an explicit pre-parser body limit for every request boundary."""
if boundary is AccessBoundary.CAPABILITY_CLIENT:
return settings.gateway_max_payload_bytes
if boundary in {AccessBoundary.NODE, AccessBoundary.SINGLE_USE_ENROLLMENT}:
return settings.node_agent_max_payload_bytes
return settings.control_plane_max_payload_bytes
_ROLE_RANK = {
PrincipalRole.VIEWER: 0,
PrincipalRole.OPERATOR: 1,
PrincipalRole.ADMIN: 2,
}
@dataclass(frozen=True, slots=True)
class Principal:
"""An authenticated human/control-plane principal.
Node and capability credentials deliberately never become a ``Principal``. Their separate
dependencies remain the only way into node-agent and inference surfaces, preventing credential
confusion at the type and dependency boundaries.
"""
subject: str
role: PrincipalRole
authentication_method: str
def permits(self, required: PrincipalRole) -> bool:
return _ROLE_RANK[self.role] >= _ROLE_RANK[required]
def authenticate_operator_token(settings: Settings, token: str | None) -> Principal:
"""Authenticate the backward-compatible operator key as an admin principal.
The legacy key is the sole human credential in this release. OIDC/session authentication can
add another principal producer later without changing route authorization policy.
"""
configured = settings.operator_api_key
if configured is None or not configured.get_secret_value():
raise HTTPException(status_code=503, detail="operator API authentication is not configured")
if token is None or not hmac.compare_digest(token, configured.get_secret_value()):
raise HTTPException(status_code=401, detail="invalid operator credential")
return Principal(
subject="legacy-operator",
role=PrincipalRole.ADMIN,
authentication_method="legacy_admin_token",
)
def authenticate_operator_principal(
request: Request,
settings: Annotated[Settings, Depends(get_settings)],
token: Annotated[str | None, Header(alias="X-ModelForge-Admin-Token")] = None,
) -> Principal:
"""Reuse the pre-body principal and retain a safe direct-dependency fallback."""
principal = getattr(request.state, "principal", None)
if isinstance(principal, Principal):
return principal
return authenticate_operator_token(settings, token)
AuthenticatedPrincipal = Annotated[Principal, Depends(authenticate_operator_principal)]
def _require_role(principal: Principal, required: PrincipalRole) -> Principal:
if not principal.permits(required):
raise HTTPException(status_code=403, detail="operator role is not authorized")
return principal
def require_viewer(principal: AuthenticatedPrincipal) -> Principal:
return _require_role(principal, PrincipalRole.VIEWER)
def require_operator(principal: AuthenticatedPrincipal) -> Principal:
return _require_role(principal, PrincipalRole.OPERATOR)
def require_admin(principal: AuthenticatedPrincipal) -> Principal:
return _require_role(principal, PrincipalRole.ADMIN)
Viewer = Annotated[Principal, Depends(require_viewer)]
Operator = Annotated[Principal, Depends(require_operator)]
Admin = Annotated[Principal, Depends(require_admin)]