"""GSAP Pydantic models — GCAP-SPEC-SHELLBOUND-BROKER-0001.""" from datetime import datetime from enum import Enum from typing import Optional from uuid import UUID, uuid4 from pydantic import BaseModel, Field class ACStatus(str, Enum): PENDING = "pending" AUTHORIZED = "authorized" ACTIVE = "active" # Session-scoped: accepts multiple CRs until session_end CONSUMED = "consumed" EXPIRED = "expired" REVOKED = "revoked" class Outcome(str, Enum): COMPLETED = "completed" FAILED = "failed" VIOLATED = "violated" TIMED_OUT = "timed_out" SESSION_END = "session_end" # Final CR for session-scoped ACs → transitions to consumed class BehaviorStatus(str, Enum): VERIFIED = "verified" VIOLATED = "violated" UNAVAILABLE = "unavailable" class Principal(BaseModel): did: str display_name: str = "" broker_session_id: str = "" driver_id: str = "" class Accord(BaseModel): template: str capability_mask: int = 3 class Operation(BaseModel): playbook: str corpus_entry_cid: str parameters_cid: str apply_authorized_cid: Optional[str] = None class IdentityProof(BaseModel): idp_vendor: str = "keycloak" token_jti: str = "" elevation_active: list[str] = [] mfa_satisfied: bool = False class AuthorizationContext(BaseModel): gsap_version: str = "0.1.0" context_id: UUID = Field(default_factory=uuid4) issued_at: datetime expires_at: datetime principal: Principal accord: Accord operation: Operation identity_proof: IdentityProof broker: dict = Field(default_factory=dict) signature: Optional[dict] = None device_id: Optional[str] = None device_compliant: Optional[bool] = None compliance_checked_at: Optional[datetime] = None class ChronicleEvidence(BaseModel): session_id: Optional[str] = None events: list[dict] = [] merkle_root: Optional[str] = None class BehavioralAttestation(BaseModel): status: BehaviorStatus = BehaviorStatus.UNAVAILABLE observed_behavior_cid: Optional[str] = None declared_behavior_cid: Optional[str] = None class AuthorizeRequest(BaseModel): playbook: str corpus_entry_cid: str parameters_cid: str accord_template: str driver_id: str session_mode: bool = False # When true, AC stays active across multiple CRs # When set by a trusted caller (e.g. Bascule), overrides the driver-derived principal. # The SA authenticates the request; this field says who the AC is FOR. on_behalf_of: Optional[str] = None class AuthorizeResponse(BaseModel): status: str authorization_context: Optional[AuthorizationContext] = None poll_token: Optional[str] = None elevation_instructions: Optional[str] = None activation_url: Optional[str] = None class CompleteRequest(BaseModel): context_id: UUID outcome: Outcome completed_at: datetime failure_reason: Optional[str] = None chronicle_session_id: Optional[str] = None chronicle_evidence: ChronicleEvidence = Field(default_factory=ChronicleEvidence) behavioral_attestation: BehavioralAttestation = Field(default_factory=BehavioralAttestation) ffc: dict = Field(default_factory=dict) signature: Optional[dict] = None class CompleteResponse(BaseModel): status: str = "received" receipt_id: UUID signature_verified: bool chronicle_event_cid: Optional[str] = None class SessionResponse(BaseModel): context_id: UUID principal_did: str accord_template: str playbook: str status: ACStatus issued_at: datetime expires_at: datetime consumed_at: Optional[datetime] = None chronicle_event_cid: Optional[str] = None completion_receipt: Optional[dict] = None class ElevateRequest(BaseModel): role_name: str justification: str = "" duration_minutes: int = Field(default=60, ge=5, le=480) class ElevateResponse(BaseModel): status: str elevation_id: Optional[str] = None message: str = ""