#!/usr/bin/env python3 """Security boundary for one-approval silent release execution. The signed plan binds immutable release evidence. Each capability is consumed independently so runtime deployment, tag publication, and release finalization remain separate controllers and separately recoverable Saga steps. """ from __future__ import annotations import base64 import hashlib import json import os import re import tempfile import time import uuid from dataclasses import asdict, dataclass, field from datetime import datetime, timezone from enum import Enum from pathlib import Path from typing import Any, Callable, Iterable, Mapping, Protocol from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey from silent_release_controller import ( CANDIDATE_ID_RE, OID_RE, SHA256_RE, ReleaseCandidate, ReleaseCandidateStore, ReleaseState, _atomic_json, _parse_utc, _sanitize, utc_now, ) IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:-]{2,255}$") NONCE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:-]{15,255}$") ALLOWED_CAPABILITIES = frozenset( { "runtime_switch", "tag_publish", "baseline_registry_finalize", } ) FORBIDDEN_CAPABILITIES = frozenset( { "force_push", "tag_rewrite", "direct_main_push", "baseline_mutation", "registry_mutation", } ) class CapabilityAuthorizationError(RuntimeError): """The signed plan cannot authorize the requested operation.""" class StaleApprovalError(CapabilityAuthorizationError): """Live release evidence no longer matches the signed approval.""" class SagaConflict(RuntimeError): """A stale controller attempted a non-current Saga transition.""" class JournalIntegrityError(RuntimeError): """The durable Saga journal is truncated, reordered, or modified.""" class ClaimProbeResult(str, Enum): NOT_APPLIED = "NOT_APPLIED" APPLIED_VERIFIED = "APPLIED_VERIFIED" INDETERMINATE = "INDETERMINATE" CONFLICT = "CONFLICT" @dataclass(frozen=True) class ProbeEvidence: """Fresh, operation-bound evidence for a side-effect recovery decision.""" result: ClaimProbeResult operation_digest: str observed_at: float evidence: Mapping[str, Any] = field(default_factory=dict) def validate( self, *, expected_operation_digest: str, now: float, maximum_age_seconds: float, ) -> "ProbeEvidence": if self.operation_digest != expected_operation_digest: raise CapabilityAuthorizationError( "probe evidence operation digest mismatch" ) age = float(now) - float(self.observed_at) if age < 0 or age > float(maximum_age_seconds): raise CapabilityAuthorizationError( "probe evidence is outside its freshness window" ) return self def to_dict(self) -> dict[str, Any]: return { "evidence": _sanitize(dict(self.evidence)), "evidence_sha256": hashlib.sha256( _canonical_json(_sanitize(dict(self.evidence))) ).hexdigest(), "observed_at": float(self.observed_at), "operation_digest": self.operation_digest, "result": ClaimProbeResult(self.result).value, } @dataclass(frozen=True) class TagPublicationProbeEvidence: """Independent Git/Gitea observations used to classify TAG_PENDING.""" repository_identity: str | None remote_reachable: bool gitea_api_reachable: bool gitea_listing_reachable: bool remote_tag_oid: str | None = None annotated_tag_object_oid: str | None = None remote_peeled_target_oid: str | None = None gitea_api_tag_oid: str | None = None gitea_api_peeled_target_oid: str | None = None gitea_listing_visible: bool | None = None gitea_listing_tag_oid: str | None = None gitea_listing_peeled_target_oid: str | None = None observed_at: float = field(default_factory=time.time) def to_dict(self) -> dict[str, Any]: return _sanitize(asdict(self)) def classify_tag_publication( evidence: TagPublicationProbeEvidence, plan: "TagPlan", ) -> ClaimProbeResult: """Classify a tag without mutating, deleting, or rewriting any ref.""" if ( not evidence.remote_reachable or not evidence.gitea_api_reachable or not evidence.gitea_listing_reachable or evidence.repository_identity is None ): return ClaimProbeResult.INDETERMINATE if evidence.repository_identity != plan.repository_identity: return ClaimProbeResult.CONFLICT tag_oids = ( evidence.remote_tag_oid, evidence.gitea_api_tag_oid, evidence.gitea_listing_tag_oid, ) target_oids = ( evidence.remote_peeled_target_oid, evidence.gitea_api_peeled_target_oid, evidence.gitea_listing_peeled_target_oid, ) if ( all(value is None for value in tag_oids) and all(value is None for value in target_oids) and evidence.annotated_tag_object_oid is None and evidence.gitea_listing_visible is False ): return ClaimProbeResult.NOT_APPLIED observed_tag_oids = tuple(value for value in tag_oids if value is not None) observed_targets = tuple( value for value in target_oids if value is not None ) if ( any(value != plan.expected_tag_oid for value in observed_tag_oids) or any(value != plan.expected_target_oid for value in observed_targets) or ( plan.tag_type == "annotated" and evidence.annotated_tag_object_oid is not None and evidence.annotated_tag_object_oid != plan.expected_tag_oid ) ): return ClaimProbeResult.CONFLICT exact = ( tag_oids == ( plan.expected_tag_oid, plan.expected_tag_oid, plan.expected_tag_oid, ) and target_oids == ( plan.expected_target_oid, plan.expected_target_oid, plan.expected_target_oid, ) and evidence.gitea_listing_visible is True and ( plan.tag_type != "annotated" or evidence.annotated_tag_object_oid == plan.expected_tag_oid ) ) return ( ClaimProbeResult.APPLIED_VERIFIED if exact else ClaimProbeResult.INDETERMINATE ) JOURNAL_SCHEMA_VERSION = 1 JOURNAL_GENESIS_HASH = "0" * 64 def _fsync_directory(path: Path) -> None: descriptor = os.open(Path(path), os.O_RDONLY) try: os.fsync(descriptor) finally: os.close(descriptor) def _durable_json(path: Path, payload: Mapping[str, Any]) -> None: _atomic_json(path, dict(payload)) _fsync_directory(path.parent) def _validate_identifier(name: str, value: str) -> str: normalized = str(value or "") if not IDENTIFIER_RE.fullmatch(normalized): raise ValueError(f"invalid {name}") return normalized def _validate_oid(name: str, value: str) -> str: normalized = str(value or "").lower() if not OID_RE.fullmatch(normalized): raise ValueError(f"{name} must be a full 40-character OID") return normalized def _validate_sha(name: str, value: str) -> str: normalized = str(value or "").lower() if not SHA256_RE.fullmatch(normalized): raise ValueError(f"{name} must be a SHA-256 digest") return normalized def _canonical_json(payload: Mapping[str, Any]) -> bytes: return json.dumps( payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True, ).encode("utf-8") def _safe_child(root: Path, name: str, suffix: str = ".json") -> Path: _validate_identifier("storage key", name) resolved_root = Path(root).resolve() candidate = (resolved_root / f"{name}{suffix}").resolve() if candidate.parent != resolved_root: raise ValueError("storage path escapes root") return candidate @dataclass(frozen=True) class DeploymentPlan: service: str release_path: str release_root: str dropin_path: str dropin_sha256: str rollback_path: str rollback_sha256: str source_commit: str artifact_sha256: str manifest_sha256: str policy_sha256: str health_contract: dict[str, Any] cutover_link: str = "" systemd_unit_sha256: str = "" tree_oid: str = "" package_closure_sha256: str = "" authoritative_git_dir: str = "" repository_identity: str = "" writer_expected: bool = False baseline_before_sha256: str = "" registry_before_sha256: str = "" production_tag_refset_before_sha256: str = "" health_contract_version: str = "" timeout_policy: dict[str, Any] = field(default_factory=dict) retry_policy: dict[str, Any] = field(default_factory=dict) def __post_init__(self) -> None: _validate_identifier("service", self.service) _validate_oid("source_commit", self.source_commit) for name in ( "dropin_sha256", "rollback_sha256", "artifact_sha256", "manifest_sha256", "policy_sha256", ): _validate_sha(name, getattr(self, name)) if self.tree_oid: _validate_oid("tree_oid", self.tree_oid) for name in ( "systemd_unit_sha256", "package_closure_sha256", "baseline_before_sha256", "registry_before_sha256", "production_tag_refset_before_sha256", ): if getattr(self, name): _validate_sha(name, getattr(self, name)) if not isinstance(self.health_contract, dict): raise ValueError("health_contract must be an object") if not isinstance(self.timeout_policy, dict): raise ValueError("timeout_policy must be an object") if not isinstance(self.retry_policy, dict): raise ValueError("retry_policy must be an object") if self.writer_expected is not False: raise ValueError("production writer must remain disabled") @property def canonical_payload(self) -> dict[str, Any]: return { "artifact_sha256": self.artifact_sha256, "authoritative_git_dir": self.authoritative_git_dir, "baseline_before_sha256": self.baseline_before_sha256, "cutover_link": self.cutover_link, "dropin_path": self.dropin_path, "dropin_sha256": self.dropin_sha256, "health_contract": self.health_contract, "health_contract_version": self.health_contract_version, "manifest_sha256": self.manifest_sha256, "package_closure_sha256": self.package_closure_sha256, "policy_sha256": self.policy_sha256, "production_tag_refset_before_sha256": ( self.production_tag_refset_before_sha256 ), "release_path": self.release_path, "release_root": self.release_root, "repository_identity": self.repository_identity, "retry_policy": self.retry_policy, "rollback_path": self.rollback_path, "rollback_sha256": self.rollback_sha256, "service": self.service, "source_commit": self.source_commit, "systemd_unit_sha256": self.systemd_unit_sha256, "timeout_policy": self.timeout_policy, "tree_oid": self.tree_oid, "writer_expected": self.writer_expected, "registry_before_sha256": self.registry_before_sha256, } @property def sha256(self) -> str: return hashlib.sha256( _canonical_json(self.canonical_payload) ).hexdigest() def validate( self, *, service_allowlist: Iterable[str], dropin_allowlist: Iterable[str], ) -> "DeploymentPlan": if self.service not in frozenset(service_allowlist): raise ValueError("service is not allowlisted") release_root = Path(self.release_root).resolve() release_path = Path(self.release_path).resolve() try: release_path.relative_to(release_root) except ValueError as exc: raise ValueError("release path escapes release root") from exc if release_path == release_root: raise ValueError("release path must be a release child") dropin = Path(self.dropin_path).resolve() try: dropin.relative_to(release_path) except ValueError as exc: raise ValueError("drop-in escapes release path") from exc allowed_dropins = { str(Path(value).resolve()) for value in dropin_allowlist } if str(dropin) not in allowed_dropins: raise ValueError("drop-in is not allowlisted") return self def validate_complete(self) -> "DeploymentPlan": for name in ( "cutover_link", "authoritative_git_dir", "repository_identity", "health_contract_version", ): if not str(getattr(self, name) or ""): raise ValueError(f"{name} is required") _validate_oid("tree_oid", self.tree_oid) for name in ( "systemd_unit_sha256", "package_closure_sha256", "baseline_before_sha256", "registry_before_sha256", "production_tag_refset_before_sha256", ): _validate_sha(name, getattr(self, name)) if not self.timeout_policy or not self.retry_policy: raise ValueError("timeout and retry policies are required") return self def to_dict(self) -> dict[str, Any]: return _sanitize({**self.canonical_payload, "sha256": self.sha256}) @classmethod def from_dict(cls, payload: Mapping[str, Any]) -> "DeploymentPlan": values = dict(payload) values.pop("sha256", None) return cls(**values) @dataclass(frozen=True) class TagPlan: version: str tag_type: str expected_tag_oid: str expected_target_oid: str evidence_closure_oid: str approval_plan_id: str repository_identity: str gitea_owner: str gitea_repository: str current_remote_tag_oid: str | None remote_absent_evidence_sha256: str | None verification_contract: str force_push_allowed: bool = False tag_rewrite_allowed: bool = False def __post_init__(self) -> None: _validate_identifier("version", self.version) if self.tag_type not in {"annotated", "lightweight"}: raise ValueError("unsupported tag type") for name in ( "expected_tag_oid", "expected_target_oid", "evidence_closure_oid", ): _validate_oid(name, getattr(self, name)) _validate_identifier("approval_plan_id", self.approval_plan_id) _validate_identifier("gitea_owner", self.gitea_owner) _validate_identifier("gitea_repository", self.gitea_repository) present = self.current_remote_tag_oid is not None absent = self.remote_absent_evidence_sha256 is not None if present == absent: raise ValueError( "tag plan must bind either current tag or signed absence" ) if present: _validate_oid( "current_remote_tag_oid", self.current_remote_tag_oid or "" ) if absent: _validate_sha( "remote_absent_evidence_sha256", self.remote_absent_evidence_sha256 or "", ) if not self.repository_identity or not self.verification_contract: raise ValueError("tag repository and verification are required") if self.force_push_allowed or self.tag_rewrite_allowed: raise ValueError("force push and tag rewrite are forbidden") @property def canonical_payload(self) -> dict[str, Any]: return asdict(self) @property def sha256(self) -> str: return hashlib.sha256( _canonical_json(self.canonical_payload) ).hexdigest() def to_dict(self) -> dict[str, Any]: return _sanitize({**self.canonical_payload, "sha256": self.sha256}) @classmethod def from_dict(cls, payload: Mapping[str, Any]) -> "TagPlan": values = dict(payload) values.pop("sha256", None) return cls(**values) @dataclass(frozen=True) class FinalizationPlan: version: str expected_tag_oid: str expected_target_oid: str expected_previous_baseline_sha256: str registry_expected_record: dict[str, Any] baseline_expected_record: dict[str, Any] final_consistency_contract: str def __post_init__(self) -> None: _validate_identifier("version", self.version) _validate_oid("expected_tag_oid", self.expected_tag_oid) _validate_oid("expected_target_oid", self.expected_target_oid) _validate_sha( "expected_previous_baseline_sha256", self.expected_previous_baseline_sha256, ) if not isinstance(self.registry_expected_record, dict): raise ValueError("registry expected record must be an object") if not isinstance(self.baseline_expected_record, dict): raise ValueError("baseline expected record must be an object") if not self.final_consistency_contract: raise ValueError("final consistency contract is required") @property def canonical_payload(self) -> dict[str, Any]: return asdict(self) @property def sha256(self) -> str: return hashlib.sha256( _canonical_json(self.canonical_payload) ).hexdigest() def to_dict(self) -> dict[str, Any]: return _sanitize({**self.canonical_payload, "sha256": self.sha256}) @classmethod def from_dict(cls, payload: Mapping[str, Any]) -> "FinalizationPlan": values = dict(payload) values.pop("sha256", None) return cls(**values) @dataclass(frozen=True) class ReleasePlan: deployment: DeploymentPlan tag: TagPlan finalization: FinalizationPlan policy_sha256: str def __post_init__(self) -> None: _validate_sha("policy_sha256", self.policy_sha256) def validate(self) -> "ReleasePlan": self.deployment.validate_complete() if self.deployment.policy_sha256 != self.policy_sha256: raise ValueError("deployment policy does not match release plan") if self.deployment.repository_identity != self.tag.repository_identity: raise ValueError("release repository identity is inconsistent") if self.deployment.source_commit != self.tag.expected_target_oid: raise ValueError("deployment commit and tag target are inconsistent") if self.tag.version != self.finalization.version: raise ValueError("release version is inconsistent") if self.tag.expected_tag_oid != self.finalization.expected_tag_oid: raise ValueError("release tag OID is inconsistent") if ( self.tag.expected_target_oid != self.finalization.expected_target_oid ): raise ValueError("release target OID is inconsistent") if ( self.deployment.baseline_before_sha256 != self.finalization.expected_previous_baseline_sha256 ): raise ValueError("previous baseline is inconsistent") return self @property def canonical_payload(self) -> dict[str, Any]: return { "deployment": self.deployment.canonical_payload, "finalization": self.finalization.canonical_payload, "policy_sha256": self.policy_sha256, "tag": self.tag.canonical_payload, } @property def sha256(self) -> str: return hashlib.sha256( _canonical_json(self.canonical_payload) ).hexdigest() def to_dict(self) -> dict[str, Any]: return _sanitize({**self.canonical_payload, "sha256": self.sha256}) @classmethod def from_dict(cls, payload: Mapping[str, Any]) -> "ReleasePlan": values = dict(payload) values.pop("sha256", None) return cls( deployment=DeploymentPlan.from_dict(values["deployment"]), tag=TagPlan.from_dict(values["tag"]), finalization=FinalizationPlan.from_dict( values["finalization"] ), policy_sha256=values["policy_sha256"], ) @dataclass(frozen=True) class TrustedReleasePolicy: services: frozenset[str] release_roots: frozenset[str] cutover_links: frozenset[str] dropin_paths: frozenset[str] authoritative_git_dirs: frozenset[str] repository_identities: frozenset[str] def validate_deployment(self, plan: DeploymentPlan) -> DeploymentPlan: plan.validate_complete() checks = ( (plan.service, self.services, "service"), (plan.release_root, self.release_roots, "release root"), (plan.cutover_link, self.cutover_links, "cutover link"), (plan.dropin_path, self.dropin_paths, "drop-in"), ( plan.authoritative_git_dir, self.authoritative_git_dirs, "authoritative Git directory", ), ( plan.repository_identity, self.repository_identities, "repository identity", ), ) for value, allowlist, label in checks: if value not in allowlist: raise ValueError(f"{label} is not allowlisted") plan.validate( service_allowlist=self.services, dropin_allowlist=self.dropin_paths, ) return plan class ReleasePlanStore: def __init__(self, root: Path): self.root = Path(root) def save(self, candidate_id: str, plan: ReleasePlan) -> Path: path = _safe_child(self.root, candidate_id) if path.exists(): existing = self.load(candidate_id) if existing.sha256 != plan.sha256: raise SagaConflict( "candidate is bound to another release plan" ) return path _durable_json(path, plan.to_dict()) return path def load(self, candidate_id: str) -> ReleasePlan: return ReleasePlan.from_dict( json.loads( _safe_child(self.root, candidate_id).read_text( encoding="utf-8" ) ) ) class SignedApprovalStore: def __init__(self, root: Path): self.root = Path(root) def save( self, candidate_id: str, approval: "SignedReleasePlanApproval" ) -> tuple[Path, bool]: path = _safe_child(self.root, candidate_id) if path.exists(): existing = self.load(candidate_id) if existing.fingerprint != approval.fingerprint: raise CapabilityAuthorizationError( "candidate has a conflicting owner approval" ) return path, False _durable_json(path, approval.to_dict()) return path, True def load(self, candidate_id: str) -> "SignedReleasePlanApproval": return SignedReleasePlanApproval.from_dict( json.loads( _safe_child(self.root, candidate_id).read_text( encoding="utf-8" ) ) ) @dataclass(frozen=True) class BuilderAttestation: builder_attestation_id: str builder_key_id: str source_commit: str tree_oid: str artifact_sha256: str manifest_sha256: str package_closure_sha256: str test_evidence_sha256: str canary_evidence_sha256: str issued_at: str signature: str def __post_init__(self) -> None: _validate_identifier( "builder_attestation_id", self.builder_attestation_id ) _validate_identifier("builder_key_id", self.builder_key_id) _validate_oid("source_commit", self.source_commit) _validate_oid("tree_oid", self.tree_oid) for name in ( "artifact_sha256", "manifest_sha256", "package_closure_sha256", "test_evidence_sha256", "canary_evidence_sha256", ): _validate_sha(name, getattr(self, name)) _parse_utc(self.issued_at) @property def canonical_payload(self) -> dict[str, Any]: values = asdict(self) values.pop("signature") return values def canonical_bytes(self) -> bytes: return _canonical_json(self.canonical_payload) @property def fingerprint(self) -> str: return hashlib.sha256(self.canonical_bytes()).hexdigest() def to_dict(self) -> dict[str, Any]: return { **self.canonical_payload, "fingerprint": self.fingerprint, "signature": self.signature, } @classmethod def from_dict(cls, payload: Mapping[str, Any]) -> "BuilderAttestation": values = dict(payload) values.pop("fingerprint", None) return cls(**values) class BuilderAttestationVerifier: """Public-key-only verifier; no builder private material is accepted.""" def __init__(self, public_keys: Mapping[str, bytes]): self.public_keys = { _validate_identifier("builder_key_id", key_id): bytes(value) for key_id, value in public_keys.items() } def verify( self, attestation: BuilderAttestation, candidate: ReleaseCandidate, release_plan: ReleasePlan, ) -> BuilderAttestation: expected = ( candidate.source_commit, candidate.tree_oid, candidate.artifact_sha256, candidate.manifest_sha256, release_plan.deployment.package_closure_sha256, ) actual = ( attestation.source_commit, attestation.tree_oid, attestation.artifact_sha256, attestation.manifest_sha256, attestation.package_closure_sha256, ) if actual != expected: raise CapabilityAuthorizationError( "builder attestation does not bind candidate evidence" ) key = self.public_keys.get(attestation.builder_key_id) if key is None: raise CapabilityAuthorizationError( "builder attestation key is not trusted" ) try: signature = base64.b64decode( attestation.signature, validate=True ) Ed25519PublicKey.from_public_bytes(key).verify( signature, attestation.canonical_bytes() ) except (InvalidSignature, ValueError, TypeError) as exc: raise CapabilityAuthorizationError( "builder attestation signature is invalid" ) from exc return attestation @dataclass(frozen=True) class TrustedCandidateBundle: candidate: ReleaseCandidate release_plan: ReleasePlan checks: Mapping[str, bool] attestation: BuilderAttestation | None = None REQUIRED_CHECKS = frozenset( { "authoritative_git", "artifact", "canary", "gitea", "manifest", "package_closure", "rollback", "secret_scan", "tests", } ) def validate( self, attestation_verifier: BuilderAttestationVerifier | None = None, ) -> "TrustedCandidateBundle": missing = self.REQUIRED_CHECKS.difference(self.checks) if missing or any(self.checks.get(name) is not True for name in self.REQUIRED_CHECKS): raise CapabilityAuthorizationError( "trusted builder acceptance is incomplete" ) candidate = self.candidate if ( candidate.state != ReleaseState.READY_FOR_APPROVAL or candidate.tests.get("passed") is not True or candidate.canary.get("passed") is not True or candidate.rollback_ready is not True or candidate.git_consistency.get("consistent") is not True or candidate.gitea_consistency.get("consistent") is not True ): raise CapabilityAuthorizationError( "candidate is not trusted release evidence" ) plan = self.release_plan.validate() if ( plan.deployment.source_commit != candidate.source_commit or plan.deployment.tree_oid != candidate.tree_oid or plan.deployment.artifact_sha256 != candidate.artifact_sha256 or plan.deployment.manifest_sha256 != candidate.manifest_sha256 ): raise CapabilityAuthorizationError( "trusted candidate and release plan are inconsistent" ) if attestation_verifier is not None: if self.attestation is None: raise CapabilityAuthorizationError( "trusted builder attestation is required" ) attestation_verifier.verify( self.attestation, candidate, self.release_plan ) return self def acceptance_record(self) -> dict[str, Any]: return { "attestation": ( self.attestation.to_dict() if self.attestation else None ), "candidate_id": self.candidate.candidate_id, "checks": _sanitize(dict(self.checks)), "release_plan_sha256": self.release_plan.sha256, "status": "ACCEPTED", } class TrustedCandidateBuilder(Protocol): def build(self, intent: Mapping[str, Any]) -> TrustedCandidateBundle: ... class DeploymentPlanStore: def __init__(self, root: Path): self.root = Path(root) def save(self, candidate_id: str, plan: DeploymentPlan) -> Path: path = _safe_child(self.root, candidate_id) _atomic_json(path, plan.to_dict()) return path def load(self, candidate_id: str) -> DeploymentPlan: return DeploymentPlan.from_dict( json.loads( _safe_child(self.root, candidate_id).read_text( encoding="utf-8" ) ) ) @dataclass(frozen=True) class SignedReleasePlanApproval: release_plan_id: str candidate_id: str source_commit: str tree_oid: str artifact_sha256: str manifest_sha256: str deployment_plan_sha256: str policy_sha256: str approval_plan_id: str evidence_closure_oid: str owner_approval_record_oid: str capabilities: tuple[str, ...] expires_at: str nonce: str key_id: str signature: str owner_identity: str = "" trust_domain: str = "" issued_at: str = "1970-01-01T00:00:00Z" not_before: str = "1970-01-01T00:00:00Z" release_plan_sha256: str = "" def __post_init__(self) -> None: for name in ( "release_plan_id", "candidate_id", "approval_plan_id", "key_id", ): _validate_identifier(name, getattr(self, name)) if not NONCE_RE.fullmatch(str(self.nonce or "")): raise ValueError("invalid nonce") for name in ( "source_commit", "tree_oid", "evidence_closure_oid", "owner_approval_record_oid", ): _validate_oid(name, getattr(self, name)) for name in ( "artifact_sha256", "manifest_sha256", "deployment_plan_sha256", "policy_sha256", ): _validate_sha(name, getattr(self, name)) if self.release_plan_sha256: _validate_sha( "release_plan_sha256", self.release_plan_sha256 ) capabilities = tuple(str(item) for item in self.capabilities) object.__setattr__(self, "capabilities", capabilities) if ( not capabilities or len(capabilities) != len(set(capabilities)) or not set(capabilities).issubset(ALLOWED_CAPABILITIES) ): raise ValueError("approval contains invalid capabilities") _parse_utc(self.expires_at) _parse_utc(self.issued_at) _parse_utc(self.not_before) @property def canonical_payload(self) -> dict[str, Any]: return { "approval_plan_id": self.approval_plan_id, "artifact_sha256": self.artifact_sha256, "candidate_id": self.candidate_id, "capabilities": list(self.capabilities), "deployment_plan_sha256": self.deployment_plan_sha256, "evidence_closure_oid": self.evidence_closure_oid, "expires_at": self.expires_at, "key_id": self.key_id, "manifest_sha256": self.manifest_sha256, "nonce": self.nonce, "not_before": self.not_before, "owner_identity": self.owner_identity, "owner_approval_record_oid": self.owner_approval_record_oid, "policy_sha256": self.policy_sha256, "release_plan_sha256": self.release_plan_sha256, "release_plan_id": self.release_plan_id, "source_commit": self.source_commit, "tree_oid": self.tree_oid, "trust_domain": self.trust_domain, "issued_at": self.issued_at, } def canonical_bytes(self) -> bytes: return _canonical_json(self.canonical_payload) @property def fingerprint(self) -> str: return hashlib.sha256(self.canonical_bytes()).hexdigest() def to_dict(self) -> dict[str, Any]: return { **self.canonical_payload, "fingerprint": self.fingerprint, "signature": self.signature, } @classmethod def from_dict( cls, payload: Mapping[str, Any] ) -> "SignedReleasePlanApproval": values = dict(payload) values.pop("fingerprint", None) values["capabilities"] = tuple(values.get("capabilities") or ()) return cls(**values) class ApprovalKeyRing: """Public-only Ed25519 key ring with in-process rotation/revocation.""" def __init__(self, public_keys: Mapping[str, bytes]): self._keys: dict[str, bytes] = {} self._revoked: set[str] = set() for key_id, public_key in public_keys.items(): self.add(key_id, public_key) def add(self, key_id: str, public_key: bytes) -> None: key_id = _validate_identifier("key_id", key_id) raw = bytes(public_key) if len(raw) != 32: raise ValueError("Ed25519 public key must contain 32 bytes") Ed25519PublicKey.from_public_bytes(raw) self._keys[key_id] = raw self._revoked.discard(key_id) def revoke(self, key_id: str) -> None: if key_id not in self._keys: raise KeyError("unknown approval signing key") self._revoked.add(key_id) def verify( self, key_id: str, signature: bytes, message: bytes ) -> None: if key_id not in self._keys or key_id in self._revoked: raise CapabilityAuthorizationError( "approval signing key is unavailable or revoked" ) try: Ed25519PublicKey.from_public_bytes( self._keys[key_id] ).verify(signature, message) except InvalidSignature as exc: raise CapabilityAuthorizationError( "owner approval signature is invalid" ) from exc def save_public(self, path: Path) -> None: payload = { "algorithm": "Ed25519", "keys": { key_id: base64.b64encode(value).decode("ascii") for key_id, value in sorted(self._keys.items()) }, "revoked": sorted(self._revoked), } _atomic_json(Path(path), payload) @classmethod def from_file(cls, path: Path) -> "ApprovalKeyRing": payload = json.loads(Path(path).read_text(encoding="utf-8")) if payload.get("algorithm") != "Ed25519": raise ValueError("unsupported approval signature algorithm") ring = cls( { key_id: base64.b64decode(encoded, validate=True) for key_id, encoded in payload.get("keys", {}).items() } ) for key_id in payload.get("revoked", []): ring.revoke(key_id) return ring class ApprovalRevocationStore: def __init__(self, root: Path): self.root = Path(root) def revoke(self, approval_plan_id: str, reason: str) -> dict[str, Any]: path = _safe_child(self.root, approval_plan_id) payload = { "approval_plan_id": approval_plan_id, "reason": str(reason or "revoked"), "revoked_at": utc_now(), } _atomic_json(path, payload) return payload def is_revoked(self, approval_plan_id: str) -> bool: return _safe_child(self.root, approval_plan_id).is_file() class SignedApprovalVerifier: def __init__( self, keyring: ApprovalKeyRing, revocations: ApprovalRevocationStore, *, allowed_trust_domains: Iterable[str] = (), maximum_approval_lifetime_seconds: int = 3600, ): self.keyring = keyring self.revocations = revocations self.allowed_trust_domains = frozenset(allowed_trust_domains) self.maximum_approval_lifetime_seconds = int( maximum_approval_lifetime_seconds ) def _verify_signature( self, approval: SignedReleasePlanApproval ) -> None: try: signature = base64.b64decode( approval.signature, validate=True ) except (ValueError, TypeError) as exc: raise CapabilityAuthorizationError( "owner approval signature encoding is invalid" ) from exc self.keyring.verify( approval.key_id, signature, approval.canonical_bytes(), ) def verify( self, approval: SignedReleasePlanApproval, candidate: ReleaseCandidate, deployment_plan: DeploymentPlan, policy_sha256: str, ) -> SignedReleasePlanApproval: try: if _parse_utc(approval.expires_at) <= datetime.now(timezone.utc): raise CapabilityAuthorizationError( "owner approval has expired" ) if self.revocations.is_revoked(approval.approval_plan_id): raise CapabilityAuthorizationError( "owner approval has been revoked" ) expected = ( candidate.candidate_id, candidate.source_commit, candidate.tree_oid, candidate.artifact_sha256, candidate.manifest_sha256, deployment_plan.sha256, _validate_sha("policy_sha256", policy_sha256), ) actual = ( approval.candidate_id, approval.source_commit, approval.tree_oid, approval.artifact_sha256, approval.manifest_sha256, approval.deployment_plan_sha256, approval.policy_sha256, ) if actual != expected: raise CapabilityAuthorizationError( "owner approval binding does not match release evidence" ) self._verify_signature(approval) return approval except CapabilityAuthorizationError: raise except Exception as exc: raise CapabilityAuthorizationError( "owner approval verification failed" ) from exc def verify_release_plan( self, approval: SignedReleasePlanApproval, candidate: ReleaseCandidate, release_plan: ReleasePlan, policy_sha256: str, *, now: str | datetime | None = None, ) -> SignedReleasePlanApproval: try: release_plan.validate() policy_sha256 = _validate_sha( "policy_sha256", policy_sha256 ) instant = ( datetime.now(timezone.utc) if now is None else _parse_utc(now) if isinstance(now, str) else now ) if instant.tzinfo is None: raise CapabilityAuthorizationError( "verification time must be timezone-aware" ) issued_at = _parse_utc(approval.issued_at) not_before = _parse_utc(approval.not_before) expires_at = _parse_utc(approval.expires_at) if not issued_at <= not_before <= expires_at: raise CapabilityAuthorizationError( "owner approval time window is invalid" ) if not not_before <= instant <= expires_at: raise CapabilityAuthorizationError( "owner approval is outside its validity window" ) lifetime = (expires_at - issued_at).total_seconds() if ( lifetime <= 0 or lifetime > self.maximum_approval_lifetime_seconds ): raise CapabilityAuthorizationError( "owner approval lifetime exceeds policy" ) if ( not approval.owner_identity or not approval.trust_domain or ( self.allowed_trust_domains and approval.trust_domain not in self.allowed_trust_domains ) ): raise CapabilityAuthorizationError( "owner approval trust binding is invalid" ) if self.revocations.is_revoked(approval.approval_plan_id): raise CapabilityAuthorizationError( "owner approval has been revoked" ) expected = ( candidate.candidate_id, candidate.source_commit, candidate.tree_oid, candidate.artifact_sha256, candidate.manifest_sha256, release_plan.deployment.sha256, policy_sha256, release_plan.sha256, release_plan.tag.approval_plan_id, ) actual = ( approval.candidate_id, approval.source_commit, approval.tree_oid, approval.artifact_sha256, approval.manifest_sha256, approval.deployment_plan_sha256, approval.policy_sha256, approval.release_plan_sha256, approval.approval_plan_id, ) if actual != expected: raise CapabilityAuthorizationError( "owner approval does not bind the complete release plan" ) self._verify_signature(approval) return approval except CapabilityAuthorizationError: raise except Exception as exc: raise CapabilityAuthorizationError( "owner release plan verification failed" ) from exc class CapabilityLedger: """Durable exclusive claims with leases and fail-closed recovery probes.""" STATES = frozenset( { "PENDING", "CLAIMED", "COMPLETED", "FAILED_RECOVERABLE", "RECONCILIATION_REQUIRED", "MANUAL_OWNER_REVIEW_REQUIRED", } ) def __init__( self, root: Path, *, maximum_probe_age_seconds: float = 60, ): self.root = Path(root) self.maximum_probe_age_seconds = float(maximum_probe_age_seconds) if self.maximum_probe_age_seconds <= 0: raise ValueError("maximum_probe_age_seconds must be positive") def _operation_path( self, approval: SignedReleasePlanApproval, capability: str, operation: str, ) -> Path: key = hashlib.sha256( "\0".join( (approval.release_plan_id, capability, operation) ).encode("utf-8") ).hexdigest() return _safe_child(self.root, key) def _nonce_path(self, nonce: str) -> Path: key = hashlib.sha256(nonce.encode("utf-8")).hexdigest() return _safe_child(self.root / "nonces", key) def _lock(self, path: Path): lock_path = self.root / ".locks" / f"{path.stem}.lock" lock_path.parent.mkdir(parents=True, exist_ok=True) os.chmod(lock_path.parent, 0o700) handle = lock_path.open("a+", encoding="utf-8") os.chmod(lock_path, 0o600) try: import fcntl fcntl.flock(handle.fileno(), fcntl.LOCK_EX) except ImportError: pass return handle @staticmethod def _unlock(handle) -> None: try: import fcntl fcntl.flock(handle.fileno(), fcntl.LOCK_UN) except ImportError: pass handle.close() @staticmethod def _assert_authorized( approval: SignedReleasePlanApproval, capability: str, operation: str, ) -> None: if ( capability in FORBIDDEN_CAPABILITIES or capability not in ALLOWED_CAPABILITIES or capability not in approval.capabilities ): raise CapabilityAuthorizationError( "capability is not authorized by owner approval" ) _validate_identifier("operation", operation) @staticmethod def _immutable_payload( approval: SignedReleasePlanApproval, capability: str, operation: str, ) -> dict[str, Any]: operation_digest = hashlib.sha256( _canonical_json( { "approval_fingerprint": approval.fingerprint, "capability": capability, "operation": operation, "release_plan_id": approval.release_plan_id, } ) ).hexdigest() return { "approval_fingerprint": approval.fingerprint, "approval_plan_id": approval.approval_plan_id, "capability": capability, "operation": operation, "operation_digest": operation_digest, "release_plan_id": approval.release_plan_id, } @staticmethod def _assert_record_matches( existing: Mapping[str, Any], expected: Mapping[str, Any], ) -> None: if {key: existing.get(key) for key in expected} != dict(expected): raise CapabilityAuthorizationError( "capability replay conflicts with durable record" ) def _write(self, path: Path, payload: Mapping[str, Any]) -> None: path.parent.mkdir(parents=True, exist_ok=True) os.chmod(path.parent, 0o700) _durable_json(path, payload) os.chmod(path, 0o600) def _probe_journal_path(self, operation_path: Path) -> Path: return _safe_child( self.root / ".probe-journal", operation_path.stem, ".events.jsonl", ) def _append_probe_event( self, operation_path: Path, *, probe: ProbeEvidence, ) -> dict[str, Any]: path = self._probe_journal_path(operation_path) path.parent.mkdir(parents=True, exist_ok=True) os.chmod(path.parent, 0o700) records = self.verify_probe_journal(operation_path, missing_ok=True) previous_hash = ( records[-1]["event_hash"] if records else JOURNAL_GENESIS_HASH ) core = { "sequence": len(records) + 1, "previous_hash": previous_hash, "payload": probe.to_dict(), } record = { "schema_version": JOURNAL_SCHEMA_VERSION, **core, "event_hash": hashlib.sha256(_canonical_json(core)).hexdigest(), } with path.open("a", encoding="utf-8") as output: output.write( json.dumps(record, sort_keys=True, separators=(",", ":")) + "\n" ) output.flush() os.fsync(output.fileno()) os.chmod(path, 0o600) _fsync_directory(path.parent) return record def verify_probe_journal( self, operation_path: Path, *, missing_ok: bool = False, ) -> list[dict[str, Any]]: path = self._probe_journal_path(operation_path) if not path.exists(): if missing_ok: return [] raise JournalIntegrityError("capability probe journal is missing") records: list[dict[str, Any]] = [] previous = JOURNAL_GENESIS_HASH for sequence, line in enumerate( path.read_text(encoding="utf-8").splitlines(), 1 ): try: record = json.loads(line) except json.JSONDecodeError as exc: raise JournalIntegrityError( "capability probe journal contains invalid JSON" ) from exc if set(record) != { "schema_version", "sequence", "previous_hash", "payload", "event_hash", }: raise JournalIntegrityError( "capability probe journal schema is invalid" ) core = { "sequence": record["sequence"], "previous_hash": record["previous_hash"], "payload": record["payload"], } expected_hash = hashlib.sha256(_canonical_json(core)).hexdigest() if ( record["schema_version"] != JOURNAL_SCHEMA_VERSION or record["sequence"] != sequence or record["previous_hash"] != previous or record["event_hash"] != expected_hash ): raise JournalIntegrityError( "capability probe journal hash chain verification failed" ) previous = record["event_hash"] records.append(record) return records @staticmethod def _coerce_probe( value: ClaimProbeResult | ProbeEvidence | Mapping[str, Any], *, operation_digest: str, now: float, ) -> ProbeEvidence: if isinstance(value, ProbeEvidence): return value if isinstance(value, Mapping): return ProbeEvidence( result=ClaimProbeResult(value["result"]), operation_digest=str(value["operation_digest"]), observed_at=float(value["observed_at"]), evidence=dict(value.get("evidence") or {}), ) return ProbeEvidence( result=ClaimProbeResult(value), operation_digest=operation_digest, observed_at=now, evidence={}, ) def _run_probe_locked( self, path: Path, record: dict[str, Any], side_effect_probe: Callable[ [], ClaimProbeResult | ProbeEvidence | Mapping[str, Any] ], *, now: float, ) -> tuple[dict[str, Any], ProbeEvidence]: probe = self._coerce_probe( side_effect_probe(), operation_digest=str(record["operation_digest"]), now=now, ).validate( expected_operation_digest=str(record["operation_digest"]), now=now, maximum_age_seconds=self.maximum_probe_age_seconds, ) event = self._append_probe_event(path, probe=probe) record.update( { "last_probe": probe.to_dict(), "probe_journal_event_hash": event["event_hash"], "probe_result": probe.result.value, } ) return record, probe def read( self, approval: SignedReleasePlanApproval, capability: str, *, operation: str, ) -> dict[str, Any] | None: path = self._operation_path(approval, capability, operation) if not path.is_file(): return None record = json.loads(path.read_text(encoding="utf-8")) self._assert_record_matches( record, self._immutable_payload(approval, capability, operation), ) return _sanitize(record) def _bind_nonce(self, approval: SignedReleasePlanApproval) -> None: path = self._nonce_path(approval.nonce) expected = { "fingerprint": approval.fingerprint, "release_plan_id": approval.release_plan_id, } path.parent.mkdir(parents=True, exist_ok=True) os.chmod(path.parent, 0o700) try: descriptor = os.open( path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600, ) except FileExistsError: actual = json.loads(path.read_text(encoding="utf-8")) if actual != expected: raise CapabilityAuthorizationError( "approval nonce replay does not match original plan" ) return with os.fdopen(descriptor, "w", encoding="utf-8") as output: json.dump(expected, output, sort_keys=True) output.write("\n") output.flush() os.fsync(output.fileno()) _fsync_directory(path.parent) def claim( self, approval: SignedReleasePlanApproval, capability: str, *, operation: str, executor_id: str, lease_seconds: float, now: float | None = None, side_effect_probe: Callable[ [], ClaimProbeResult | ProbeEvidence | Mapping[str, Any] ] | None = None, ) -> dict[str, Any]: self._assert_authorized(approval, capability, operation) _validate_identifier("executor_id", executor_id) if lease_seconds <= 0: raise ValueError("lease_seconds must be positive") timestamp = time.time() if now is None else float(now) path = self._operation_path(approval, capability, operation) path.parent.mkdir(parents=True, exist_ok=True) self._bind_nonce(approval) immutable = self._immutable_payload( approval, capability, operation ) lock = self._lock(path) try: if path.exists(): record = json.loads(path.read_text(encoding="utf-8")) self._assert_record_matches(record, immutable) else: record = { **immutable, "attempt": 0, "state": "PENDING", } state = str(record.get("state") or "PENDING") if state == "COMPLETED": return {**record, "status": "IDEMPOTENT"} if state in { "RECONCILIATION_REQUIRED", "MANUAL_OWNER_REVIEW_REQUIRED", }: return {**record, "status": state} recovery_required = state == "FAILED_RECOVERABLE" if state == "CLAIMED": lease_until = float(record.get("lease_until") or 0) if lease_until > timestamp: if record.get("executor_id") == executor_id: return {**record, "status": "CLAIMED"} return {**record, "status": "BUSY"} recovery_required = True if recovery_required: if side_effect_probe is None: return {**record, "status": "PROBE_REQUIRED"} record, probe = self._run_probe_locked( path, record, side_effect_probe, now=timestamp, ) if probe.result == ClaimProbeResult.APPLIED_VERIFIED: record.update( { "completed_at": utc_now(), "state": "COMPLETED", } ) self._write(path, record) return {**record, "status": "IDEMPOTENT"} if probe.result == ClaimProbeResult.INDETERMINATE: record.update( { "state": "RECONCILIATION_REQUIRED", } ) self._write(path, record) return {**record, "status": record["state"]} if probe.result == ClaimProbeResult.CONFLICT: record.update( {"state": "MANUAL_OWNER_REVIEW_REQUIRED"} ) self._write(path, record) return {**record, "status": record["state"]} claim_id = uuid.uuid4().hex claimed = { **record, **immutable, "attempt": int(record.get("attempt") or 0) + 1, "claim_id": claim_id, "claimed_at": timestamp, "executor_id": executor_id, "lease_until": timestamp + float(lease_seconds), "state": "CLAIMED", } self._write(path, claimed) return {**claimed, "status": "CLAIMED"} finally: self._unlock(lock) def complete( self, approval: SignedReleasePlanApproval, capability: str, *, operation: str, claim_id: str | None = None, evidence: Mapping[str, Any] | None = None, ) -> dict[str, Any]: self._assert_authorized(approval, capability, operation) path = self._operation_path(approval, capability, operation) immutable = self._immutable_payload( approval, capability, operation ) lock = self._lock(path) try: record = json.loads(path.read_text(encoding="utf-8")) self._assert_record_matches(record, immutable) if record.get("state") == "COMPLETED": return {**record, "status": "IDEMPOTENT"} if ( record.get("state") != "CLAIMED" or not claim_id or record.get("claim_id") != claim_id ): raise CapabilityAuthorizationError( "capability completion claim_id mismatch" ) record.update( { "completed_at": utc_now(), "evidence": _sanitize(dict(evidence or {})), "state": "COMPLETED", } ) self._write(path, record) return {**record, "status": "COMPLETED"} finally: self._unlock(lock) def fail_recoverable( self, approval: SignedReleasePlanApproval, capability: str, *, operation: str, claim_id: str, reason: str, ) -> dict[str, Any]: self._assert_authorized(approval, capability, operation) path = self._operation_path(approval, capability, operation) immutable = self._immutable_payload( approval, capability, operation ) lock = self._lock(path) try: record = json.loads(path.read_text(encoding="utf-8")) self._assert_record_matches(record, immutable) if ( record.get("state") != "CLAIMED" or record.get("claim_id") != claim_id ): raise CapabilityAuthorizationError( "capability failure claim_id mismatch" ) record.update( { "failure_reason": str(reason), "state": "FAILED_RECOVERABLE", } ) self._write(path, record) return record finally: self._unlock(lock) def reserve( self, approval: SignedReleasePlanApproval, capability: str, *, operation: str, ) -> dict[str, Any]: """Compatibility wrapper; production controllers use claim().""" path = self._operation_path(approval, capability, operation) if path.exists(): record = json.loads(path.read_text(encoding="utf-8")) if record.get("state") == "COMPLETED": return {**record, "status": "IDEMPOTENT"} if record.get("state") in { "CLAIMED", "FAILED_RECOVERABLE", }: return {**record, "status": "RESUME"} result = self.claim( approval, capability, operation=operation, executor_id="compatibility-reservation", lease_seconds=300, ) aliases = { "CLAIMED": "RESERVED", "BUSY": "RESUME", "IDEMPOTENT": "IDEMPOTENT", } return {**result, "status": aliases.get(result["status"], result["status"])} def consume( self, approval: SignedReleasePlanApproval, capability: str, *, operation: str, ) -> dict[str, Any]: reservation = self.reserve( approval, capability, operation=operation ) if reservation["status"] == "IDEMPOTENT": return reservation completed = self.complete( approval, capability, operation=operation, claim_id=reservation["claim_id"], ) return {**completed, "status": "CONSUMED"} class SagaState(str, Enum): PREPARING = "PREPARING" VERIFYING = "VERIFYING" READY_FOR_APPROVAL = "READY_FOR_APPROVAL" APPROVED = "APPROVED" PRE_SWITCH_REVALIDATING = "PRE_SWITCH_REVALIDATING" SWITCH_PENDING = "SWITCH_PENDING" SWITCHED = "SWITCHED" RUNTIME_VERIFYING = "RUNTIME_VERIFYING" RUNTIME_VERIFIED = "RUNTIME_VERIFIED" TAG_PENDING = "TAG_PENDING" TAG_VERIFIED = "TAG_VERIFIED" BASELINE_REGISTRY_PENDING = "BASELINE_REGISTRY_PENDING" COMPLETED = "COMPLETED" ROLLBACK_PENDING = "ROLLBACK_PENDING" ROLLED_BACK = "ROLLED_BACK" RECONCILIATION_REQUIRED = "RECONCILIATION_REQUIRED" MANUAL_OWNER_REVIEW_REQUIRED = "MANUAL_OWNER_REVIEW_REQUIRED" @dataclass class ReleaseSaga: candidate_id: str release_plan_id: str state: SagaState = SagaState.PREPARING revision: int = 0 events: list[dict[str, Any]] = field(default_factory=list) journal_sequence: int = 0 journal_head_hash: str = JOURNAL_GENESIS_HASH journal_integrity: bool = True created_at: str = field(default_factory=utc_now) updated_at: str = field(default_factory=utc_now) def to_dict(self) -> dict[str, Any]: payload = asdict(self) payload["state"] = self.state.value return _sanitize(payload) @classmethod def from_dict(cls, payload: Mapping[str, Any]) -> "ReleaseSaga": values = dict(payload) values["state"] = SagaState(values["state"]) return cls(**values) class ReleaseSagaStore: """Hash-chained journal is truth; atomic snapshot is a rebuildable cache.""" RECOVERY_ACTIONS = { SagaState.SWITCH_PENDING: "resume_runtime_switch", SagaState.SWITCHED: "verify_runtime", SagaState.RUNTIME_VERIFYING: "verify_runtime", SagaState.TAG_PENDING: "reconcile_tag", SagaState.TAG_VERIFIED: "reconcile_baseline_registry", SagaState.BASELINE_REGISTRY_PENDING: "reconcile_baseline_registry", SagaState.ROLLBACK_PENDING: "resume_rollback", SagaState.RECONCILIATION_REQUIRED: "reconcile_release", SagaState.MANUAL_OWNER_REVIEW_REQUIRED: "manual_owner_review", } def __init__( self, root: Path, *, after_journal_hook: Callable[[Mapping[str, Any]], None] | None = None, ): self.root = Path(root) self.after_journal_hook = after_journal_hook def _path(self, candidate_id: str) -> Path: if not CANDIDATE_ID_RE.fullmatch(str(candidate_id or "")): raise ValueError("invalid candidate_id") return _safe_child(self.root, candidate_id) def _journal(self, candidate_id: str) -> Path: if not CANDIDATE_ID_RE.fullmatch(str(candidate_id or "")): raise ValueError("invalid candidate_id") return _safe_child(self.root, candidate_id, ".events.jsonl") def _lock(self, candidate_id: str): path = _safe_child(self.root / ".locks", candidate_id, ".lock") path.parent.mkdir(parents=True, exist_ok=True) handle = path.open("a+", encoding="utf-8") try: import fcntl fcntl.flock(handle.fileno(), fcntl.LOCK_EX) except ImportError: pass return handle @staticmethod def _unlock(handle) -> None: try: import fcntl fcntl.flock(handle.fileno(), fcntl.LOCK_UN) except ImportError: pass handle.close() def create( self, candidate_id: str, release_plan_id: str ) -> ReleaseSaga: _validate_identifier("release_plan_id", release_plan_id) path = self._path(candidate_id) path.parent.mkdir(parents=True, exist_ok=True) lock = self._lock(candidate_id) try: if path.exists() or self._journal(candidate_id).exists(): existing = self._load_locked(candidate_id) if existing.release_plan_id != release_plan_id: raise SagaConflict( "candidate is bound to a different release plan" ) return existing saga = ReleaseSaga( candidate_id=candidate_id, release_plan_id=release_plan_id, ) payload = { "candidate_id": candidate_id, "details": {}, "event": "saga_created", "release_plan_id": release_plan_id, "revision": 0, "state": saga.state.value, "timestamp": saga.created_at, } record = self._append_event( candidate_id, payload, sequence=1, previous_hash=JOURNAL_GENESIS_HASH, ) saga.events.append(payload) saga.journal_sequence = 1 saga.journal_head_hash = record["event_hash"] self._after_journal(record) _durable_json(path, saga.to_dict()) return saga finally: self._unlock(lock) def load(self, candidate_id: str) -> ReleaseSaga: lock = self._lock(candidate_id) try: try: return self._load_locked(candidate_id) except JournalIntegrityError as exc: return self._manual_review_snapshot(candidate_id, str(exc)) finally: self._unlock(lock) def _load_locked(self, candidate_id: str) -> ReleaseSaga: records = self.verify_journal(candidate_id) saga = self._rebuild(records) path = self._path(candidate_id) cached = None if path.exists(): try: cached = ReleaseSaga.from_dict( json.loads(path.read_text(encoding="utf-8")) ) except Exception: cached = None if cached is not None and ( cached.journal_sequence > saga.journal_sequence or ( cached.journal_sequence == saga.journal_sequence and cached.journal_head_hash != saga.journal_head_hash ) ): raise JournalIntegrityError( "Saga snapshot references a missing or different journal head" ) if cached is None or cached.to_dict() != saga.to_dict(): _durable_json(path, saga.to_dict()) return saga def compare_and_set( self, candidate_id: str, *, expected_revision: int, expected_states: Iterable[SagaState], target: SagaState, event: str, details: Mapping[str, Any] | None = None, ) -> ReleaseSaga: lock = self._lock(candidate_id) try: try: saga = self._load_locked(candidate_id) except JournalIntegrityError as exc: return self._manual_review_snapshot(candidate_id, str(exc)) states = {SagaState(value) for value in expected_states} if ( saga.revision != expected_revision or saga.state not in states ): raise SagaConflict("Saga compare-and-set conflict") saga.revision += 1 saga.state = SagaState(target) saga.updated_at = utc_now() payload = { "candidate_id": saga.candidate_id, "details": _sanitize(dict(details or {})), "event": str(event), "release_plan_id": saga.release_plan_id, "revision": saga.revision, "state": saga.state.value, "timestamp": saga.updated_at, } record = self._append_event( candidate_id, payload, sequence=saga.journal_sequence + 1, previous_hash=saga.journal_head_hash, ) saga.events.append(payload) saga.journal_sequence = record["sequence"] saga.journal_head_hash = record["event_hash"] self._after_journal(record) _durable_json(self._path(candidate_id), saga.to_dict()) return saga finally: self._unlock(lock) def force_state_for_recovery_test( self, candidate_id: str, state: SagaState ) -> ReleaseSaga: saga = self.load(candidate_id) return self.compare_and_set( candidate_id, expected_revision=saga.revision, expected_states={saga.state}, target=state, event="test_recovery_checkpoint", ) def bind_release_plan( self, candidate_id: str, release_plan_id: str ) -> ReleaseSaga: _validate_identifier("release_plan_id", release_plan_id) lock = self._lock(candidate_id) try: saga = self._load_locked(candidate_id) pending = f"pending-{candidate_id}" if saga.release_plan_id not in {pending, release_plan_id}: raise SagaConflict( "Saga is already bound to another release plan" ) if saga.release_plan_id == release_plan_id: return saga saga.release_plan_id = release_plan_id saga.revision += 1 saga.updated_at = utc_now() payload = { "candidate_id": saga.candidate_id, "details": {"release_plan_id": release_plan_id}, "event": "owner_approval_bound", "release_plan_id": release_plan_id, "revision": saga.revision, "state": saga.state.value, "timestamp": saga.updated_at, } record = self._append_event( candidate_id, payload, sequence=saga.journal_sequence + 1, previous_hash=saga.journal_head_hash, ) saga.events.append(payload) saga.journal_sequence = record["sequence"] saga.journal_head_hash = record["event_hash"] self._after_journal(record) _durable_json(self._path(candidate_id), saga.to_dict()) return saga finally: self._unlock(lock) def _append_event( self, candidate_id: str, payload: Mapping[str, Any], *, sequence: int, previous_hash: str, ) -> dict[str, Any]: path = self._journal(candidate_id) path.parent.mkdir(parents=True, exist_ok=True) core = { "sequence": int(sequence), "previous_hash": str(previous_hash), "payload": _sanitize(dict(payload)), } record = { "schema_version": JOURNAL_SCHEMA_VERSION, **core, "event_hash": hashlib.sha256( _canonical_json(core) ).hexdigest(), } with path.open("a", encoding="utf-8") as output: output.write( json.dumps( record, sort_keys=True, separators=(",", ":"), ) + "\n" ) output.flush() os.fsync(output.fileno()) _fsync_directory(path.parent) return record def _after_journal(self, record: Mapping[str, Any]) -> None: if self.after_journal_hook is not None: self.after_journal_hook(record) def verify_journal( self, candidate_id: str ) -> list[dict[str, Any]]: path = self._journal(candidate_id) if not path.is_file(): raise JournalIntegrityError("Saga journal is missing") records: list[dict[str, Any]] = [] previous = JOURNAL_GENESIS_HASH try: lines = path.read_text(encoding="utf-8").splitlines() except OSError as exc: raise JournalIntegrityError("Saga journal is unreadable") from exc if not lines: raise JournalIntegrityError("Saga journal is empty") for expected_sequence, line in enumerate(lines, 1): try: record = json.loads(line) except json.JSONDecodeError as exc: raise JournalIntegrityError( "Saga journal contains invalid JSON" ) from exc if set(record) != { "schema_version", "sequence", "previous_hash", "payload", "event_hash", }: raise JournalIntegrityError( "Saga journal record schema is invalid" ) core = { "sequence": record["sequence"], "previous_hash": record["previous_hash"], "payload": record["payload"], } expected_hash = hashlib.sha256( _canonical_json(core) ).hexdigest() if ( record["schema_version"] != JOURNAL_SCHEMA_VERSION or record["sequence"] != expected_sequence or record["previous_hash"] != previous or record["event_hash"] != expected_hash ): raise JournalIntegrityError( "Saga journal hash chain verification failed" ) previous = record["event_hash"] records.append(record) return records @staticmethod def _rebuild(records: list[Mapping[str, Any]]) -> ReleaseSaga: first = dict(records[0]["payload"]) saga = ReleaseSaga( candidate_id=str(first["candidate_id"]), release_plan_id=str(first["release_plan_id"]), state=SagaState(first["state"]), revision=int(first["revision"]), events=[], created_at=str(first["timestamp"]), updated_at=str(first["timestamp"]), ) for record in records: payload = dict(record["payload"]) if payload.get("candidate_id") != saga.candidate_id: raise JournalIntegrityError( "Saga journal candidate identity changed" ) saga.release_plan_id = str(payload["release_plan_id"]) saga.state = SagaState(payload["state"]) saga.revision = int(payload["revision"]) saga.updated_at = str(payload["timestamp"]) saga.events.append(_sanitize(payload)) saga.journal_sequence = int(record["sequence"]) saga.journal_head_hash = str(record["event_hash"]) return saga def _manual_review_snapshot( self, candidate_id: str, reason: str ) -> ReleaseSaga: path = self._path(candidate_id) try: cached = ReleaseSaga.from_dict( json.loads(path.read_text(encoding="utf-8")) ) except Exception: cached = ReleaseSaga( candidate_id=candidate_id, release_plan_id=f"corrupt-{candidate_id}", ) cached.state = SagaState.MANUAL_OWNER_REVIEW_REQUIRED cached.journal_integrity = False cached.updated_at = utc_now() cached.events.append( { "event": "journal_integrity_failure", "reason": str(reason), "timestamp": cached.updated_at, } ) _durable_json(path, cached.to_dict()) return cached @classmethod def recovery_action(cls, state: SagaState) -> str: return cls.RECOVERY_ACTIONS.get( SagaState(state), "no_automatic_action" ) class PreSwitchProbe(Protocol): def collect( self, release_candidate: ReleaseCandidate, deployment_plan: DeploymentPlan, ) -> Mapping[str, Any]: ... class PreSwitchValidator: def __init__(self, probe: PreSwitchProbe): self.probe = probe def validate( self, candidate: ReleaseCandidate, approval: SignedReleasePlanApproval, plan: DeploymentPlan, *, expected_repository: str, ) -> dict[str, Any]: expected = { "source_commit": candidate.source_commit, "tree_oid": candidate.tree_oid, "artifact_sha256": candidate.artifact_sha256, "manifest_sha256": candidate.manifest_sha256, "deployment_plan_sha256": approval.deployment_plan_sha256, "policy_sha256": approval.policy_sha256, "rollback_ready": True, "git_refs_consistent": True, "repository_identity": expected_repository, "writer_disabled": True, } plan_binding = ( approval.candidate_id == candidate.candidate_id and approval.source_commit == candidate.source_commit and approval.tree_oid == candidate.tree_oid and approval.artifact_sha256 == candidate.artifact_sha256 and approval.manifest_sha256 == candidate.manifest_sha256 and approval.deployment_plan_sha256 == plan.sha256 and plan.source_commit == candidate.source_commit and plan.artifact_sha256 == candidate.artifact_sha256 and plan.manifest_sha256 == candidate.manifest_sha256 and plan.policy_sha256 == approval.policy_sha256 ) if not plan_binding: raise StaleApprovalError( "APPROVAL_STALE_REAPPROVAL_REQUIRED: " "deployment plan binding changed" ) actual = dict(self.probe.collect(candidate, plan)) failed = [ name for name, expected_value in expected.items() if actual.get(name) != expected_value ] if failed: raise StaleApprovalError( "APPROVAL_STALE_REAPPROVAL_REQUIRED: " + ", ".join(sorted(failed)) ) return { "valid": True, "checks": {name: True for name in expected}, "validated_at": utc_now(), } class CapabilityController: """One narrow controller consumes one capability and runs one adapter.""" def __init__( self, *, capability: str, ledger: CapabilityLedger, adapter: Callable[..., Mapping[str, Any]], executor_id: str = "silent-release-controller", lease_seconds: float = 300, recovery_probe: Callable[[], ClaimProbeResult] | None = None, ): if capability not in ALLOWED_CAPABILITIES: raise ValueError("invalid release capability") self.capability = capability self.ledger = ledger self.adapter = adapter self.executor_id = executor_id self.lease_seconds = lease_seconds self.recovery_probe = recovery_probe def execute( self, approval: SignedReleasePlanApproval, *, operation: str, **kwargs: Any, ) -> dict[str, Any]: recovery_probe = kwargs.pop("_recovery_probe", self.recovery_probe) stop_after_not_applied_probe = bool( kwargs.pop("_stop_after_not_applied_probe", False) ) claim = self.ledger.claim( approval, self.capability, operation=operation, executor_id=self.executor_id, lease_seconds=self.lease_seconds, side_effect_probe=recovery_probe, ) if ( stop_after_not_applied_probe and claim["status"] == "CLAIMED" and claim.get("probe_result") == ClaimProbeResult.NOT_APPLIED.value ): self.ledger.fail_recoverable( approval, self.capability, operation=operation, claim_id=claim["claim_id"], reason="verified_not_applied", ) return { "capability": self.capability, "probe_result": ClaimProbeResult.NOT_APPLIED.value, "status": "NOT_APPLIED", } if claim["status"] == "IDEMPOTENT": return { "capability": self.capability, "status": "IDEMPOTENT", } if claim["status"] == "BUSY": return { "capability": self.capability, "claim_id": claim.get("claim_id"), "status": "BUSY", } if claim["status"] in { "PROBE_REQUIRED", "RECONCILIATION_REQUIRED", "MANUAL_OWNER_REVIEW_REQUIRED", }: return { "capability": self.capability, "probe_result": claim.get("probe_result"), "status": claim["status"], } if claim["status"] != "CLAIMED": raise CapabilityAuthorizationError( f"capability claim is not executable: {claim['status']}" ) try: result = dict(self.adapter(**kwargs)) self.validate_result(approval, result) self.ledger.complete( approval, self.capability, operation=operation, claim_id=claim["claim_id"], evidence={ "result_sha256": hashlib.sha256( _canonical_json(_sanitize(result)) ).hexdigest() }, ) except Exception as exc: self.ledger.fail_recoverable( approval, self.capability, operation=operation, claim_id=claim["claim_id"], reason=type(exc).__name__, ) raise return { "capability": self.capability, "result": _sanitize(result), "status": "EXECUTED", } def validate_result( self, approval: SignedReleasePlanApproval, result: Mapping[str, Any], ) -> None: if result.get("verified") is not True: raise CapabilityAuthorizationError( "capability result is not verified" ) class RuntimeSwitchController(CapabilityController): def __init__( self, ledger: CapabilityLedger, adapter: Callable[..., Any], *, recovery_probe: Callable[ [], ClaimProbeResult | ProbeEvidence | Mapping[str, Any] ] | None = None, executor_id: str = "silent-release-runtime-switch", lease_seconds: float = 300, ): super().__init__( capability="runtime_switch", ledger=ledger, adapter=adapter, recovery_probe=recovery_probe, executor_id=executor_id, lease_seconds=lease_seconds, ) class HardenedTagController(CapabilityController): """Tag adapter must independently verify Git, Gitea API, and listing.""" REQUIRED_PROOF = frozenset( { "evidence_closure_oid", "approval_plan_id", "repository_identity", "remote_tag_oid", "remote_peeled_target_oid", "gitea_api_tag_oid", "gitea_api_peeled_target_oid", "gitea_listing_visible", } ) def __init__( self, ledger: CapabilityLedger, adapter: Callable[..., Any], *, expected_repository: str = "", publication_probe: Callable[ [TagPlan], TagPublicationProbeEvidence ] | None = None, executor_id: str = "silent-release-tag-publish", lease_seconds: float = 300, ): self.expected_repository = expected_repository self.publication_probe = publication_probe super().__init__( capability="tag_publish", ledger=ledger, adapter=adapter, executor_id=executor_id, lease_seconds=lease_seconds, ) def execute( self, approval: SignedReleasePlanApproval, *, operation: str, tag_plan: TagPlan | None = None, **kwargs: Any, ) -> dict[str, Any]: recovery_probe = None if self.publication_probe is not None and tag_plan is not None: immutable = self.ledger._immutable_payload( approval, self.capability, operation ) def recovery_probe() -> ProbeEvidence: evidence = self.publication_probe(tag_plan) return ProbeEvidence( result=classify_tag_publication(evidence, tag_plan), operation_digest=immutable["operation_digest"], observed_at=evidence.observed_at, evidence=evidence.to_dict(), ) adapter_kwargs = dict(kwargs) if tag_plan is not None: adapter_kwargs["tag_plan"] = tag_plan result = super().execute( approval, operation=operation, _recovery_probe=recovery_probe, _stop_after_not_applied_probe=True, **adapter_kwargs, ) if ( result["status"] == "EXECUTED" and result.get("result", {}).get("classification") in {member.value for member in ClaimProbeResult} ): classification = ClaimProbeResult( result["result"]["classification"] ) if classification == ClaimProbeResult.CONFLICT: raise TagPublicationConflict( "tag publication conflicts with the signed tag plan" ) if classification == ClaimProbeResult.INDETERMINATE: return { "capability": self.capability, "probe_result": classification.value, "status": "RECONCILIATION_REQUIRED", } return result def validate_result(self, approval, proof): if ( not self.REQUIRED_PROOF.issubset(proof) or proof.get("evidence_closure_oid") != approval.evidence_closure_oid or proof.get("approval_plan_id") != approval.approval_plan_id or proof.get("gitea_listing_visible") is not True or proof.get("remote_peeled_target_oid") != approval.source_commit or proof.get("gitea_api_peeled_target_oid") != approval.source_commit or proof.get("gitea_api_tag_oid") != proof.get("remote_tag_oid") or ( self.expected_repository and proof.get("repository_identity") != self.expected_repository ) ): raise CapabilityAuthorizationError( "tag publication proof is incomplete" ) class BaselineRegistryFinalizeController(CapabilityController): def __init__( self, ledger: CapabilityLedger, adapter: Callable[..., Any], *, recovery_probe: Callable[ [], ClaimProbeResult | ProbeEvidence | Mapping[str, Any] ] | None = None, executor_id: str = "silent-release-finalization", lease_seconds: float = 300, ): super().__init__( capability="baseline_registry_finalize", ledger=ledger, adapter=adapter, recovery_probe=recovery_probe, executor_id=executor_id, lease_seconds=lease_seconds, ) def validate_result(self, approval, result): required = { "verified": True, "tag_verified": True, "remote_peeled_target_oid": approval.source_commit, "gitea_api_peeled_target_oid": approval.source_commit, "gitea_listing_visible": True, "evidence_closure_oid": approval.evidence_closure_oid, "approval_plan_id": approval.approval_plan_id, } if any(result.get(key) != value for key, value in required.items()): raise CapabilityAuthorizationError( "finalization is blocked until exact tag proof is verified" ) class BaselineController(BaselineRegistryFinalizeController): """Narrow Baseline half of the governed finalization capability.""" def validate_result(self, approval, result): super().validate_result(approval, result) required = { "verified": True, "baseline_target_oid": approval.source_commit, "evidence_closure_oid": approval.evidence_closure_oid, "approval_plan_id": approval.approval_plan_id, } if any(result.get(key) != value for key, value in required.items()): raise CapabilityAuthorizationError( "Baseline finalization proof is inconsistent" ) class RegistryController(BaselineRegistryFinalizeController): """Narrow Registry half of the governed finalization capability.""" def validate_result(self, approval, result): super().validate_result(approval, result) required = { "verified": True, "registry_target_oid": approval.source_commit, "evidence_closure_oid": approval.evidence_closure_oid, "approval_plan_id": approval.approval_plan_id, } if any(result.get(key) != value for key, value in required.items()): raise CapabilityAuthorizationError( "Registry finalization proof is inconsistent" ) class GovernedFinalizationCoordinator: """Registry is verified first; Baseline is the final mutation.""" def __init__( self, registry: RegistryController, baseline: BaselineController, ): self.registry = registry self.baseline = baseline def execute( self, approval: SignedReleasePlanApproval, *, operation: str, finalization_plan: FinalizationPlan, ) -> dict[str, Any]: registry = self.registry.execute( approval, operation=f"{operation}:registry", finalization_plan=finalization_plan, ) if registry["status"] in { "BUSY", "PROBE_REQUIRED", "RECONCILIATION_REQUIRED", "MANUAL_OWNER_REVIEW_REQUIRED", }: return registry baseline = self.baseline.execute( approval, operation=f"{operation}:baseline", finalization_plan=finalization_plan, ) if baseline["status"] in { "BUSY", "PROBE_REQUIRED", "RECONCILIATION_REQUIRED", "MANUAL_OWNER_REVIEW_REQUIRED", }: return baseline return { "baseline_status": baseline["status"], "registry_status": registry["status"], "result": baseline.get("result") or {}, "status": "EXECUTED", } class RecoverableReleaseError(RuntimeError): """A side effect is unknown or temporarily unverifiable.""" class TagPublicationConflict(RuntimeError): """An existing tag disagrees with the signed immutable tag plan.""" class ReleaseOrchestrator: """Durable one-approval execution with Baseline/Registry finalized last.""" def __init__( self, *, candidates: ReleaseCandidateStore, plans: ReleasePlanStore, approvals: SignedApprovalStore, sagas: ReleaseSagaStore, approval_verifier: SignedApprovalVerifier, trusted_policy: TrustedReleasePolicy, actual_plan_factory: Callable[[ReleaseCandidate], ReleasePlan], pre_switch_validator: PreSwitchValidator, runtime_switch: RuntimeSwitchController, runtime_verify: Callable[..., Mapping[str, Any]], runtime_rollback: Callable[..., Mapping[str, Any]], tag_publish: HardenedTagController, finalizer: GovernedFinalizationCoordinator, ): self.candidates = candidates self.plans = plans self.approvals = approvals self.sagas = sagas self.approval_verifier = approval_verifier self.trusted_policy = trusted_policy self.actual_plan_factory = actual_plan_factory self.pre_switch_validator = pre_switch_validator self.runtime_switch = runtime_switch self.runtime_verify = runtime_verify self.runtime_rollback = runtime_rollback self.tag_publish = tag_publish self.finalizer = finalizer def _transition( self, saga: ReleaseSaga, target: SagaState, event: str, details: Mapping[str, Any] | None = None, ) -> ReleaseSaga: return self.sagas.compare_and_set( saga.candidate_id, expected_revision=saga.revision, expected_states={saga.state}, target=target, event=event, details=details, ) def _load_and_reverify( self, candidate_id: str ) -> tuple[ ReleaseCandidate, ReleasePlan, SignedReleasePlanApproval, ReleaseSaga, ]: candidate = self.candidates.load(candidate_id) plan = self.plans.load(candidate_id) approval = self.approvals.load(candidate_id) saga = self.sagas.load(candidate_id) if not saga.journal_integrity: raise JournalIntegrityError( "Saga journal requires manual owner review" ) actual_plan = self.actual_plan_factory(candidate) self.trusted_policy.validate_deployment(actual_plan.deployment) if actual_plan.sha256 != plan.sha256: raise StaleApprovalError( "actual deployment configuration changed after approval" ) self.approval_verifier.verify_release_plan( approval, candidate, plan, plan.policy_sha256, ) return candidate, plan, approval, saga @staticmethod def _runtime_proof_matches( proof: Mapping[str, Any], candidate: ReleaseCandidate, plan: ReleasePlan, ) -> bool: expected = { "verified": True, "source_commit": candidate.source_commit, "tree_oid": candidate.tree_oid, "artifact_sha256": candidate.artifact_sha256, "manifest_sha256": candidate.manifest_sha256, "repository_identity": plan.deployment.repository_identity, "authoritative_git_dir": ( plan.deployment.authoritative_git_dir ), "writer_disabled": True, } return all(proof.get(key) == value for key, value in expected.items()) @staticmethod def _finalization_proof_matches( proof: Mapping[str, Any], plan: ReleasePlan ) -> bool: expected = { "verified": True, "remote_tag_oid": plan.tag.expected_tag_oid, "remote_peeled_target_oid": plan.tag.expected_target_oid, "registry_record": ( plan.finalization.registry_expected_record ), "baseline_record": ( plan.finalization.baseline_expected_record ), "baseline_written_last": True, } return all(proof.get(key) == value for key, value in expected.items()) def _rollback( self, saga: ReleaseSaga, candidate: ReleaseCandidate, plan: ReleasePlan, reason: str, ) -> dict[str, Any]: if saga.state != SagaState.ROLLBACK_PENDING: saga = self._transition( saga, SagaState.ROLLBACK_PENDING, "runtime_rollback_pending", {"reason": reason}, ) proof = dict( self.runtime_rollback(candidate=candidate, plan=plan) ) if proof.get("verified") is not True: return { "candidate_id": candidate.candidate_id, "state": saga.state.value, "status": "ROLLBACK_PENDING", } saga = self._transition( saga, SagaState.ROLLED_BACK, "runtime_rollback_verified", {"proof": proof}, ) return { "candidate_id": candidate.candidate_id, "state": saga.state.value, "status": "ROLLED_BACK", } def _manual( self, saga: ReleaseSaga, reason: str ) -> dict[str, Any]: if saga.state != SagaState.MANUAL_OWNER_REVIEW_REQUIRED: saga = self._transition( saga, SagaState.MANUAL_OWNER_REVIEW_REQUIRED, "manual_owner_review_required", {"reason": reason}, ) return { "candidate_id": saga.candidate_id, "state": saga.state.value, "status": saga.state.value, } def _reconciliation( self, saga: ReleaseSaga, reason: str ) -> dict[str, Any]: if saga.state != SagaState.RECONCILIATION_REQUIRED: saga = self._transition( saga, SagaState.RECONCILIATION_REQUIRED, "release_reconciliation_required", {"reason": reason}, ) return { "candidate_id": saga.candidate_id, "state": saga.state.value, "status": saga.state.value, } def execute(self, candidate_id: str) -> dict[str, Any]: candidate, plan, approval, saga = self._load_and_reverify( candidate_id ) if saga.state == SagaState.MANUAL_OWNER_REVIEW_REQUIRED: return self._manual(saga, "existing manual review gate") if saga.state in {SagaState.COMPLETED, SagaState.ROLLED_BACK}: return { "candidate_id": candidate_id, "state": saga.state.value, "status": "IDEMPOTENT", } if saga.state == SagaState.ROLLBACK_PENDING: return self._rollback( saga, candidate, plan, "resuming rollback" ) if saga.state == SagaState.RECONCILIATION_REQUIRED: return self._reconciliation( saga, "automatic reconciliation is forbidden" ) runtime_has_switched = saga.state in { SagaState.SWITCH_PENDING, SagaState.SWITCHED, SagaState.RUNTIME_VERIFYING, SagaState.RUNTIME_VERIFIED, SagaState.TAG_PENDING, SagaState.TAG_VERIFIED, SagaState.BASELINE_REGISTRY_PENDING, } try: if saga.state in { SagaState.APPROVED, SagaState.PRE_SWITCH_REVALIDATING, }: if saga.state == SagaState.APPROVED: saga = self._transition( saga, SagaState.PRE_SWITCH_REVALIDATING, "pre_switch_revalidation_started", ) self.pre_switch_validator.validate( candidate, approval, plan.deployment, expected_repository=( plan.deployment.repository_identity ), ) saga = self._transition( saga, SagaState.SWITCH_PENDING, "runtime_switch_pending", ) if saga.state == SagaState.SWITCH_PENDING: result = self.runtime_switch.execute( approval, operation=f"runtime:{plan.sha256}", candidate=candidate, plan=plan, ) if result["status"] == "BUSY": return { "candidate_id": candidate_id, "state": saga.state.value, "status": "BUSY", } if result["status"] == "RECONCILIATION_REQUIRED": return self._reconciliation( saga, "runtime switch probe is indeterminate" ) if result["status"] == "MANUAL_OWNER_REVIEW_REQUIRED": return self._manual( saga, "runtime switch probe found a conflict" ) if result["status"] == "PROBE_REQUIRED": return self._reconciliation( saga, "runtime switch probe is required" ) runtime_has_switched = True saga = self._transition( saga, SagaState.SWITCHED, "runtime_switch_completed", {"capability_status": result["status"]}, ) if saga.state in { SagaState.SWITCHED, SagaState.RUNTIME_VERIFYING, }: if saga.state == SagaState.SWITCHED: saga = self._transition( saga, SagaState.RUNTIME_VERIFYING, "runtime_verification_started", ) proof = dict( self.runtime_verify(candidate=candidate, plan=plan) ) if not self._runtime_proof_matches( proof, candidate, plan ): raise RecoverableReleaseError( "runtime verification failed" ) saga = self._transition( saga, SagaState.RUNTIME_VERIFIED, "runtime_verification_completed", {"proof": proof}, ) if saga.state == SagaState.RUNTIME_VERIFIED: saga = self._transition( saga, SagaState.TAG_PENDING, "tag_publication_pending", ) if saga.state == SagaState.TAG_PENDING: result = self.tag_publish.execute( approval, operation=f"tag:{plan.tag.sha256}", tag_plan=plan.tag, ) if result["status"] == "BUSY": return { "candidate_id": candidate_id, "state": saga.state.value, "status": "BUSY", } if result["status"] == "RECONCILIATION_REQUIRED": return self._reconciliation( saga, "tag publication is indeterminate" ) if result["status"] == "MANUAL_OWNER_REVIEW_REQUIRED": return self._manual( saga, "tag publication conflicts with signed plan" ) if result["status"] == "PROBE_REQUIRED": return self._reconciliation( saga, "tag publication probe is required" ) if result["status"] == "NOT_APPLIED": return self._rollback( saga, candidate, plan, "tag publication was verified absent", ) saga = self._transition( saga, SagaState.TAG_VERIFIED, "tag_publication_verified", {"capability_status": result["status"]}, ) if saga.state == SagaState.TAG_VERIFIED: saga = self._transition( saga, SagaState.BASELINE_REGISTRY_PENDING, "baseline_registry_finalization_pending", ) if saga.state == SagaState.BASELINE_REGISTRY_PENDING: result = self.finalizer.execute( approval, operation=f"finalize:{plan.finalization.sha256}", finalization_plan=plan.finalization, ) if result["status"] == "BUSY": return { "candidate_id": candidate_id, "state": saga.state.value, "status": "BUSY", } if result["status"] == "RECONCILIATION_REQUIRED": return self._reconciliation( saga, "finalization probe is indeterminate" ) if result["status"] == "MANUAL_OWNER_REVIEW_REQUIRED": return self._manual( saga, "finalization probe found a conflict" ) if result["status"] == "PROBE_REQUIRED": return self._reconciliation( saga, "finalization probe is required" ) proof = result.get("result") or {} if not self._finalization_proof_matches(proof, plan): raise RecoverableReleaseError( "final consistency verification failed" ) saga = self._transition( saga, SagaState.COMPLETED, "release_consistency_verified", {"proof": proof}, ) return { "candidate_id": candidate_id, "state": saga.state.value, "status": "VERIFIED", } except TagPublicationConflict as exc: return self._manual(saga, str(exc)) except Exception as exc: if saga.state in { SagaState.TAG_PENDING, SagaState.TAG_VERIFIED, SagaState.BASELINE_REGISTRY_PENDING, }: return self._reconciliation(saga, type(exc).__name__) if runtime_has_switched: return self._rollback( saga, candidate, plan, type(exc).__name__ ) raise class ReleaseRecoveryWorker: def __init__( self, saga_store: ReleaseSagaStore, orchestrator: ReleaseOrchestrator, *, shadow_mode: bool, ): self.saga_store = saga_store self.orchestrator = orchestrator self.shadow_mode = bool(shadow_mode) def run_once(self) -> dict[str, Any]: reports: list[dict[str, Any]] = [] root = self.saga_store.root for journal in sorted(root.glob("*.events.jsonl")): candidate_id = journal.name[: -len(".events.jsonl")] saga = self.saga_store.load(candidate_id) if saga.state == SagaState.MANUAL_OWNER_REVIEW_REQUIRED: reports.append( { "candidate_id": candidate_id, "status": "SKIPPED_MANUAL_REVIEW", } ) elif self.shadow_mode: reports.append( { "candidate_id": candidate_id, "state": saga.state.value, "status": "SHADOW_REPORTED", } ) elif saga.state not in { SagaState.COMPLETED, SagaState.ROLLED_BACK, }: reports.append(self.orchestrator.execute(candidate_id)) return { "shadow_mode": self.shadow_mode, "reports": reports, } class SilentReleaseActionService: """Durable control-plane facade; execution is shadow-disabled by default.""" def __init__( self, root: Path, *, execution_enabled: bool = False, runtime_executor: Any = None, approval_verifier: SignedApprovalVerifier | None = None, pre_switch_validator: PreSwitchValidator | None = None, candidate_builder: TrustedCandidateBuilder | None = None, builder_attestation_verifier: BuilderAttestationVerifier | None = None, trusted_policy: TrustedReleasePolicy | None = None, orchestrator: ReleaseOrchestrator | None = None, allow_legacy_candidate_input: bool = False, expected_repository: str = "", policy_sha256: str = "", ): self.root = Path(root) self.execution_enabled = bool(execution_enabled) self.runtime_executor = runtime_executor self.approval_verifier = approval_verifier self.pre_switch_validator = pre_switch_validator self.candidate_builder = candidate_builder self.builder_attestation_verifier = builder_attestation_verifier self.trusted_policy = trusted_policy self.orchestrator = orchestrator self.allow_legacy_candidate_input = bool( allow_legacy_candidate_input ) self.expected_repository = expected_repository self.policy_sha256 = policy_sha256 self.candidates = ReleaseCandidateStore( self.root / "candidates" ) self.plans = DeploymentPlanStore(self.root / "plans") self.release_plans = ReleasePlanStore( self.root / "release-plans" ) self.sagas = ReleaseSagaStore(self.root / "sagas") self.approvals_root = self.root / "approvals" self.approvals = SignedApprovalStore(self.approvals_root) self.intents_root = self.root / "intents" self.acceptance_root = self.root / "acceptance" self.notifications_root = self.root / "notifications" self.capabilities_root = self.root / "capabilities" if self.execution_enabled: missing = [ name for name, component in ( ("approval_verifier", approval_verifier), ("candidate_builder", candidate_builder), ( "builder_attestation_verifier", builder_attestation_verifier, ), ("orchestrator", orchestrator), ("pre_switch_validator", pre_switch_validator), ("trusted_policy", trusted_policy), ) if component is None ] if missing: raise CapabilityAuthorizationError( "production execution components are missing: " + ", ".join(missing) ) def create_release_intent( self, payload: Mapping[str, Any] ) -> dict[str, Any]: allowed = {"event_id", "source_commit"} unknown = set(payload).difference(allowed) if unknown: raise CapabilityAuthorizationError( "release intent contains caller-supplied evidence" ) event_id = _validate_identifier( "event_id", str(payload.get("event_id") or "") ) source_commit = _validate_oid( "source_commit", str(payload.get("source_commit") or "") ) intent_id = "intent-" + hashlib.sha256( f"{event_id}\0{source_commit}".encode("utf-8") ).hexdigest()[:24] path = _safe_child(self.intents_root, intent_id) record = { "created_at": utc_now(), "event_id": event_id, "intent_id": intent_id, "source_commit": source_commit, "status": ( "BUILDING" if self.candidate_builder is not None else "BUILDER_UNAVAILABLE" ), } if path.exists(): existing = json.loads(path.read_text(encoding="utf-8")) if ( existing.get("event_id") != event_id or existing.get("source_commit") != source_commit ): raise SagaConflict( "release intent id is bound to different evidence" ) return { **_sanitize(existing), "idempotent": True, "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } _durable_json(path, record) result = dict(record) if self.candidate_builder is not None: candidate = self.create_release_candidate( { "event_id": event_id, "intent_id": intent_id, "source_commit": source_commit, } ) result.update( { "candidate_id": candidate["candidate_id"], "status": candidate["saga_state"], } ) _durable_json(path, result) return { **_sanitize(result), "idempotent": False, "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } @classmethod def shadow( cls, root: Path, *, runtime_executor: Any = None ) -> "SilentReleaseActionService": return cls( root, execution_enabled=False, runtime_executor=runtime_executor, allow_legacy_candidate_input=True, ) def create_release_candidate( self, payload: Mapping[str, Any] ) -> dict[str, Any]: if self.candidate_builder is not None: forbidden_evidence = { "artifact_sha256", "canary", "deployment_plan", "git_consistency", "gitea_consistency", "manifest_sha256", "release_plan", "rollback_ready", "tests", "tree_oid", } if forbidden_evidence.intersection(payload): raise CapabilityAuthorizationError( "candidate evidence must come from the trusted builder" ) bundle = self.candidate_builder.build(dict(payload)).validate( self.builder_attestation_verifier ) if self.trusted_policy is None: raise CapabilityAuthorizationError( "trusted release policy is not configured" ) self.trusted_policy.validate_deployment( bundle.release_plan.deployment ) if ( bundle.release_plan.policy_sha256 != self.policy_sha256 ): raise CapabilityAuthorizationError( "trusted builder used a different release policy" ) candidate = bundle.candidate try: existing = self.candidates.load( candidate.candidate_id ) except FileNotFoundError: self.candidates.save(candidate) existing = candidate else: if existing.fingerprint != candidate.fingerprint: raise SagaConflict( "candidate id is already bound to other evidence" ) self.release_plans.save( existing.candidate_id, bundle.release_plan ) _durable_json( _safe_child(self.acceptance_root, existing.candidate_id), bundle.acceptance_record(), ) saga = self.sagas.create( existing.candidate_id, f"pending-{existing.candidate_id}", ) if saga.state == SagaState.PREPARING: saga = self.sagas.compare_and_set( existing.candidate_id, expected_revision=saga.revision, expected_states={SagaState.PREPARING}, target=SagaState.READY_FOR_APPROVAL, event="trusted_candidate_ready_for_approval", details={ "release_plan_sha256": ( bundle.release_plan.sha256 ) }, ) return { **existing.to_dict(), "release_plan_sha256": bundle.release_plan.sha256, "saga_state": saga.state.value, "builder_attestation_id": ( bundle.attestation.builder_attestation_id if bundle.attestation else None ), "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } if not self.allow_legacy_candidate_input: raise CapabilityAuthorizationError( "trusted candidate builder is not configured" ) values = dict(payload) raw_plan = values.pop("deployment_plan", None) candidate = ReleaseCandidate.from_dict(values) try: existing = self.candidates.load(candidate.candidate_id) except FileNotFoundError: self.candidates.save(candidate) existing = candidate else: if existing.fingerprint != candidate.fingerprint: raise SagaConflict( "candidate id is already bound to other evidence" ) self.sagas.create( existing.candidate_id, f"pending-{existing.candidate_id}", ) result = existing.to_dict() if raw_plan is not None: plan = DeploymentPlan.from_dict(raw_plan) if ( plan.source_commit != existing.source_commit or plan.artifact_sha256 != existing.artifact_sha256 or plan.manifest_sha256 != existing.manifest_sha256 ): raise StaleApprovalError( "deployment plan does not match release candidate" ) try: stored = self.plans.load(existing.candidate_id) except FileNotFoundError: self.plans.save(existing.candidate_id, plan) else: if stored.sha256 != plan.sha256: raise SagaConflict( "candidate has a different deployment plan" ) result["deployment_plan_sha256"] = plan.sha256 return result def get_release_candidate(self, candidate_id: str) -> dict[str, Any]: return { **self.candidates.load(candidate_id).to_dict(), "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } def get_release_saga(self, candidate_id: str) -> dict[str, Any]: return { **self.sagas.load(candidate_id).to_dict(), "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } def get_release_plan(self, candidate_id: str) -> dict[str, Any]: return { **self.release_plans.load(candidate_id).to_dict(), "candidate_id": candidate_id, "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } def get_acceptance(self, candidate_id: str) -> dict[str, Any]: record = json.loads( _safe_child(self.acceptance_root, candidate_id).read_text( encoding="utf-8" ) ) return { **_sanitize(record), "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } def get_capability_status( self, candidate_id: str ) -> dict[str, Any]: self.candidates.load(candidate_id) records: list[dict[str, Any]] = [] for path in sorted(self.capabilities_root.glob("*.json")): try: record = json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): continue if record.get("release_plan_id") == self.sagas.load( candidate_id ).release_plan_id: records.append(_sanitize(record)) return { "candidate_id": candidate_id, "capabilities": records, "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } def get_recovery_status(self) -> dict[str, Any]: reports: list[dict[str, Any]] = [] for journal in sorted(self.sagas.root.glob("*.events.jsonl")): candidate_id = journal.name[: -len(".events.jsonl")] saga = self.sagas.load(candidate_id) reports.append( { "candidate_id": candidate_id, "recovery_action": self.sagas.recovery_action( saga.state ), "state": saga.state.value, } ) return { "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, "sagas": reports, } def ensure_owner_notification( self, candidate_id: str ) -> dict[str, Any]: self.candidates.load(candidate_id) path = _safe_child(self.notifications_root, candidate_id) payload = { "candidate_id": candidate_id, "created_at": utc_now(), "notification_id": "notification-" + hashlib.sha256(candidate_id.encode("utf-8")).hexdigest()[:24], "status": "OWNER_APPROVAL_REQUESTED", } path.parent.mkdir(parents=True, exist_ok=True) try: descriptor = os.open( path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600 ) except FileExistsError: existing = json.loads(path.read_text(encoding="utf-8")) return {**_sanitize(existing), "idempotent": True} with os.fdopen(descriptor, "w", encoding="utf-8") as output: json.dump(payload, output, sort_keys=True) output.write("\n") output.flush() os.fsync(output.fileno()) _fsync_directory(path.parent) return {**payload, "idempotent": False} def get_approval_envelope(self, candidate_id: str) -> dict[str, Any]: candidate = self.candidates.load(candidate_id) try: release_plan = self.release_plans.load(candidate_id) deployment_plan_sha256 = release_plan.deployment.sha256 release_plan_sha256 = release_plan.sha256 except FileNotFoundError: try: deployment_plan_sha256 = self.plans.load( candidate_id ).sha256 except FileNotFoundError: deployment_plan_sha256 = None release_plan_sha256 = None return { "candidate_id": candidate.candidate_id, "candidate_fingerprint": candidate.fingerprint, "execution_enabled": self.execution_enabled, "required_capabilities": sorted(ALLOWED_CAPABILITIES), "signature_algorithm": "Ed25519", "deployment_plan_sha256": deployment_plan_sha256, "release_plan_sha256": release_plan_sha256, "policy_sha256": self.policy_sha256 or None, "status": "READY_FOR_OWNER_SIGNATURE", } def submit_owner_approval( self, payload: Mapping[str, Any] ) -> dict[str, Any]: approval = SignedReleasePlanApproval.from_dict(payload) if self.approval_verifier is None: raise CapabilityAuthorizationError( "owner approval verifier is not configured" ) candidate = self.candidates.load(approval.candidate_id) try: release_plan = self.release_plans.load( approval.candidate_id ) except FileNotFoundError: plan = self.plans.load(approval.candidate_id) self.approval_verifier.verify( approval, candidate, plan, self.policy_sha256, ) else: self.approval_verifier.verify_release_plan( approval, candidate, release_plan, self.policy_sha256, ) _, created = self.approvals.save( approval.candidate_id, approval ) saga = self.sagas.bind_release_plan( approval.candidate_id, approval.release_plan_id ) if saga.state == SagaState.READY_FOR_APPROVAL: saga = self.sagas.compare_and_set( approval.candidate_id, expected_revision=saga.revision, expected_states={SagaState.READY_FOR_APPROVAL}, target=SagaState.APPROVED, event="signed_owner_approval_accepted", details={ "approval_fingerprint": approval.fingerprint, "release_plan_sha256": ( approval.release_plan_sha256 or None ), }, ) return { "fingerprint": approval.fingerprint, "saga_state": saga.state.value, "status": ( "VERIFIED_AND_STORED" if created else "IDEMPOTENT" ), "execution_enabled": self.execution_enabled, "shadow_mode": not self.execution_enabled, "side_effects_executed": False, } def start_deployment( self, candidate_id: str, *, approval: SignedReleasePlanApproval | None = None, ) -> dict[str, Any]: self.candidates.load(candidate_id) if not self.execution_enabled: return { "candidate_id": candidate_id, "execution_enabled": False, "shadow_mode": True, "side_effects": [], "side_effects_executed": False, "status": "SHADOW_COMPLETED", } if self.orchestrator is None: raise CapabilityAuthorizationError( "release orchestrator is not configured" ) # Caller-supplied approvals are deliberately ignored. The orchestrator # loads the durable approval bound during submit_owner_approval(). return _sanitize(dict(self.orchestrator.execute(candidate_id)))