feat: integrate durable authorization audit and runtime composition
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e747-8f27-7242-8df8-8bc44f88c929
This commit is contained in:
parent
3e386147fd
commit
c9b6916dac
14 changed files with 767 additions and 16 deletions
|
|
@ -3,6 +3,8 @@ from __future__ import annotations
|
|||
import asyncio
|
||||
from contextlib import asynccontextmanager, suppress
|
||||
|
||||
import httpx
|
||||
|
||||
from fastapi import FastAPI, Response, status
|
||||
|
||||
from hub_core import __version__
|
||||
|
|
@ -27,7 +29,8 @@ from hub_core.runtime.workload_projection import (
|
|||
WorkloadProjectionService,
|
||||
)
|
||||
from hub_core.runtime.workload_projection_routes import create_workload_projection_router
|
||||
from hub_core.security.boundary import AccessBoundary, AccessController
|
||||
from hub_core.security.boundary import AccessBoundary, AccessController, FactSource
|
||||
from hub_core.security.config import SecuritySettings
|
||||
|
||||
|
||||
def create_app(
|
||||
|
|
@ -37,8 +40,25 @@ def create_app(
|
|||
repo_projection_client: RepoProjectionClient | None = None,
|
||||
workload_projection_client: WorkloadProjectionClient | None = None,
|
||||
access_controller: AccessController | None = None,
|
||||
access_facts: FactSource | None = None,
|
||||
security_settings: SecuritySettings | None = None,
|
||||
) -> FastAPI:
|
||||
resolved_settings = settings or RuntimeSettings.from_env()
|
||||
# Importing this module also constructs the standalone app. Environment
|
||||
# configuration is activated only by an explicit owner-facts composition;
|
||||
# without that adapter the default app stays closed, not import-broken.
|
||||
if security_settings is None and access_facts is not None:
|
||||
security_settings = SecuritySettings.from_env()
|
||||
security_client = None
|
||||
if access_controller is not None and (access_facts is not None or security_settings is not None):
|
||||
raise ValueError("choose an access controller or owner-facts composition")
|
||||
if security_settings is not None or access_facts is not None:
|
||||
if not resolved_settings.enforce_access:
|
||||
raise ValueError("security composition requires enforcement mode")
|
||||
if security_settings is None or access_facts is None:
|
||||
raise ValueError("security composition requires configuration and authoritative owner facts")
|
||||
security_client = httpx.AsyncClient(trust_env=False)
|
||||
access_controller = security_settings.compose(facts=access_facts, client=security_client)
|
||||
resolved_store = port_store or _create_store(resolved_settings)
|
||||
owns_store = port_store is None
|
||||
resolved_repo_projection_client = repo_projection_client
|
||||
|
|
@ -84,15 +104,19 @@ def create_app(
|
|||
await workload_projection.refresh()
|
||||
except WorkloadProjectionRejected:
|
||||
pass
|
||||
yield
|
||||
if refresh_task is not None:
|
||||
refresh_task.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await refresh_task
|
||||
if owns_repo_projection_client:
|
||||
await resolved_repo_projection_client.aclose() # type: ignore[union-attr]
|
||||
if owns_store and (closer := getattr(resolved_store, "aclose", None)):
|
||||
await closer()
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if refresh_task is not None:
|
||||
refresh_task.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await refresh_task
|
||||
if security_client is not None:
|
||||
await security_client.aclose()
|
||||
if owns_repo_projection_client:
|
||||
await resolved_repo_projection_client.aclose() # type: ignore[union-attr]
|
||||
if owns_store and (closer := getattr(resolved_store, "aclose", None)):
|
||||
await closer()
|
||||
|
||||
app = FastAPI(
|
||||
title="Hub Core Runtime",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue