feat: implement project bus MVP

This commit is contained in:
Codex Lead Engineer
2026-07-30 02:13:26 +02:00
commit bc55924198
28 changed files with 3518 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
from __future__ import annotations
import hashlib
import hmac
import json
import os
from dataclasses import dataclass
from typing import Mapping, Protocol
from .errors import AuthenticationError
from .models import Principal
class AuthProvider(Protocol):
def authenticate(self, authorization_header: str | None) -> Principal:
"""Authenticate a request without trusting actor parameters."""
@dataclass(frozen=True)
class TokenIdentity:
actor_id: str
auth_subject: str
display_name: str
class StaticTokenAuthProvider:
"""Small deployment auth adapter intended for local and controlled use.
Tokens are compared using SHA-256 digests and constant-time comparison.
Production deployments should replace this adapter with an OIDC/JWT or
mTLS-backed implementation and keep the same ``AuthProvider`` contract.
"""
def __init__(self, token_identities: Mapping[str, TokenIdentity]):
if not token_identities:
raise ValueError("At least one authentication token is required")
if any(len(token) < 24 for token in token_identities):
raise ValueError("Every authentication token must contain at least 24 characters")
self._digests = {
hashlib.sha256(token.encode("utf-8")).digest(): identity
for token, identity in token_identities.items()
}
@classmethod
def from_environment(cls) -> "StaticTokenAuthProvider":
raw = os.environ.get("PROJECT_BUS_TOKENS_JSON")
bootstrap = os.environ.get("PROJECT_BUS_BOOTSTRAP_TOKEN")
if not bootstrap:
raise ValueError("PROJECT_BUS_BOOTSTRAP_TOKEN is required")
if len(bootstrap) < 24:
raise ValueError("PROJECT_BUS_BOOTSTRAP_TOKEN must contain at least 24 characters")
entries: dict[str, TokenIdentity] = {
bootstrap: TokenIdentity("system", "system", "Bootstrap system")
}
if raw:
decoded = json.loads(raw)
if not isinstance(decoded, dict):
raise ValueError("PROJECT_BUS_TOKENS_JSON must be a JSON object")
for token, identity in decoded.items():
entries[token] = TokenIdentity(
actor_id=identity["actor_id"],
auth_subject=identity.get("auth_subject", identity["actor_id"]),
display_name=identity.get("display_name", identity["actor_id"]),
)
return cls(entries)
def authenticate(self, authorization_header: str | None) -> Principal:
if not authorization_header or not authorization_header.startswith("Bearer "):
raise AuthenticationError("A Bearer token is required")
token = authorization_header[7:]
candidate = hashlib.sha256(token.encode("utf-8")).digest()
for expected, identity in self._digests.items():
if hmac.compare_digest(candidate, expected):
return Principal(
actor_id=identity.actor_id,
auth_subject=identity.auth_subject,
display_name=identity.display_name,
)
raise AuthenticationError("Invalid Bearer token")