from __future__ import annotations import os from pathlib import Path from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, ConfigDict, Field from sqlmodel import Session from ..db.session import get_session from ..services.audit_logger import log_event from ..services.policy_engine import evaluate_policy from ..services.privatemuse_artifact_installer import ( ArtifactInstallError, install, validate_request, ) router = APIRouter(prefix="/api/privatemuse/artifacts") class ArtifactInstallRequest(BaseModel): model_config = ConfigDict(extra="forbid") artifact_type: str = Field(pattern="^(lora|checkpoint|unet|vae|clip|gguf)$") source_url: str = Field(min_length=9, max_length=2048) sha256: str = Field(pattern="^[0-9a-f]{64}$") filename: str = Field(min_length=13, max_length=192) source_id: str = Field(min_length=1, max_length=240) license: str = Field(min_length=1, max_length=240) reason: str = Field(min_length=1, max_length=1000) @router.post("/preflight") def preflight( payload: ArtifactInstallRequest, session: Session = Depends(get_session), ): action = "privatemuse.comfyui.install_artifact" target = "privatemuse/comfyui" decision = evaluate_policy( session, action=action, target=target, source="manual", ) try: normalized = validate_request(payload.model_dump()) except ArtifactInstallError as exc: raise HTTPException(422, str(exc)) from exc return { "ready": decision["decision"] != "blocked", "policy": decision, "artifact": { "artifact_type": normalized["artifact_type"], "filename": normalized["filename"], "sha256": normalized["sha256"], "source_id": normalized["source_id"], "source_host": normalized["source_url"].split("/")[2], "license": normalized["license"], }, } @router.post("/install") def install_artifact( payload: ArtifactInstallRequest, session: Session = Depends(get_session), ): action = "privatemuse.comfyui.install_artifact" target = "privatemuse/comfyui" decision = evaluate_policy( session, action=action, target=target, source="manual", ) if decision["decision"] != "allowed": raise HTTPException( 409, "Artifact installation requires an explicitly allowed policy/approved execution context.", ) model_root = Path( os.environ.get( "APPOPS_PRIVATEMUSE_COMFYUI_MODEL_ROOT", "/mnt/privatemuse-comfyui-models", ) ) receipt_root = Path( os.environ.get( "APPOPS_PRIVATEMUSE_ARTIFACT_RECEIPT_ROOT", "/data/privatemuse-artifact-receipts", ) ) try: result = install( payload.model_dump(), model_root=model_root, receipt_root=receipt_root, ) except ArtifactInstallError as exc: log_event( session, source="action", identity="manual", action_id=action, target=target, risk="high", policy_decision="allowed", reason=payload.reason, result="failed", redacted_metadata={ "filename": payload.filename, "sha256": payload.sha256, "source_id": payload.source_id, }, ) raise HTTPException(409, str(exc)) from exc audit = log_event( session, source="action", identity="manual", action_id=action, target=target, risk="high", policy_decision="allowed", reason=payload.reason, result="success", after_state={ "status": result["status"], "sha256": result["sha256"], "bytes": result["bytes"], }, redacted_metadata={ "filename": payload.filename, "source_id": payload.source_id, "license": payload.license, }, ) return {**result, "auditId": audit.id}