"""Non-Owner Gitea machine capability and branch reconciliation boundary.""" from __future__ import annotations from dataclasses import dataclass from typing import Any, Mapping, Protocol class MachineBrokerError(RuntimeError): pass class GiteaTransport(Protocol): def compare_and_swap_branch(self, branch: str, expected_oid: str, new_oid: str) -> str: ... def create_or_update_pr(self, branch: str, target: str, title: str, body: str) -> Mapping[str, Any]: ... def publish_status(self, branch: str, state: str, description: str) -> Mapping[str, Any]: ... def protected_merge(self, pr_number: int) -> Mapping[str, Any]: ... def read_branch(self, branch: str) -> str | None: ... def whoami(self) -> Mapping[str, Any]: ... def repository(self, owner: str, name: str) -> Mapping[str, Any]: ... @dataclass(frozen=True, slots=True) class MachineCredentialProjection: """Opaque systemd credential reference; the credential value is never accepted.""" reference: str account: str owner_account: str = "aiman" @classmethod def from_mapping(cls, value: Mapping[str, Any]) -> "MachineCredentialProjection": if set(value) != {"scheme", "name", "account"}: raise MachineBrokerError("CREDENTIAL_REFERENCE_INVALID") if value["scheme"] != "systemd-credential" or value["name"] != "gitea-machine-token": raise MachineBrokerError("CREDENTIAL_REFERENCE_INVALID") return cls(f"{value['scheme']}:{value['name']}", str(value["account"])) def __post_init__(self) -> None: if self.reference != "systemd-credential:gitea-machine-token": raise MachineBrokerError("CREDENTIAL_REFERENCE_INVALID") if not self.account or self.account == self.owner_account: raise MachineBrokerError("OWNER_MACHINE_IDENTITY_REJECTED") @dataclass(frozen=True, slots=True) class CampaignCapabilityReceipt: campaign_id: str task_id: str repository: str branch: str expected_oid: str capabilities: frozenset[str] denied: frozenset[str] def require(self, capability: str) -> None: if capability in self.denied or capability not in self.capabilities: raise MachineBrokerError("CAPABILITY_DENIED") if self.branch in {"main", "master"}: raise MachineBrokerError("PROTECTED_BRANCH_DENIED") class GiteaMachineBroker: def __init__(self, transport: GiteaTransport, credential: MachineCredentialProjection, receipt: CampaignCapabilityReceipt) -> None: self.transport = transport self.credential = credential self.receipt = receipt def verify_identity(self) -> Mapping[str, Any]: identity = dict(self.transport.whoami()) login = identity.get("login") or identity.get("username") if not isinstance(login, str) or not login or login == self.credential.owner_account or login != self.credential.account: raise MachineBrokerError("GITEA_MACHINE_IDENTITY_INVALID") owner, name = self.receipt.repository.split("/", 1) repo = dict(self.transport.repository(owner, name)) if repo.get("full_name") != self.receipt.repository: raise MachineBrokerError("GITEA_REPOSITORY_MISMATCH") return {"login": login, "repository": self.receipt.repository, "owner_account": self.credential.owner_account} def push_branch(self, new_oid: str) -> str: self.receipt.require("exact_task_branch_push") return self.transport.compare_and_swap_branch(self.receipt.branch, self.receipt.expected_oid, new_oid) def create_pr(self, title: str, body: str) -> Mapping[str, Any]: self.receipt.require("pr_create_update") return self.transport.create_or_update_pr(self.receipt.branch, "main", title, body) def status(self, state: str, description: str, context: str = "aios/durable-release") -> Mapping[str, Any]: self.receipt.require("status_publish") return self.transport.publish_status(self.receipt.branch, state, description, context) def merge(self, pr_number: int) -> Mapping[str, Any]: self.receipt.require("protected_merge") return self.transport.protected_merge(pr_number) def readback(self) -> str | None: self.receipt.require("remote_readback") return self.transport.read_branch(self.receipt.branch) def reconcile_exact_branch(authority_oid: str, gitea_oid: str | None, expected_oid: str) -> str: if authority_oid != expected_oid: return "AUTHORITY_EXPECTATION_MISMATCH" if gitea_oid is None: return "CREATE_REQUIRED" if gitea_oid == expected_oid: return "ALREADY_IN_SYNC" return "MANUAL_OWNER_REVIEW_REQUIRED" def reconcile_fast_forward( remote_oid: str | None, expected_old_oid: str, new_oid: str, *, old_is_ancestor_of_new: bool, ) -> str: """Return a bounded action for an active Job/lease branch scope.""" if remote_oid is None: return "CREATE_REQUIRED" if remote_oid == new_oid: return "ALREADY_IN_SYNC" if remote_oid == expected_old_oid and old_is_ancestor_of_new: return "FAST_FORWARD_REQUIRED" return "MANUAL_OWNER_REVIEW_REQUIRED"