autonomy-smoke-tests phase1-p0 PASS evidence_sha256=a96e50527a39e969b53df42ce799526faa8e3bcd618b6f5e2ec2e2e13c574f02
autonomy-unit-tests phase1-p0 FAIL evidence_sha256=d61da9d108d6ace7d845f78b1010773b4b1ce315a538209d7e60eb870c8eb953
campaign-approval-gate phase1-p0 PASS evidence_sha256=29d249ebfb389c3137e411c1d87fb88c7f755cdba4fea5118be187259c707295
git-diff-check phase1-p0 FAIL evidence_sha256=a0adbb54c3b220b9ffc82656470f1d67904823e461fb8ffedd713846814acc78
py-compile phase1-p0 PASS evidence_sha256=f504e34aa0a28ad009ba3b3fd3a75448297be43c452f4dc5ba445d3a4d0f7f07
reconciliation-contract phase1-p0 PASS evidence_sha256=8965ee765da46e32e79d046eeb57db023a2e9bd5105f057a27546b42eed470e3
release-state-machine phase1-p0 PASS evidence_sha256=e5a4c127d4b5b6eb27918fd9c54c06ee23d36d613bb816be475006c81b8ff479
secret-scan phase1-p0 PASS evidence_sha256=fc82389ca65008f045aa9357e5f276eeb0ce040ac5511197d65f1027975bc238
signer-validator-contract phase1-p0 PASS evidence_sha256=79a1d0246c73f0485816f77345fbc769c23f659cd177fefba90bb27e842214f3
1292 lines
69 KiB
Python
1292 lines
69 KiB
Python
"""Loopback-only governed Bridge v2 HTTP gateway with durable handlers."""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime, timedelta, timezone
|
|
import base64
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
from pathlib import Path
|
|
import re
|
|
import sqlite3
|
|
import stat
|
|
from typing import Any, Callable, Mapping
|
|
from urllib.parse import parse_qsl, urlsplit
|
|
|
|
from aios_authority_git_executor import AuthorityGitExecutor
|
|
from aios_chatgpt_bridge_v2 import (
|
|
BridgeV2Adapter,
|
|
BridgeV2Error,
|
|
OPERATION_OPTIONAL_FIELDS,
|
|
OPERATION_REQUIRED_FIELDS,
|
|
TASK_ADMISSION_OPERATIONS,
|
|
TASK_ADMISSION_OPERATION_OPTIONAL_FIELDS,
|
|
TASK_ADMISSION_ROUTES,
|
|
)
|
|
from aios_repository_discovery import RepositoryDiscovery, RepositoryDiscoveryError
|
|
from aios_task_admission_bootstrap import TaskAdmissionError
|
|
from gitea_tag_publication import validate_gitea_api_url
|
|
from aios_continuation_executor import AuthorityGitAdapter, ContinuationCommit, ContinuationExecutor, ContinuationPermissions, ContinuationRuntimeBinding, DetachedGitWorkspace, GiteaContinuationRemote, ServerSideCredentialProjection
|
|
from aios_continuation_lease import WriterLeaseRequestV2
|
|
from aios_control_plane_snapshot import build_control_plane_snapshot
|
|
from aios_gitops_job_controller import GitOpsJobController, JobState, JobStore, _RECOVERABLE, sha256_json
|
|
from aios_governed_task_bootstrap import (
|
|
BootstrapError,
|
|
GovernedTaskBinding,
|
|
GovernedTaskBootstrap,
|
|
)
|
|
from governed_production_release import build_executor_config
|
|
|
|
MAX_BODY = 2 * 1024 * 1024
|
|
TaskPrincipalVerifier = Callable[
|
|
[Mapping[str, Any], Mapping[str, Any]], Mapping[str, Any] | None
|
|
]
|
|
_PRIVATE_PRINCIPAL = "_verified_task_principal"
|
|
ROUTES = {
|
|
"/v2/runtime": "getRuntimeStatus",
|
|
"/v2/capabilities": "getGovernedWriteCapabilities",
|
|
"/v2/governed-task": "createGovernedTask",
|
|
"/v2/execution-envelope": "projectOnlineAgentExecution",
|
|
"/v2/writer-lease": "acquireWriterLease",
|
|
"/v2/commit-file": "commitFileGoverned",
|
|
"/v2/commit-files": "commitFilesGoverned",
|
|
"/v2/job": "getGitOpsJob",
|
|
"/v2/job/resume": "resumeGitOpsJob",
|
|
"/v2/job/reconcile": "reconcileGitOpsJob",
|
|
"/v2/tag/approval-request": "createTagApprovalRequest",
|
|
"/v2/tag/publish": "requestOrCreateTag",
|
|
"/v2/tag/status": "getTagPublicationStatus",
|
|
"/v2/release/artifact": "buildProductionArtifact",
|
|
"/v2/release/execute": "executeApprovedProductionRelease",
|
|
"/v2/release/consistency": "getReleaseConsistency",
|
|
"/v2/release/acceptance": "runReleaseAcceptance",
|
|
"/v2/task-admission/envelope": "getTaskAdmissionEnvelope",
|
|
"/v2/task-admission/authorize": "submitTaskAdmissionAuthorization",
|
|
"/v2/task-admission/status": "getTaskAdmissionStatus",
|
|
"/v2/repository/tree": "listRepositoryTree",
|
|
"/v2/repository/search": "searchRepositorySource",
|
|
"/v2/repository/diff-index": "getDiffIndex",
|
|
"/v2/repository/file": "readRepositoryFile",
|
|
}
|
|
|
|
# Admission is deliberately separate from a TaskPrincipal. A successful
|
|
# admission can create only its durable, Owner-authorized Task record; every
|
|
# Git-mutating operation still requires a verified TaskPrincipal and this
|
|
# independently evaluated runtime gate.
|
|
_TASK_PRINCIPAL_MUTATING_OPERATIONS = frozenset({
|
|
"acquireWriterLease",
|
|
"commitFileGoverned",
|
|
"commitFilesGoverned",
|
|
"resumeGitOpsJob",
|
|
"reconcileGitOpsJob",
|
|
})
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class RuntimeConfig:
|
|
target_oid: str
|
|
authoritative_git_dir: Path
|
|
state_root: Path
|
|
v2_job_root: Path
|
|
token_path: Path
|
|
ssh_key_path: Path
|
|
remote_name: str = "gitea-http"
|
|
repository: str = "aios/aios"
|
|
api_base: str = ""
|
|
v2_task_id: str = "TASK-P0-CHATGPT-BRIDGE-V2-CONTROL-PLANE-CONVERGENCE-20260809"
|
|
v2_branch: str = "agent/p0-chatgpt-bridge-v2-control-plane-convergence-20260809"
|
|
target_version: str = "V2R2C1"
|
|
registry_root: Path = Path("/var/lib/aios-gitops/runtime/registry-projection")
|
|
baseline_path: Path = Path("/var/lib/aios-gitops-runtime-anchor/baseline/current.json")
|
|
health_url: str = "http://127.0.0.1:18927/health"
|
|
release_plan_path: Path | None = None
|
|
repository_discovery_cursor_secret: str | bytes | None = None
|
|
|
|
|
|
def _safe(value: str) -> str:
|
|
return re.sub(r"[^A-Za-z0-9_.-]+", "-", value).strip("-")[:120] or "runtime"
|
|
|
|
|
|
class GovernedRuntime:
|
|
def __init__(self, config: RuntimeConfig) -> None:
|
|
self.config = config
|
|
config.state_root.mkdir(parents=True, exist_ok=True)
|
|
self.authority = AuthorityGitExecutor(config.authoritative_git_dir, config.state_root / "worktrees")
|
|
self.bootstrap = GovernedTaskBootstrap(self.authority, config.state_root, remote_name=config.remote_name, token_path=config.token_path, ssh_key_path=config.ssh_key_path, api_base=config.api_base)
|
|
self.runtimes: dict[tuple[str, int], tuple[Any, GitOpsJobController, ContinuationExecutor]] = {}
|
|
self.controllers: dict[str, GitOpsJobController] = {}
|
|
self.bindings: dict[str, dict[str, Any]] = {}
|
|
self.release = build_executor_config(config)
|
|
self._repository_discovery_instance: RepositoryDiscovery | None = None
|
|
metadata_root = config.state_root / "task-bindings"
|
|
if metadata_root.is_dir():
|
|
for metadata in metadata_root.glob("*.json"):
|
|
try:
|
|
value = json.loads(metadata.read_text(encoding="utf-8"))
|
|
if isinstance(value, dict) and value.get("task_id"):
|
|
self.bindings[str(value["task_id"])] = value
|
|
except (OSError, ValueError, TypeError):
|
|
continue
|
|
askpass = config.state_root / "bridge-v2-askpass.sh"
|
|
if not askpass.exists():
|
|
askpass.write_text('#!/bin/sh\ncase "$1" in *Username*) printf "%s\\n" "$GITEA_MACHINE_ACTOR" ;; *) cat "$CREDENTIAL_FILE" ;; esac\n', encoding="utf-8")
|
|
askpass.chmod(0o700)
|
|
os.environ.setdefault("GIT_ASKPASS", str(askpass)); os.environ.setdefault("GIT_ASKPASS_REQUIRE", "force"); os.environ.setdefault("GIT_TERMINAL_PROMPT", "0"); os.environ.setdefault("GITEA_MACHINE_ACTOR", "aios-autonomy-agent")
|
|
|
|
def runtime_status(self) -> dict[str, Any]:
|
|
verifier = BridgeHandler.principal_verifier
|
|
readiness_reader = getattr(verifier, "readiness", None)
|
|
if callable(readiness_reader):
|
|
try:
|
|
principal_readiness = dict(readiness_reader())
|
|
except Exception:
|
|
principal_readiness = {
|
|
"ready": False,
|
|
"error": "TASK_PRINCIPAL_SEALED_READINESS_UNAVAILABLE",
|
|
}
|
|
else:
|
|
principal_readiness = {
|
|
"ready": False,
|
|
"error": "TASK_PRINCIPAL_SEALED_READINESS_UNAVAILABLE",
|
|
}
|
|
legacy_global_writes_enabled = os.environ.get(
|
|
"AIOS_GITOPS_WRITES_ENABLED", "false"
|
|
).strip().lower() in {"1", "true", "yes", "on"}
|
|
task_principal_writes_enabled = os.environ.get(
|
|
"AIOS_P0_TASK_PRINCIPAL_WRITES_ENABLED", "false"
|
|
).strip().lower() in {"1", "true", "yes", "on"}
|
|
blockers: list[str] = []
|
|
if principal_readiness.get("ready") is not True:
|
|
blockers.append("TASK_PRINCIPAL_VERIFIER_NOT_READY")
|
|
if legacy_global_writes_enabled:
|
|
blockers.append("LEGACY_GLOBAL_WRITES_MUST_REMAIN_DISABLED")
|
|
if not task_principal_writes_enabled:
|
|
blockers.append("TASK_PRINCIPAL_WRITES_DISABLED")
|
|
return {
|
|
"status": "active",
|
|
"health": 200,
|
|
"bridge_schema_version": "aios.chatgpt-gitops-bridge.v2",
|
|
"control_plane_release_version": self.config.target_version,
|
|
"control_plane_target_oid": self.config.target_oid,
|
|
"runtime_release_commit": self.config.target_oid,
|
|
"runtime_path": str(self.config.state_root),
|
|
"artifact_sha256": os.environ.get("AIOS_CONTROL_PLANE_ARTIFACT_SHA256"),
|
|
"deployment_state": "STAGING",
|
|
"drift_status": "PASS",
|
|
"repository": self.config.repository,
|
|
"repository_identity": self.config.repository,
|
|
"authoritative_git_dir": str(self.config.authoritative_git_dir),
|
|
"legacy_global_writes_enabled": legacy_global_writes_enabled,
|
|
"task_principal_writes_enabled": task_principal_writes_enabled,
|
|
"principal_verifier_configured": verifier is not None,
|
|
"task_principal_readiness": principal_readiness,
|
|
"governed_writes_enabled": not blockers,
|
|
"governed_write_blockers": blockers,
|
|
}
|
|
|
|
def project_admitted_task(
|
|
self,
|
|
grant: Any,
|
|
task_result: Mapping[str, Any],
|
|
) -> Mapping[str, Any]:
|
|
"""Durably bind one verified admission to its exact local Job input.
|
|
|
|
This hook is called only after the Agent Task API returns an exact
|
|
readback. It writes a local binding, not a Job or a lease; later
|
|
TaskPrincipal-gated continuation remains responsible for every Git
|
|
side effect.
|
|
"""
|
|
task_id = str(getattr(grant, "task_id", ""))
|
|
repository = str(getattr(grant, "repository", ""))
|
|
base_oid = str(getattr(grant, "authority_base_oid", ""))
|
|
target_branch = str(getattr(grant, "target_branch", ""))
|
|
risk = str(getattr(grant, "risk", ""))
|
|
generation = int(getattr(grant, "generation", 0))
|
|
external_job_id = str(task_result.get("external_job_id") or "")
|
|
if (
|
|
not task_id
|
|
or repository != self.config.repository
|
|
or not base_oid
|
|
or not target_branch
|
|
or generation < 1
|
|
or re.fullmatch(r"job-[0-9a-f]{32}", external_job_id) is None
|
|
):
|
|
raise RuntimeError("TASK_ADMISSION_PROJECTION_COORDINATES_INVALID")
|
|
projection_key = "task-admission:" + task_id
|
|
description = (
|
|
"P0 governed execution projection for officially admitted Agent Task."
|
|
)
|
|
try:
|
|
existing = self.bootstrap.get_binding(task_id)
|
|
except BootstrapError as exc:
|
|
if str(exc) != "TASK_EXECUTION_PROJECTION_MISSING":
|
|
raise
|
|
existing = None
|
|
if existing is not None:
|
|
if (
|
|
existing.repository != repository
|
|
or existing.base_oid != base_oid
|
|
or existing.target_branch != target_branch
|
|
or existing.risk != risk
|
|
or existing.description != description
|
|
or existing.idempotency_key != projection_key
|
|
or existing.generation != generation
|
|
or existing.job_id != external_job_id
|
|
):
|
|
raise RuntimeError("TASK_ADMISSION_PROJECTION_BINDING_CONFLICT")
|
|
result = existing.response(idempotent=True)
|
|
else:
|
|
if not self.authority.commit_exists(base_oid):
|
|
raise RuntimeError("TASK_ADMISSION_PROJECTION_BASE_NOT_FOUND")
|
|
current_branch_oid = self.authority.read_ref(
|
|
"refs/heads/" + target_branch
|
|
)
|
|
if current_branch_oid is None:
|
|
branch_mode = "CREATE_NEW"
|
|
expected_branch_oid = base_oid
|
|
elif current_branch_oid == base_oid:
|
|
branch_mode = "CONTINUE_EXISTING"
|
|
expected_branch_oid = current_branch_oid
|
|
else:
|
|
raise RuntimeError("TASK_ADMISSION_PROJECTION_BRANCH_CONFLICT")
|
|
binding = GovernedTaskBinding(
|
|
task_id=task_id,
|
|
repository=repository,
|
|
base_oid=base_oid,
|
|
target_branch=target_branch,
|
|
risk=risk,
|
|
description=description,
|
|
idempotency_key=projection_key,
|
|
expected_branch_oid=expected_branch_oid,
|
|
branch_mode=branch_mode,
|
|
generation=generation,
|
|
job_id=external_job_id,
|
|
)
|
|
self.bootstrap._write(binding)
|
|
readback = self.bootstrap.get_binding(task_id)
|
|
if readback != binding:
|
|
raise RuntimeError("TASK_ADMISSION_PROJECTION_READBACK_MISMATCH")
|
|
result = readback.response()
|
|
self.bindings[task_id] = dict(result)
|
|
return result
|
|
|
|
def _job_root(self, task_id: str) -> Path:
|
|
return self.config.state_root / "jobs" / _safe(task_id)
|
|
|
|
def _runtime(self, request: Mapping[str, Any]) -> tuple[Any, GitOpsJobController, ContinuationExecutor]:
|
|
key = (str(request["task_id"]), int(request["generation"]))
|
|
if key in self.runtimes: return self.runtimes[key]
|
|
lease = WriterLeaseRequestV2(task_id=str(request["task_id"]), repository=str(request["repository"]), branch_mode=str(request.get("branch_mode", "CONTINUE_EXISTING")), base_oid=str(request["base_oid"]), expected_branch_oid=str(request["expected_branch_oid"]), target_branch=str(request["target_branch"]), generation=int(request["generation"]), lease_seconds=int(request.get("lease_seconds", 900)))
|
|
original_branch_mode = lease.branch_mode
|
|
if lease.branch_mode == "CREATE_NEW":
|
|
try:
|
|
lease.validate(AuthorityGitAdapter(self.authority))
|
|
except Exception as exc:
|
|
# A request replay after the authority CAS may observe the
|
|
# already-created branch. Only the exact base identity is
|
|
# idempotent; all other validation failures remain fail-closed.
|
|
if str(exc) != "TARGET_BRANCH_ALREADY_EXISTS":
|
|
raise
|
|
# Bootstrap owns the durable binding; the runtime performs the one-time
|
|
# branch materialization through the authority CAS before continuation
|
|
# validation. No direct Git or legacy writer path is used.
|
|
self.authority.create_task_branch(lease.target_branch, lease.base_oid)
|
|
lease = WriterLeaseRequestV2(
|
|
task_id=lease.task_id,
|
|
repository=lease.repository,
|
|
branch_mode="CONTINUE_EXISTING",
|
|
base_oid=lease.base_oid,
|
|
expected_branch_oid=lease.expected_branch_oid,
|
|
target_branch=lease.target_branch,
|
|
generation=lease.generation,
|
|
lease_seconds=lease.lease_seconds,
|
|
)
|
|
lease.validate(AuthorityGitAdapter(self.authority))
|
|
worktree_path = self.config.state_root / "worktrees" / _safe(lease.task_id)
|
|
if worktree_path.exists():
|
|
workspace = DetachedGitWorkspace(worktree_path)
|
|
else:
|
|
self.authority.create_detached_worktree(lease.expected_branch_oid, _safe(lease.task_id), self.config.state_root / "worktrees")
|
|
workspace = DetachedGitWorkspace(worktree_path)
|
|
if workspace.head_oid() != lease.expected_branch_oid or not workspace.is_detached(): raise RuntimeError("WORKTREE_HEAD_MISMATCH")
|
|
job_root = self._job_root(lease.task_id); controller = GitOpsJobController(JobStore(job_root, payload_root=job_root / "payloads")); credential = ServerSideCredentialProjection(self.config.ssh_key_path, self.config.token_path); remote = GiteaContinuationRemote(workspace=worktree_path, credential=credential, remote_name=self.config.remote_name, repository=lease.repository, api_base=self.config.api_base); executor = ContinuationExecutor(controller, AuthorityGitAdapter(self.authority), workspace, remote, credential)
|
|
binding = ContinuationRuntimeBinding(request=lease, workspace_path=worktree_path, lease_not_before=datetime.now(timezone.utc) - timedelta(seconds=1), lease_expires_at=datetime.now(timezone.utc) + timedelta(seconds=lease.lease_seconds), original_receipt_valid=True, original_grant_consumed=True, permissions=ContinuationPermissions(), remote_branch_create_allowed=original_branch_mode == "CREATE_NEW", external_job_id=str(request.get("job_id") or "") or None)
|
|
result = (binding, controller, executor); self.runtimes[key] = result; self.controllers[lease.task_id] = controller; return result
|
|
|
|
def create_task(self, request: Mapping[str, Any]) -> dict[str, Any]:
|
|
result = self.bootstrap.create(request); self.bindings[result["task_id"]] = result; return result
|
|
|
|
def project_online_agent_execution(self, request: Mapping[str, Any]) -> dict[str, Any]:
|
|
capabilities = request.get("required_capabilities") or []
|
|
if not isinstance(capabilities, list) or not all(isinstance(item, str) for item in capabilities):
|
|
raise ValueError("CAPABILITY_SCOPE_INVALID")
|
|
execution = request.get("execution")
|
|
if execution is not None and not isinstance(execution, Mapping):
|
|
raise ValueError("EXECUTION_REQUEST_INVALID")
|
|
task_id = str(request["task_id"])
|
|
expected_job_id = str(request.get("job_id") or "") or None
|
|
return self.bootstrap.execution_envelope(
|
|
task_id,
|
|
execution,
|
|
required_capabilities=tuple(capabilities),
|
|
expected_job_id=expected_job_id,
|
|
)
|
|
result = self.bootstrap.create(request); self.bindings[result["task_id"]] = result; return result
|
|
|
|
def _repository_discovery(self) -> RepositoryDiscovery:
|
|
if self._repository_discovery_instance is None:
|
|
self._repository_discovery_instance = RepositoryDiscovery(
|
|
allowed_repositories=(self.config.repository,),
|
|
git_dir=self.config.authoritative_git_dir,
|
|
cursor_secret=(
|
|
self.config.repository_discovery_cursor_secret
|
|
if self.config.repository_discovery_cursor_secret is not None
|
|
else os.environ.get("AIOS_REPOSITORY_DISCOVERY_CURSOR_SECRET")
|
|
),
|
|
)
|
|
return self._repository_discovery_instance
|
|
|
|
def repository_discovery(
|
|
self, operation: str, request: Mapping[str, Any]
|
|
) -> dict[str, Any]:
|
|
method = {
|
|
"listRepositoryTree": "list_repository_tree",
|
|
"searchRepositorySource": "search_repository_source",
|
|
"getDiffIndex": "get_diff_index",
|
|
"readRepositoryFile": "read_repository_file",
|
|
}.get(operation)
|
|
if method is None:
|
|
raise ValueError("REPOSITORY_DISCOVERY_OPERATION_INVALID")
|
|
return getattr(self._repository_discovery(), method)(request)
|
|
|
|
def acquire_lease(self, request: Mapping[str, Any]) -> dict[str, Any]:
|
|
replay = self._durable_completed_replay_lease(request)
|
|
if replay is not None:
|
|
return replay
|
|
binding, _, _ = self._runtime(request)
|
|
req = binding.request
|
|
return {"schema": WriterLeaseRequestV2.schema, "task_id": req.task_id, "repository": req.repository, "branch_mode": req.branch_mode, "base_oid": req.base_oid, "expected_branch_oid": req.expected_branch_oid, "target_branch": req.target_branch, "generation": req.generation, "lease_seconds": req.lease_seconds, "create_target_branch": req.branch_mode == "CREATE_NEW", "worktree_mode": "detached_at_base_oid" if req.branch_mode == "CREATE_NEW" else "detached_at_expected_head", "cas_ref_update_required": True}
|
|
|
|
@staticmethod
|
|
def _files(request: Mapping[str, Any]) -> dict[str, bytes]:
|
|
raw = request.get("files") or {request["path"]: request["content_base64"]}; pairs = raw.items() if isinstance(raw, dict) else ((item["path"], item["content_base64"]) for item in raw); files = {str(path): base64.b64decode(encoded, validate=True) for path, encoded in pairs}
|
|
if not files: raise ValueError("FILES_EMPTY")
|
|
return files
|
|
|
|
def commit_files(self, request: Mapping[str, Any]) -> dict[str, Any]:
|
|
replay = self._durable_completed_replay(request)
|
|
if replay is not None:
|
|
return replay
|
|
runtime = self.runtimes.get((str(request["task_id"]), int(request["generation"])))
|
|
if runtime is None: raise RuntimeError("LEASE_NOT_FOUND")
|
|
binding, _, executor = runtime
|
|
if request["target_branch"] != binding.request.target_branch or request["expected_branch_oid"] != binding.request.expected_branch_oid: raise RuntimeError("LEASE_BINDING_CONFLICT")
|
|
commit = ContinuationCommit(idempotency_key=str(request["idempotency_key"]), files=self._files(request), message=str(request["message"]))
|
|
executor.workspace.materialize_files(commit.files)
|
|
return executor.execute(binding, commit)
|
|
|
|
def _find_completed_replay_job(self, external_job_id: str) -> tuple[Path, dict[str, Any]] | None:
|
|
matches: list[tuple[Path, dict[str, Any]]] = []
|
|
roots = [self.config.state_root / "jobs"]
|
|
for controller in self.controllers.values():
|
|
roots.append(controller.store.root.parent)
|
|
seen: set[str] = set()
|
|
for jobs_root in roots:
|
|
if not jobs_root.is_dir():
|
|
continue
|
|
candidates = []
|
|
if (jobs_root / "state.sqlite3").is_file():
|
|
candidates.append(jobs_root)
|
|
candidates.extend(root for root in jobs_root.iterdir() if root.is_dir())
|
|
for root in candidates:
|
|
db = root / "state.sqlite3"
|
|
key = str(db.resolve()) if db.exists() else str(db)
|
|
if key in seen:
|
|
continue
|
|
seen.add(key)
|
|
if not db.is_file() or db.is_symlink():
|
|
continue
|
|
try:
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
rows = connection.execute("SELECT * FROM jobs").fetchall()
|
|
finally:
|
|
connection.close()
|
|
for raw in rows:
|
|
row = dict(raw)
|
|
durable = json.loads(row["request_json"])
|
|
binding = durable.get("binding", durable)
|
|
if str(binding.get("external_job_id") or "") == external_job_id:
|
|
matches.append((root, row))
|
|
except (OSError, ValueError, TypeError, sqlite3.Error):
|
|
continue
|
|
if not matches:
|
|
return None
|
|
if len(matches) != 1:
|
|
raise RuntimeError("EXTERNAL_JOB_MAPPING_AMBIGUOUS")
|
|
return matches[0]
|
|
|
|
def _durable_completed_replay_lease(self, request: Mapping[str, Any]) -> dict[str, Any] | None:
|
|
"""Admit an exact completed replay before ordinary lease validation."""
|
|
external_job_id = str(request.get("job_id") or "").strip()
|
|
if not external_job_id:
|
|
if request.get("source_lease_epoch") is not None:
|
|
raise RuntimeError("COMPLETED_REPLAY_EXTERNAL_JOB_ID_REQUIRED")
|
|
return None
|
|
match = self._find_completed_replay_job(external_job_id)
|
|
if match is None:
|
|
return None
|
|
root, row = match
|
|
if str(row["state"]) != JobState.COMPLETED.value:
|
|
return None
|
|
db = root / "state.sqlite3"
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
evidence_rows = connection.execute(
|
|
"SELECT * FROM completed_replay_reconciliations WHERE job_id=? ORDER BY created_at ASC",
|
|
(row["job_id"],),
|
|
).fetchall()
|
|
finally:
|
|
connection.close()
|
|
if not evidence_rows:
|
|
return None
|
|
evidence = dict(evidence_rows[0])
|
|
immutable = tuple(key for key in evidence if key != "created_at")
|
|
if any(any(item[key] != evidence[key] for key in immutable) for item in evidence_rows[1:]):
|
|
raise RuntimeError("COMPLETED_REPLAY_AMBIGUOUS")
|
|
durable = json.loads(row["request_json"])
|
|
binding = durable.get("binding", durable)
|
|
target_branch = str(binding.get("target_branch") or binding.get("branch") or "")
|
|
for field, incoming in (
|
|
("task_id", request.get("task_id")),
|
|
("repository", request.get("repository")),
|
|
("target_branch", request.get("target_branch")),
|
|
("generation", request.get("generation")),
|
|
("branch_mode", request.get("branch_mode")),
|
|
):
|
|
durable_value = target_branch if field == "target_branch" else binding.get(field)
|
|
if str(durable_value) != str(incoming):
|
|
raise RuntimeError("COMPLETED_REPLAY_BINDING_CONFLICT")
|
|
historical_head = str(evidence.get("historical_lease_head_oid") or "")
|
|
if str(request.get("base_oid") or "") != historical_head or str(request.get("expected_branch_oid") or "") != historical_head:
|
|
raise RuntimeError("COMPLETED_REPLAY_EXPECTED_HEAD_CONFLICT")
|
|
if request.get("source_lease_epoch") is not None and int(request["source_lease_epoch"]) != int(evidence["source_lease_epoch"]):
|
|
raise RuntimeError("COMPLETED_REPLAY_LEASE_EPOCH_CONFLICT")
|
|
receipt = json.loads(row["receipt_json"] or "null")
|
|
if not isinstance(receipt, Mapping) or receipt.get("commit_oid") != receipt.get("authority_oid"):
|
|
raise RuntimeError("COMPLETED_REPLAY_RECEIPT_INVALID")
|
|
authority_head = self.authority.read_ref("refs/heads/" + target_branch)
|
|
if authority_head != evidence.get("current_head_oid"):
|
|
raise RuntimeError("COMPLETED_REPLAY_AUTHORITY_CONFLICT")
|
|
if not (
|
|
evidence.get("commit_oid")
|
|
== evidence.get("authority_head_oid")
|
|
== evidence.get("current_head_oid")
|
|
== receipt.get("commit_oid")
|
|
and evidence.get("commit_oid") != historical_head
|
|
):
|
|
raise RuntimeError("COMPLETED_REPLAY_EVIDENCE_INCOHERENT")
|
|
return {
|
|
"schema": WriterLeaseRequestV2.schema,
|
|
"task_id": request["task_id"],
|
|
"job_id": external_job_id,
|
|
"repository": request["repository"],
|
|
"branch_mode": request["branch_mode"],
|
|
"base_oid": request["base_oid"],
|
|
"expected_branch_oid": request["expected_branch_oid"],
|
|
"target_branch": request["target_branch"],
|
|
"generation": int(request["generation"]),
|
|
"lease_seconds": int(request.get("lease_seconds") or 900),
|
|
"create_target_branch": False,
|
|
"worktree_mode": "detached_at_expected_head",
|
|
"cas_ref_update_required": True,
|
|
"lease_created": False,
|
|
"completed_replay": True,
|
|
"current_head_oid": evidence["current_head_oid"],
|
|
"completed_replay_reconciliation_id": evidence["reconciliation_id"],
|
|
}
|
|
|
|
def _durable_completed_replay(self, request: Mapping[str, Any]) -> dict[str, Any] | None:
|
|
"""Reconcile an exact completed replay before any worktree mutation."""
|
|
external_job_id = str(request.get("job_id") or "").strip()
|
|
if not external_job_id:
|
|
if request.get("source_lease_epoch") is not None:
|
|
raise RuntimeError("COMPLETED_REPLAY_EXTERNAL_JOB_ID_REQUIRED")
|
|
return None
|
|
matches: list[tuple[Path, dict[str, Any]]] = []
|
|
roots = [self.config.state_root / "jobs"]
|
|
for controller in self.controllers.values():
|
|
roots.append(controller.store.root.parent)
|
|
seen: set[str] = set()
|
|
for jobs_root in roots:
|
|
if not jobs_root.is_dir():
|
|
continue
|
|
candidates = []
|
|
if (jobs_root / "state.sqlite3").is_file():
|
|
candidates.append(jobs_root)
|
|
candidates.extend(root for root in jobs_root.iterdir() if root.is_dir())
|
|
for root in candidates:
|
|
db = root / "state.sqlite3"
|
|
key = str(db.resolve()) if db.exists() else str(db)
|
|
if key in seen:
|
|
continue
|
|
seen.add(key)
|
|
if not db.is_file() or db.is_symlink():
|
|
continue
|
|
try:
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
rows = connection.execute("SELECT * FROM jobs").fetchall()
|
|
finally:
|
|
connection.close()
|
|
for raw in rows:
|
|
row = dict(raw)
|
|
durable = json.loads(row["request_json"])
|
|
binding = durable.get("binding", durable)
|
|
if str(binding.get("external_job_id") or "") == external_job_id:
|
|
matches.append((root, row))
|
|
except (OSError, ValueError, TypeError, sqlite3.Error):
|
|
continue
|
|
if not matches:
|
|
return None
|
|
if len(matches) != 1:
|
|
raise RuntimeError("EXTERNAL_JOB_MAPPING_AMBIGUOUS")
|
|
root, row = matches[0]
|
|
if str(row["state"]) != JobState.COMPLETED.value:
|
|
return None
|
|
durable = json.loads(row["request_json"])
|
|
binding = durable.get("binding", durable)
|
|
source_lease_epoch = request.get("source_lease_epoch")
|
|
if source_lease_epoch is None:
|
|
db = root / "state.sqlite3"
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
evidence = connection.execute(
|
|
"SELECT source_lease_epoch FROM completed_replay_reconciliations WHERE job_id=? ORDER BY created_at ASC LIMIT 1",
|
|
(row["job_id"],),
|
|
).fetchone()
|
|
finally:
|
|
connection.close()
|
|
if evidence is not None:
|
|
source_lease_epoch = int(evidence["source_lease_epoch"])
|
|
files = self._files(request)
|
|
commit = ContinuationCommit(str(request["idempotency_key"]), files, str(request["message"]))
|
|
payload = commit.payload()
|
|
receipt = json.loads(row["receipt_json"] or "null")
|
|
if not isinstance(receipt, Mapping):
|
|
raise RuntimeError("COMPLETED_REPLAY_RECEIPT_INVALID")
|
|
incoming = {
|
|
"task_id": str(request.get("task_id") or ""),
|
|
"external_job_id": external_job_id,
|
|
"internal_job_id": str(row["job_id"]),
|
|
"repository": str(request.get("repository") or ""),
|
|
"target_branch": str(request.get("target_branch") or ""),
|
|
"generation": int(request.get("generation") or 0),
|
|
"branch_mode": str(request.get("branch_mode") or ""),
|
|
"payload_digest": hashlib.sha256(payload).hexdigest(),
|
|
"files_digest": hashlib.sha256(json.dumps({path: hashlib.sha256(content).hexdigest() for path, content in sorted(files.items())}, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest(),
|
|
"message_digest": hashlib.sha256(str(request["message"]).encode("utf-8")).hexdigest(),
|
|
"worker_principal": str(binding.get("worker_principal") or ""),
|
|
"worker_lineage": str(binding.get("worker_lineage") or ""),
|
|
"source_lease_epoch": int(source_lease_epoch or 0),
|
|
"durable_revision": int(row["revision"]),
|
|
"completion_identity": sha256_json({"job_id": row["job_id"], "revision": int(row["revision"]), "receipt": receipt}),
|
|
"reason": "COMPLETED_REPLAY_LEASE_EVIDENCE_RECONCILIATION",
|
|
"provenance": {"source": "governed-completed-replay", "authority_readback": True},
|
|
}
|
|
for field in ("task_id", "repository", "target_branch", "generation", "branch_mode", "payload_digest", "files_digest", "message_digest", "worker_principal", "worker_lineage"):
|
|
durable_value = binding.get(field)
|
|
if field == "target_branch":
|
|
durable_value = binding.get("target_branch") or binding.get("branch")
|
|
elif field in {"worker_principal", "worker_lineage"}:
|
|
durable_value = durable_value or ""
|
|
if durable_value not in (None, "") and str(durable_value) != str(incoming[field]):
|
|
raise RuntimeError("COMPLETED_REPLAY_BINDING_CONFLICT")
|
|
db = root / "state.sqlite3"
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
columns = {str(item[1]) for item in connection.execute("PRAGMA table_info(branch_leases)").fetchall()}
|
|
if "epoch" in columns:
|
|
lease = connection.execute("SELECT lease_id, state, current_head_oid, generation FROM branch_leases WHERE job_id=? AND epoch=? ORDER BY rowid DESC LIMIT 1", (row["job_id"], incoming["source_lease_epoch"])).fetchone()
|
|
else:
|
|
if incoming["source_lease_epoch"] != 1:
|
|
raise RuntimeError("COMPLETED_REPLAY_LEASE_EPOCH_UNAVAILABLE")
|
|
lease = connection.execute("SELECT lease_id, state, current_head_oid, generation FROM branch_leases WHERE job_id=? ORDER BY rowid DESC LIMIT 1", (row["job_id"],)).fetchone()
|
|
if lease is None:
|
|
raise RuntimeError("COMPLETED_REPLAY_LEASE_MISSING")
|
|
historical_lease_head = str(lease["current_head_oid"])
|
|
event_tables = {str(item[0]) for item in connection.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='branch_lease_events'").fetchall()}
|
|
lease_state = str(lease["state"])
|
|
lease_generation = int(lease["generation"])
|
|
if "branch_lease_events" in event_tables:
|
|
event = connection.execute("SELECT state, current_head_oid, generation FROM branch_lease_events WHERE lease_id=? ORDER BY rowid DESC LIMIT 1", (lease["lease_id"],)).fetchone()
|
|
if event is not None:
|
|
lease_state = str(event["state"])
|
|
historical_lease_head = str(event["current_head_oid"])
|
|
lease_generation = int(event["generation"])
|
|
if lease_state not in {"ACTIVE", "USED", "EXPIRED"}:
|
|
raise RuntimeError("COMPLETED_REPLAY_LEASE_STATE_INVALID")
|
|
if lease_generation != incoming["generation"]:
|
|
raise RuntimeError("COMPLETED_REPLAY_LEASE_GENERATION_CONFLICT")
|
|
finally:
|
|
connection.close()
|
|
incoming["historical_lease_head_oid"] = historical_lease_head
|
|
authority_head = self.authority.read_ref("refs/heads/" + incoming["target_branch"])
|
|
if authority_head is None:
|
|
raise RuntimeError("COMPLETED_REPLAY_AUTHORITY_MISSING")
|
|
if receipt.get("commit_oid") != receipt.get("authority_oid"):
|
|
raise RuntimeError("COMPLETED_REPLAY_RECEIPT_INVALID")
|
|
incoming["commit_oid"] = str(receipt["commit_oid"])
|
|
incoming["authority_head_oid"] = authority_head
|
|
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
evidence_rows = connection.execute("SELECT * FROM completed_replay_reconciliations WHERE job_id=? ORDER BY created_at ASC", (row["job_id"],)).fetchall()
|
|
finally:
|
|
connection.close()
|
|
if evidence_rows:
|
|
evidence = dict(evidence_rows[0])
|
|
immutable = tuple(key for key in evidence if key != "created_at")
|
|
if any(any(item[key] != evidence[key] for key in immutable) for item in evidence_rows[1:]):
|
|
raise RuntimeError("COMPLETED_REPLAY_AMBIGUOUS")
|
|
normalized = JobStore._completed_replay_identity(incoming)
|
|
columns = {
|
|
"task_id": "task_id",
|
|
"external_job_id": "external_job_id",
|
|
"internal_job_id": "internal_job_id",
|
|
"repository": "repository",
|
|
"target_branch": "target_branch",
|
|
"generation": "generation",
|
|
"branch_mode": "branch_mode",
|
|
"payload_digest": "payload_digest",
|
|
"files_digest": "files_digest",
|
|
"message_digest": "message_digest",
|
|
"commit_oid": "commit_oid",
|
|
"authority_head_oid": "authority_head_oid",
|
|
"historical_lease_head_oid": "historical_lease_head_oid",
|
|
"worker_principal": "worker_principal",
|
|
"worker_lineage": "worker_lineage",
|
|
"source_lease_epoch": "source_lease_epoch",
|
|
"durable_revision": "durable_revision",
|
|
"completion_identity": "completion_identity",
|
|
"reason": "reason",
|
|
}
|
|
if any(str(evidence[column]) != str(normalized[field]) for field, column in columns.items()):
|
|
raise RuntimeError("COMPLETED_REPLAY_BINDING_CONFLICT")
|
|
if evidence["provenance_json"] != json.dumps(normalized["provenance"], sort_keys=True, separators=(",", ":")):
|
|
raise RuntimeError("COMPLETED_REPLAY_PROVENANCE_CONFLICT")
|
|
if evidence["identity_digest"] != sha256_json(normalized):
|
|
raise RuntimeError("COMPLETED_REPLAY_IDENTITY_CONFLICT")
|
|
if not (evidence["commit_oid"] == evidence["authority_head_oid"] == evidence["current_head_oid"] and evidence["commit_oid"] != evidence["historical_lease_head_oid"]):
|
|
raise RuntimeError("COMPLETED_REPLAY_EVIDENCE_INCOHERENT")
|
|
if self.authority.read_ref("refs/heads/" + incoming["target_branch"]) != evidence["current_head_oid"]:
|
|
raise RuntimeError("COMPLETED_REPLAY_AUTHORITY_CONFLICT")
|
|
result = {"job_id": external_job_id, "task_id": incoming["task_id"], "repository": incoming["repository"], "branch_mode": incoming["branch_mode"], "base_oid": request.get("base_oid"), "expected_branch_oid": request.get("expected_branch_oid"), "target_branch": incoming["target_branch"], "generation": incoming["generation"], "commit_oid": evidence["commit_oid"], "idempotency_key": row["idempotency_key"], "state": JobState.COMPLETED.value, "side_effect_state": row["side_effect_state"], "http_status": 200, "revision": int(row["revision"]), "receipt": {**receipt, "commit_oid": evidence["commit_oid"], "authority_oid": evidence["authority_head_oid"], "current_head_oid": evidence["current_head_oid"], "external_job_id": evidence["external_job_id"], "completed_replay_reconciliation_id": evidence["reconciliation_id"]}, "current_head_oid": evidence["current_head_oid"], "completed_replay_reconciliation_id": evidence["reconciliation_id"]}
|
|
return result
|
|
|
|
controller = GitOpsJobController(JobStore.for_existing_append(root))
|
|
reconciliation = controller.store.append_completed_replay_reconciliation(str(row["job_id"]), incoming, authority_head_oid=authority_head)
|
|
evidence = {**receipt, "commit_oid": reconciliation["commit_oid"], "authority_oid": reconciliation["authority_head_oid"], "current_head_oid": reconciliation["current_head_oid"], "completed_replay_reconciliation_id": reconciliation["reconciliation_id"], "external_job_id": external_job_id}
|
|
return {"job_id": external_job_id, "task_id": incoming["task_id"], "repository": incoming["repository"], "branch_mode": incoming["branch_mode"], "base_oid": request.get("base_oid"), "expected_branch_oid": request.get("expected_branch_oid"), "target_branch": incoming["target_branch"], "generation": incoming["generation"], "commit_oid": reconciliation["commit_oid"], "idempotency_key": row["idempotency_key"], "state": JobState.COMPLETED.value, "side_effect_state": row["side_effect_state"], "http_status": 200, "revision": int(row["revision"]), "receipt": evidence, "current_head_oid": reconciliation["current_head_oid"], "completed_replay_reconciliation_id": reconciliation["reconciliation_id"]}
|
|
|
|
def _controller_for_job(self, job_id: str) -> GitOpsJobController:
|
|
for controller in self.controllers.values():
|
|
try:
|
|
controller.store.read(job_id)
|
|
return controller
|
|
except Exception:
|
|
continue
|
|
jobs_root = self.config.state_root / "jobs"
|
|
if jobs_root.is_dir():
|
|
for root in jobs_root.iterdir():
|
|
if not root.is_dir():
|
|
continue
|
|
db = root / "state.sqlite3"
|
|
if not db.is_file() or db.is_symlink():
|
|
continue
|
|
try:
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
rows = connection.execute("SELECT job_id, request_json FROM jobs").fetchall()
|
|
finally:
|
|
connection.close()
|
|
matched = False
|
|
for row in rows:
|
|
if str(row["job_id"]) == job_id:
|
|
matched = True
|
|
break
|
|
durable = json.loads(row["request_json"])
|
|
binding = durable.get("binding", durable)
|
|
if str(binding.get("external_job_id") or "") == job_id:
|
|
matched = True
|
|
break
|
|
if not matched:
|
|
continue
|
|
controller = GitOpsJobController(JobStore(root, payload_root=root / "payloads"))
|
|
self.controllers[str(job_id)] = controller
|
|
return controller
|
|
except (OSError, ValueError, TypeError, sqlite3.Error):
|
|
continue
|
|
raise RuntimeError("JOB_NOT_FOUND")
|
|
|
|
@staticmethod
|
|
def _valid_oid(value: object) -> bool:
|
|
return isinstance(value, str) and re.fullmatch(r"[0-9a-f]{40}", value) is not None
|
|
|
|
def _reconstruct_legacy_binding(
|
|
self,
|
|
row: Mapping[str, Any],
|
|
controller: GitOpsJobController,
|
|
) -> dict[str, Any]:
|
|
raw = json.loads(row["request_json"])
|
|
binding = raw.get("binding", raw)
|
|
if not isinstance(binding, dict):
|
|
raise RuntimeError("DURABLE_BINDING_INVALID")
|
|
task_id = str(binding.get("task_id") or binding.get("campaign_id") or "").strip()
|
|
repository = str(binding.get("repository") or "").strip()
|
|
operation = str(binding.get("operation") or row.get("operation") or "").strip()
|
|
branch = str(binding.get("target_branch") or binding.get("branch") or row.get("branch") or "").strip()
|
|
expected = str(binding.get("expected_branch_oid") or row.get("expected_branch_oid") or "").strip()
|
|
base = binding.get("base_oid") or binding.get("lineage_anchor_oid")
|
|
if not base:
|
|
with controller.store._connect() as connection:
|
|
lease_row = connection.execute(
|
|
"SELECT lineage_anchor_oid FROM branch_leases WHERE job_id=? ORDER BY revision DESC LIMIT 1",
|
|
(str(row["job_id"]),),
|
|
).fetchone()
|
|
if lease_row is not None:
|
|
base = lease_row["lineage_anchor_oid"]
|
|
base = str(base or "").strip()
|
|
branch_mode = str(
|
|
binding.get("branch_mode")
|
|
or ("CREATE_NEW" if operation.endswith("_CREATE_NEW") else "CONTINUE_EXISTING")
|
|
).strip()
|
|
try:
|
|
generation = int(binding.get("generation") or 0)
|
|
except (TypeError, ValueError) as exc:
|
|
raise RuntimeError("DURABLE_BINDING_GENERATION_INVALID") from exc
|
|
if (
|
|
not task_id
|
|
or repository != self.config.repository
|
|
or not branch.startswith("agent/")
|
|
or branch in {"main", "master"}
|
|
or branch_mode not in {"CREATE_NEW", "CONTINUE_EXISTING"}
|
|
or generation < 1
|
|
or not self._valid_oid(base)
|
|
or not self._valid_oid(expected)
|
|
):
|
|
raise RuntimeError("DURABLE_BINDING_INVALID")
|
|
current = self.authority.read_ref("refs/heads/" + branch)
|
|
if (
|
|
current is None
|
|
or not self.authority.commit_exists(base)
|
|
or not self.authority.commit_exists(expected)
|
|
or not self.authority.ancestry_check(base, current)
|
|
or not self.authority.ancestry_check(expected, current)
|
|
):
|
|
raise RuntimeError("DURABLE_BINDING_LINEAGE_INVALID")
|
|
return {
|
|
"task_id": task_id,
|
|
"repository": repository,
|
|
"branch_mode": branch_mode,
|
|
"base_oid": base,
|
|
"expected_branch_oid": expected,
|
|
"target_branch": branch,
|
|
"generation": generation,
|
|
"lease_seconds": int(binding.get("lease_seconds") or 900),
|
|
}
|
|
|
|
def _executor_from_row(
|
|
self,
|
|
row: Mapping[str, Any],
|
|
controller: GitOpsJobController,
|
|
) -> ContinuationExecutor:
|
|
request = self._reconstruct_legacy_binding(row, controller)
|
|
lease = WriterLeaseRequestV2(**request)
|
|
worktree_path = self.config.state_root / "worktrees" / _safe(lease.task_id)
|
|
if not worktree_path.exists():
|
|
current = self.authority.read_ref("refs/heads/" + lease.target_branch)
|
|
if current is None:
|
|
raise RuntimeError("DURABLE_WORKTREE_BRANCH_MISSING")
|
|
self.authority.create_detached_worktree(
|
|
current,
|
|
_safe(lease.task_id),
|
|
self.config.state_root / "worktrees",
|
|
)
|
|
workspace = DetachedGitWorkspace(worktree_path)
|
|
credential = ServerSideCredentialProjection(self.config.ssh_key_path, self.config.token_path)
|
|
remote = GiteaContinuationRemote(
|
|
workspace=worktree_path,
|
|
credential=credential,
|
|
remote_name=self.config.remote_name,
|
|
repository=lease.repository,
|
|
api_base=self.config.api_base,
|
|
)
|
|
return ContinuationExecutor(
|
|
controller,
|
|
AuthorityGitAdapter(self.authority),
|
|
workspace,
|
|
remote,
|
|
credential,
|
|
)
|
|
|
|
def job(self, request: Mapping[str, Any], action: str) -> dict[str, Any]:
|
|
job_id = str(request["job_id"])
|
|
controller = self._controller_for_job(job_id)
|
|
row = controller.store.read(job_id)
|
|
if action == "get":
|
|
result = controller.store._receipt(row, duplicate=True).as_dict()
|
|
evidence_reader = getattr(controller.store, "completed_replay_evidence", None)
|
|
evidence = evidence_reader(job_id) if callable(evidence_reader) else None
|
|
if evidence is not None:
|
|
branch = str(json.loads(row["request_json"]).get("binding", {}).get("branch") or row["branch"])
|
|
authority_head = self.authority.read_ref("refs/heads/" + branch)
|
|
if authority_head != evidence["authority_head_oid"] or evidence["current_head_oid"] != authority_head:
|
|
raise RuntimeError("COMPLETED_REPLAY_AUTHORITY_CONFLICT")
|
|
result["job_id"] = evidence["external_job_id"]
|
|
result["current_head_oid"] = evidence["current_head_oid"]
|
|
result["completed_replay_reconciliation_id"] = evidence["reconciliation_id"]
|
|
result["receipt"] = {
|
|
**(result.get("receipt") or {}),
|
|
"commit_oid": evidence["commit_oid"],
|
|
"authority_oid": evidence["authority_head_oid"],
|
|
"current_head_oid": evidence["current_head_oid"],
|
|
"external_job_id": evidence["external_job_id"],
|
|
"completed_replay_reconciliation_id": evidence["reconciliation_id"],
|
|
}
|
|
return result
|
|
if action == "resume":
|
|
return controller.resume(job_id).as_dict()
|
|
if JobState(row["state"]) not in _RECOVERABLE:
|
|
return controller.store._receipt(row, duplicate=True).as_dict()
|
|
return self._executor_from_row(row, controller).reconcile(job_id)
|
|
|
|
def _snapshot_task(self) -> dict[str, Any]:
|
|
candidates: list[dict[str, Any]] = []
|
|
for value in self.bindings.values():
|
|
task_id = str(value.get("task_id") or "").strip()
|
|
branch = str(value.get("target_branch") or "").strip()
|
|
if not task_id or not branch.startswith("agent/"):
|
|
continue
|
|
authority = self.authority.read_ref("refs/heads/" + branch)
|
|
try:
|
|
generation = int(value.get("generation") or 0)
|
|
except (TypeError, ValueError):
|
|
generation = 0
|
|
reconciliation_state = "OBSERVATION_REQUIRED"
|
|
projection: dict[str, Any] = {}
|
|
db = self.config.state_root / "jobs" / _safe(task_id) / "state.sqlite3"
|
|
if db.is_file() and not db.is_symlink():
|
|
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
|
|
connection.row_factory = sqlite3.Row
|
|
try:
|
|
lease = connection.execute("SELECT MAX(generation) FROM branch_leases WHERE branch=?", (branch,)).fetchone()
|
|
generation = max(generation, int((lease or (0,))[0] or 0))
|
|
latest = connection.execute("SELECT job_id, state, side_effect_state FROM jobs WHERE branch=? ORDER BY updated_at DESC LIMIT 1", (branch,)).fetchone()
|
|
if latest is not None:
|
|
reconciliation_state = "COMPLETED" if latest["state"] == "COMPLETED" else str(latest["side_effect_state"] or latest["state"])
|
|
evidence_rows = connection.execute("SELECT * FROM completed_replay_reconciliations WHERE job_id=? ORDER BY created_at ASC", (latest["job_id"],)).fetchall()
|
|
if evidence_rows:
|
|
evidence = dict(evidence_rows[0])
|
|
immutable = tuple(key for key in evidence if key != "created_at")
|
|
if any(any(item[key] != evidence[key] for key in immutable) for item in evidence_rows[1:]):
|
|
raise RuntimeError("COMPLETED_REPLAY_AMBIGUOUS")
|
|
if not (evidence["commit_oid"] == evidence["authority_head_oid"] == evidence["current_head_oid"] and evidence["commit_oid"] != evidence["historical_lease_head_oid"]):
|
|
raise RuntimeError("COMPLETED_REPLAY_EVIDENCE_INCOHERENT")
|
|
current = self.authority.read_ref("refs/heads/" + branch)
|
|
if current != evidence["authority_head_oid"] or current != evidence["current_head_oid"]:
|
|
raise RuntimeError("COMPLETED_REPLAY_AUTHORITY_CONFLICT")
|
|
reconciliation_state = "COMPLETED_REPLAY_RECONCILED"
|
|
projection = {"external_job_id": evidence["external_job_id"], "commit_oid": evidence["commit_oid"], "current_head_oid": evidence["current_head_oid"], "completed_replay_reconciliation_id": evidence["reconciliation_id"], "receipt_authority_oid": evidence["authority_head_oid"]}
|
|
finally:
|
|
connection.close()
|
|
candidate = {"task_id": task_id, "branch": branch, "authority_branch_oid": authority, "gitea_git_oid": None, "gitea_api_oid": None, "commit_visible": None, "generation": generation, "reconciliation_state": reconciliation_state}
|
|
candidate.update(projection)
|
|
candidates.append(candidate)
|
|
if not candidates:
|
|
return {}
|
|
return max(candidates, key=lambda item: (int(item["generation"] or 0), bool(item["authority_branch_oid"])))
|
|
|
|
def snapshot(self) -> dict[str, Any]:
|
|
task = self._snapshot_task()
|
|
runtime = self.runtime_status()
|
|
return build_control_plane_snapshot(target_version=self.config.target_version, runtime=runtime, repository={"identity": self.config.repository, "authority_git_dir": str(self.config.authoritative_git_dir), "authority_main_oid": self.authority.read_ref("refs/heads/main")}, production={"baseline_version": "V2R1C7", "target_oid": "c7adece1cc8beffe7c718d53c775898b45d6c7f8", "deployment_state": "ACTIVE"}, task=task, capabilities={"legacy_writes_enabled": False, "governed_writes_enabled": runtime["governed_writes_enabled"], "force_push": False, "main_write": False, "tag_write": False, "baseline_write": False, "production_write": False}, credential_broker={"status": "SERVER_SIDE_ONLY", "provider": "FileCredentialProvider"})
|
|
|
|
def handlers(self) -> dict[str, Any]:
|
|
return {
|
|
"projectOnlineAgentExecution": self.project_online_agent_execution,
|
|
"createGovernedTask": self.create_task,
|
|
"acquireWriterLease": self.acquire_lease,
|
|
"commitFileGoverned": lambda request: self.commit_files({**request, "files": {request["path"]: request["content_base64"]}}),
|
|
"commitFilesGoverned": self.commit_files,
|
|
"getGitOpsJob": lambda request: self.job(request, "get"),
|
|
"resumeGitOpsJob": lambda request: self.job(request, "resume"),
|
|
"reconcileGitOpsJob": lambda request: self.job(request, "reconcile"),
|
|
"getControlPlaneSnapshot": lambda request: self.snapshot(),
|
|
"listRepositoryTree": lambda request: self.repository_discovery(
|
|
"listRepositoryTree", request
|
|
),
|
|
"searchRepositorySource": lambda request: self.repository_discovery(
|
|
"searchRepositorySource", request
|
|
),
|
|
"getDiffIndex": lambda request: self.repository_discovery(
|
|
"getDiffIndex", request
|
|
),
|
|
"readRepositoryFile": lambda request: self.repository_discovery(
|
|
"readRepositoryFile", request
|
|
),
|
|
"createTagApprovalRequest": self.release.approval_request,
|
|
"requestOrCreateTag": self.release.publish_tag,
|
|
"getTagPublicationStatus": self.release.tag_status,
|
|
"buildProductionArtifact": self.release.build_artifact,
|
|
"executeApprovedProductionRelease": self.release.execute_request,
|
|
"getReleaseConsistency": self.release.consistency,
|
|
"runReleaseAcceptance": self.release.acceptance,
|
|
}
|
|
|
|
|
|
def build_governed_handlers(runtime_config: RuntimeConfig | Mapping[str, Any]) -> Mapping[str, Any]:
|
|
if isinstance(runtime_config, Mapping): runtime_config = RuntimeConfig(**runtime_config)
|
|
return GovernedRuntime(runtime_config).handlers()
|
|
|
|
|
|
def build_bridge_adapter(
|
|
runtime: GovernedRuntime,
|
|
*,
|
|
task_admission_handlers: Mapping[str, Callable[[Mapping[str, Any]], Any]] | None = None,
|
|
) -> BridgeV2Adapter:
|
|
handlers = dict(runtime.handlers())
|
|
if task_admission_handlers is not None:
|
|
if (
|
|
set(task_admission_handlers) != set(TASK_ADMISSION_OPERATIONS)
|
|
or any(
|
|
not callable(task_admission_handlers.get(operation))
|
|
for operation in TASK_ADMISSION_OPERATIONS
|
|
)
|
|
):
|
|
raise ValueError("TASK_ADMISSION_HANDLERS_INCOMPLETE")
|
|
handlers.update(task_admission_handlers)
|
|
return BridgeV2Adapter(runtime_status=runtime.runtime_status, handlers=handlers)
|
|
|
|
|
|
class _HTTPError(RuntimeError): pass
|
|
|
|
|
|
class BridgeHandler(BaseHTTPRequestHandler):
|
|
adapter: BridgeV2Adapter | None = None
|
|
principal_verifier: TaskPrincipalVerifier | None = None
|
|
|
|
def log_message(self, *_args: Any) -> None: return
|
|
|
|
def _json(self, value: Any, status: int = 200) -> None:
|
|
raw = json.dumps(value, sort_keys=True, separators=(",", ":")).encode(); self.send_response(status); self.send_header("Content-Type", "application/json"); self.send_header("Content-Length", str(len(raw))); self.end_headers(); self.wfile.write(raw)
|
|
|
|
@staticmethod
|
|
def _result_status(value: Any) -> int:
|
|
status = value.get("http_status") if isinstance(value, Mapping) else None
|
|
return status if isinstance(status, int) and 100 <= status <= 599 else 200
|
|
|
|
def _body(self) -> dict[str, Any]:
|
|
try: length = int(self.headers.get("Content-Length", "-1"))
|
|
except ValueError as exc: raise _HTTPError("CONTENT_LENGTH_INVALID") from exc
|
|
if length < 0 or length > MAX_BODY: raise _HTTPError("REQUEST_TOO_LARGE")
|
|
def strict_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
|
|
value: dict[str, Any] = {}
|
|
for key, item in pairs:
|
|
if key in value:
|
|
raise _HTTPError("JSON_DUPLICATE_FIELD")
|
|
value[key] = item
|
|
return value
|
|
value = json.loads(
|
|
self.rfile.read(length).decode("utf-8"),
|
|
object_pairs_hook=strict_object,
|
|
)
|
|
if not isinstance(value, dict): raise _HTTPError("JSON_OBJECT_REQUIRED")
|
|
return value
|
|
|
|
def _allowed(self, operation: str, body: Mapping[str, Any]) -> None:
|
|
if operation in TASK_ADMISSION_OPERATIONS:
|
|
allowed = set(OPERATION_REQUIRED_FIELDS[operation]) | set(
|
|
TASK_ADMISSION_OPERATION_OPTIONAL_FIELDS[operation]
|
|
)
|
|
elif operation in OPERATION_OPTIONAL_FIELDS:
|
|
allowed = set(OPERATION_REQUIRED_FIELDS[operation]) | set(
|
|
OPERATION_OPTIONAL_FIELDS[operation]
|
|
)
|
|
else:
|
|
allowed = set(OPERATION_REQUIRED_FIELDS[operation]) | {"schema", "lease_seconds", "create_target_branch", "worktree_mode", "cas_ref_update_required", "expected_branch_oid", "expected_revision", "generation", "branch_mode", "source_lease_epoch"}
|
|
if operation == "projectOnlineAgentExecution": allowed.add("execution")
|
|
if operation == "commitFilesGoverned": allowed.add("files")
|
|
if operation not in TASK_ADMISSION_OPERATIONS and operation not in OPERATION_OPTIONAL_FIELDS:
|
|
allowed.update({"owner_approval", "execute", "job_id", "historical_lease_head_oid"})
|
|
if "principal" in body or _PRIVATE_PRINCIPAL in body:
|
|
raise _HTTPError("CALLER_PRINCIPAL_FORBIDDEN")
|
|
if set(body) - allowed: raise _HTTPError("UNKNOWN_FIELDS")
|
|
|
|
def _verified_request(self, operation: str, body: Mapping[str, Any]) -> dict[str, Any]:
|
|
protected = {
|
|
"createGovernedTask", "projectOnlineAgentExecution",
|
|
"acquireWriterLease", "commitFileGoverned", "commitFilesGoverned",
|
|
"getGitOpsJob", "resumeGitOpsJob", "reconcileGitOpsJob",
|
|
}
|
|
if operation not in protected:
|
|
return dict(body)
|
|
if operation in _TASK_PRINCIPAL_MUTATING_OPERATIONS:
|
|
adapter = self.adapter
|
|
if adapter is None:
|
|
raise _HTTPError("TASK_PRINCIPAL_WRITES_DISABLED")
|
|
try:
|
|
runtime = adapter.getRuntimeStatus()
|
|
except Exception as exc:
|
|
raise _HTTPError("TASK_PRINCIPAL_WRITES_DISABLED") from exc
|
|
if (
|
|
not isinstance(runtime, Mapping)
|
|
or runtime.get("governed_writes_enabled") is not True
|
|
or runtime.get("legacy_global_writes_enabled") is not False
|
|
or runtime.get("task_principal_writes_enabled") is not True
|
|
):
|
|
raise _HTTPError("TASK_PRINCIPAL_WRITES_DISABLED")
|
|
verifier = type(self).principal_verifier
|
|
if verifier is None:
|
|
raise _HTTPError("TASK_PRINCIPAL_VERIFIER_UNAVAILABLE")
|
|
get_all = getattr(self.headers, "get_all", None)
|
|
if callable(get_all):
|
|
authorization_values = get_all("Authorization") or []
|
|
else:
|
|
authorization = self.headers.get("Authorization")
|
|
authorization_values = [] if authorization is None else [authorization]
|
|
transport = {
|
|
"operation": operation,
|
|
"client_address": self.client_address[0] if self.client_address else None,
|
|
"headers": {
|
|
"authorization": authorization_values[0] if len(authorization_values) == 1 else None,
|
|
"x-request-id": self.headers.get("X-Request-Id"),
|
|
},
|
|
}
|
|
principal = verifier(transport, dict(body))
|
|
if not isinstance(principal, Mapping):
|
|
raise _HTTPError("TASK_PRINCIPAL_REJECTED")
|
|
return {**body, _PRIVATE_PRINCIPAL: dict(principal)}
|
|
|
|
def _query_body(self, operation: str) -> dict[str, Any]:
|
|
parsed = urlsplit(self.path)
|
|
if len(self.path) > 8192:
|
|
raise _HTTPError("QUERY_TOO_LARGE")
|
|
try:
|
|
pairs = parse_qsl(
|
|
parsed.query,
|
|
keep_blank_values=True,
|
|
strict_parsing=False,
|
|
max_num_fields=64,
|
|
)
|
|
except ValueError as exc:
|
|
raise _HTTPError("QUERY_INVALID") from exc
|
|
allowed = set(OPERATION_REQUIRED_FIELDS[operation]) | set(
|
|
OPERATION_OPTIONAL_FIELDS[operation]
|
|
)
|
|
result: dict[str, Any] = {}
|
|
for key, value in pairs:
|
|
if key not in allowed:
|
|
raise _HTTPError("UNKNOWN_FIELDS")
|
|
if key == "path_globs":
|
|
result.setdefault(key, []).append(value)
|
|
continue
|
|
if key in result:
|
|
raise _HTTPError("DUPLICATE_FIELD")
|
|
if key in {"depth", "limit", "max_matches", "max_bytes"}:
|
|
try:
|
|
value = int(value, 10)
|
|
except (TypeError, ValueError) as exc:
|
|
raise _HTTPError("INVALID_INTEGER") from exc
|
|
result[key] = value
|
|
if set(OPERATION_REQUIRED_FIELDS[operation]) - set(result):
|
|
raise _HTTPError("MISSING_FIELDS")
|
|
return result
|
|
|
|
def do_GET(self) -> None:
|
|
if self.adapter is None: self._json({"error": "RUNTIME_UNAVAILABLE"}, 503); return
|
|
parsed = urlsplit(self.path)
|
|
if parsed.path == "/v2/runtime": self._json(self.adapter.getRuntimeStatus()); return
|
|
if parsed.path == "/v2/capabilities": self._json(self.adapter.getGovernedWriteCapabilities()); return
|
|
if parsed.path == "/v2/control-plane-snapshot": self._json(self.adapter.getControlPlaneSnapshot({})); return
|
|
if parsed.path == "/v2/task-admission/status":
|
|
if not callable(self.adapter.handlers.get("getTaskAdmissionStatus")):
|
|
self._json({"error": "NOT_FOUND"}, 404)
|
|
return
|
|
try:
|
|
parameters = parse_qsl(parsed.query, keep_blank_values=True)
|
|
if (
|
|
len(parameters) != 1
|
|
or parameters[0][0] != "envelope_id"
|
|
or not parameters[0][1]
|
|
):
|
|
raise _HTTPError("TASK_ADMISSION_QUERY_INVALID")
|
|
result = self.adapter.getTaskAdmissionStatus(
|
|
{"envelope_id": parameters[0][1]}
|
|
)
|
|
self._json(result, self._result_status(result))
|
|
except TaskAdmissionError as exc:
|
|
self._json({"error": str(exc)}, exc.status)
|
|
except _HTTPError as exc:
|
|
self._json({"error": str(exc)}, 400)
|
|
except (ValueError, BridgeV2Error) as exc:
|
|
self._json({"error": str(exc)}, 400)
|
|
except Exception as exc:
|
|
self._json({"error": str(exc) or type(exc).__name__}, 503)
|
|
return
|
|
operation = ROUTES.get(parsed.path)
|
|
if operation in OPERATION_OPTIONAL_FIELDS:
|
|
try:
|
|
body = self._query_body(operation)
|
|
self._allowed(operation, body)
|
|
result = getattr(self.adapter, operation)(body)
|
|
self._json(result, self._result_status(result))
|
|
except _HTTPError as exc:
|
|
status = 413 if str(exc) == "QUERY_TOO_LARGE" else 400
|
|
self._json({"error": str(exc)}, status)
|
|
except RepositoryDiscoveryError as exc:
|
|
self._json({"error": exc.code}, exc.status_code)
|
|
except (BridgeV2Error, ValueError) as exc:
|
|
self._json({"error": str(exc)}, 400)
|
|
except Exception as exc:
|
|
self._json({"error": str(exc) or type(exc).__name__}, 503)
|
|
return
|
|
self._json({"error": "NOT_FOUND"}, 404)
|
|
|
|
def do_POST(self) -> None:
|
|
operation = ROUTES.get(urlsplit(self.path).path)
|
|
if operation in OPERATION_OPTIONAL_FIELDS:
|
|
self._json({"error": "METHOD_NOT_ALLOWED"}, 405)
|
|
return
|
|
if operation is None or operation in ("getRuntimeStatus", "getGovernedWriteCapabilities") or self.adapter is None: self._json({"error": "NOT_FOUND"}, 404); return
|
|
if operation in TASK_ADMISSION_OPERATIONS and not callable(self.adapter.handlers.get(operation)):
|
|
self._json({"error": "NOT_FOUND"}, 404)
|
|
return
|
|
try:
|
|
body = self._body(); self._allowed(operation, body)
|
|
result = getattr(self.adapter, operation)(self._verified_request(operation, body))
|
|
self._json(result, self._result_status(result))
|
|
except _HTTPError as exc:
|
|
error = str(exc)
|
|
if error == "REQUEST_TOO_LARGE":
|
|
status = 413
|
|
elif error == "TASK_PRINCIPAL_WRITES_DISABLED":
|
|
status = 423
|
|
else:
|
|
status = 401 if error.startswith("TASK_PRINCIPAL_") else 400
|
|
self._json({"error": error}, status)
|
|
except TaskAdmissionError as exc: self._json({"error": str(exc)}, exc.status)
|
|
except (BootstrapError, ValueError, BridgeV2Error) as exc: self._json({"error": str(exc)}, 409 if "CONFLICT" in str(exc) else 400)
|
|
except Exception as exc:
|
|
error = str(exc) or type(exc).__name__
|
|
if error.startswith("TASK_PRINCIPAL_"):
|
|
status = 403
|
|
elif any(token in error for token in ("CONFLICT", "EXPECTATION", "MONOTONIC", "REVISION_CAS")):
|
|
status = 409
|
|
else:
|
|
status = 503
|
|
self._json({"error": error}, status)
|
|
|
|
|
|
def serve(adapter: BridgeV2Adapter, host: str = "127.0.0.1", port: int = 18892) -> None:
|
|
BridgeHandler.adapter = adapter; ThreadingHTTPServer((host, port), BridgeHandler).serve_forever()
|
|
|
|
|
|
def main(
|
|
*,
|
|
task_admission_handlers: Mapping[str, Callable[[Mapping[str, Any]], Any]] | None = None,
|
|
) -> None:
|
|
activation_raw = os.environ.get(
|
|
"AIOS_TASK_ADMISSION_ACTIVATION_FILE",
|
|
"/var/lib/aios-gitops/bridge-v2-staging/task-admission-activation.json",
|
|
).strip()
|
|
discovery_secret_file = os.environ.get(
|
|
"AIOS_REPOSITORY_DISCOVERY_CURSOR_SECRET_FILE", ""
|
|
).strip()
|
|
if discovery_secret_file:
|
|
secret_path = Path(discovery_secret_file)
|
|
try:
|
|
secret_metadata = secret_path.lstat()
|
|
if (
|
|
stat.S_ISLNK(secret_metadata.st_mode)
|
|
or not stat.S_ISREG(secret_metadata.st_mode)
|
|
or secret_metadata.st_mode & 0o022
|
|
or secret_metadata.st_size > 4096
|
|
):
|
|
raise RuntimeError("REPOSITORY_DISCOVERY_CURSOR_SECRET_INVALID")
|
|
discovery_cursor_secret: str | bytes | None = secret_path.read_bytes()
|
|
except (OSError, RuntimeError) as exc:
|
|
if str(exc) == "REPOSITORY_DISCOVERY_CURSOR_SECRET_INVALID":
|
|
raise
|
|
raise RuntimeError(
|
|
"REPOSITORY_DISCOVERY_CURSOR_SECRET_UNAVAILABLE"
|
|
) from exc
|
|
if not discovery_cursor_secret:
|
|
raise RuntimeError("REPOSITORY_DISCOVERY_CURSOR_SECRET_EMPTY")
|
|
else:
|
|
discovery_cursor_secret = os.environ.get(
|
|
"AIOS_REPOSITORY_DISCOVERY_CURSOR_SECRET"
|
|
)
|
|
state_root = Path("/var/lib/aios-gitops/bridge-v2-staging")
|
|
token_path = Path(os.environ.get("AIOS_GITEA_TOKEN_FILE", "/run/credentials/aios-chatgpt-bridge-v2-staging.service/gitea_token"))
|
|
ssh_key_path = Path(os.environ.get("AIOS_GITEA_SSH_KEY_PATH", "/home/aiman/.ssh/id_ed25519_codex_tmp"))
|
|
os.environ["CREDENTIAL_FILE"] = str(token_path)
|
|
os.environ.setdefault("GITEA_MACHINE_ACTOR", "aios-autonomy-agent")
|
|
config = RuntimeConfig(
|
|
os.environ.get("AIOS_CONTROL_PLANE_TARGET_OID", ""),
|
|
Path("/data/aios-gitops/repo.git"),
|
|
state_root,
|
|
state_root / "jobs",
|
|
token_path,
|
|
ssh_key_path,
|
|
remote_name=os.environ.get("AIOS_GITEA_REMOTE", "gitea-http"),
|
|
api_base=validate_gitea_api_url(os.environ.get("AIOS_GITEA_API_BASE", "")),
|
|
target_version=os.environ.get("AIOS_CONTROL_PLANE_TARGET_VERSION", "V2R2C1"),
|
|
baseline_path=Path(os.environ.get(
|
|
"AIOS_GITOPS_BASELINE_AUTHORITY",
|
|
"/var/lib/aios-gitops-runtime-anchor/baseline/current.json",
|
|
)),
|
|
repository_discovery_cursor_secret=discovery_cursor_secret,
|
|
)
|
|
runtime = GovernedRuntime(config)
|
|
# A TaskPrincipal verifier is deliberately supplied only by the hosting
|
|
# service. Without that independently authenticated verifier, all Git
|
|
# mutation requests fail closed while the admission-only routes remain
|
|
# available for a configured Owner-approved epoch.
|
|
BridgeHandler.principal_verifier = None
|
|
if task_admission_handlers is None:
|
|
if os.environ.get("AIOS_TASK_ADMISSION_EPOCH_ROOT", "").strip():
|
|
from aios_task_admission_live_adapters import (
|
|
build_task_admission_handlers_from_environment,
|
|
)
|
|
task_admission_handlers = build_task_admission_handlers_from_environment(
|
|
post_admission=runtime.project_admitted_task,
|
|
)
|
|
elif activation_raw and Path(activation_raw).is_file():
|
|
from aios_task_admission_live_adapters import (
|
|
build_task_admission_handlers_from_activation_file,
|
|
)
|
|
task_admission_handlers = build_task_admission_handlers_from_activation_file(
|
|
Path(activation_raw),
|
|
post_admission=runtime.project_admitted_task,
|
|
)
|
|
serve(
|
|
build_bridge_adapter(
|
|
runtime,
|
|
task_admission_handlers=task_admission_handlers,
|
|
),
|
|
port=int(os.environ.get("AIOS_BRIDGE_V2_PORT", "18892")),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__": main()
|