refactor(harness): route workflow persistence through repositories
This commit is contained in:
@@ -2,10 +2,12 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Protocol, Sequence
|
||||
|
||||
from tht.decisions import DecisionInput, DecisionRecord
|
||||
from tht.session.models import PrincipalContext, SessionManifest, SessionSnapshot
|
||||
from tht.session.store import SessionError
|
||||
|
||||
|
||||
class SessionRepository(Protocol):
|
||||
@@ -17,16 +19,22 @@ class SessionRepository(Protocol):
|
||||
|
||||
def get(self, session_id: str) -> SessionSnapshot: ...
|
||||
|
||||
def list(self) -> list[SessionSnapshot]: ...
|
||||
|
||||
def save_manifest(self, manifest: SessionManifest) -> SessionSnapshot: ...
|
||||
|
||||
def read_artifact(self, session_id: str, key: str) -> str | None: ...
|
||||
|
||||
def write_artifact(self, session_id: str, key: str, content: str) -> None: ...
|
||||
|
||||
def delete_artifact(self, session_id: str, key: str) -> None: ...
|
||||
|
||||
def append_decisions(
|
||||
self, session_id: str, decisions: Sequence[DecisionInput | dict]
|
||||
) -> list[DecisionRecord]: ...
|
||||
|
||||
def finalize(self, manifest: SessionManifest, artifacts: dict[str, str]) -> SessionSnapshot: ...
|
||||
|
||||
def get_preferences(self) -> dict: ...
|
||||
|
||||
def set_preferences(self, preferences: dict) -> None: ...
|
||||
@@ -34,8 +42,35 @@ class SessionRepository(Protocol):
|
||||
def delete(self, session_id: str) -> None: ...
|
||||
|
||||
|
||||
def build_session_repository(config, principal: PrincipalContext, *, home=None) -> SessionRepository:
|
||||
def resolve_principal(config) -> PrincipalContext:
|
||||
"""Resolve the only principal source permitted for this CLI invocation.
|
||||
|
||||
The backend injects these values from its authenticated request context before
|
||||
spawning ``tht``. A server-storage command without them must fail closed;
|
||||
substituting a workstation identity would cross user ownership boundaries.
|
||||
"""
|
||||
if getattr(config, "session_storage", None) is None:
|
||||
from tht.session.models import local_principal
|
||||
|
||||
return local_principal()
|
||||
issuer = os.environ.get("THT_PRINCIPAL_ISSUER", "").strip()
|
||||
subject = os.environ.get("THT_PRINCIPAL_SUBJECT", "").strip()
|
||||
if not issuer or not subject:
|
||||
raise SessionError(
|
||||
"THT_PRINCIPAL_ISSUER e THT_PRINCIPAL_SUBJECT sono obbligatori per session storage server"
|
||||
)
|
||||
display_name = os.environ.get("THT_PRINCIPAL_DISPLAY_NAME", "").strip() or None
|
||||
is_admin = os.environ.get("THT_PRINCIPAL_IS_ADMIN", "").strip().lower() in {"1", "true"}
|
||||
return PrincipalContext(
|
||||
issuer=issuer, subject=subject, display_name=display_name, is_admin=is_admin
|
||||
)
|
||||
|
||||
|
||||
def build_session_repository(
|
||||
config, principal: PrincipalContext | None = None, *, home=None
|
||||
) -> SessionRepository:
|
||||
"""Build the configured private session persistence adapter."""
|
||||
principal = principal or resolve_principal(config)
|
||||
session_storage = getattr(config, "session_storage", None)
|
||||
if session_storage is not None:
|
||||
from tht.session.postgres_repository import PostgresSessionRepository
|
||||
@@ -46,4 +81,7 @@ def build_session_repository(config, principal: PrincipalContext, *, home=None)
|
||||
from tht.session.filesystem_repository import FilesystemSessionRepository
|
||||
|
||||
workspace = getattr(config, "_workspace_id", "default")
|
||||
return FilesystemSessionRepository(home or local_tht_home(), workspace, principal)
|
||||
return FilesystemSessionRepository(
|
||||
home or local_tht_home(), workspace, principal,
|
||||
root=None if home is not None else getattr(config.paths, "sessions", None),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user