148 lines
5.1 KiB
Python
148 lines
5.1 KiB
Python
|
|
"""Fail-closed candidate-specific governed admission preflight.
|
|
|
|
Ordinary/global writes are deliberately NOT a prerequisite. This evaluates the
|
|
governed Bridge/TaskPrincipal path only.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from enum import Enum
|
|
from typing import Sequence
|
|
|
|
from .governance_resolver import ResolutionResult, ResolutionState
|
|
|
|
|
|
class AdmissionOperation(str, Enum):
|
|
GOVERNED_COMMIT = "GOVERNED_COMMIT"
|
|
RECOVER_EXISTING_CHILD = "RECOVER_EXISTING_CHILD"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GovernanceFacts:
|
|
governed_writes_enabled: bool
|
|
task_principal_writes_enabled: bool
|
|
recovery_execution_enabled: bool
|
|
recovery_shadow_mode: bool
|
|
authenticated_principal_id: str | None
|
|
target_branch: str | None
|
|
branch_protection_known: bool
|
|
expected_branch_oid: str | None
|
|
generation: int | None
|
|
task_lease_id: str | None
|
|
task_principal_id: str | None
|
|
writer_lease_id: str | None
|
|
accepted_file_allowlist: tuple[str, ...] = ()
|
|
acceptance_revision: str | None = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AdmissionBlocker:
|
|
code: str
|
|
detail: str
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AdmissionResult:
|
|
ready: bool
|
|
operation: AdmissionOperation
|
|
blockers: tuple[AdmissionBlocker, ...]
|
|
|
|
|
|
class AdmissionPreflight:
|
|
def evaluate(
|
|
self,
|
|
*,
|
|
resolution: ResolutionResult,
|
|
facts: GovernanceFacts,
|
|
operation: AdmissionOperation,
|
|
) -> AdmissionResult:
|
|
blockers: list[AdmissionBlocker] = []
|
|
|
|
if resolution.state is ResolutionState.NOT_FOUND:
|
|
blockers.append(AdmissionBlocker(
|
|
"TASK_NOT_RESOLVED", "exact candidate task not found"
|
|
))
|
|
elif resolution.state is ResolutionState.AMBIGUOUS:
|
|
blockers.append(AdmissionBlocker(
|
|
"TASK_RESOLUTION_AMBIGUOUS", "multiple exact candidate tasks"
|
|
))
|
|
elif resolution.state is not ResolutionState.RESOLVED:
|
|
blockers.append(AdmissionBlocker(
|
|
"TASK_RESOLUTION_INVALID", resolution.detail or "resolver invalid"
|
|
))
|
|
|
|
if not facts.governed_writes_enabled:
|
|
blockers.append(AdmissionBlocker(
|
|
"GOVERNED_WRITES_DISABLED",
|
|
"governed Bridge write path is disabled",
|
|
))
|
|
if not facts.task_principal_writes_enabled:
|
|
blockers.append(AdmissionBlocker(
|
|
"TASK_PRINCIPAL_WRITES_DISABLED",
|
|
"TaskPrincipal governed writes are disabled",
|
|
))
|
|
if not facts.authenticated_principal_id:
|
|
blockers.append(AdmissionBlocker(
|
|
"CALLER_PRINCIPAL_UNRESOLVED",
|
|
"authenticated governed caller principal is missing",
|
|
))
|
|
if not facts.target_branch:
|
|
blockers.append(AdmissionBlocker(
|
|
"TARGET_BRANCH_UNRESOLVED", "target branch is missing"
|
|
))
|
|
if not facts.branch_protection_known:
|
|
blockers.append(AdmissionBlocker(
|
|
"BRANCH_PROTECTION_UNKNOWN",
|
|
"branch protection has not been read through authority",
|
|
))
|
|
if not facts.expected_branch_oid:
|
|
blockers.append(AdmissionBlocker(
|
|
"EXPECTED_BRANCH_OID_UNRESOLVED",
|
|
"expected_branch_oid/CAS preimage is missing",
|
|
))
|
|
if facts.generation is None:
|
|
blockers.append(AdmissionBlocker(
|
|
"GENERATION_UNRESOLVED", "governed generation is missing"
|
|
))
|
|
if not facts.task_lease_id:
|
|
blockers.append(AdmissionBlocker(
|
|
"TASK_LEASE_MISSING", "TaskLease not established"
|
|
))
|
|
if not facts.task_principal_id:
|
|
blockers.append(AdmissionBlocker(
|
|
"TASK_PRINCIPAL_MISSING", "TaskPrincipal not established"
|
|
))
|
|
if not facts.writer_lease_id:
|
|
blockers.append(AdmissionBlocker(
|
|
"WRITER_LEASE_MISSING", "WriterLease not established"
|
|
))
|
|
if not facts.accepted_file_allowlist:
|
|
blockers.append(AdmissionBlocker(
|
|
"FILE_ALLOWLIST_MISSING", "accepted file allowlist is empty"
|
|
))
|
|
if not facts.acceptance_revision:
|
|
blockers.append(AdmissionBlocker(
|
|
"ACCEPTANCE_REVISION_MISSING",
|
|
"candidate acceptance revision is missing",
|
|
))
|
|
|
|
if operation is AdmissionOperation.RECOVER_EXISTING_CHILD:
|
|
if not facts.recovery_execution_enabled:
|
|
blockers.append(AdmissionBlocker(
|
|
"RECOVERY_EXECUTION_DISABLED",
|
|
"recovery execution path is disabled",
|
|
))
|
|
if facts.recovery_shadow_mode:
|
|
blockers.append(AdmissionBlocker(
|
|
"RECOVERY_SHADOW_MODE",
|
|
"recovery is still shadow-only",
|
|
))
|
|
|
|
# Ordinary/global write state is intentionally absent from the model.
|
|
return AdmissionResult(
|
|
ready=not blockers,
|
|
operation=operation,
|
|
blockers=tuple(blockers),
|
|
)
|