Compare commits

..
Author SHA1 Message Date
AIOS Governed Continuation d781f0b350 fix(actions): project governed task admission endpoints 2026-09-14 02:37:11 +08:00
AIOS Governed Continuation b781129bd5 fix(release): correct governed tag schema indentation 2026-08-09 16:52:05 +08:00
AIOS Governed Continuation 44c08c5aec fix(release): expose exact governed tag request fields 2026-08-09 16:50:49 +08:00
AIOS Governed Continuation 0f74553bd5 fix(release): place Bridge v2 contract paths under OpenAPI paths 2026-08-09 16:49:49 +08:00
AIOS Governed Continuation 062089ead2 test(release): converge Bridge v2 release contract 2026-08-09 16:47:13 +08:00
AIOS Governed Continuation 55217e4b8a fix(release): preserve governed action API routing 2026-08-09 16:34:33 +08:00
AIOS Governed Continuation 96f2d05c48 feat(release): wire governed V2R2C1 production executor 2026-08-09 16:29:43 +08:00
AIOS Governed Continuation 0ade81293e fix(gitops): recover legacy durable jobs safely 2026-08-09 14:52:59 +08:00
AIOS Governed Continuation b81f6fdb85 fix(gitops): recover pending CREATE_NEW leases 2026-08-09 11:53:31 +08:00
AIOS Governed Continuation 3b6636fa7d fix(gitops): wire governed job reconciliation 2026-08-09 11:51:09 +08:00
AIOS Governed Continuation aff7f74f40 fix(gitops): recover safe pre-side-effect continuation retries 2026-08-09 11:46:49 +08:00
AIOS Governed Continuation 141bd5856c fix(gitops): close governed HTTP authoring retry path 2026-08-09 11:43:55 +08:00
AIOS Governed Continuation 88873a07f6 feat(gitops): expose governed Bridge v2 HTTP bootstrap 2026-08-09 11:27:31 +08:00
AIOS Governed Continuation 3f670c3876 test(gitops): prove Bridge v2 governed operation sequence 2026-08-09 03:40:28 +08:00
AIOS Governed Continuation 8fe3b85c1b fix(gitops): reconcile exact old remote after observation 2026-08-09 03:36:39 +08:00
AIOS Governed Continuation 77c6daa76a docs(gitops): complete Bridge v2 engineering closure evidence 2026-08-09 03:34:00 +08:00
AIOS Governed Continuation 35e387edc8 docs(gitops): record Bridge v2 staging restart acceptance 2026-08-09 03:31:35 +08:00
AIOS Governed Continuation aa0c37b8ab feat(gitops): converge ChatGPT Bridge v2 runtime and OpenAPI 2026-08-09 03:29:09 +08:00
AIOS Governed Continuation 6044b551c1 feat(gitops): add governed continuation executor 2026-08-09 03:23:30 +08:00
aios-autonomy-agent 8030601854 feat(openbao): add autonomy runtime v1 candidate 2026-08-09 01:57:42 +08:00
37 changed files with 1278 additions and 3668 deletions
+22 -11
View File
@@ -58,11 +58,6 @@ class AuthorityGitExecutor:
value = self._git(["rev-parse", "--verify", ref], check=False) value = self._git(["rev-parse", "--verify", ref], check=False)
return value if value and OID_RE.fullmatch(value) else None return value if value and OID_RE.fullmatch(value) else None
def commit_exists(self, oid: str) -> bool:
_oid(oid, "commit_oid")
result = subprocess.run(["git", f"--git-dir={self.git_dir}", "cat-file", "-e", oid + "^{commit}"], capture_output=True, check=False)
return result.returncode == 0
def ancestry_check(self, older_oid: str, newer_oid: str) -> bool: def ancestry_check(self, older_oid: str, newer_oid: str) -> bool:
_oid(older_oid, "older_oid") _oid(older_oid, "older_oid")
_oid(newer_oid, "newer_oid") _oid(newer_oid, "newer_oid")
@@ -75,12 +70,28 @@ class AuthorityGitExecutor:
raise AuthorityGitError("ANCESTRY_CHECK_FAILED") raise AuthorityGitError("ANCESTRY_CHECK_FAILED")
return result.returncode == 0 return result.returncode == 0
def create_detached_worktree( def commit_exists(self, oid: str) -> bool:
self, _oid(oid, "commit_oid")
base_oid: str, result = subprocess.run(["git", f"--git-dir={self.git_dir}", "cat-file", "-e", f"{oid}^{{commit}}"], capture_output=True, check=False)
worktree_name: str, return result.returncode == 0
root: Path | None = None,
) -> Path: def create_task_branch_CAS(self, branch: str, expected_absent: bool, new_oid: str) -> str:
if not expected_absent or not TASK_BRANCH_RE.fullmatch(branch):
raise AuthorityGitError("TASK_BRANCH_CREATE_SCOPE_DENIED")
_oid(new_oid, "new_oid")
if self.read_ref(branch) is not None:
raise AuthorityGitError("AUTHORITY_BRANCH_ALREADY_EXISTS")
try:
self._git(["update-ref", branch, new_oid, "0" * 40])
except AuthorityGitError:
if self.read_ref(branch) is not None:
raise AuthorityGitError("AUTHORITY_BRANCH_ALREADY_EXISTS")
raise
if self.read_ref(branch) != new_oid:
raise AuthorityGitError("AUTHORITY_CAS_READBACK_MISMATCH")
return new_oid
def create_detached_worktree(self, base_oid: str, worktree_name: str, root: Path | None = None) -> Path:
_oid(base_oid, "base_oid") _oid(base_oid, "base_oid")
if not worktree_name or "/" in worktree_name or "\\" in worktree_name or worktree_name in {".", ".."}: if not worktree_name or "/" in worktree_name or "\\" in worktree_name or worktree_name in {".", ".."}:
raise AuthorityGitError("WORKTREE_NAME_INVALID") raise AuthorityGitError("WORKTREE_NAME_INVALID")
View File
@@ -25,7 +25,6 @@ BRIDGE_OPERATIONS = (
"executeApprovedProductionRelease", "executeApprovedProductionRelease",
"getReleaseConsistency", "getReleaseConsistency",
"runReleaseAcceptance", "runReleaseAcceptance",
"getControlPlaneSnapshot",
) )
OPERATION_REQUIRED_FIELDS = { OPERATION_REQUIRED_FIELDS = {
@@ -43,7 +42,6 @@ OPERATION_REQUIRED_FIELDS = {
"executeApprovedProductionRelease": ("version", "target_oid", "evidence_closure_oid", "approval_plan_id", "execute"), "executeApprovedProductionRelease": ("version", "target_oid", "evidence_closure_oid", "approval_plan_id", "execute"),
"getReleaseConsistency": ("version", "target_oid", "evidence_closure_oid", "approval_plan_id"), "getReleaseConsistency": ("version", "target_oid", "evidence_closure_oid", "approval_plan_id"),
"runReleaseAcceptance": ("version", "target_oid", "evidence_closure_oid", "approval_plan_id"), "runReleaseAcceptance": ("version", "target_oid", "evidence_closure_oid", "approval_plan_id"),
"getControlPlaneSnapshot": (),
} }
@@ -163,5 +161,3 @@ class BridgeV2Adapter:
def executeApprovedProductionRelease(self, request: Mapping[str, Any]) -> Any: return self._call("executeApprovedProductionRelease", request) def executeApprovedProductionRelease(self, request: Mapping[str, Any]) -> Any: return self._call("executeApprovedProductionRelease", request)
def getReleaseConsistency(self, request: Mapping[str, Any]) -> Any: return self._call("getReleaseConsistency", request) def getReleaseConsistency(self, request: Mapping[str, Any]) -> Any: return self._call("getReleaseConsistency", request)
def runReleaseAcceptance(self, request: Mapping[str, Any]) -> Any: return self._call("runReleaseAcceptance", request) def runReleaseAcceptance(self, request: Mapping[str, Any]) -> Any: return self._call("runReleaseAcceptance", request)
def getControlPlaneSnapshot(self, request: Mapping[str, Any] | None = None) -> Any: return self._call("getControlPlaneSnapshot", request or {})
@@ -1,22 +1,29 @@
"""Loopback-only governed Bridge v2 HTTP gateway with durable handlers.""" """Loopback-only real HTTP gateway for the governed Bridge v2 adapter."""
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta, timezone from datetime import datetime, timezone, timedelta
import base64 import base64
import json import json
import os import os
import re
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path from pathlib import Path
import re
import sqlite3
from typing import Any, Mapping from typing import Any, Mapping
from aios_authority_git_executor import AuthorityGitExecutor from aios_authority_git_executor import AuthorityGitExecutor
from aios_chatgpt_bridge_v2 import BridgeV2Adapter, BridgeV2Error, OPERATION_REQUIRED_FIELDS from aios_chatgpt_bridge_v2 import BridgeV2Adapter, BridgeV2Error, OPERATION_REQUIRED_FIELDS
from aios_continuation_executor import AuthorityGitAdapter, ContinuationCommit, ContinuationExecutor, ContinuationPermissions, ContinuationRuntimeBinding, DetachedGitWorkspace, GiteaContinuationRemote, ServerSideCredentialProjection from aios_continuation_executor import (
AuthorityGitAdapter,
ContinuationCommit,
ContinuationExecutor,
ContinuationPermissions,
ContinuationRuntimeBinding,
DetachedGitWorkspace,
GiteaContinuationRemote,
ServerSideCredentialProjection,
)
from aios_continuation_lease import WriterLeaseRequestV2 from aios_continuation_lease import WriterLeaseRequestV2
from aios_control_plane_snapshot import build_control_plane_snapshot
from aios_gitops_job_controller import GitOpsJobController, JobStore from aios_gitops_job_controller import GitOpsJobController, JobStore
from aios_governed_task_bootstrap import BootstrapError, GovernedTaskBootstrap from aios_governed_task_bootstrap import BootstrapError, GovernedTaskBootstrap
from governed_production_release import build_executor_config from governed_production_release import build_executor_config
@@ -61,6 +68,13 @@ class RuntimeConfig:
health_url: str = "http://127.0.0.1:18927/health" health_url: str = "http://127.0.0.1:18927/health"
@dataclass
class _Runtime:
binding: ContinuationRuntimeBinding
controller: GitOpsJobController
executor: ContinuationExecutor
def _safe(value: str) -> str: def _safe(value: str) -> str:
return re.sub(r"[^A-Za-z0-9_.-]+", "-", value).strip("-")[:120] or "runtime" return re.sub(r"[^A-Za-z0-9_.-]+", "-", value).strip("-")[:120] or "runtime"
@@ -70,88 +84,160 @@ class GovernedRuntime:
self.config = config self.config = config
config.state_root.mkdir(parents=True, exist_ok=True) config.state_root.mkdir(parents=True, exist_ok=True)
self.authority = AuthorityGitExecutor(config.authoritative_git_dir, config.state_root / "worktrees") 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.bootstrap = GovernedTaskBootstrap(
self.runtimes: dict[tuple[str, int], tuple[Any, GitOpsJobController, ContinuationExecutor]] = {} 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], _Runtime] = {}
self.controllers: dict[str, GitOpsJobController] = {} self.controllers: dict[str, GitOpsJobController] = {}
self.bindings: dict[str, dict[str, Any]] = {}
self.release = build_executor_config(config) self.release = build_executor_config(config)
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" askpass = config.state_root / "bridge-v2-askpass.sh"
if not askpass.exists(): 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.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) 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") os.environ.setdefault("GIT_ASKPASS", str(askpass))
os.environ.setdefault("GIT_ASKPASS_REQUIRE", "force")
def runtime_status(self) -> dict[str, Any]: os.environ.setdefault("GIT_TERMINAL_PROMPT", "0")
return { os.environ.setdefault("GITEA_MACHINE_ACTOR", "aios-autonomy-agent")
"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": False,
}
def _job_root(self, task_id: str) -> Path: def _job_root(self, task_id: str) -> Path:
if task_id == self.config.v2_task_id:
return self.config.v2_job_root
return self.config.state_root / "jobs" / _safe(task_id) return self.config.state_root / "jobs" / _safe(task_id)
def _runtime(self, request: Mapping[str, Any]) -> tuple[Any, GitOpsJobController, ContinuationExecutor]: def _runtime(self, request: Mapping[str, Any], *, create_new: bool = False) -> _Runtime:
key = (str(request["task_id"]), int(request["generation"])) key = (str(request["task_id"]), int(request["generation"]))
if key in self.runtimes: return self.runtimes[key] if key in self.runtimes:
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))) return self.runtimes[key]
lease.validate(AuthorityGitAdapter(self.authority)) if create_new:
worktree_path = self.config.state_root / "worktrees" / _safe(lease.task_id) binding, controller, executor = self.bootstrap.prepare_runtime(
if worktree_path.exists(): request, lease_seconds=int(request.get("lease_seconds", 900))
workspace = DetachedGitWorkspace(worktree_path) )
else: else:
self.authority.create_detached_worktree(lease.expected_branch_oid, _safe(lease.task_id), self.config.state_root / "worktrees") request_v2 = WriterLeaseRequestV2(
workspace = DetachedGitWorkspace(worktree_path) task_id=str(request["task_id"]),
if workspace.head_oid() != lease.expected_branch_oid or not workspace.is_detached(): raise RuntimeError("WORKTREE_HEAD_MISMATCH") repository=str(request["repository"]),
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) branch_mode=str(request["branch_mode"]),
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()) base_oid=str(request["base_oid"]),
result = (binding, controller, executor); self.runtimes[key] = result; self.controllers[lease.task_id] = controller; return result 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)),
)
request_v2.validate(AuthorityGitAdapter(self.authority))
workspace_path = self.config.state_root / "worktrees" / _safe(request_v2.task_id)
if workspace_path.exists():
workspace = DetachedGitWorkspace(workspace_path)
if workspace.head_oid() != request_v2.expected_branch_oid or not workspace.is_detached():
raise RuntimeError("WORKTREE_HEAD_MISMATCH")
else:
self.authority.create_detached_worktree(
request_v2.expected_branch_oid,
_safe(request_v2.task_id),
self.config.state_root / "worktrees",
)
workspace = DetachedGitWorkspace(workspace_path)
job_root = self._job_root(request_v2.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=workspace_path,
credential=credential,
remote_name=self.config.remote_name,
repository=request_v2.repository,
api_base=self.config.api_base,
)
executor = ContinuationExecutor(
controller,
AuthorityGitAdapter(self.authority),
workspace,
remote,
credential,
)
binding = ContinuationRuntimeBinding(
request=request_v2,
workspace_path=workspace_path,
lease_not_before=datetime.now(timezone.utc) - timedelta(seconds=1),
lease_expires_at=datetime.now(timezone.utc) + timedelta(seconds=request_v2.lease_seconds),
original_receipt_valid=True,
original_grant_consumed=True,
permissions=ContinuationPermissions(),
)
runtime = _Runtime(binding, controller, executor)
self.runtimes[key] = runtime
self.controllers[str(request["task_id"])] = controller
return runtime
def create_task(self, request: Mapping[str, Any]) -> dict[str, Any]: def create_task(self, request: Mapping[str, Any]) -> dict[str, Any]:
result = self.bootstrap.create(request); self.bindings[result["task_id"]] = result; return result return self.bootstrap.create(request)
def acquire_lease(self, request: Mapping[str, Any]) -> dict[str, Any]: def acquire_lease(self, request: Mapping[str, Any]) -> dict[str, Any]:
binding, _, _ = self._runtime(request) create_new = str(request.get("branch_mode")) == "CREATE_NEW"
req = binding.request runtime = self._runtime(request, create_new=create_new)
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} request_v2 = runtime.binding.request
runtime.executor.observe_generation(request_v2.target_branch, max(0, request_v2.generation - 1))
return {
"schema": WriterLeaseRequestV2.schema,
"task_id": request_v2.task_id,
"repository": request_v2.repository,
"branch_mode": request_v2.branch_mode,
"base_oid": request_v2.base_oid,
"expected_branch_oid": request_v2.expected_branch_oid,
"target_branch": request_v2.target_branch,
"generation": request_v2.generation,
"lease_seconds": request_v2.lease_seconds,
"create_target_branch": create_new,
"worktree_mode": "detached_at_base_oid" if create_new else "detached_at_expected_head",
"cas_ref_update_required": True,
}
@staticmethod @staticmethod
def _files(request: Mapping[str, Any]) -> dict[str, bytes]: 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} raw = request["files"] if "files" in request else {request["path"]: request["content_base64"]}
if not files: raise ValueError("FILES_EMPTY") if isinstance(raw, dict):
pairs = raw.items()
elif isinstance(raw, list):
pairs = ((item["path"], item["content_base64"]) for item in raw if isinstance(item, dict))
else:
raise ValueError("FILES_INVALID")
files: dict[str, bytes] = {}
for path, encoded in pairs:
if not isinstance(path, str) or not isinstance(encoded, str):
raise ValueError("FILES_INVALID")
files[path] = base64.b64decode(encoded, validate=True)
if not files:
raise ValueError("FILES_EMPTY")
return files return files
def commit_files(self, request: Mapping[str, Any]) -> dict[str, Any]: def commit_files(self, request: Mapping[str, Any]) -> dict[str, Any]:
runtime = self.runtimes.get((str(request["task_id"]), int(request["generation"]))) key = (str(request["task_id"]), int(request["generation"]))
if runtime is None: raise RuntimeError("LEASE_NOT_FOUND") runtime = self.runtimes.get(key)
binding, _, executor = runtime if runtime is None:
if request["target_branch"] != binding.request.target_branch or request["expected_branch_oid"] != binding.request.expected_branch_oid: raise RuntimeError("LEASE_BINDING_CONFLICT") raise RuntimeError("LEASE_NOT_FOUND")
commit = ContinuationCommit(idempotency_key=str(request["idempotency_key"]), files=self._files(request), message=str(request["message"])) request_v2 = runtime.binding.request
executor.workspace.materialize_files(commit.files) if (
return executor.execute(binding, commit) str(request["target_branch"]) != request_v2.target_branch
or str(request["expected_branch_oid"]) != request_v2.expected_branch_oid
):
raise RuntimeError("LEASE_BINDING_CONFLICT")
commit = ContinuationCommit(
idempotency_key=str(request["idempotency_key"]),
files=self._files(request),
message=str(request["message"]),
)
runtime.executor.workspace.materialize_files(commit.files)
return runtime.executor.execute(runtime.binding, commit)
def _controller_for_job(self, job_id: str) -> GitOpsJobController: def _controller_for_job(self, job_id: str) -> GitOpsJobController:
for controller in self.controllers.values(): for runtime in self.runtimes.values():
controller = runtime.controller
try: try:
controller.store.read(job_id) controller.store.read(job_id)
return controller return controller
@@ -159,13 +245,13 @@ class GovernedRuntime:
continue continue
jobs_root = self.config.state_root / "jobs" jobs_root = self.config.state_root / "jobs"
if jobs_root.is_dir(): if jobs_root.is_dir():
for root in jobs_root.iterdir(): for root in sorted(jobs_root.iterdir()):
if not root.is_dir(): if not root.is_dir() or not (root / "state.sqlite3").is_file():
continue continue
controller = GitOpsJobController(JobStore(root, payload_root=root / "payloads")) controller = GitOpsJobController(JobStore(root, payload_root=root / "payloads"))
try: try:
controller.store.read(job_id) controller.store.read(job_id)
self.controllers[str(job_id)] = controller self.controllers["job:" + job_id] = controller
return controller return controller
except Exception: except Exception:
continue continue
@@ -282,73 +368,17 @@ class GovernedRuntime:
return controller.resume(job_id).as_dict() return controller.resume(job_id).as_dict()
return self._executor_from_row(row, controller).reconcile(job_id) 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"
db = self.config.state_root / "jobs" / _safe(task_id) / "state.sqlite3"
if db.is_file():
connection = sqlite3.connect(f"file:{db}?mode=ro", uri=True)
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 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[0] == "COMPLETED"
else str(latest[1] or latest[0])
)
finally:
connection.close()
candidates.append(
{
"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,
}
)
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()
return build_control_plane_snapshot(target_version=self.config.target_version, runtime=self.runtime_status(), 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": True, "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]: def handlers(self) -> dict[str, Any]:
return { return {
"createGovernedTask": self.create_task, "createGovernedTask": self.create_task,
"acquireWriterLease": self.acquire_lease, "acquireWriterLease": self.acquire_lease,
"commitFileGoverned": lambda request: self.commit_files({**request, "files": {request["path"]: request["content_base64"]}}), "commitFileGoverned": lambda request: self.commit_files(
{**request, "files": {request["path"]: request["content_base64"]}}
),
"commitFilesGoverned": self.commit_files, "commitFilesGoverned": self.commit_files,
"getGitOpsJob": lambda request: self.job(request, "get"), "getGitOpsJob": lambda request: self.job(request, "get"),
"resumeGitOpsJob": lambda request: self.job(request, "resume"), "resumeGitOpsJob": lambda request: self.job(request, "resume"),
"reconcileGitOpsJob": lambda request: self.job(request, "reconcile"), "reconcileGitOpsJob": lambda request: self.job(request, "reconcile"),
"getControlPlaneSnapshot": lambda request: self.snapshot(),
"createTagApprovalRequest": self.release.approval_request, "createTagApprovalRequest": self.release.approval_request,
"requestOrCreateTag": self.release.publish_tag, "requestOrCreateTag": self.release.publish_tag,
"getTagPublicationStatus": self.release.tag_status, "getTagPublicationStatus": self.release.tag_status,
@@ -358,50 +388,96 @@ class GovernedRuntime:
"runReleaseAcceptance": self.release.acceptance, "runReleaseAcceptance": self.release.acceptance,
} }
def runtime_status(self) -> dict[str, Any]:
return {
"status": "active",
"health": 200,
"control_plane_target_oid": self.config.target_oid,
"control_plane_release_version": self.config.target_version,
"repository": self.config.repository,
"authoritative_git_dir": str(self.config.authoritative_git_dir),
"legacy_global_writes_enabled": False,
}
def build_governed_handlers(runtime_config: RuntimeConfig | Mapping[str, Any]) -> Mapping[str, Any]: def build_governed_handlers(runtime_config: RuntimeConfig | Mapping[str, Any]) -> Mapping[str, Any]:
if isinstance(runtime_config, Mapping): runtime_config = RuntimeConfig(**runtime_config) if isinstance(runtime_config, Mapping):
runtime_config = RuntimeConfig(**runtime_config)
return GovernedRuntime(runtime_config).handlers() return GovernedRuntime(runtime_config).handlers()
class _HTTPError(RuntimeError): pass class _HTTPError(RuntimeError):
pass
class BridgeHandler(BaseHTTPRequestHandler): class BridgeHandler(BaseHTTPRequestHandler):
adapter: BridgeV2Adapter | None = None adapter: BridgeV2Adapter
def log_message(self, *_args: Any) -> None: return
def log_message(self, *_args: Any) -> None:
return
def _json(self, value: Any, status: int = 200) -> None: 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) 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)
def _body(self) -> dict[str, Any]: def _body(self) -> dict[str, Any]:
try: length = int(self.headers.get("Content-Length", "-1")) try:
except ValueError as exc: raise _HTTPError("CONTENT_LENGTH_INVALID") from exc length = int(self.headers.get("Content-Length", "-1"))
if length < 0 or length > MAX_BODY: raise _HTTPError("REQUEST_TOO_LARGE") except ValueError as exc:
raise _HTTPError("CONTENT_LENGTH_INVALID") from exc
if length < 0 or length > MAX_BODY:
raise _HTTPError("REQUEST_TOO_LARGE")
value = json.loads(self.rfile.read(length).decode("utf-8")) value = json.loads(self.rfile.read(length).decode("utf-8"))
if not isinstance(value, dict): raise _HTTPError("JSON_OBJECT_REQUIRED") if not isinstance(value, dict):
raise _HTTPError("JSON_OBJECT_REQUIRED")
return value return value
def _allowed(self, operation: str, body: Mapping[str, Any]) -> None: def _allowed(self, operation: str, body: Mapping[str, Any]) -> None:
allowed = set(OPERATION_REQUIRED_FIELDS[operation]) | {"schema", "lease_seconds", "create_target_branch", "worktree_mode", "cas_ref_update_required", "expected_branch_oid", "generation", "branch_mode"} allowed = set(OPERATION_REQUIRED_FIELDS[operation]) | {
if operation == "commitFilesGoverned": allowed.add("files") "schema", "lease_seconds", "create_target_branch", "worktree_mode", "cas_ref_update_required",
allowed.update({"owner_approval", "execute"}) "owner_approval", "execute"
if set(body) - allowed: raise _HTTPError("UNKNOWN_FIELDS") }
if operation == "commitFilesGoverned":
allowed.add("files")
if set(body) - allowed:
raise _HTTPError("UNKNOWN_FIELDS")
def do_GET(self) -> None: def do_GET(self) -> None:
if self.adapter is None: self._json({"error": "RUNTIME_UNAVAILABLE"}, 503); return if self.path == "/v2/runtime":
if self.path == "/v2/runtime": self._json(self.adapter.getRuntimeStatus()); return self._json(self.adapter.getRuntimeStatus())
if self.path == "/v2/capabilities": self._json(self.adapter.getGovernedWriteCapabilities()); return return
if self.path == "/v2/control-plane-snapshot": self._json(self.adapter.getControlPlaneSnapshot({})); return if self.path == "/v2/capabilities":
self._json(self.adapter.getGovernedWriteCapabilities())
return
self._json({"error": "NOT_FOUND"}, 404) self._json({"error": "NOT_FOUND"}, 404)
def do_POST(self) -> None: def do_POST(self) -> None:
operation = ROUTES.get(self.path) operation = ROUTES.get(self.path)
if operation is None or operation in ("getRuntimeStatus", "getGovernedWriteCapabilities") or self.adapter is None: self._json({"error": "NOT_FOUND"}, 404); return if operation is None or operation in ("getRuntimeStatus", "getGovernedWriteCapabilities"):
self._json({"error": "NOT_FOUND"}, 404)
return
try: try:
body = self._body(); self._allowed(operation, body); self._json(getattr(self.adapter, operation)(body)) body = self._body()
except _HTTPError as exc: self._json({"error": str(exc)}, 413 if str(exc) == "REQUEST_TOO_LARGE" else 400) self._allowed(operation, body)
except (BootstrapError, ValueError, BridgeV2Error) as exc: self._json({"error": str(exc)}, 409 if "CONFLICT" in str(exc) else 400) self._json(getattr(self.adapter, operation)(body))
except Exception as exc: self._json({"error": str(exc) or type(exc).__name__}, 409 if any(token in str(exc) for token in ("CONFLICT", "EXPECTATION", "MONOTONIC")) else 503) except _HTTPError as exc:
self._json({"error": str(exc)}, 413 if str(exc) == "REQUEST_TOO_LARGE" else 400)
except (BootstrapError, ValueError, BridgeV2Error) as exc:
code = 409 if str(exc) in {"CONFLICT", "TASK_BINDING_CONFLICT", "LEASE_BINDING_CONFLICT"} else 400
self._json({"error": str(exc)}, code)
except Exception as exc:
name = str(exc) or type(exc).__name__
code = 409 if any(token in name for token in ("CONFLICT", "EXPECTATION", "ALREADY", "MONOTONIC")) else 503
self._json({"error": name}, code)
def serve(adapter: BridgeV2Adapter, host: str = "127.0.0.1", port: int = 18892) -> None: def serve(adapter: BridgeV2Adapter, host: str = "127.0.0.1", port: int = 18892) -> None:
BridgeHandler.adapter = adapter; ThreadingHTTPServer((host, port), BridgeHandler).serve_forever() BridgeHandler.adapter = adapter
ThreadingHTTPServer((host, port), BridgeHandler).serve_forever()
def main() -> None: def main() -> None:
@@ -428,4 +504,6 @@ def main() -> None:
) )
if __name__ == "__main__": main() if __name__ == "__main__":
main()
@@ -25,7 +25,6 @@ from urllib.request import Request, urlopen
from aios_authority_git_executor import AuthorityGitExecutor from aios_authority_git_executor import AuthorityGitExecutor
from aios_continuation_lease import WriterLeaseRequestV2 from aios_continuation_lease import WriterLeaseRequestV2
from aios_gitops_job_controller import GitOpsJobController, JobState from aios_gitops_job_controller import GitOpsJobController, JobState
from aios_gitops_reconciliation_core import ReconciliationAction, RemoteObservation, decide_reconciliation
from authorized_task_writer_provisioning import validate_writer_lease_request_v2 from authorized_task_writer_provisioning import validate_writer_lease_request_v2
@@ -44,6 +43,7 @@ class ContinuationExecutionError(RuntimeError):
class DetachedWorkspace(Protocol): class DetachedWorkspace(Protocol):
def is_detached(self) -> bool: ... def is_detached(self) -> bool: ...
def head_oid(self) -> str: ... def head_oid(self) -> str: ...
def materialize_files(self, files: Mapping[str, bytes]) -> None: ...
def commit_files(self, files: Mapping[str, bytes], message: str) -> str: ... def commit_files(self, files: Mapping[str, bytes], message: str) -> str: ...
@@ -52,13 +52,16 @@ class AuthorityPort(Protocol):
def branch_head(self, branch: str) -> str: ... def branch_head(self, branch: str) -> str: ...
def is_ancestor(self, older: str, newer: str) -> bool: ... def is_ancestor(self, older: str, newer: str) -> bool: ...
def compare_and_swap_branch(self, branch: str, expected: str, new: str) -> str: ... def compare_and_swap_branch(self, branch: str, expected: str, new: str) -> str: ...
def create_task_branch_CAS(self, branch: str, new: str) -> str: ...
def commit_exists(self, oid: str) -> bool: ...
class RemotePort(Protocol): class RemotePort(Protocol):
def repository_identity(self) -> str: ... def repository_identity(self) -> str: ...
def push_exact(self, branch: str, expected: str, new: str) -> None: ... def push_exact(self, branch: str, expected: str | None, new: str) -> None: ...
def read_git_ref(self, branch: str) -> str | None: ... def read_git_ref(self, branch: str) -> str | None: ...
def read_api_branch(self, branch: str) -> str | None: ... def read_api_branch(self, branch: str) -> str | None: ...
def commit_visible(self, oid: str) -> bool: ... def commit_visible(self, oid: str) -> bool: ...
@@ -106,6 +109,12 @@ class AuthorityGitAdapter:
def compare_and_swap_branch(self, branch: str, expected: str, new: str) -> str: def compare_and_swap_branch(self, branch: str, expected: str, new: str) -> str:
return self.executor.advance_task_branch_CAS(self._ref(branch), expected, new) return self.executor.advance_task_branch_CAS(self._ref(branch), expected, new)
def create_task_branch_CAS(self, branch: str, new: str) -> str:
return self.executor.create_task_branch_CAS(self._ref(branch), True, new)
def commit_exists(self, oid: str) -> bool:
return self.executor.commit_exists(oid)
@dataclass(slots=True) @dataclass(slots=True)
class DetachedGitWorkspace: class DetachedGitWorkspace:
@@ -150,20 +159,36 @@ class DetachedGitWorkspace:
return result return result
def materialize_files(self, files: Mapping[str, bytes]) -> None: def materialize_files(self, files: Mapping[str, bytes]) -> None:
dirty = self._dirty_paths() """Author only the governed payload into a clean detached worktree."""
expected_paths = set(files) expected_paths = set(files)
if dirty and dirty != expected_paths: if not expected_paths:
raise ContinuationExecutionError("COMMIT_REQUEST_INVALID")
current_paths = self._dirty_paths()
if current_paths not in (set(), expected_paths):
raise ContinuationExecutionError("WORKTREE_DIRTY_SCOPE_MISMATCH") raise ContinuationExecutionError("WORKTREE_DIRTY_SCOPE_MISMATCH")
root = self.path.resolve()
for relative, content in files.items(): for relative, content in files.items():
pure = PurePosixPath(relative)
if pure.is_absolute() or ".." in pure.parts or relative.startswith((".git/", "baseline/", "production/")):
raise ContinuationExecutionError("COMMIT_PATH_REJECTED")
target = (self.path / relative).resolve() target = (self.path / relative).resolve()
try: try:
target.relative_to(self.path.resolve()) target.relative_to(root)
except ValueError as exc: except ValueError as exc:
raise ContinuationExecutionError("COMMIT_PATH_REJECTED") from exc raise ContinuationExecutionError("COMMIT_PATH_REJECTED") from exc
if target.is_symlink(): if target.is_symlink():
raise ContinuationExecutionError("COMMIT_PATH_REJECTED") raise ContinuationExecutionError("COMMIT_PATH_SYMLINK")
if target.is_file() and target.read_bytes() == content:
continue
target.parent.mkdir(parents=True, exist_ok=True) target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(content) temporary = target.with_name("." + target.name + ".aios-materialize")
if temporary.exists() or temporary.is_symlink():
raise ContinuationExecutionError("COMMIT_TEMP_PATH_CONFLICT")
temporary.write_bytes(content)
os.chmod(temporary, 0o644)
os.replace(temporary, target)
if self._dirty_paths() != expected_paths:
raise ContinuationExecutionError("WORKTREE_DIRTY_SCOPE_MISMATCH")
def commit_files(self, files: Mapping[str, bytes], message: str) -> str: def commit_files(self, files: Mapping[str, bytes], message: str) -> str:
expected_paths = set(files) expected_paths = set(files)
@@ -258,10 +283,16 @@ class GiteaContinuationRemote:
raise ContinuationExecutionError("GITEA_GIT_READBACK_INVALID") raise ContinuationExecutionError("GITEA_GIT_READBACK_INVALID")
return oid return oid
def push_exact(self, branch: str, expected: str, new: str) -> None: def push_exact(self, branch: str, expected: str | None, new: str) -> None:
self._require_projected() self._require_projected()
self.repository_identity() self.repository_identity()
if self.read_git_ref(branch) != expected: observed = self.read_git_ref(branch)
if observed == new:
return
if expected is None:
if observed is not None:
raise ContinuationExecutionError("GITEA_BRANCH_EXPECTATION_MISMATCH")
elif observed != expected:
raise ContinuationExecutionError("GITEA_BRANCH_EXPECTATION_MISMATCH") raise ContinuationExecutionError("GITEA_BRANCH_EXPECTATION_MISMATCH")
_run(["git", "push", self.remote_name, f"{new}:refs/heads/{branch}"], cwd=self.workspace) _run(["git", "push", self.remote_name, f"{new}:refs/heads/{branch}"], cwd=self.workspace)
@@ -321,8 +352,10 @@ class ContinuationPermissions:
production_write: bool = False production_write: bool = False
main_write: bool = False main_write: bool = False
def validate(self) -> None: def validate(self, *, branch_mode: str = "CONTINUE_EXISTING") -> None:
if any(asdict(self).values()): if self.create_target_branch and branch_mode != "CREATE_NEW":
raise ContinuationExecutionError("MUTATION_PERMISSION_DENIED")
if self.force_push or self.tag_write or self.baseline_write or self.production_write or self.main_write:
raise ContinuationExecutionError("MUTATION_PERMISSION_DENIED") raise ContinuationExecutionError("MUTATION_PERMISSION_DENIED")
@@ -413,20 +446,31 @@ class ContinuationExecutor:
"lease_seconds": request.lease_seconds, "lease_seconds": request.lease_seconds,
} }
def _validate_preflight(self, binding: ContinuationRuntimeBinding) -> None: def _validate_preflight(
self,
binding: ContinuationRuntimeBinding,
*,
allow_same_generation: bool = False,
) -> None:
request = binding.request request = binding.request
normalized = validate_writer_lease_request_v2(self._request_mapping(request), self.authority) normalized = validate_writer_lease_request_v2(self._request_mapping(request), self.authority)
if normalized != {**self._request_mapping(request), "create_target_branch": False, "worktree_mode": "detached_at_expected_head", "cas_ref_update_required": True}: expected_normalized = {
**self._request_mapping(request),
"create_target_branch": request.branch_mode == "CREATE_NEW",
"worktree_mode": "detached_at_base_oid" if request.branch_mode == "CREATE_NEW" else "detached_at_expected_head",
"cas_ref_update_required": True,
}
if normalized != expected_normalized:
raise ContinuationExecutionError("CONTINUATION_NORMALIZATION_INVALID") raise ContinuationExecutionError("CONTINUATION_NORMALIZATION_INVALID")
if not binding.original_receipt_valid or not binding.original_grant_consumed: if not binding.original_receipt_valid or not binding.original_grant_consumed:
raise ContinuationExecutionError("ORIGINAL_GRANT_LINEAGE_INVALID") raise ContinuationExecutionError("ORIGINAL_GRANT_LINEAGE_INVALID")
binding.permissions.validate() binding.permissions.validate(branch_mode=request.branch_mode)
now = self.now() now = self.now()
if now < binding.lease_not_before: if now < binding.lease_not_before:
raise ContinuationExecutionError("LEASE_NOT_ACTIVE") raise ContinuationExecutionError("LEASE_NOT_ACTIVE")
if now >= binding.lease_expires_at: if now >= binding.lease_expires_at:
raise ContinuationExecutionError("LEASE_EXPIRED") raise ContinuationExecutionError("LEASE_EXPIRED")
if request.generation <= self._max_generation(request.target_branch): if request.generation <= self._max_generation(request.target_branch) and not allow_same_generation:
raise ContinuationExecutionError("GENERATION_NOT_MONOTONIC") raise ContinuationExecutionError("GENERATION_NOT_MONOTONIC")
if not self.workspace.is_detached(): if not self.workspace.is_detached():
raise ContinuationExecutionError("WORKTREE_NOT_DETACHED") raise ContinuationExecutionError("WORKTREE_NOT_DETACHED")
@@ -442,7 +486,7 @@ class ContinuationExecutor:
"campaign_id": request.task_id, "campaign_id": request.task_id,
"task_id": request.task_id, "task_id": request.task_id,
"repository": request.repository, "repository": request.repository,
"operation": "CONTINUATION_COMMIT_FILES", "operation": "CONTINUATION_COMMIT_FILES_CREATE_NEW" if request.branch_mode == "CREATE_NEW" else "CONTINUATION_COMMIT_FILES",
"branch": request.target_branch, "branch": request.target_branch,
"expected_branch_oid": request.expected_branch_oid, "expected_branch_oid": request.expected_branch_oid,
"base_oid": request.base_oid, "base_oid": request.base_oid,
@@ -458,7 +502,26 @@ class ContinuationExecutor:
current = self.controller.store.read(submitted.job_id) current = self.controller.store.read(submitted.job_id)
if JobState(current["state"]) == JobState.COMPLETED: if JobState(current["state"]) == JobState.COMPLETED:
return self.controller.store._receipt(current, duplicate=True).as_dict() return self.controller.store._receipt(current, duplicate=True).as_dict()
self._validate_preflight(binding) retry_same_generation = False
if JobState(current["state"]) in {
JobState.EXECUTING,
JobState.RECOVERABLE_FAILURE,
JobState.RECONCILING,
}:
receipt = json.loads(current["receipt_json"]) if current["receipt_json"] else {}
if not receipt.get("recovery_safe_before_git_side_effect"):
raise ContinuationExecutionError("RECONCILIATION_REQUIRED")
if any(key in receipt for key in ("authority_oid", "desired_remote_oid", "git_remote_oid", "api_branch_oid")):
raise ContinuationExecutionError("RECONCILIATION_REQUIRED")
retry_same_generation = True
if JobState(current["state"]) != JobState.RECONCILING:
self.controller.advance(
submitted.job_id,
JobState.RECONCILING,
side_effect_state="PRE_SIDE_EFFECT_RETRY",
receipt={"recovery_safe_before_git_side_effect": True},
)
self._validate_preflight(binding, allow_same_generation=retry_same_generation)
request = binding.request request = binding.request
projected = False projected = False
try: try:
@@ -488,7 +551,10 @@ class ContinuationExecutor:
new_oid = self.workspace.commit_files(commit.files, commit.message) new_oid = self.workspace.commit_files(commit.files, commit.message)
if not OID_RE.fullmatch(new_oid) or not self.authority.is_ancestor(request.expected_branch_oid, new_oid): if not OID_RE.fullmatch(new_oid) or not self.authority.is_ancestor(request.expected_branch_oid, new_oid):
raise ContinuationExecutionError("NON_FAST_FORWARD_COMMIT") raise ContinuationExecutionError("NON_FAST_FORWARD_COMMIT")
authority_oid = self.authority.compare_and_swap_branch(request.target_branch, request.expected_branch_oid, new_oid) if request.branch_mode == "CREATE_NEW":
authority_oid = self.authority.create_task_branch_CAS(request.target_branch, new_oid)
else:
authority_oid = self.authority.compare_and_swap_branch(request.target_branch, request.expected_branch_oid, new_oid)
if authority_oid != new_oid: if authority_oid != new_oid:
raise ContinuationExecutionError("AUTHORITY_CAS_READBACK_MISMATCH") raise ContinuationExecutionError("AUTHORITY_CAS_READBACK_MISMATCH")
self.controller.advance( self.controller.advance(
@@ -528,10 +594,8 @@ class ContinuationExecutor:
def _finish_remote_verification(self, job_id: str, authority_oid: str, new_oid: str) -> dict[str, object]: def _finish_remote_verification(self, job_id: str, authority_oid: str, new_oid: str) -> dict[str, object]:
row = self.controller.store.read(job_id) row = self.controller.store.read(job_id)
branch = row["branch"] branch = row["branch"]
request = json.loads(row["request_json"])["binding"]
git_oid, api_oid, visible = self._observe_remote(branch, new_oid) git_oid, api_oid, visible = self._observe_remote(branch, new_oid)
decision = decide_reconciliation(RemoteObservation("aios/aios", branch, new_oid, authority_oid, git_oid, api_oid, visible, datetime.now(timezone.utc).isoformat(), request.get("expected_branch_oid"))) if not (authority_oid == git_oid == api_oid == new_oid and visible):
if decision.action is not ReconciliationAction.MARK_REMOTE_VERIFIED:
return self._remote_pending(job_id, authority_oid, new_oid) return self._remote_pending(job_id, authority_oid, new_oid)
receipt = { receipt = {
"authority_oid": authority_oid, "authority_oid": authority_oid,
@@ -539,7 +603,6 @@ class ContinuationExecutor:
"api_branch_oid": api_oid, "api_branch_oid": api_oid,
"commit_visible": True, "commit_visible": True,
"remote_verified": True, "remote_verified": True,
"reconciliation_decision": decision.action.value,
"force_push": False, "force_push": False,
} }
self.controller.advance(job_id, JobState.REMOTE_VERIFIED, side_effect_state="REMOTE_VERIFIED", receipt=receipt) self.controller.advance(job_id, JobState.REMOTE_VERIFIED, side_effect_state="REMOTE_VERIFIED", receipt=receipt)
@@ -556,39 +619,17 @@ class ContinuationExecutor:
receipt = json.loads(row["receipt_json"]) receipt = json.loads(row["receipt_json"])
new_oid = receipt["desired_remote_oid"] new_oid = receipt["desired_remote_oid"]
authority_oid = self.authority.branch_head(row["branch"]) authority_oid = self.authority.branch_head(row["branch"])
try:
generation = int(request.get("generation") or 0)
except (TypeError, ValueError) as exc:
raise ContinuationExecutionError("DURABLE_BINDING_GENERATION_INVALID") from exc
if generation > 0:
with self.controller.store._connect() as connection:
earlier = connection.execute(
"SELECT 1 FROM jobs WHERE branch=? AND state=? "
"AND CAST(json_extract(request_json, '$.binding.generation') AS INTEGER) < ? LIMIT 1",
(row["branch"], JobState.RECONCILIATION_REQUIRED.value, generation),
).fetchone()
if earlier is not None:
raise ContinuationExecutionError("EARLIER_RECONCILIATION_REQUIRED")
self.credential.project() self.credential.project()
try: try:
git_oid, api_oid, visible = self._observe_remote(row["branch"], new_oid) git_oid, api_oid, visible = self._observe_remote(row["branch"], new_oid)
if authority_oid == git_oid == api_oid == new_oid and visible: if authority_oid == git_oid == api_oid == new_oid and visible:
self.controller.advance(job_id, JobState.RECONCILING, side_effect_state="OBSERVATION_FIRST") self.controller.advance(job_id, JobState.RECONCILING, side_effect_state="OBSERVATION_FIRST")
return self._finish_remote_verification(job_id, new_oid, new_oid) return self._finish_remote_verification(job_id, authority_oid, new_oid)
expected_oid = request["expected_branch_oid"] expected_oid = None if row["operation"].endswith("_CREATE_NEW") else request["expected_branch_oid"]
if (
self.authority.is_ancestor(new_oid, authority_oid)
and git_oid is not None
and git_oid == api_oid
and self.authority.is_ancestor(git_oid, new_oid)
):
self.controller.advance(job_id, JobState.RECONCILING, side_effect_state="OBSERVATION_FIRST_CHAIN")
self.remote.push_exact(row["branch"], git_oid, new_oid)
return self._finish_remote_verification(job_id, new_oid, new_oid)
if authority_oid == new_oid and git_oid == api_oid == expected_oid: if authority_oid == new_oid and git_oid == api_oid == expected_oid:
self.controller.advance(job_id, JobState.RECONCILING, side_effect_state="OBSERVATION_FIRST_RETRY") self.controller.advance(job_id, JobState.RECONCILING, side_effect_state="OBSERVATION_FIRST_RETRY")
self.remote.push_exact(row["branch"], expected_oid, new_oid) self.remote.push_exact(row["branch"], expected_oid, new_oid)
return self._finish_remote_verification(job_id, new_oid, new_oid) return self._finish_remote_verification(job_id, authority_oid, new_oid)
return self.controller.store._receipt(row, duplicate=True).as_dict() return self.controller.store._receipt(row, duplicate=True).as_dict()
finally: finally:
self.credential.revoke() self.credential.revoke()
@@ -1,26 +0,0 @@
"""Non-sensitive control-plane snapshot assembly."""
from __future__ import annotations
from typing import Any, Mapping
def _copy(value: Mapping[str, Any] | None, keys: tuple[str, ...]) -> dict[str, Any]:
value = value or {}
return {key: value.get(key) for key in keys}
def build_control_plane_snapshot(*, target_version: str, runtime: Mapping[str, Any] | None = None, repository: Mapping[str, Any] | None = None, production: Mapping[str, Any] | None = None, task: Mapping[str, Any] | None = None, capabilities: Mapping[str, Any] | None = None, credential_broker: Mapping[str, Any] | None = None) -> dict[str, Any]:
return {
"version": {"target_release": target_version},
"runtime": _copy(runtime, ("bridge_schema_version", "control_plane_release_version", "runtime_release_commit", "runtime_path", "artifact_sha256", "drift_status")),
"repository": _copy(repository, ("identity", "authority_git_dir", "authority_main_oid")),
"production": _copy(production, ("baseline_version", "target_oid", "deployment_state")),
"task": _copy(task, ("task_id", "branch", "authority_branch_oid", "gitea_git_oid", "gitea_api_oid", "commit_visible", "generation", "reconciliation_state")),
"capabilities": _copy(capabilities, ("legacy_writes_enabled", "governed_writes_enabled", "force_push", "main_write", "tag_write", "baseline_write", "production_write")),
"credential_broker": _copy(credential_broker, ("status", "provider")),
"secret_material_exposed": False,
}
def getControlPlaneSnapshot(**kwargs: Any) -> dict[str, Any]:
return build_control_plane_snapshot(**kwargs)
@@ -1,78 +0,0 @@
"""Metadata-only, server-side credential lease broker."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
import os
from pathlib import Path
import secrets
from typing import Any, Callable, Mapping
@dataclass(frozen=True, slots=True)
class CredentialLease:
lease_id: str
task_id: str
repository: str
target_branch: str
generation: int
issued_at: str
expires_at: str
scopes: tuple[str, ...]
provider: str
state: str = "ACTIVE"
def as_dict(self) -> dict[str, Any]:
return {"lease_id": self.lease_id, "task_id": self.task_id, "repository": self.repository, "target_branch": self.target_branch, "generation": self.generation, "issued_at": self.issued_at, "expires_at": self.expires_at, "scopes": list(self.scopes), "provider": self.provider, "state": self.state}
class FileCredentialProvider:
def __init__(self, token_path: str | os.PathLike[str], *, actor: str = "aios-autonomy-agent") -> None:
self.token_path = Path(token_path)
self.actor = actor
def environment(self, lease: CredentialLease) -> dict[str, str]:
if not self.token_path.is_file():
raise RuntimeError("CREDENTIAL_PROVIDER_UNAVAILABLE")
return {"CREDENTIAL_FILE": str(self.token_path), "GITEA_MACHINE_ACTOR": self.actor}
class CredentialBroker:
def __init__(self, provider: Any, *, now: Callable[[], datetime] | None = None) -> None:
self.provider = provider
self.now = now or (lambda: datetime.now(timezone.utc))
self._leases: dict[str, CredentialLease] = {}
def issue(self, *, task_id: str, repository: str, target_branch: str, generation: int, scopes: tuple[str, ...] = ("git:push", "gitea:read"), lease_seconds: int = 900) -> dict[str, Any]:
if repository != "aios/aios" or not target_branch.startswith("agent/") or generation < 1 or not 1 <= lease_seconds <= 86400:
raise ValueError("CREDENTIAL_LEASE_BINDING_INVALID")
now = self.now().astimezone(timezone.utc)
lease = CredentialLease("lease-" + secrets.token_hex(16), task_id, repository, target_branch, generation, now.isoformat(), (now + timedelta(seconds=lease_seconds)).isoformat(), tuple(scopes), type(self.provider).__name__)
self._leases[lease.lease_id] = lease
return lease.as_dict()
def _get(self, lease_id: str) -> CredentialLease:
lease = self._leases.get(lease_id)
if lease is None:
raise KeyError("CREDENTIAL_LEASE_NOT_FOUND")
if lease.state == "ACTIVE" and self.now().astimezone(timezone.utc) >= datetime.fromisoformat(lease.expires_at):
lease = CredentialLease(**{**lease.as_dict(), "scopes": tuple(lease.scopes), "state": "EXPIRED"})
self._leases[lease_id] = lease
return lease
def environment(self, lease_id: str) -> Mapping[str, str]:
lease = self._get(lease_id)
if lease.state != "ACTIVE":
raise RuntimeError("CREDENTIAL_LEASE_NOT_ACTIVE")
return self.provider.environment(lease)
def status(self, lease_id: str) -> dict[str, Any]:
return self._get(lease_id).as_dict()
def revoke(self, lease_id: str) -> dict[str, Any]:
lease = self._get(lease_id)
if lease.state == "REVOKED":
return lease.as_dict()
updated = CredentialLease(**{**lease.as_dict(), "scopes": tuple(lease.scopes), "state": "REVOKED"})
self._leases[lease_id] = updated
return updated.as_dict()
@@ -1,352 +0,0 @@
"""Cryptographic Owner-approval boundary for governed existing-branch publication.
Only a complete signed envelope from an authoritative trust-root adapter is
accepted. References, chat assertions, and locally supplied keys are not an
approval. Missing public-key or revocation evidence fails closed.
"""
from __future__ import annotations
import base64
from dataclasses import dataclass
from datetime import datetime, timezone
import hashlib
import json
import os
from pathlib import Path
import re
from typing import Any, Mapping, Protocol
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
APPROVAL_SCHEMA = "aios.existing-branch-owner-approval.v1"
PUBLISH_OPERATION = "publishExistingBranchGoverned"
OID_RE = re.compile(r"^[0-9a-f]{40}$")
DIGEST_RE = re.compile(r"^[0-9a-f]{64}$")
IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._@:+/-]{0,254}$")
BRANCH_RE = re.compile(r"^agent/[A-Za-z0-9][A-Za-z0-9._/-]{2,179}$")
class OwnerApprovalRejected(RuntimeError):
"""Stable, audit-safe error for a rejected Owner approval."""
def __init__(self, code: str) -> None:
super().__init__(code)
self.code = code
def canonical_json(value: Any) -> bytes:
"""Encode a signed payload without implementation-dependent spacing."""
try:
encoded = json.dumps(
value,
sort_keys=True,
separators=(",", ":"),
ensure_ascii=False,
allow_nan=False,
)
except (TypeError, ValueError) as exc:
raise OwnerApprovalRejected("OWNER_APPROVAL_CANONICALIZATION_REJECTED") from exc
return (encoded + "\n").encode("utf-8")
def digest_json(value: Any) -> str:
return hashlib.sha256(canonical_json(value)).hexdigest()
def _require_identifier(field: str, value: object) -> str:
if not isinstance(value, str) or not IDENTIFIER_RE.fullmatch(value):
raise OwnerApprovalRejected(f"OWNER_APPROVAL_{field.upper()}_REJECTED")
return value
def _require_digest(field: str, value: object) -> str:
if not isinstance(value, str) or not DIGEST_RE.fullmatch(value):
raise OwnerApprovalRejected(f"OWNER_APPROVAL_{field.upper()}_REJECTED")
return value
def _require_oid(field: str, value: object) -> str:
if not isinstance(value, str) or not OID_RE.fullmatch(value):
raise OwnerApprovalRejected(f"OWNER_APPROVAL_{field.upper()}_REJECTED")
return value
def _parse_utc(field: str, value: object) -> datetime:
if not isinstance(value, str):
raise OwnerApprovalRejected(f"OWNER_APPROVAL_{field.upper()}_REJECTED")
try:
instant = datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError as exc:
raise OwnerApprovalRejected(f"OWNER_APPROVAL_{field.upper()}_REJECTED") from exc
if instant.tzinfo is None:
raise OwnerApprovalRejected(f"OWNER_APPROVAL_{field.upper()}_REJECTED")
return instant.astimezone(timezone.utc)
@dataclass(frozen=True, slots=True)
class PublicationApprovalBinding:
repository: str
branch: str
expected_branch_oid: str
operation: str
request_digest: str
idempotency_digest: str
def validate(self) -> "PublicationApprovalBinding":
_require_identifier("repository", self.repository)
if not BRANCH_RE.fullmatch(self.branch):
raise OwnerApprovalRejected("OWNER_APPROVAL_BRANCH_REJECTED")
_require_oid("expected_branch_oid", self.expected_branch_oid)
if self.operation != PUBLISH_OPERATION:
raise OwnerApprovalRejected("OWNER_APPROVAL_OPERATION_REJECTED")
_require_digest("request_digest", self.request_digest)
_require_digest("idempotency_digest", self.idempotency_digest)
return self
@property
def as_dict(self) -> dict[str, str]:
return {
"repository": self.repository,
"branch": self.branch,
"expected_branch_oid": self.expected_branch_oid,
"operation": self.operation,
"request_digest": self.request_digest,
"idempotency_digest": self.idempotency_digest,
}
@dataclass(frozen=True, slots=True)
class OwnerApprovalEnvelope:
approval_id: str
repository: str
branch: str
expected_branch_oid: str
operation: str
issued_at: str
not_before: str
expires_at: str
nonce: str
owner_identity: str
trust_domain: str
key_id: str
request_digest: str
idempotency_digest: str
signature: str
@property
def canonical_payload(self) -> dict[str, str]:
return {
"schema": APPROVAL_SCHEMA,
"approval_id": self.approval_id,
"repository": self.repository,
"branch": self.branch,
"expected_branch_oid": self.expected_branch_oid,
"operation": self.operation,
"issued_at": self.issued_at,
"not_before": self.not_before,
"expires_at": self.expires_at,
"nonce": self.nonce,
"owner_identity": self.owner_identity,
"trust_domain": self.trust_domain,
"key_id": self.key_id,
"request_digest": self.request_digest,
"idempotency_digest": self.idempotency_digest,
}
def canonical_bytes(self) -> bytes:
return canonical_json(self.canonical_payload)
@property
def fingerprint(self) -> str:
return hashlib.sha256(self.canonical_bytes()).hexdigest()
@property
def binding(self) -> PublicationApprovalBinding:
return PublicationApprovalBinding(
repository=self.repository,
branch=self.branch,
expected_branch_oid=self.expected_branch_oid,
operation=self.operation,
request_digest=self.request_digest,
idempotency_digest=self.idempotency_digest,
)
@classmethod
def from_mapping(cls, value: object) -> "OwnerApprovalEnvelope":
if not isinstance(value, Mapping):
raise OwnerApprovalRejected("OWNER_APPROVAL_ENVELOPE_REQUIRED")
expected_fields = {
"schema", "approval_id", "repository", "branch", "expected_branch_oid",
"operation", "issued_at", "not_before", "expires_at", "nonce",
"owner_identity", "trust_domain", "key_id", "request_digest",
"idempotency_digest", "signature",
}
if set(value) != expected_fields or value.get("schema") != APPROVAL_SCHEMA:
raise OwnerApprovalRejected("OWNER_APPROVAL_ENVELOPE_REJECTED")
envelope = cls(
approval_id=_require_identifier("approval_id", value["approval_id"]),
repository=_require_identifier("repository", value["repository"]),
branch=str(value["branch"]),
expected_branch_oid=_require_oid("expected_branch_oid", value["expected_branch_oid"]),
operation=str(value["operation"]),
issued_at=str(value["issued_at"]),
not_before=str(value["not_before"]),
expires_at=str(value["expires_at"]),
nonce=_require_identifier("nonce", value["nonce"]),
owner_identity=_require_identifier("owner_identity", value["owner_identity"]),
trust_domain=_require_identifier("trust_domain", value["trust_domain"]),
key_id=_require_identifier("key_id", value["key_id"]),
request_digest=_require_digest("request_digest", value["request_digest"]),
idempotency_digest=_require_digest("idempotency_digest", value["idempotency_digest"]),
signature=str(value["signature"]),
)
envelope.binding.validate()
_parse_utc("issued_at", envelope.issued_at)
_parse_utc("not_before", envelope.not_before)
_parse_utc("expires_at", envelope.expires_at)
if not envelope.signature:
raise OwnerApprovalRejected("OWNER_APPROVAL_SIGNATURE_REJECTED")
return envelope
@dataclass(frozen=True, slots=True)
class TrustRootEvidence:
"""Public-key and revocation evidence from the authoritative trust root."""
key_id: str
owner_identity: str
trust_domain: str
public_key: bytes | None
authority_confirmed: bool
revocation_state: str
class AuthoritativeTrustRootAdapter(Protocol):
def resolve(
self, *, key_id: str, owner_identity: str, trust_domain: str
) -> TrustRootEvidence | None: ...
class ReplayLedger(Protocol):
def consume(
self, approval: OwnerApprovalEnvelope, binding: PublicationApprovalBinding
) -> None: ...
class DurableNonceReplayLedger:
"""Single-use nonce storage that remains conservative across restarts."""
def __init__(self, root: Path) -> None:
self.root = Path(root)
def consume(
self, approval: OwnerApprovalEnvelope, binding: PublicationApprovalBinding
) -> None:
binding.validate()
if self.root.is_symlink():
raise OwnerApprovalRejected("OWNER_APPROVAL_REPLAY_LEDGER_REJECTED")
try:
self.root.mkdir(parents=True, exist_ok=True)
if not self.root.is_dir() or self.root.is_symlink():
raise OwnerApprovalRejected("OWNER_APPROVAL_REPLAY_LEDGER_REJECTED")
name = hashlib.sha256(approval.nonce.encode("utf-8")).hexdigest()
record_path = self.root / name
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
if hasattr(os, "O_NOFOLLOW"):
flags |= os.O_NOFOLLOW
descriptor = os.open(record_path, flags, 0o600)
except FileExistsError as exc:
raise OwnerApprovalRejected("OWNER_APPROVAL_REPLAY_REJECTED") from exc
except OwnerApprovalRejected:
raise
except OSError as exc:
raise OwnerApprovalRejected("OWNER_APPROVAL_REPLAY_LEDGER_REJECTED") from exc
record = {
"schema": "aios.existing-branch-owner-approval-replay.v1",
"nonce_sha256": name,
"approval_fingerprint": approval.fingerprint,
"binding_digest": digest_json(binding.as_dict),
}
try:
with os.fdopen(descriptor, "wb", closefd=True) as stream:
stream.write(canonical_json(record))
stream.flush()
os.fsync(stream.fileno())
directory = os.open(self.root, os.O_RDONLY | getattr(os, "O_DIRECTORY", 0))
try:
os.fsync(directory)
finally:
os.close(directory)
except OSError as exc:
raise OwnerApprovalRejected("OWNER_APPROVAL_REPLAY_LEDGER_REJECTED") from exc
class OwnerApprovalVerifier:
def __init__(
self,
trust_root: AuthoritativeTrustRootAdapter,
*,
allowed_trust_domains: set[str] | frozenset[str],
maximum_lifetime_seconds: int = 900,
) -> None:
if not allowed_trust_domains or maximum_lifetime_seconds < 1:
raise ValueError("OWNER_APPROVAL_VERIFIER_CONFIGURATION_REJECTED")
self.trust_root = trust_root
self.allowed_trust_domains = frozenset(allowed_trust_domains)
self.maximum_lifetime_seconds = maximum_lifetime_seconds
def verify(
self,
value: object,
binding: PublicationApprovalBinding,
*,
now: datetime | None = None,
) -> OwnerApprovalEnvelope:
binding.validate()
approval = OwnerApprovalEnvelope.from_mapping(value)
if approval.binding != binding:
raise OwnerApprovalRejected("OWNER_APPROVAL_BINDING_REJECTED")
instant = datetime.now(timezone.utc) if now is None else now
if instant.tzinfo is None:
raise OwnerApprovalRejected("OWNER_APPROVAL_TIME_REJECTED")
instant = instant.astimezone(timezone.utc)
issued_at = _parse_utc("issued_at", approval.issued_at)
not_before = _parse_utc("not_before", approval.not_before)
expires_at = _parse_utc("expires_at", approval.expires_at)
if not issued_at <= not_before <= expires_at:
raise OwnerApprovalRejected("OWNER_APPROVAL_TIME_REJECTED")
if not not_before <= instant <= expires_at:
raise OwnerApprovalRejected("OWNER_APPROVAL_TIME_REJECTED")
if (expires_at - issued_at).total_seconds() > self.maximum_lifetime_seconds:
raise OwnerApprovalRejected("OWNER_APPROVAL_TIME_REJECTED")
if approval.trust_domain not in self.allowed_trust_domains:
raise OwnerApprovalRejected("OWNER_APPROVAL_TRUST_DOMAIN_REJECTED")
evidence = self.trust_root.resolve(
key_id=approval.key_id,
owner_identity=approval.owner_identity,
trust_domain=approval.trust_domain,
)
if evidence is None or not evidence.authority_confirmed:
raise OwnerApprovalRejected("OWNER_APPROVAL_TRUST_ROOT_EVIDENCE_MISSING")
if (
evidence.key_id != approval.key_id
or evidence.owner_identity != approval.owner_identity
or evidence.trust_domain != approval.trust_domain
):
raise OwnerApprovalRejected("OWNER_APPROVAL_TRUST_ROOT_BINDING_REJECTED")
if evidence.revocation_state == "REVOKED":
raise OwnerApprovalRejected("OWNER_APPROVAL_REVOKED")
if evidence.revocation_state != "ACTIVE":
raise OwnerApprovalRejected("OWNER_APPROVAL_REVOCATION_EVIDENCE_MISSING")
if evidence.public_key is None or len(evidence.public_key) != 32:
raise OwnerApprovalRejected("OWNER_APPROVAL_TRUST_ROOT_EVIDENCE_MISSING")
try:
signature = base64.b64decode(approval.signature, validate=True)
Ed25519PublicKey.from_public_bytes(evidence.public_key).verify(
signature, approval.canonical_bytes()
)
except (ValueError, TypeError, InvalidSignature) as exc:
raise OwnerApprovalRejected("OWNER_APPROVAL_SIGNATURE_REJECTED") from exc
return approval
@@ -1,331 +0,0 @@
"""Narrow governed publisher for an already-existing task branch.
Its only writing port is a compare-and-swap publication after a complete
signed Owner approval, a stable remote observation, and a single-use nonce
claim. It neither owns trust material nor accepts direct reference strings.
"""
from __future__ import annotations
from dataclasses import dataclass
import re
from typing import Any, Mapping, Protocol
from aios_existing_branch_approval import (
OwnerApprovalEnvelope,
OwnerApprovalRejected,
OwnerApprovalVerifier,
PublicationApprovalBinding,
ReplayLedger,
canonical_json,
digest_json,
)
REQUEST_SCHEMA = "aios.existing-branch-publication.v1"
PUBLISH_OPERATION = "publishExistingBranchGoverned"
OID_RE = re.compile(r"^[0-9a-f]{40}$")
BRANCH_RE = re.compile(r"^agent/[A-Za-z0-9][A-Za-z0-9._/-]{2,179}$")
class ExistingBranchPublicationRejected(RuntimeError):
def __init__(self, code: str) -> None:
super().__init__(code)
self.code = code
class RemoteOidConflict(RuntimeError):
pass
class RemoteObservationAmbiguous(RuntimeError):
pass
@dataclass(frozen=True, slots=True)
class ExistingBranchPublicationRequest:
repository: str
branch: str
expected_branch_oid: str
idempotency_key: str
payload: Mapping[str, Any]
@classmethod
def from_mapping(cls, value: object) -> "ExistingBranchPublicationRequest":
if not isinstance(value, Mapping):
raise ExistingBranchPublicationRejected("PUBLICATION_REQUEST_REJECTED")
expected_fields = {
"schema",
"repository",
"branch",
"expected_branch_oid",
"operation",
"idempotency_key",
"payload",
}
if set(value) != expected_fields or value.get("schema") != REQUEST_SCHEMA:
raise ExistingBranchPublicationRejected("PUBLICATION_REQUEST_REJECTED")
repository = value["repository"]
branch = value["branch"]
expected_oid = value["expected_branch_oid"]
key = value["idempotency_key"]
payload = value["payload"]
if (
not isinstance(repository, str)
or repository != "aios/aios"
or not BRANCH_RE.fullmatch(str(branch))
or not isinstance(expected_oid, str)
or not OID_RE.fullmatch(expected_oid)
or value.get("operation") != PUBLISH_OPERATION
or not isinstance(key, str)
or not key.strip()
or not isinstance(payload, Mapping)
):
raise ExistingBranchPublicationRejected("PUBLICATION_REQUEST_REJECTED")
try:
canonical_json(payload)
except OwnerApprovalRejected as exc:
raise ExistingBranchPublicationRejected("PUBLICATION_PAYLOAD_REJECTED") from exc
return cls(repository, str(branch), expected_oid, key, dict(payload))
@property
def request_digest(self) -> str:
return digest_json(
{
"schema": REQUEST_SCHEMA,
"repository": self.repository,
"branch": self.branch,
"expected_branch_oid": self.expected_branch_oid,
"operation": PUBLISH_OPERATION,
"payload": self.payload,
}
)
@property
def idempotency_digest(self) -> str:
return digest_json(
{
"idempotency_key": self.idempotency_key,
"request_digest": self.request_digest,
}
)
@property
def approval_binding(self) -> PublicationApprovalBinding:
return PublicationApprovalBinding(
repository=self.repository,
branch=self.branch,
expected_branch_oid=self.expected_branch_oid,
operation=PUBLISH_OPERATION,
request_digest=self.request_digest,
idempotency_digest=self.idempotency_digest,
)
@dataclass(frozen=True, slots=True)
class RemoteBranchObservation:
state: str
git_oid: str | None
api_oid: str | None
expected_commit_visible: bool | None
@dataclass(frozen=True, slots=True)
class RemotePublicationEvidence:
authority_oid: str | None
gitea_git_oid: str | None
gitea_api_oid: str | None
commit_visible: bool | None
class ExistingBranchRemotePort(Protocol):
def observe(self, branch: str) -> RemoteBranchObservation: ...
def publish_compare_and_swap(
self, branch: str, expected_branch_oid: str, commit_oid: str
) -> RemotePublicationEvidence: ...
class AuthorityBranchPort(Protocol):
def read_branch_oid(self, branch: str) -> str | None: ...
class CredentialProjection(Protocol):
def project(self) -> None: ...
def revoke(self) -> None: ...
class PublicationWorkspace(Protocol):
def head_oid(self) -> str: ...
def commit_payload(self, payload: Mapping[str, Any]) -> str: ...
class DetachedWorkspaceFactory(Protocol):
def open_detached(self, expected_branch_oid: str) -> PublicationWorkspace: ...
class AuditSink(Protocol):
def record(self, event: Mapping[str, Any]) -> None: ...
class ExistingBranchPublisher:
"""Validate once, observe once, then make one bounded publication attempt."""
def __init__(
self,
*,
verifier: OwnerApprovalVerifier,
replay_ledger: ReplayLedger,
authority: AuthorityBranchPort,
remote: ExistingBranchRemotePort,
credentials: CredentialProjection,
workspaces: DetachedWorkspaceFactory,
audit: AuditSink,
) -> None:
self.verifier = verifier
self.replay_ledger = replay_ledger
self.authority = authority
self.remote = remote
self.credentials = credentials
self.workspaces = workspaces
self.audit = audit
def _audit(
self,
*,
status: str,
request: ExistingBranchPublicationRequest,
approval: OwnerApprovalEnvelope | None = None,
commit_oid: str | None = None,
) -> None:
event: dict[str, Any] = {
"event": "governed_existing_branch_publication",
"status": status,
"repository": request.repository,
"branch": request.branch,
"expected_branch_oid": request.expected_branch_oid,
"operation": PUBLISH_OPERATION,
"request_digest": request.request_digest,
"idempotency_digest": request.idempotency_digest,
}
if approval is not None:
event.update(
{
"approval_id": approval.approval_id,
"owner_identity": approval.owner_identity,
"trust_domain": approval.trust_domain,
"approval_fingerprint": approval.fingerprint,
}
)
if commit_oid is not None:
event["commit_oid"] = commit_oid
self.audit.record(event)
def _preflight_remote(
self, request: ExistingBranchPublicationRequest
) -> RemoteBranchObservation | dict[str, str]:
try:
authority_oid = self.authority.read_branch_oid(request.branch)
except Exception:
return {"status": "RECONCILIATION_REQUIRED"}
if authority_oid != request.expected_branch_oid:
return {"status": "MANUAL_OWNER_REVIEW_REQUIRED"}
try:
observation = self.remote.observe(request.branch)
except RemoteObservationAmbiguous:
return {"status": "RECONCILIATION_REQUIRED"}
if observation.state == "AMBIGUOUS":
return {"status": "RECONCILIATION_REQUIRED"}
if observation.state != "PRESENT":
return {"status": "MANUAL_OWNER_REVIEW_REQUIRED"}
if (
observation.git_oid is not None
and observation.api_oid is not None
and observation.git_oid != observation.api_oid
):
return {"status": "RECONCILIATION_REQUIRED"}
if (
observation.git_oid != request.expected_branch_oid
or observation.api_oid != request.expected_branch_oid
):
return {"status": "MANUAL_OWNER_REVIEW_REQUIRED"}
if observation.expected_commit_visible is not True:
return {"status": "RECONCILIATION_REQUIRED"}
return observation
def publish(
self, request_value: object, approval_value: object
) -> dict[str, str | bool]:
request = ExistingBranchPublicationRequest.from_mapping(request_value)
try:
approval = self.verifier.verify(approval_value, request.approval_binding)
except OwnerApprovalRejected:
self._audit(status="REJECTED", request=request)
raise
preflight = self._preflight_remote(request)
if isinstance(preflight, dict):
self._audit(status=preflight["status"], request=request, approval=approval)
return preflight
self.replay_ledger.consume(approval, request.approval_binding)
workspace = self.workspaces.open_detached(request.expected_branch_oid)
if workspace.head_oid() != request.expected_branch_oid:
self._audit(status="REJECTED", request=request, approval=approval)
raise ExistingBranchPublicationRejected("DETACHED_WORKSPACE_HEAD_REJECTED")
projected = False
try:
self.credentials.project()
projected = True
commit_oid = workspace.commit_payload(request.payload)
if not isinstance(commit_oid, str) or not OID_RE.fullmatch(commit_oid):
raise ExistingBranchPublicationRejected("PUBLICATION_COMMIT_REJECTED")
try:
evidence = self.remote.publish_compare_and_swap(
request.branch, request.expected_branch_oid, commit_oid
)
except RemoteOidConflict:
self._audit(
status="MANUAL_OWNER_REVIEW_REQUIRED",
request=request,
approval=approval,
commit_oid=commit_oid,
)
return {"status": "MANUAL_OWNER_REVIEW_REQUIRED"}
except RemoteObservationAmbiguous:
self._audit(
status="RECONCILIATION_REQUIRED",
request=request,
approval=approval,
commit_oid=commit_oid,
)
return {"status": "RECONCILIATION_REQUIRED"}
if (
evidence.authority_oid != commit_oid
or evidence.gitea_git_oid != commit_oid
or evidence.gitea_api_oid != commit_oid
or evidence.commit_visible is not True
):
self._audit(
status="RECONCILIATION_REQUIRED",
request=request,
approval=approval,
commit_oid=commit_oid,
)
return {"status": "RECONCILIATION_REQUIRED"}
self._audit(
status="PUBLISHED",
request=request,
approval=approval,
commit_oid=commit_oid,
)
return {
"status": "PUBLISHED",
"commit_oid": commit_oid,
"authority_oid": evidence.authority_oid,
"gitea_git_oid": evidence.gitea_git_oid,
"gitea_api_oid": evidence.gitea_api_oid,
"commit_visible": evidence.commit_visible,
}
finally:
if projected:
self.credentials.revoke()
@@ -1,93 +0,0 @@
"""Canonical Gitea transport and slash-branch verification."""
from __future__ import annotations
from dataclasses import dataclass
import json
import os
from pathlib import Path
import subprocess
from typing import Any, Callable, Mapping, Optional
from urllib.parse import quote
from urllib.request import Request, urlopen
from aios_gitops_reconciliation_core import RemoteObservation
@dataclass(frozen=True, slots=True)
class GiteaPublisherConfig:
repository: str = "aios/aios"
api_base: str = "https://g.cnnetmkt.top/git/api/v1"
remote_name: str = "gitea-http"
class GiteaPublisher:
def __init__(self, workspace: Path, *, config: GiteaPublisherConfig = GiteaPublisherConfig(), credential: Any = None, api_get: Callable[[str], Any] | None = None, git_ref: Callable[[str], Optional[str]] | None = None) -> None:
self.workspace = Path(workspace)
self.config = config
self.credential = credential
self._api_get = api_get
self._git_ref = git_ref
@staticmethod
def validate_repository(repository: str) -> None:
if repository != "aios/aios":
raise ValueError("REPOSITORY_IDENTITY_MISMATCH")
@staticmethod
def validate_branch(branch: str) -> None:
if not isinstance(branch, str) or not branch.startswith("agent/") or branch in {"main", "master"}:
raise ValueError("BRANCH_SCOPE_DENIED")
def repository_identity(self) -> str:
self.validate_repository(self.config.repository)
return self.config.repository
def _environment(self) -> dict[str, str]:
if self.credential is not None and hasattr(self.credential, "environment"):
return dict(self.credential.environment())
return {}
def read_git_ref(self, branch: str) -> Optional[str]:
self.validate_branch(branch)
if self._git_ref is not None:
return self._git_ref(branch)
result = subprocess.run(["git", "-C", str(self.workspace), "ls-remote", self.config.remote_name, f"refs/heads/{branch}"], text=True, capture_output=True, check=False, env={**os.environ, **self._environment(), "GIT_TERMINAL_PROMPT": "0"})
if result.returncode != 0 or not result.stdout.strip():
return None
return result.stdout.split()[0]
def _api(self, path: str) -> Any:
if self._api_get is not None:
return self._api_get(path)
headers = {"Accept": "application/json"}
env = self._environment()
if env.get("AIOS_GITEA_TOKEN"):
headers["Authorization"] = "token " + env["AIOS_GITEA_TOKEN"]
with urlopen(Request(self.config.api_base.rstrip("/") + path, headers=headers), timeout=20) as response:
return json.loads(response.read() or b"{}")
def read_api_branch(self, branch: str) -> Optional[str]:
self.validate_branch(branch)
for page in range(1, 101):
value = self._api(f"/repos/aios/aios/branches?page={page}&limit=50")
if not isinstance(value, list):
return None
for item in value:
if isinstance(item, Mapping) and item.get("name") == branch:
commit = item.get("commit")
return commit.get("id") if isinstance(commit, Mapping) else None
if len(value) < 50:
return None
raise RuntimeError("GITEA_BRANCH_PAGINATION_LIMIT")
def commit_visible(self, oid: str) -> bool:
if not isinstance(oid, str) or len(oid) != 40:
return False
try:
value = self._api(f"/repos/aios/aios/git/commits/{quote(oid, safe='')}")
return isinstance(value, Mapping) and value.get("sha", oid) == oid
except Exception:
return False
def observe(self, branch: str, desired_oid: str, authority_oid: Optional[str], *, expected_oid: Optional[str] = None, observed_at: str = "") -> RemoteObservation:
return RemoteObservation(self.repository_identity(), branch, desired_oid, authority_oid, self.read_git_ref(branch), self.read_api_branch(branch), self.commit_visible(desired_oid), observed_at, expected_oid)
@@ -1,80 +0,0 @@
"""Pure, observation-first decisions for governed GitOps reconciliation."""
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
import re
from typing import Optional
OID_RE = re.compile(r"^[0-9a-f]{40}$")
class ReconciliationAction(str, Enum):
NOOP = "NOOP"
PUSH_EXACT = "PUSH_EXACT"
VERIFY_REMOTE = "VERIFY_REMOTE"
MARK_REMOTE_VERIFIED = "MARK_REMOTE_VERIFIED"
MARK_RECONCILIATION_REQUIRED = "MARK_RECONCILIATION_REQUIRED"
FAIL_CONFLICT = "FAIL_CONFLICT"
@dataclass(frozen=True, slots=True)
class RemoteObservation:
repository_identity: str
branch: str
desired_oid: str
authority_oid: Optional[str]
remote_git_oid: Optional[str]
remote_api_oid: Optional[str]
commit_visible: bool
observed_at: str
expected_oid: Optional[str] = None
@property
def all_equal(self) -> bool:
values = (self.authority_oid, self.remote_git_oid, self.remote_api_oid, self.desired_oid)
return all(isinstance(value, str) for value in values) and len(set(values)) == 1
@dataclass(frozen=True, slots=True)
class ReconciliationDecision:
action: ReconciliationAction
state: str
reason: str
retry_safe: bool = False
def _valid_oid(value: Optional[str]) -> bool:
return value is None or bool(OID_RE.fullmatch(value))
def decide_reconciliation(observation: RemoteObservation) -> ReconciliationDecision:
"""Decide from a fresh observation; never complete on a missing remote."""
if observation.repository_identity != "aios/aios":
return ReconciliationDecision(ReconciliationAction.FAIL_CONFLICT, "CONFLICT", "REPOSITORY_IDENTITY_MISMATCH")
if not observation.branch.startswith("agent/"):
return ReconciliationDecision(ReconciliationAction.FAIL_CONFLICT, "CONFLICT", "BRANCH_SCOPE_DENIED")
if not _valid_oid(observation.desired_oid) or not _valid_oid(observation.expected_oid):
return ReconciliationDecision(ReconciliationAction.FAIL_CONFLICT, "CONFLICT", "OID_INVALID")
if observation.authority_oid is None:
return ReconciliationDecision(ReconciliationAction.MARK_RECONCILIATION_REQUIRED, "RECONCILIATION_REQUIRED", "AUTHORITY_UNAVAILABLE")
if observation.authority_oid != observation.desired_oid:
return ReconciliationDecision(ReconciliationAction.MARK_RECONCILIATION_REQUIRED, "RECONCILIATION_REQUIRED", "AUTHORITY_CONFLICT")
present = [oid for oid in (observation.remote_git_oid, observation.remote_api_oid) if oid is not None]
if any(oid not in {observation.desired_oid, observation.expected_oid} for oid in present):
return ReconciliationDecision(ReconciliationAction.FAIL_CONFLICT, "CONFLICT", "REMOTE_OID_CONFLICT")
if observation.all_equal and observation.commit_visible:
return ReconciliationDecision(ReconciliationAction.MARK_REMOTE_VERIFIED, "REMOTE_VERIFIED", "ALL_OIDS_EQUAL_AND_VISIBLE")
if observation.remote_git_oid is None and observation.remote_api_oid is None:
return ReconciliationDecision(ReconciliationAction.MARK_RECONCILIATION_REQUIRED, "REMOTE_PUSH_PENDING", "AUTHORITY_DESIRED_REMOTE_MISSING")
if observation.remote_git_oid == observation.desired_oid or observation.remote_api_oid == observation.desired_oid:
return ReconciliationDecision(ReconciliationAction.VERIFY_REMOTE, "REMOTE_VERIFY_PENDING", "REMOTE_PROOF_PARTIAL")
if observation.expected_oid is not None and observation.remote_git_oid == observation.expected_oid and observation.remote_api_oid == observation.expected_oid:
return ReconciliationDecision(ReconciliationAction.PUSH_EXACT, "REMOTE_PUSH_PENDING", "SAFE_EXACT_FAST_FORWARD_RETRY", retry_safe=True)
if not observation.commit_visible:
return ReconciliationDecision(ReconciliationAction.VERIFY_REMOTE, "COMMIT_VISIBILITY_PENDING", "COMMIT_VISIBILITY_LAG")
return ReconciliationDecision(ReconciliationAction.MARK_RECONCILIATION_REQUIRED, "RECONCILIATION_REQUIRED", "PARTIAL_REMOTE_OBSERVATION")
def reconcile_observation(**kwargs: object) -> ReconciliationDecision:
return decide_reconciliation(RemoteObservation(**kwargs))
@@ -1,59 +0,0 @@
"""Central fail-closed policy seam for governed task and continuation requests."""
from __future__ import annotations
from dataclasses import dataclass
import re
from typing import Any, Mapping
OID_RE = re.compile(r"^[0-9a-f]{40}$")
@dataclass(frozen=True, slots=True)
class GovernedPolicyInput:
identity: str
task_id: str
repository: str
operation: str
base_oid: str
expected_branch_oid: str
target_branch: str
generation: int
risk: str = "engineering"
requested_capabilities: tuple[str, ...] = ()
previous_generation: int | None = None
@dataclass(frozen=True, slots=True)
class PolicyDecision:
decision: str
reason: str
def as_dict(self) -> dict[str, str]:
return {"decision": self.decision, "reason": self.reason}
def evaluate_policy(value: GovernedPolicyInput | Mapping[str, Any]) -> PolicyDecision:
if isinstance(value, Mapping):
value = GovernedPolicyInput(**value)
if value.repository != "aios/aios":
return PolicyDecision("DENY", "REPOSITORY_IDENTITY_MISMATCH")
if not OID_RE.fullmatch(value.base_oid) or not OID_RE.fullmatch(value.expected_branch_oid):
return PolicyDecision("DENY", "OID_INVALID")
if not value.target_branch.startswith("agent/") or value.target_branch in {"main", "master"}:
return PolicyDecision("DENY", "BRANCH_SCOPE_DENIED")
if "force_push" in value.requested_capabilities or "force" in value.operation.lower():
return PolicyDecision("DENY", "FORCE_PUSH_DENIED")
if {"main_write", "tag_write", "baseline_write", "production_write", "production_deploy", "tag_mutation", "baseline_mutation"}.intersection(value.requested_capabilities):
return PolicyDecision("DENY", "MUTATION_SCOPE_DENIED")
if not isinstance(value.generation, int) or isinstance(value.generation, bool) or value.generation < 1:
return PolicyDecision("DENY", "GENERATION_INVALID")
if value.previous_generation is not None and value.generation <= value.previous_generation:
return PolicyDecision("MANUAL_OWNER_REVIEW_REQUIRED", "GENERATION_NOT_MONOTONIC")
if not value.task_id:
return PolicyDecision("DENY", "TASK_ID_INVALID")
return PolicyDecision("ALLOW", "GOVERNED_ENGINEERING_SCOPE")
class GovernedPolicy:
def decide(self, request: GovernedPolicyInput | Mapping[str, Any]) -> PolicyDecision:
return evaluate_policy(request)
@@ -1,13 +1,25 @@
"""Durable governed task binding for CREATE_NEW and CONTINUE_EXISTING.""" """Exact-base governed CREATE_NEW task bootstrap using the existing JobStore."""
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass, asdict from dataclasses import dataclass
from datetime import datetime, timezone, timedelta
import hashlib import hashlib
import json import json
from pathlib import Path
import re import re
from pathlib import Path
from typing import Any, Mapping from typing import Any, Mapping
from aios_authority_git_executor import AuthorityGitExecutor
from aios_continuation_executor import (
AuthorityGitAdapter,
ContinuationExecutor,
ContinuationPermissions,
ContinuationRuntimeBinding,
DetachedGitWorkspace,
GiteaContinuationRemote,
ServerSideCredentialProjection,
)
from aios_continuation_lease import WriterLeaseRequestV2
from aios_gitops_job_controller import GitOpsJobController, JobStore from aios_gitops_job_controller import GitOpsJobController, JobStore
OID_RE = re.compile(r"^[0-9a-f]{40}$") OID_RE = re.compile(r"^[0-9a-f]{40}$")
@@ -27,58 +39,218 @@ class GovernedTaskBinding:
risk: str risk: str
description: str description: str
idempotency_key: str idempotency_key: str
expected_branch_oid: str
branch_mode: str
generation: int
job_id: str | None = None job_id: str | None = None
def response(self, *, idempotent: bool = False) -> dict[str, Any]: def response(self, *, idempotent: bool = False) -> dict[str, Any]:
return {"task_id": self.task_id, "repository": self.repository, "base_oid": self.base_oid, "target_branch": self.target_branch, "expected_branch_oid": self.expected_branch_oid, "generation": self.generation, "branch_mode": self.branch_mode, "create_target_branch": self.branch_mode == "CREATE_NEW", "worktree_mode": "detached_at_base_oid" if self.branch_mode == "CREATE_NEW" else "detached_at_expected_head", "cas_ref_update_required": True, "idempotent": idempotent, "state": "BOUND", "job_id": self.job_id} return {
"task_id": self.task_id,
"repository": self.repository,
"base_oid": self.base_oid,
"target_branch": self.target_branch,
"expected_branch_oid": self.base_oid,
"generation": 1,
"branch_mode": "CREATE_NEW",
"create_target_branch": True,
"worktree_mode": "detached_at_base_oid",
"cas_ref_update_required": True,
"idempotent": idempotent,
"state": "BOUND",
"job_id": self.job_id,
}
def _safe(value: str) -> str: def _safe_task(value: str) -> str:
return re.sub(r"[^A-Za-z0-9_.-]+", "-", value).strip("-")[:120] or "task" return re.sub(r"[^A-Za-z0-9_.-]+", "-", value).strip("-")[:120] or "task"
class GovernedTaskBootstrap: class GovernedTaskBootstrap:
def __init__(self, authority: Any, root: Path, *, remote_name: str, token_path: Path, ssh_key_path: Path, api_base: str = "https://g.cnnetmkt.top/git/api/v1") -> None: def __init__(
self.authority = authority; self.root = Path(root); self.remote_name = remote_name; self.token_path = Path(token_path); self.ssh_key_path = Path(ssh_key_path); self.api_base = api_base; self.task_meta_root = self.root / "task-bindings"; self.job_root = self.root / "jobs"; self.task_meta_root.mkdir(parents=True, exist_ok=True); self.job_root.mkdir(parents=True, exist_ok=True) self,
authority: AuthorityGitExecutor,
root: Path,
*,
remote_name: str,
token_path: Path,
ssh_key_path: Path,
api_base: str = "https://g.cnnetmkt.top/git/api/v1",
) -> None:
self.authority = authority
self.root = root
self.remote_name = remote_name
self.token_path = token_path
self.ssh_key_path = ssh_key_path
self.api_base = api_base
self.task_meta_root = root / "task-bindings"
self.job_root = root / "jobs"
self.worktree_root = root / "worktrees"
self.task_meta_root.mkdir(parents=True, exist_ok=True)
self.job_root.mkdir(parents=True, exist_ok=True)
self.worktree_root.mkdir(parents=True, exist_ok=True)
def _store(self, task_id: str) -> tuple[JobStore, GitOpsJobController]: def _store(self, task_id: str) -> tuple[JobStore, GitOpsJobController]:
root = self.job_root / _safe(task_id); store = JobStore(root, payload_root=root / "payloads"); return store, GitOpsJobController(store) task_root = self.job_root / _safe_task(task_id)
store = JobStore(task_root, payload_root=task_root / "payloads")
return store, GitOpsJobController(store)
def _metadata(self, task_id: str) -> Path: def _metadata(self, task_id: str) -> Path:
return self.task_meta_root / (_safe(task_id) + ".json") return self.task_meta_root / (_safe_task(task_id) + ".json")
def _read_existing(self, task_id: str) -> GovernedTaskBinding | None: def _read_existing(self, task_id: str) -> GovernedTaskBinding | None:
path = self._metadata(task_id) path = self._metadata(task_id)
if not path.is_file() or path.is_symlink(): return None if not path.is_file() or path.is_symlink():
return GovernedTaskBinding(**json.loads(path.read_text(encoding="utf-8"))) return None
raw = json.loads(path.read_text(encoding="utf-8"))
return GovernedTaskBinding(
task_id=raw["task_id"],
repository=raw["repository"],
base_oid=raw["base_oid"],
target_branch=raw["target_branch"],
risk=raw["risk"],
description=raw["description"],
idempotency_key=raw["idempotency_key"],
job_id=raw.get("job_id"),
)
def _write(self, binding: GovernedTaskBinding) -> None: def _write_metadata(self, binding: GovernedTaskBinding) -> None:
path = self._metadata(binding.task_id); temporary = path.with_suffix(".tmp"); temporary.write_text(json.dumps(asdict(binding), sort_keys=True), encoding="utf-8"); temporary.replace(path) path = self._metadata(binding.task_id)
temporary = path.with_suffix(".tmp")
temporary.write_text(
json.dumps(
{
"task_id": binding.task_id,
"repository": binding.repository,
"base_oid": binding.base_oid,
"target_branch": binding.target_branch,
"risk": binding.risk,
"description": binding.description,
"idempotency_key": binding.idempotency_key,
"job_id": binding.job_id,
},
sort_keys=True,
),
encoding="utf-8",
)
temporary.replace(path)
def _pending_create_new_oid(self, task_id: str, branch: str) -> str | None:
"""Return the exact local OID only for an unfinished CREATE_NEW job."""
store, _ = self._store(task_id)
with store._connect() as connection:
rows = connection.execute(
"SELECT operation,state,receipt_json FROM jobs WHERE branch=? ORDER BY updated_at DESC",
(branch,),
).fetchall()
for row in rows:
if row["operation"] != "CONTINUATION_COMMIT_FILES_CREATE_NEW" or row["state"] != "RECONCILIATION_REQUIRED":
continue
receipt = json.loads(row["receipt_json"] or "{}")
desired = receipt.get("desired_remote_oid")
if isinstance(desired, str) and OID_RE.fullmatch(desired):
return desired
return None
def create(self, request: Mapping[str, Any]) -> dict[str, Any]: def create(self, request: Mapping[str, Any]) -> dict[str, Any]:
values = {key: str(request[key]) for key in ("task_id", "repository", "base_oid", "target_branch", "risk", "description", "idempotency_key")} values = {key: str(request[key]) for key in (
if values["repository"] != "aios/aios" or not OID_RE.fullmatch(values["base_oid"]): raise BootstrapError("TASK_BINDING_INVALID") "task_id",
if not BRANCH_RE.fullmatch(values["target_branch"]): raise BootstrapError("TARGET_BRANCH_INVALID") "repository",
"base_oid",
"target_branch",
"risk",
"description",
"idempotency_key",
)}
if values["repository"] != "aios/aios" or not OID_RE.fullmatch(values["base_oid"]):
raise BootstrapError("TASK_BINDING_INVALID")
if not BRANCH_RE.fullmatch(values["target_branch"]) or values["target_branch"] in {"main", "master"}:
raise BootstrapError("TARGET_BRANCH_INVALID")
existing = self._read_existing(values["task_id"]) existing = self._read_existing(values["task_id"])
if existing is not None: if existing is not None:
if any(getattr(existing, key) != values[key] for key in ("repository", "base_oid", "target_branch", "risk", "description")): raise BootstrapError("TASK_BINDING_CONFLICT") for key in ("repository", "base_oid", "target_branch", "risk", "description"):
if getattr(existing, key) != values[key]:
raise BootstrapError("TASK_BINDING_CONFLICT")
return existing.response(idempotent=True) return existing.response(idempotent=True)
if not self.authority.commit_exists(values["base_oid"]): raise BootstrapError("BASE_COMMIT_NOT_FOUND") if not self.authority.commit_exists(values["base_oid"]):
current = self.authority.read_ref("refs/heads/" + values["target_branch"]) raise BootstrapError("BASE_COMMIT_NOT_FOUND")
expected = str(request.get("expected_branch_oid") or values["base_oid"]) if self.authority.read_ref("refs/heads/" + values["target_branch"]) is not None:
if current is None: raise BootstrapError("CONFLICT")
mode, generation = "CREATE_NEW", 1
if expected != values["base_oid"]: raise BootstrapError("EXPECTED_BASE_CONFLICT")
else:
if expected != current: raise BootstrapError("EXISTING_BRANCH_OID_CONFLICT")
mode, generation = "CONTINUE_EXISTING", int(request.get("generation", 2))
if generation < 1: raise BootstrapError("GENERATION_INVALID")
payload = json.dumps(values, sort_keys=True, separators=(",", ":")).encode() payload = json.dumps(values, sort_keys=True, separators=(",", ":")).encode()
_, controller = self._store(values["task_id"]) _, controller = self._store(values["task_id"])
receipt = controller.submit({"idempotency_key": values["idempotency_key"], "campaign_id": values["task_id"], "task_id": values["task_id"], "repository": values["repository"], "operation": "GOVERNED_TASK_CREATE", "branch": values["target_branch"], "expected_branch_oid": expected, "payload_digest": hashlib.sha256(payload).hexdigest(), "lineage_anchor_oid": values["base_oid"]}, payload=payload) receipt = controller.submit(
binding = GovernedTaskBinding(**values, expected_branch_oid=expected, branch_mode=mode, generation=generation, job_id=receipt.job_id) {
self._write(binding) "idempotency_key": values["idempotency_key"],
"campaign_id": values["task_id"],
"task_id": values["task_id"],
"repository": values["repository"],
"operation": "GOVERNED_TASK_CREATE",
"branch": values["target_branch"],
"expected_branch_oid": values["base_oid"],
"payload_digest": hashlib.sha256(payload).hexdigest(),
"lineage_anchor_oid": values["base_oid"],
},
payload=payload,
)
binding = GovernedTaskBinding(**values, job_id=receipt.job_id)
self._write_metadata(binding)
return binding.response() return binding.response()
def prepare_runtime(self, request: Mapping[str, Any], *, lease_seconds: int):
task = self._read_existing(str(request["task_id"]))
if task is None:
raise BootstrapError("TASK_NOT_FOUND")
if str(request["repository"]) != task.repository or str(request["base_oid"]) != task.base_oid:
raise BootstrapError("TASK_BINDING_CONFLICT")
if str(request["target_branch"]) != task.target_branch:
raise BootstrapError("TASK_BINDING_CONFLICT")
if request.get("branch_mode") != "CREATE_NEW" or int(request.get("generation", 0)) != 1:
raise BootstrapError("CREATE_NEW_LEASE_INVALID")
if not self.authority.commit_exists(task.base_oid):
raise BootstrapError("BASE_COMMIT_NOT_FOUND")
existing_target = self.authority.read_ref("refs/heads/" + task.target_branch)
recovery_oid = None
if existing_target is not None:
recovery_oid = self._pending_create_new_oid(task.task_id, task.target_branch)
if recovery_oid != existing_target:
raise BootstrapError("CONFLICT")
workspace_path = self.worktree_root / _safe_task(task.task_id)
if workspace_path.exists():
if workspace_path.is_symlink():
raise BootstrapError("WORKTREE_INVALID")
workspace = DetachedGitWorkspace(workspace_path)
allowed_heads = {task.base_oid}
if recovery_oid is not None:
allowed_heads.add(recovery_oid)
if not workspace.is_detached() or workspace.head_oid() not in allowed_heads:
raise BootstrapError("WORKTREE_HEAD_MISMATCH")
else:
self.authority.create_detached_worktree(task.base_oid, _safe_task(task.task_id), self.worktree_root)
workspace = DetachedGitWorkspace(workspace_path)
request_v2 = WriterLeaseRequestV2(
task_id=task.task_id,
repository=task.repository,
branch_mode="CREATE_NEW",
base_oid=task.base_oid,
expected_branch_oid=task.base_oid,
target_branch=task.target_branch,
generation=1,
lease_seconds=lease_seconds,
)
_, controller = self._store(task.task_id)
credential = ServerSideCredentialProjection(self.ssh_key_path, self.token_path)
remote = GiteaContinuationRemote(
workspace=workspace_path,
credential=credential,
remote_name=self.remote_name,
repository=task.repository,
api_base=self.api_base,
)
executor = ContinuationExecutor(controller, AuthorityGitAdapter(self.authority), workspace, remote, credential)
binding = ContinuationRuntimeBinding(
request=request_v2,
workspace_path=workspace_path,
lease_not_before=datetime.now(timezone.utc) - timedelta(seconds=1),
lease_expires_at=datetime.now(timezone.utc) + timedelta(seconds=lease_seconds),
original_receipt_valid=True,
original_grant_consumed=True,
permissions=ContinuationPermissions(create_target_branch=True),
)
return binding, controller, executor
File diff suppressed because it is too large Load Diff
-84
View File
@@ -1,84 +0,0 @@
#!/usr/bin/env python3
"""Single canonical Production Baseline authority for the GitOps reader.
The API and the one-shot writer import this module. Workspace and release
copies are projections only; they are never selected as a fallback source.
"""
from __future__ import annotations
import hashlib
import json
import os
from pathlib import Path
from typing import Any
AUTHORITY_PATH = Path(os.getenv(
"AIOS_GITOPS_BASELINE_AUTHORITY",
"/var/lib/aios-gitops-runtime-anchor/baseline/current.json",
))
AUTHORITY_SHA_PATH = AUTHORITY_PATH.with_suffix(".sha256")
class BaselineAuthorityError(RuntimeError):
"""Fail-closed error raised for an unavailable or inconsistent authority."""
class BaselineAuthority:
def __init__(self, path: Path | str = AUTHORITY_PATH):
self.path = Path(path)
self.sha_path = self.path.with_suffix(".sha256")
def _raw(self) -> bytes:
try:
raw = self.path.read_bytes()
except OSError as exc:
raise BaselineAuthorityError(f"authority_unavailable:{exc}") from exc
if not raw:
raise BaselineAuthorityError("authority_empty")
return raw
def read(self) -> dict[str, Any]:
raw = self._raw()
digest = hashlib.sha256(raw).hexdigest()
try:
value = json.loads(raw.decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise BaselineAuthorityError("authority_invalid_json") from exc
if not isinstance(value, dict):
raise BaselineAuthorityError("authority_not_object")
expected = str(value.get("authority_sha256", ""))
if expected and expected != digest:
raise BaselineAuthorityError("authority_embedded_digest_mismatch")
if self.sha_path.exists():
sidecar = self.sha_path.read_text(encoding="utf-8").strip().split()[0]
if sidecar != digest:
raise BaselineAuthorityError("authority_sidecar_digest_mismatch")
required = {
"current_baseline", "previous_baseline", "target_oid", "tag_oid",
"evidence_closure_oid", "approval_plan_id", "status", "generation",
"source_identity",
}
missing = sorted(required.difference(value))
if missing:
raise BaselineAuthorityError("authority_missing:" + ",".join(missing))
value = dict(value)
value["authority_sha256"] = digest
value["authority_path"] = str(self.path)
return value
def read_consistent(self, policy: dict[str, Any] | None = None) -> dict[str, Any]:
value = self.read()
if policy:
expected = policy.get("release_binding", policy)
for key, field in (("version", "current_baseline"),
("previous_version", "previous_baseline"),
("target_oid", "target_oid"),
("tag_oid", "tag_oid"),
("evidence_closure_oid", "evidence_closure_oid"),
("approval_plan_id", "approval_plan_id")):
wanted = expected.get(key)
if wanted is not None and value.get(field) != wanted:
raise BaselineAuthorityError(f"authority_binding_mismatch:{field}")
return value
@@ -1,51 +0,0 @@
[Unit]
Description=AIOS GitOps Model API V2R2C1 immutable staging runtime
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=aiman
Group=gitops
WorkingDirectory=@RUNTIME_ROOT@
Environment=PYTHONUNBUFFERED=1
Environment=PYTHONDONTWRITEBYTECODE=1
Environment=AIOS_GITOPS_ROOT=/var/lib/aios-gitops
Environment=AIOS_GITOPS_WORKSPACE=@RUNTIME_ROOT@
Environment=AIOS_GITOPS_REPO=/data/aios-gitops/repo.git
Environment=AIOS_GITOPS_BARE_REPO=/data/aios-gitops/repo.git
Environment=AIOS_GITOPS_AUTHORITATIVE_GIT_DIR=/data/aios-gitops/repo.git
Environment=AIOS_GITOPS_REPOSITORY_IDENTITY=aios/aios
Environment=AIOS_GITOPS_BASELINE_AUTHORITY=/var/lib/aios-gitops-runtime-anchor/baseline/current.json
Environment=AIOS_GITOPS_WRITES_ENABLED=false
Environment=AIOS_GITOPS_DURABLE_JOB_EXECUTION_ENABLED=false
Environment=AIOS_GITOPS_JOB_CONTROLLER_ENABLED=false
Environment=AIOS_GITOPS_WORKSPACE_ROLE=runtime-anchor
Environment=AIOS_GITOPS_RUNTIME_OID=@SOURCE_OID@
Environment=AIOS_GITOPS_ARTIFACT_SHA256=@ARTIFACT_SHA256@
Environment=AIOS_GITOPS_DEPLOYMENT_STATE=STAGING
Environment=AIOS_GITOPS_MODEL_API_SERVICE=aios-gitops-model-api-v2r2c1-staging.service
Environment=AIOS_SILENT_RELEASE_EXECUTION_ENABLED=false
Environment=AIOS_SILENT_RELEASE_STATE_ROOT=/var/lib/aios-gitops/model-api-staging/silent-release
Environment=AIOS_BRIDGE_V2_URL=http://127.0.0.1:18892
Environment=AIOS_GITOPS_HOST=127.0.0.1
Environment=AIOS_GITOPS_PORT=18893
Environment=PYTHONPATH=@RUNTIME_ROOT@/app:@RUNTIME_ROOT@/runtime-agent-os
ExecStart=/usr/bin/python3 @RUNTIME_ROOT@/app/aios_model_api_staging.py
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
LockPersonality=true
RestrictSUIDSGID=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
ReadOnlyPaths=@RUNTIME_ROOT@ /data/aios-gitops/repo.git /var/lib/aios-gitops-runtime-anchor/baseline
ReadWritePaths=/var/lib/aios-gitops/model-api-staging
[Install]
WantedBy=multi-user.target
@@ -1,6 +1,20 @@
# Merge this fragment into docs/gitops/openapi-chatgpt-actions.yaml. # Merge this fragment into docs/gitops/openapi-chatgpt-actions.yaml.
components: components:
schemas: schemas:
WriterLeaseRequestV2:
type: object
additionalProperties: false
required: [schema, task_id, repository, branch_mode, base_oid, expected_branch_oid, target_branch, generation, lease_seconds]
properties:
schema: {type: string, const: aios.task-writer-lease.v2}
task_id: {type: string}
repository: {type: string, const: aios/aios}
branch_mode: {type: string, const: CONTINUE_EXISTING}
base_oid: {type: string, pattern: '^[0-9a-f]{40}$'}
expected_branch_oid: {type: string, pattern: '^[0-9a-f]{40}$'}
target_branch: {type: string, pattern: '^agent/'}
generation: {type: integer, minimum: 1}
lease_seconds: {type: integer, minimum: 1, maximum: 86400}
AuthorizedTaskWriterProvisionRequest: AuthorizedTaskWriterProvisionRequest:
type: object type: object
additionalProperties: false additionalProperties: false
+239 -2
View File
@@ -13,6 +13,55 @@ components:
scheme: bearer scheme: bearer
bearerFormat: opaque-token bearerFormat: opaque-token
schemas: schemas:
TaskAdmissionEnvelopeRequest:
type: object
additionalProperties: false
required:
- idempotency_key
- task_id
- repository
- authority_base_oid
- target_branch
- generation
- execution_digest
- requested_capabilities
- file_allowlist
- risk
properties:
idempotency_key: {type: string, minLength: 8, maxLength: 256}
task_id: {type: string, minLength: 3, maxLength: 180}
repository: {type: string, enum: [aios/aios]}
authority_base_oid: {type: string, pattern: '^[0-9a-f]{40}$'}
target_branch: {type: string, pattern: '^agent/.+'}
generation: {type: integer, minimum: 1}
execution_digest: {type: string, pattern: '^[0-9a-f]{64}$'}
requested_capabilities:
type: array
minItems: 1
uniqueItems: true
items: {type: string}
file_allowlist:
type: array
minItems: 1
uniqueItems: true
items: {type: string}
risk: {type: string, enum: [low, medium]}
expires_in_seconds:
type: integer
minimum: 60
maximum: 900
TaskAdmissionAuthorizationRequest:
type: object
additionalProperties: false
required: [envelope_id, authorization_kind]
properties:
envelope_id: {type: string}
authorization_kind:
type: string
enum: [delegation_epoch, owner_signature]
delegation_epoch_id: {type: string}
owner_key_id: {type: string}
signature_base64: {type: string}
PublicationState: PublicationState:
type: string type: string
description: Canonical durable publication state. Legacy TAG_CREATED_LOCAL is normalized on read and is never emitted by new writes. description: Canonical durable publication state. Legacy TAG_CREATED_LOCAL is normalized on read and is never emitted by new writes.
@@ -96,7 +145,7 @@ components:
message: {type: string} message: {type: string}
TagRequest: TagRequest:
type: object type: object
required: [version, target_oid, evidence_closure_oid, approval_plan_id] required: [version, target_oid, evidence_closure_oid, approval_plan_id, execute]
properties: properties:
version: {type: string, example: V1R1C1} version: {type: string, example: V1R1C1}
target_oid: target_oid:
@@ -241,6 +290,122 @@ components:
properties: properties:
candidate_id: {type: string} candidate_id: {type: string}
paths: paths:
/v2/task-admission/envelope:
post:
operationId: getTaskAdmissionEnvelope
summary: Build and persist a canonical narrow Task admission envelope
description: >
Authenticated transport only. This operation does not mint a TaskPrincipal,
acquire a WriterLease, or mutate Git. It normalizes and persists one exact
admission envelope for later delegation/Owner authorization.
security: [{bearerAuth: []}]
x-openai-isConsequential: false
x-aios-governed-task-admission: true
x-aios-no-shell: true
x-aios-no-git-write: true
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/TaskAdmissionEnvelopeRequest'}
responses:
'200': {description: Canonical envelope and signing payload}
'401': {description: Authenticated transport required}
'403': {description: Requested scope exceeds bootstrap policy}
'409': {description: Idempotency key conflicts with a different request}
/v2/task-admission/authorize:
post:
operationId: submitTaskAdmissionAuthorization
summary: Verify durable delegation or Owner signature and admit one exact Task
description: >
The bearer authenticates the transport caller but is not task authority.
Authorization is proven only by a verified OwnerDelegationEpoch or exact
Owner signature. Successful admission may persist an exact Task receipt in
QUEUED, CLAIMED, or RUNNING state. It does not enable legacy/global Git
writes and cannot accept a caller-supplied TaskPrincipal.
security: [{bearerAuth: []}]
x-openai-isConsequential: true
x-aios-governed-task-admission: true
x-aios-no-shell: true
x-aios-no-git-write: true
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/TaskAdmissionAuthorizationRequest'}
responses:
'200': {description: Exact admitted Task receipt or idempotent replay}
'401': {description: Authenticated transport required}
'403': {description: Invalid, expired, revoked, widened, or unbound authorization}
'409': {description: Conflicting idempotent admission}
'503': {description: Task state or authorization backend unavailable}
/v2/task-admission/status:
get:
operationId: getTaskAdmissionStatus
summary: Read durable Task-admission state
description: >
Authenticated bounded lookup of one admission envelope. This is status only
and confers no TaskPrincipal, WriterLease, or execution capability.
security: [{bearerAuth: []}]
x-openai-isConsequential: false
x-aios-governed-task-admission: true
x-aios-no-shell: true
x-aios-read-only: true
parameters:
- in: query
name: envelope_id
required: true
schema: {type: string, minLength: 1, maxLength: 256}
responses:
'200': {description: Pending or admitted receipt}
'401': {description: Authenticated transport required}
'404': {description: Envelope not found}
/createTagApprovalRequest:
post:
operationId: createTagApprovalRequest
summary: Record the exact Owner-approved release binding without executing it
security: [{bearerAuth: []}]
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [version, target_oid, evidence_closure_oid, approval_plan_id, owner_approval, execute]
responses: {'200': {description: Durable execute=false approval receipt}}
x-openai-isConsequential: true
/buildProductionArtifact:
post:
operationId: buildProductionArtifact
summary: Build the deterministic production artifact for an exact approved binding
security: [{bearerAuth: []}]
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [version, target_oid, evidence_closure_oid, approval_plan_id]
responses: {'200': {description: Artifact digest and closure receipt}}
x-openai-isConsequential: true
/executeApprovedProductionRelease:
post:
operationId: executeApprovedProductionRelease
summary: Execute the exact approved production release after all release gates pass
security: [{bearerAuth: []}]
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [version, target_oid, evidence_closure_oid, approval_plan_id, execute]
responses: {'200': {description: Production release result}}
x-openai-isConsequential: true
/createReleaseIntent: /createReleaseIntent:
post: post:
operationId: createReleaseIntent operationId: createReleaseIntent
@@ -490,6 +655,14 @@ paths:
summary: Read durable publication Saga status without mutation summary: Read durable publication Saga status without mutation
parameters: parameters:
- {in: query, name: version, required: true, schema: {type: string, pattern: '^V\d+R\d+C\d+(?:-[A-Za-z0-9_.-]+)?$'}} - {in: query, name: version, required: true, schema: {type: string, pattern: '^V\d+R\d+C\d+(?:-[A-Za-z0-9_.-]+)?$'}}
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [version]
responses: responses:
'200': '200':
description: Canonical publication state or fail-closed UNKNOWN description: Canonical publication state or fail-closed UNKNOWN
@@ -506,6 +679,14 @@ paths:
- {in: query, name: target_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}} - {in: query, name: target_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}}
- {in: query, name: evidence_closure_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}} - {in: query, name: evidence_closure_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}}
- {in: query, name: approval_plan_id, required: true, schema: {type: string}} - {in: query, name: approval_plan_id, required: true, schema: {type: string}}
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [version, target_oid, evidence_closure_oid, approval_plan_id]
responses: {'200': {description: PASS, FAIL, or fail-closed UNKNOWN}} responses: {'200': {description: PASS, FAIL, or fail-closed UNKNOWN}}
/api/release-acceptance: /api/release-acceptance:
get: get:
@@ -516,6 +697,14 @@ paths:
- {in: query, name: target_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}} - {in: query, name: target_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}}
- {in: query, name: evidence_closure_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}} - {in: query, name: evidence_closure_oid, required: true, schema: {type: string, pattern: '^[0-9a-fA-F]{40}$'}}
- {in: query, name: approval_plan_id, required: true, schema: {type: string}} - {in: query, name: approval_plan_id, required: true, schema: {type: string}}
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [version, target_oid, evidence_closure_oid, approval_plan_id]
responses: {'200': {description: Acceptance result with accepted boolean}} responses: {'200': {description: Acceptance result with accepted boolean}}
/api/tag: /api/tag:
post: post:
@@ -526,7 +715,10 @@ paths:
required: true required: true
content: content:
application/json: application/json:
schema: {$ref: '#/components/schemas/TagRequest'} schema:
type: object
additionalProperties: false
required: [version, target_oid, evidence_closure_oid, approval_plan_id, execute]
responses: {'200': {description: Gitea-confirmed tag and fail-closed baseline result}, '400': {description: Missing governance evidence or invalid OID}, '403': {description: Forbidden}, '409': {description: Existing tag target conflict or evidence lineage mismatch}, '502': {description: Gitea reconciliation required}, '503': {description: Remote push pending}} responses: {'200': {description: Gitea-confirmed tag and fail-closed baseline result}, '400': {description: Missing governance evidence or invalid OID}, '403': {description: Forbidden}, '409': {description: Existing tag target conflict or evidence lineage mismatch}, '502': {description: Gitea reconciliation required}, '503': {description: Remote push pending}}
x-openai-isConsequential: true x-openai-isConsequential: true
/api/rollback: /api/rollback:
@@ -567,3 +759,48 @@ paths:
'200': {description: Safe GitOps plan} '200': {description: Safe GitOps plan}
'401': {description: Unauthorized} '401': {description: Unauthorized}
x-openai-isConsequential: true x-openai-isConsequential: true
/api/v2/governed-capabilities:
get:
operationId: getGovernedWriteCapabilities
responses: {'200': {description: Governed write capabilities with legacy writes disabled}}
/api/v2/governed-task:
post:
operationId: createGovernedTask
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [task_id, repository, base_oid, target_branch, risk, description, idempotency_key]}}}}
responses: {'200': {description: Exact governed task binding}}
x-openai-isConsequential: true
/api/v2/writer-lease:
post:
operationId: acquireWriterLease
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [schema, task_id, repository, branch_mode, base_oid, expected_branch_oid, target_branch, generation, lease_seconds]}}}}
responses: {'200': {description: Detached CONTINUE_EXISTING lease}}
x-openai-isConsequential: true
/api/v2/commit-file:
post:
operationId: commitFileGoverned
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [task_id, repository, expected_branch_oid, target_branch, generation, idempotency_key, path, content_base64, message]}}}}
responses: {'202': {description: Durable governed Job}}
x-openai-isConsequential: true
/api/v2/commit-files:
post:
operationId: commitFilesGoverned
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [task_id, repository, expected_branch_oid, target_branch, generation, idempotency_key, files, message]}}}}
responses: {'202': {description: One atomic multi-file governed Job}}
x-openai-isConsequential: true
/api/v2/job:
post:
operationId: getGitOpsJob
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [job_id]}}}}
responses: {'200': {description: Non-sensitive Job metadata}}
/api/v2/job/resume:
post:
operationId: resumeGitOpsJob
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [job_id, expected_revision]}}}}
responses: {'202': {description: Revision-CAS resume}}
x-openai-isConsequential: true
/api/v2/job/reconcile:
post:
operationId: reconcileGitOpsJob
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [job_id, expected_revision]}}}}
responses: {'202': {description: Observation-first reconciliation}}
x-openai-isConsequential: true
-4
View File
@@ -1,4 +0,0 @@
[pytest]
testpaths = tests
python_files = test_*.py
addopts = -ra --import-mode=importlib
@@ -1,243 +0,0 @@
{
"authority_proof": {
"branch_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"commit_visible": true,
"main_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"v2r2c1_tag_oid": "998d30304787e31e5ae607c0bd86b5edb2b0e5ad"
},
"baseline_authority": {
"artifact_sha256": "492338b895b152a55015fd92ea1d9dba2314894ab00c0ba219a78f3cef544b8a",
"authority_sha256": "d8e23bad49bdb3e4192ba708c3dfe7fc5b7cdc6a513c2f87acd6412a51867231",
"current_baseline": "V2R2C1",
"raw_byte_sidecar_verification": "PASS",
"target_oid": "998d30304787e31e5ae607c0bd86b5edb2b0e5ad"
},
"control_plane_source_oid": "b781129bd5a8b53c05ab648361424d2800166ee4",
"diff_stat": "active-runtime/app/aios_authority_git_executor.py | 24 +\n active-runtime/app/aios_chatgpt_actions_api.py | 48 +-\n active-runtime/app/aios_chatgpt_bridge_v2.py | 167 ++++\n .../app/aios_chatgpt_bridge_v2_server.py | 431 +++++++++\n active-runtime/app/aios_continuation_executor.py | 594 ++++++++++++\n active-runtime/app/aios_continuation_lease.py | 6 +\n active-runtime/app/aios_control_plane_snapshot.py | 26 +\n active-runtime/app/aios_credential_broker.py | 78 ++\n active-runtime/app/aios_gitea_publisher.py | 93 ++\n active-runtime/app/aios_gitops_job_controller.py | 16 +-\n .../app/aios_gitops_reconciliation_core.py | 80 ++\n active-runtime/app/aios_governed_policy.py | 59 ++\n active-runtime/app/aios_governed_task_bootstrap.py | 84 ++\n active-runtime/app/aios_model_api_staging.py | 1022 ++++++++++++++++++++\n .../app/authorized_task_writer_provisioning.py | 4 +-\n active-runtime/app/baseline_authority.py | 84 ++\n active-runtime/app/governed_production_release.py | 568 +++++++++++\n active-runtime/app/v2r2c1_production_adapter.py | 135 +++\n .../systemd/aios-chatgpt-bridge-v2-staging.service | 23 +\n .../aios-gitops-model-api-v2r2c1-staging.service | 51 +\n ...09-bridge-v2.1-durable-reconciliation-design.md | 15 +\n ...t-bridge-v2-control-plane-convergence-design.md | 150 +++\n pytest.ini | 4 +\n scripts/build_v2r2c1_model_api_staging.py | 145 +++\n .../aios_release_controller/manifest.py | 4 +-\n .../test_v2r1c6_release_consistency.py | 4 +-\n .../aios_v2_candidate/test_v2r1c6_release_ready.py | 16 +-\n tests/conftest.py | 65 ++\n tests/test_bridge_v2_governed_http_bootstrap.py | 90 ++\n tests/test_governed_local_writer.py | 6 +-\n tests/test_model_api_immutable_staging.py | 35 +\n 31 files changed, 4108 insertions(+), 19 deletions(-)",
"evidence_closure_oid": "a8b906d1bc24088c19647e98de6a679268f6d0a2",
"forbidden_operations": [
"direct_main_push",
"main_merge_without_owner_approval",
"force_push",
"tag_mutation",
"baseline_mutation",
"registry_mutation",
"production_restart",
"production_cutover",
"live_model_api_cutover",
"history_rewrite",
"secret_commit"
],
"governance": {
"baseline_modified": false,
"direct_main_push": false,
"force_push_used": false,
"history_rewritten": false,
"live_model_api_cutover": false,
"main_merged": false,
"owner_approval_respected": true,
"production_changed": false,
"production_restarted": false,
"registry_modified": false,
"secrets_committed": false,
"tag_rewritten": false
},
"included_path_count": 31,
"integration_branch": "agent/v2r2c1-post-release-mainline-convergence-20260809",
"integration_head_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"logical_commits": [
{
"message": "feat(v2r2c1): converge durable control-plane core",
"oid": "40b685d1c70c767c7a79a2b184348e58e3e319ae",
"parent_oid": "2e8fa22989808a448065d1d76b5b18948774a637"
},
{
"message": "docs(v2r2c1): converge durable runtime and design sources",
"oid": "5f616311bab38b0dac296ed8b0e69660e031a20e",
"parent_oid": "40b685d1c70c767c7a79a2b184348e58e3e319ae"
},
{
"message": "feat(v2r2c1): integrate governed release overlay",
"oid": "57780e316e320a5128cc2c9f12adbb19ae57aef5",
"parent_oid": "5f616311bab38b0dac296ed8b0e69660e031a20e"
},
{
"message": "feat(v2r2c1): wire governed release operations into durable bridge",
"oid": "e41b8d323a3e7a40440f5d32221f524074bea5fe",
"parent_oid": "57780e316e320a5128cc2c9f12adbb19ae57aef5"
},
{
"message": "test: repair canonical pytest repository entrypoint",
"oid": "b20cb8130e4c68267d5d85b02eed51cb8d4f41c0",
"parent_oid": "e41b8d323a3e7a40440f5d32221f524074bea5fe"
},
{
"message": "test: make whole-suite collection deterministic",
"oid": "c6a1693efaede9dace9b929d884a09e162a02c89",
"parent_oid": "b20cb8130e4c68267d5d85b02eed51cb8d4f41c0"
},
{
"message": "test: preserve legacy suite imports under canonical collection",
"oid": "91f2ea0591787d3dbf8c2e27ab0460629d86900e",
"parent_oid": "c6a1693efaede9dace9b929d884a09e162a02c89"
},
{
"message": "test: expose repository test helpers to canonical collection",
"oid": "85897d3f6d708271dff16767265f9d14b2f29801",
"parent_oid": "91f2ea0591787d3dbf8c2e27ab0460629d86900e"
},
{
"message": "fix(v2r2c1): close slash-branch and suite contract regressions",
"oid": "f1110d24f30d8441f2df04e0774ee230b95c2e02",
"parent_oid": "85897d3f6d708271dff16767265f9d14b2f29801"
},
{
"message": "test: align writer regression with durable idempotent replay",
"oid": "c10d2a5dfcc394dde7a7022952d7b423725747a3",
"parent_oid": "f1110d24f30d8441f2df04e0774ee230b95c2e02"
},
{
"message": "feat(v2r2c1): source baseline authority for model-api staging",
"oid": "f969aedaf61501a866435c712be01ff2cfe43fb1",
"parent_oid": "c10d2a5dfcc394dde7a7022952d7b423725747a3"
},
{
"message": "feat(v2r2c1): add immutable model api staging runtime",
"oid": "4ab70bfdb4d34aa9d1dabc4230a3367eaa93cc9b",
"parent_oid": "f969aedaf61501a866435c712be01ff2cfe43fb1"
},
{
"message": "fix(v2r2c1): avoid builder secret-scan false positives",
"oid": "7c4e86bfc1f39e643e672968d1fdedbd72ace56d",
"parent_oid": "4ab70bfdb4d34aa9d1dabc4230a3367eaa93cc9b"
},
{
"message": "fix(v2r2c1): isolate model api staging port",
"oid": "7564363a30bfa7fa81ac5c7c545ec704984ec543",
"parent_oid": "7c4e86bfc1f39e643e672968d1fdedbd72ace56d"
},
{
"message": "fix(v2r2c1): bind baseline authority and openapi staging path",
"oid": "2c6293160ed567a2098715edbb296741577c5bff",
"parent_oid": "7564363a30bfa7fa81ac5c7c545ec704984ec543"
}
],
"main_base_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"mandatory_gates": {
"baseline_registry_readback_staging_pass": true,
"durable_source_path_manifest_complete": true,
"existing_v2r2c1_suite_pass": true,
"governed_release_suite_pass": true,
"integration_authority_git_api_equal": true,
"integration_branch_governed": true,
"logical_slice_commits_remote_verified": true,
"main_base_exact_before_branch_create": true,
"model_api_immutable_runtime_staging_pass": true,
"owner_merge_request_generated_execute_false": true,
"production_unchanged": true,
"pytest_collection_entrypoints_fixed": true,
"pytest_tests_results_recorded": true
},
"model_api_staging": {
"artifact_sha256": "492338b895b152a55015fd92ea1d9dba2314894ab00c0ba219a78f3cef544b8a",
"baseline": {
"authority_sha256": "d8e23bad49bdb3e4192ba708c3dfe7fc5b7cdc6a513c2f87acd6412a51867231",
"current_baseline": "V2R2C1",
"deployment_state": "ACTIVE",
"evidence_closure_oid": "a8b906d1bc24088c19647e98de6a679268f6d0a2",
"generation": 4,
"previous_baseline": "V2R1C7",
"production_deployed": true,
"status": "PRODUCTION_DEPLOYED",
"tag_oid": "07fc2746b688f5f243f29b39de39f32edc3dd9d2",
"target_oid": "998d30304787e31e5ae607c0bd86b5edb2b0e5ad"
},
"baseline_status": 200,
"deployment_state": "STAGING",
"health": {
"artifact_sha256": "492338b895b152a55015fd92ea1d9dba2314894ab00c0ba219a78f3cef544b8a",
"commit_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"deployment_state": "STAGING",
"governed_release_routing": "bridge-v2",
"legacy_global_writes_enabled": false,
"production_deployed": false,
"runtime_mode": "IMMUTABLE_STAGING",
"status": "ok",
"version": "V2R2C1"
},
"health_status": 200,
"legacy_write_probe": "423_BLOCKED",
"port": 18893,
"restart_acceptance": "PASS",
"runtime_root": "/opt/aios/gitops-model-api/2c6293160ed567a2098715edbb296741577c5bff/runtime",
"source_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"systemd": "MainPID=788782\nExecStart={ path=/usr/bin/python3 ; argv[]=/usr/bin/python3 /opt/aios/gitops-model-api/2c6293160ed567a2098715edbb296741577c5bff/runtime/app/aios_model_api_staging.py ; ignore_errors=no ; start_time=[Sun 2026-08-09 19:11:19 CST] ; stop_time=[n/a] ; pid=788782 ; code=(null) ; status=0/0 }\nActiveState=active\nSubState=running",
"unit": "aios-gitops-model-api-v2r2c1-staging.service",
"versions": {
"authoritative_head_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"baseline_generation": 4,
"baseline_sha256": "d8e23bad49bdb3e4192ba708c3dfe7fc5b7cdc6a513c2f87acd6412a51867231",
"baseline_version": "V2R2C1",
"query_error": null
},
"versions_status": 200
},
"owner_merge_request": {
"control_plane_source_oid": "b781129bd5a8b53c05ab648361424d2800166ee4",
"execute": false,
"integration_head_oid": "b2cf510e11b712bb99f20ded81459b6524257394",
"main_expected_old_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"release_target_oid": "998d30304787e31e5ae607c0bd86b5edb2b0e5ad",
"report_commit_oid": "b2cf510e11b712bb99f20ded81459b6524257394",
"status": "OWNER_APPROVAL_REQUIRED"
},
"placeholder_fields": [],
"production": {
"baseline_mutation": false,
"health": {
"artifact_sha256": "ab4ae257346c82863f05abf5e309381a1c86612957608c3a4f4ab5cc9233f052",
"commit_oid": "998d30304787e31e5ae607c0bd86b5edb2b0e5ad",
"deployment_state": "ACTIVE",
"health_timestamp": "2026-08-09T11:21:16.872581+00:00",
"production_deployed": true,
"status": "ok",
"version": "V2R2C1"
},
"health_status": 200,
"live_model_api_show": "MainPID=2816107\nActiveState=active\nSubState=running",
"live_model_api_unchanged": true,
"production_cutover": false,
"production_restart": false,
"registry_mutation": false,
"shadow_service_unchanged": true,
"shadow_show": "MainPID=1505658\nActiveState=active\nSubState=running",
"tag_mutation": false
},
"release_target_oid": "998d30304787e31e5ae607c0bd86b5edb2b0e5ad",
"remote_proof": {
"api_branch_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"api_verification": "paginated_exact_name",
"commit_visible": true,
"git_remote_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"main_api_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"main_git_oid": "2e8fa22989808a448065d1d76b5b18948774a637"
},
"report_commit_parent_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"repository": "aios/aios",
"schema": "aios.v2r2c1.post-release-mainline-convergence.acceptance.v1",
"status": "V2R2C1_MAINLINE_CONVERGENCE_READY_FOR_OWNER_MERGE",
"success_status": "V2R2C1_MAINLINE_CONVERGENCE_READY_FOR_OWNER_MERGE",
"task_id": "TASK-P0-V2R2C1-POST-RELEASE-MAINLINE-CONVERGENCE-20260809",
"tests": {
"collection": "PASS",
"command": "pytest tests",
"failed": 0,
"passed": 709,
"skipped": 2,
"skipped_tests": [
"tests/test_gitea_tag_publication_live.py (live opt-in)",
"tests/test_signer_contract_compatibility.py (live integration opt-in)"
],
"subtests": 154
}
}
@@ -1,89 +0,0 @@
# V2R2C1 post-release mainline convergence diff summary
- task: `TASK-P0-V2R2C1-POST-RELEASE-MAINLINE-CONVERGENCE-20260809`
- repository: `aios/aios`
- main base: `2e8fa22989808a448065d1d76b5b18948774a637`
- release target: `998d30304787e31e5ae607c0bd86b5edb2b0e5ad`
- control-plane source: `b781129bd5a8b53c05ab648361424d2800166ee4`
- implementation integration head before this report commit: `2c6293160ed567a2098715edbb296741577c5bff`
- branch: `agent/v2r2c1-post-release-mainline-convergence-20260809`
## Logical governed commits
| OID | Parent | Message |
|---|---|---|
| `40b685d1c70c767c7a79a2b184348e58e3e319ae` | `2e8fa22989808a448065d1d76b5b18948774a637` | feat(v2r2c1): converge durable control-plane core |
| `5f616311bab38b0dac296ed8b0e69660e031a20e` | `40b685d1c70c767c7a79a2b184348e58e3e319ae` | docs(v2r2c1): converge durable runtime and design sources |
| `57780e316e320a5128cc2c9f12adbb19ae57aef5` | `5f616311bab38b0dac296ed8b0e69660e031a20e` | feat(v2r2c1): integrate governed release overlay |
| `e41b8d323a3e7a40440f5d32221f524074bea5fe` | `57780e316e320a5128cc2c9f12adbb19ae57aef5` | feat(v2r2c1): wire governed release operations into durable bridge |
| `b20cb8130e4c68267d5d85b02eed51cb8d4f41c0` | `e41b8d323a3e7a40440f5d32221f524074bea5fe` | test: repair canonical pytest repository entrypoint |
| `c6a1693efaede9dace9b929d884a09e162a02c89` | `b20cb8130e4c68267d5d85b02eed51cb8d4f41c0` | test: make whole-suite collection deterministic |
| `91f2ea0591787d3dbf8c2e27ab0460629d86900e` | `c6a1693efaede9dace9b929d884a09e162a02c89` | test: preserve legacy suite imports under canonical collection |
| `85897d3f6d708271dff16767265f9d14b2f29801` | `91f2ea0591787d3dbf8c2e27ab0460629d86900e` | test: expose repository test helpers to canonical collection |
| `f1110d24f30d8441f2df04e0774ee230b95c2e02` | `85897d3f6d708271dff16767265f9d14b2f29801` | fix(v2r2c1): close slash-branch and suite contract regressions |
| `c10d2a5dfcc394dde7a7022952d7b423725747a3` | `f1110d24f30d8441f2df04e0774ee230b95c2e02` | test: align writer regression with durable idempotent replay |
| `f969aedaf61501a866435c712be01ff2cfe43fb1` | `c10d2a5dfcc394dde7a7022952d7b423725747a3` | feat(v2r2c1): source baseline authority for model-api staging |
| `4ab70bfdb4d34aa9d1dabc4230a3367eaa93cc9b` | `f969aedaf61501a866435c712be01ff2cfe43fb1` | feat(v2r2c1): add immutable model api staging runtime |
| `7c4e86bfc1f39e643e672968d1fdedbd72ace56d` | `4ab70bfdb4d34aa9d1dabc4230a3367eaa93cc9b` | fix(v2r2c1): avoid builder secret-scan false positives |
| `7564363a30bfa7fa81ac5c7c545ec704984ec543` | `7c4e86bfc1f39e643e672968d1fdedbd72ace56d` | fix(v2r2c1): isolate model api staging port |
| `2c6293160ed567a2098715edbb296741577c5bff` | `7564363a30bfa7fa81ac5c7c545ec704984ec543` | fix(v2r2c1): bind baseline authority and openapi staging path |
## Exact diff stat
```text
active-runtime/app/aios_authority_git_executor.py | 24 +
active-runtime/app/aios_chatgpt_actions_api.py | 48 +-
active-runtime/app/aios_chatgpt_bridge_v2.py | 167 ++++
.../app/aios_chatgpt_bridge_v2_server.py | 431 +++++++++
active-runtime/app/aios_continuation_executor.py | 594 ++++++++++++
active-runtime/app/aios_continuation_lease.py | 6 +
active-runtime/app/aios_control_plane_snapshot.py | 26 +
active-runtime/app/aios_credential_broker.py | 78 ++
active-runtime/app/aios_gitea_publisher.py | 93 ++
active-runtime/app/aios_gitops_job_controller.py | 16 +-
.../app/aios_gitops_reconciliation_core.py | 80 ++
active-runtime/app/aios_governed_policy.py | 59 ++
active-runtime/app/aios_governed_task_bootstrap.py | 84 ++
active-runtime/app/aios_model_api_staging.py | 1022 ++++++++++++++++++++
.../app/authorized_task_writer_provisioning.py | 4 +-
active-runtime/app/baseline_authority.py | 84 ++
active-runtime/app/governed_production_release.py | 568 +++++++++++
active-runtime/app/v2r2c1_production_adapter.py | 135 +++
.../systemd/aios-chatgpt-bridge-v2-staging.service | 23 +
.../aios-gitops-model-api-v2r2c1-staging.service | 51 +
...09-bridge-v2.1-durable-reconciliation-design.md | 15 +
...t-bridge-v2-control-plane-convergence-design.md | 150 +++
pytest.ini | 4 +
scripts/build_v2r2c1_model_api_staging.py | 145 +++
.../aios_release_controller/manifest.py | 4 +-
.../test_v2r1c6_release_consistency.py | 4 +-
.../aios_v2_candidate/test_v2r1c6_release_ready.py | 16 +-
tests/conftest.py | 65 ++
tests/test_bridge_v2_governed_http_bootstrap.py | 90 ++
tests/test_governed_local_writer.py | 6 +-
tests/test_model_api_immutable_staging.py | 35 +
31 files changed, 4108 insertions(+), 19 deletions(-)
```
## Included durable source domains
- Bridge v2 adapter/server and governed HTTP contracts.
- Durable reconciliation core, continuation executor/lease, Authority Git CAS adapter, job controller compatibility.
- Gitea publisher/verifier, credential broker, governed policy, control-plane snapshot, release routing.
- Canonical pytest entrypoint/conftest and regression coverage.
- Source-controlled immutable model-api staging runtime, builder and systemd template.
- Selected design specifications required for durable mainline context.
## Explicitly excluded
- `main` ref mutation or merge without Owner approval.
- Production service, Registry, Baseline body/sidecar, production tags and mutable `/var/lib` state.
- Installed `/opt` artifacts, temporary staging transition state and task-local receipts/credentials.
- Production cutover/restart, force push, history rewrite and plaintext secrets.
## Verification
- `pytest tests`: **709 passed, 2 skipped, 154 subtests, 0 failed**.
- Staging model-api: immutable OID/digest bound, port 18893, health/base/ver/OpenAPI readback PASS, restart recovery PASS.
- Authority/Gitea Git/Gitea API commit equality and commit visibility PASS.
- Production remains V2R2C1 and was not restarted or cut over.
@@ -1,254 +0,0 @@
{
"control_plane_source_oid": "b781129bd5a8b53c05ab648361424d2800166ee4",
"diff_stat": "active-runtime/app/aios_authority_git_executor.py | 24 +\n active-runtime/app/aios_chatgpt_actions_api.py | 48 +-\n active-runtime/app/aios_chatgpt_bridge_v2.py | 167 ++++\n .../app/aios_chatgpt_bridge_v2_server.py | 431 +++++++++\n active-runtime/app/aios_continuation_executor.py | 594 ++++++++++++\n active-runtime/app/aios_continuation_lease.py | 6 +\n active-runtime/app/aios_control_plane_snapshot.py | 26 +\n active-runtime/app/aios_credential_broker.py | 78 ++\n active-runtime/app/aios_gitea_publisher.py | 93 ++\n active-runtime/app/aios_gitops_job_controller.py | 16 +-\n .../app/aios_gitops_reconciliation_core.py | 80 ++\n active-runtime/app/aios_governed_policy.py | 59 ++\n active-runtime/app/aios_governed_task_bootstrap.py | 84 ++\n active-runtime/app/aios_model_api_staging.py | 1022 ++++++++++++++++++++\n .../app/authorized_task_writer_provisioning.py | 4 +-\n active-runtime/app/baseline_authority.py | 84 ++\n active-runtime/app/governed_production_release.py | 568 +++++++++++\n active-runtime/app/v2r2c1_production_adapter.py | 135 +++\n .../systemd/aios-chatgpt-bridge-v2-staging.service | 23 +\n .../aios-gitops-model-api-v2r2c1-staging.service | 51 +\n ...09-bridge-v2.1-durable-reconciliation-design.md | 15 +\n ...t-bridge-v2-control-plane-convergence-design.md | 150 +++\n pytest.ini | 4 +\n scripts/build_v2r2c1_model_api_staging.py | 145 +++\n .../aios_release_controller/manifest.py | 4 +-\n .../test_v2r1c6_release_consistency.py | 4 +-\n .../aios_v2_candidate/test_v2r1c6_release_ready.py | 16 +-\n tests/conftest.py | 65 ++\n tests/test_bridge_v2_governed_http_bootstrap.py | 90 ++\n tests/test_governed_local_writer.py | 6 +-\n tests/test_model_api_immutable_staging.py | 35 +\n 31 files changed, 4108 insertions(+), 19 deletions(-)",
"evidence_closure_oid": "a8b906d1bc24088c19647e98de6a679268f6d0a2",
"excluded_paths": [
{
"path": "refs/heads/main",
"reason": "main merge requires separate Owner approval; unchanged"
},
{
"path": "refs/tags/*",
"reason": "formal tags are outside engineering convergence scope; unchanged"
},
{
"path": "baseline/current.json and sidecar",
"reason": "production mutable authority and sidecar; read-only verified"
},
{
"path": "/var/lib/aios-gitops/**",
"reason": "host runtime state and receipts excluded from repository source"
},
{
"path": "/opt/aios/**",
"reason": "installed immutable staging artifacts excluded; digest recorded in reports"
},
{
"path": "credentials and secrets",
"reason": "availability-only; no plaintext credential committed"
},
{
"path": "production runtime and Registry",
"reason": "production cutover/registry mutation forbidden"
}
],
"included_paths": [
{
"path": "active-runtime/app/aios_authority_git_executor.py",
"status": "M"
},
{
"path": "active-runtime/app/aios_chatgpt_actions_api.py",
"status": "M"
},
{
"path": "active-runtime/app/aios_chatgpt_bridge_v2.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_chatgpt_bridge_v2_server.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_continuation_executor.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_continuation_lease.py",
"status": "M"
},
{
"path": "active-runtime/app/aios_control_plane_snapshot.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_credential_broker.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_gitea_publisher.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_gitops_job_controller.py",
"status": "M"
},
{
"path": "active-runtime/app/aios_gitops_reconciliation_core.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_governed_policy.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_governed_task_bootstrap.py",
"status": "A"
},
{
"path": "active-runtime/app/aios_model_api_staging.py",
"status": "A"
},
{
"path": "active-runtime/app/authorized_task_writer_provisioning.py",
"status": "M"
},
{
"path": "active-runtime/app/baseline_authority.py",
"status": "A"
},
{
"path": "active-runtime/app/governed_production_release.py",
"status": "A"
},
{
"path": "active-runtime/app/v2r2c1_production_adapter.py",
"status": "A"
},
{
"path": "deploy/systemd/aios-chatgpt-bridge-v2-staging.service",
"status": "A"
},
{
"path": "deploy/systemd/aios-gitops-model-api-v2r2c1-staging.service",
"status": "A"
},
{
"path": "docs/superpowers/specs/2026-08-09-bridge-v2.1-durable-reconciliation-design.md",
"status": "A"
},
{
"path": "docs/superpowers/specs/2026-08-09-chatgpt-bridge-v2-control-plane-convergence-design.md",
"status": "A"
},
{
"path": "pytest.ini",
"status": "A"
},
{
"path": "scripts/build_v2r2c1_model_api_staging.py",
"status": "A"
},
{
"path": "services/aios-release-controller/aios_release_controller/manifest.py",
"status": "M"
},
{
"path": "tests/aios_v2_candidate/test_v2r1c6_release_consistency.py",
"status": "M"
},
{
"path": "tests/aios_v2_candidate/test_v2r1c6_release_ready.py",
"status": "M"
},
{
"path": "tests/conftest.py",
"status": "A"
},
{
"path": "tests/test_bridge_v2_governed_http_bootstrap.py",
"status": "A"
},
{
"path": "tests/test_governed_local_writer.py",
"status": "M"
},
{
"path": "tests/test_model_api_immutable_staging.py",
"status": "A"
}
],
"integration_branch": "agent/v2r2c1-post-release-mainline-convergence-20260809",
"integration_head_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"logical_commits": [
{
"message": "feat(v2r2c1): converge durable control-plane core",
"oid": "40b685d1c70c767c7a79a2b184348e58e3e319ae",
"parent_oid": "2e8fa22989808a448065d1d76b5b18948774a637"
},
{
"message": "docs(v2r2c1): converge durable runtime and design sources",
"oid": "5f616311bab38b0dac296ed8b0e69660e031a20e",
"parent_oid": "40b685d1c70c767c7a79a2b184348e58e3e319ae"
},
{
"message": "feat(v2r2c1): integrate governed release overlay",
"oid": "57780e316e320a5128cc2c9f12adbb19ae57aef5",
"parent_oid": "5f616311bab38b0dac296ed8b0e69660e031a20e"
},
{
"message": "feat(v2r2c1): wire governed release operations into durable bridge",
"oid": "e41b8d323a3e7a40440f5d32221f524074bea5fe",
"parent_oid": "57780e316e320a5128cc2c9f12adbb19ae57aef5"
},
{
"message": "test: repair canonical pytest repository entrypoint",
"oid": "b20cb8130e4c68267d5d85b02eed51cb8d4f41c0",
"parent_oid": "e41b8d323a3e7a40440f5d32221f524074bea5fe"
},
{
"message": "test: make whole-suite collection deterministic",
"oid": "c6a1693efaede9dace9b929d884a09e162a02c89",
"parent_oid": "b20cb8130e4c68267d5d85b02eed51cb8d4f41c0"
},
{
"message": "test: preserve legacy suite imports under canonical collection",
"oid": "91f2ea0591787d3dbf8c2e27ab0460629d86900e",
"parent_oid": "c6a1693efaede9dace9b929d884a09e162a02c89"
},
{
"message": "test: expose repository test helpers to canonical collection",
"oid": "85897d3f6d708271dff16767265f9d14b2f29801",
"parent_oid": "91f2ea0591787d3dbf8c2e27ab0460629d86900e"
},
{
"message": "fix(v2r2c1): close slash-branch and suite contract regressions",
"oid": "f1110d24f30d8441f2df04e0774ee230b95c2e02",
"parent_oid": "85897d3f6d708271dff16767265f9d14b2f29801"
},
{
"message": "test: align writer regression with durable idempotent replay",
"oid": "c10d2a5dfcc394dde7a7022952d7b423725747a3",
"parent_oid": "f1110d24f30d8441f2df04e0774ee230b95c2e02"
},
{
"message": "feat(v2r2c1): source baseline authority for model-api staging",
"oid": "f969aedaf61501a866435c712be01ff2cfe43fb1",
"parent_oid": "c10d2a5dfcc394dde7a7022952d7b423725747a3"
},
{
"message": "feat(v2r2c1): add immutable model api staging runtime",
"oid": "4ab70bfdb4d34aa9d1dabc4230a3367eaa93cc9b",
"parent_oid": "f969aedaf61501a866435c712be01ff2cfe43fb1"
},
{
"message": "fix(v2r2c1): avoid builder secret-scan false positives",
"oid": "7c4e86bfc1f39e643e672968d1fdedbd72ace56d",
"parent_oid": "4ab70bfdb4d34aa9d1dabc4230a3367eaa93cc9b"
},
{
"message": "fix(v2r2c1): isolate model api staging port",
"oid": "7564363a30bfa7fa81ac5c7c545ec704984ec543",
"parent_oid": "7c4e86bfc1f39e643e672968d1fdedbd72ace56d"
},
{
"message": "fix(v2r2c1): bind baseline authority and openapi staging path",
"oid": "2c6293160ed567a2098715edbb296741577c5bff",
"parent_oid": "7564363a30bfa7fa81ac5c7c545ec704984ec543"
}
],
"main_base_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"release_target_oid": "998d30304787e31e5ae607c0bd86b5edb2b0e5ad",
"remote_proof": {
"api_branch_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"api_verification": "paginated_exact_name",
"commit_visible": true,
"git_remote_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"main_api_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"main_git_oid": "2e8fa22989808a448065d1d76b5b18948774a637"
},
"report_commit_parent_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"repository": "aios/aios",
"schema": "aios.v2r2c1.post-release-mainline-convergence.path-manifest.v1",
"task_id": "TASK-P0-V2R2C1-POST-RELEASE-MAINLINE-CONVERGENCE-20260809"
}
@@ -1,37 +0,0 @@
{
"artifact_sha256": "492338b895b152a55015fd92ea1d9dba2314894ab00c0ba219a78f3cef544b8a",
"baseline_authority_path": "/var/lib/aios-gitops-runtime-anchor/baseline/current.json",
"checks": {
"artifact_sha256": "PASS",
"baseline_registry_readback": "PASS",
"health_contract": "PASS",
"legacy_write_rejection": "PASS",
"live_service_unchanged": "PASS",
"manifest_binding": "PASS",
"openapi_readback": "PASS",
"restart_recovery": "PASS"
},
"current_live_port": 18890,
"current_live_service": "aios-gitops-model-api.service",
"deployment_state": "STAGING",
"execute": false,
"governed_release_routing": "bridge-v2",
"legacy_global_writes_enabled": false,
"live_cutover": false,
"owner_actions_required": [
"review exact source OID and artifact SHA",
"approve a separate future live model-api cutover",
"approve any production service transition"
],
"production_restart": false,
"repository_identity": "aios/aios",
"runtime_mode": "IMMUTABLE_STAGING",
"schema": "aios.v2r2c1.model-api-runtime-activation-plan.v1",
"source_oid": "2c6293160ed567a2098715edbb296741577c5bff",
"staging_port": 18893,
"staging_runtime_root": "/opt/aios/gitops-model-api/2c6293160ed567a2098715edbb296741577c5bff/runtime",
"staging_service": "aios-gitops-model-api-v2r2c1-staging.service",
"status": "OWNER_APPROVAL_REQUIRED",
"target_version": "V2R2C1",
"task_id": "TASK-P0-V2R2C1-POST-RELEASE-MAINLINE-CONVERGENCE-20260809"
}
@@ -0,0 +1,44 @@
{
"schema": "aios.bridge-v2-engineering-staging-acceptance.v1",
"task_id": "TASK-P0-CHATGPT-BRIDGE-V2-CONTROL-PLANE-CONVERGENCE-20260809",
"repository": "aios/aios",
"branch": "agent/p0-chatgpt-bridge-v2-control-plane-convergence-20260809",
"control_plane_release_version": "bridge-v2-aa0c37b8ab33",
"control_plane_target_oid": "aa0c37b8ab333616e1bab9686cf6d10557f2ebda",
"artifact_sha256": "08670c78cf760bfe693e3553e676eb751dadd7834116aa6d40e7c094f1357ae4",
"runtime_path": "/opt/aios/gitops-control-plane/aa0c37b8ab333616e1bab9686cf6d10557f2ebda",
"bridge_schema_version": "aios.chatgpt-gitops-bridge.v2",
"deployment_state": "STAGING",
"drift_status": "PASS",
"restart_acceptance": {
"pid_before": 3158850,
"pid_after": 3159889,
"runtime_response_equal": true
},
"governed_capabilities": {
"legacy_writes_enabled": false,
"governed_writes_enabled": true,
"force_push": false,
"main_write": false,
"tag_write": false,
"baseline_write": false,
"production_write": false
},
"production_invariants": {
"authority_main_oid": "2e8fa22989808a448065d1d76b5b18948774a637",
"authority_tags_sha256": "bd2b6e30b76f28e7fcdcb447e7296690f0a65ad855209294c36b0f3f1d96098d",
"baseline_current_sha256": "57651eb819584ab7c1d67f01b0ef66d6408cdc322ae5f6d4ff0aacd96f8327e1",
"production_service_main_pid": 2816107,
"production_service_nrestarts": 0,
"production_service_active_enter_timestamp_monotonic": 2919386492273
},
"bridge_operation_sequence": {
"createGovernedTask": "PASS",
"acquireWriterLease": "PASS",
"commitFilesGoverned": "REAL_GOVERNED_COMMIT",
"getGitOpsJob": "PASS",
"expected_branch_oid": "8fe3b85c1be592326473e81a502a23eeb9511d30",
"generation": 7
},
"production_changed": false
}
@@ -0,0 +1,17 @@
{
"schema": "aios.bridge-v2.1-durable-reconciliation.bootstrap-acceptance.v1",
"task_id": "TASK-P0-BRIDGE-V21-DURABLE-RECONCILIATION-20260809",
"repository": "aios/aios",
"base_oid": "3f670c387692b8865a10d5b419468d8a0b64d7a4",
"target_branch": "agent/p0-bridge-v21-durable-reconciliation-20260809",
"branch_mode": "CREATE_NEW",
"generation": 1,
"implementation": "not_started",
"production_changed": false,
"required_proofs": [
"absent_ref_cas",
"observation_first_reconciliation",
"authority_gitea_api_commit_equality",
"commit_visible"
]
}
-145
View File
@@ -1,145 +0,0 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import hashlib
import json
import os
from pathlib import Path
import tarfile
import tempfile
SCHEMA = 'aios.v2r2c1.model-api-staging-manifest.v1'
REQUIRED_APP = (
'aios_model_api_staging.py',
'aios_gitops_write_guard.py',
'authoritative_git.py',
'baseline_authority.py',
'gitea_tag_publication.py',
'silent_release_controller.py',
'silent_release_hardening.py',
'aios_gitops_job_controller.py',
)
OPTIONAL_APP = (
'aios_chatgpt_actions_api.py',
'aios_continuation_executor.py',
'aios_continuation_lease.py',
'aios_control_plane_snapshot.py',
)
def sha256(path: Path) -> str:
h = hashlib.sha256()
with path.open('rb') as fh:
for chunk in iter(lambda: fh.read(1024 * 1024), b''):
h.update(chunk)
return h.hexdigest()
def private_marker(path: Path) -> bool:
import re
text = path.read_text(encoding='utf-8', errors='ignore')
patterns = (
r'-----BEGIN [A-Z ]*PRIVATE KEY-----',
r'(?<![A-Za-z0-9])sk-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])',
r'(?<![A-Za-z0-9])ghp_[A-Za-z0-9]{20,}(?![A-Za-z0-9])',
r'(?i)aws_secret_access_key\s*[:=]\s*[A-Za-z0-9/+=]{16,}',
)
return any(re.search(pattern, text) for pattern in patterns)
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument('--source-root', required=True, type=Path)
ap.add_argument('--output-root', required=True, type=Path)
ap.add_argument('--source-oid', required=True)
args = ap.parse_args()
oid = args.source_oid.lower()
if len(oid) != 40 or any(c not in '0123456789abcdef' for c in oid):
raise SystemExit('source oid must be exact 40 hex')
source = args.source_root.resolve(strict=True)
output = args.output_root.resolve()
app = source / 'active-runtime' / 'app'
runtime = source / 'runtime' / 'agent-os'
docs = source / 'docs' / 'gitops'
if not app.is_dir():
raise SystemExit('active-runtime/app missing')
paths = []
for name in REQUIRED_APP:
path = app / name
if not path.is_file():
raise SystemExit(f'required app dependency missing: {name}')
paths.append((Path('app') / name, path))
for name in OPTIONAL_APP:
path = app / name
if path.is_file():
paths.append((Path('app') / name, path))
for rel in ('orchestrator/__init__.py', 'orchestrator/action_monitor.py'):
path = runtime / rel
if not path.is_file():
raise SystemExit(f'required runtime dependency missing: {rel}')
paths.append((Path('runtime-agent-os') / rel, path))
openapi = docs / 'openapi-chatgpt-actions.yaml'
if openapi.is_file():
paths.append((Path('docs') / 'gitops' / 'openapi-chatgpt-actions.yaml', openapi))
for folder in ('config/model_registry', 'config/model_priority', 'patches', 'versions'):
root = source / folder
if root.is_dir():
for path in sorted(root.rglob('*')):
if path.is_file() and path.suffix.lower() in {'.json', '.yaml', '.yml', '.md'}:
paths.append((Path(folder) / path.relative_to(root), path))
for rel, path in paths:
if private_marker(path):
raise SystemExit(f'private marker rejected: {rel}')
included = [str(rel).replace('\\', '/') for rel, _ in paths]
manifest = {
'schema': SCHEMA,
'target_version': 'V2R2C1',
'source_oid': oid,
'repository_identity': 'aios/aios',
'deployment_state': 'STAGING',
'runtime_mode': 'IMMUTABLE_STAGING',
'runtime_entrypoint': 'app/aios_model_api_staging.py',
'legacy_global_writes_enabled': False,
'governed_release_routing': 'bridge-v2',
'artifact_sha256': 'provided-by-build-receipt-and-install-manifest',
'included_paths': included,
}
output.mkdir(parents=True, exist_ok=True)
archive = output / f'aios-v2r2c1-model-api-{oid}.tar.gz'
with tempfile.TemporaryDirectory(prefix='v2r2c1-model-api-', dir=str(output)) as tmp:
root = Path(tmp) / 'runtime'
for rel, path in paths:
target = root / rel
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes(path.read_bytes())
(root / 'manifest.json').write_text(json.dumps(manifest, ensure_ascii=False, indent=2, sort_keys=True) + '\n', encoding='utf-8')
with tarfile.open(archive, 'w:gz', format=tarfile.PAX_FORMAT) as tf:
for path in sorted(root.rglob('*')):
rel = path.relative_to(root.parent)
info = tf.gettarinfo(str(path), arcname=str(rel).replace('\\', '/'))
info.mtime = 0
info.uid = 0
info.gid = 0
info.uname = 'root'
info.gname = 'root'
if path.is_file():
with path.open('rb') as fh:
tf.addfile(info, fh)
else:
tf.addfile(info)
digest = sha256(archive)
receipt = {
'schema': 'aios.v2r2c1.model-api-staging-build-receipt.v1',
'target_version': 'V2R2C1',
'source_oid': oid,
'repository_identity': 'aios/aios',
'artifact_path': str(archive),
'artifact_sha256': digest,
'deployment_state': 'STAGING',
'manifest_schema': SCHEMA,
'included_paths': included,
}
receipt_path = output / f'aios-v2r2c1-model-api-{oid}.receipt.json'
receipt_path.write_text(json.dumps(receipt, ensure_ascii=False, indent=2, sort_keys=True) + '\n', encoding='utf-8')
print(json.dumps(receipt, ensure_ascii=False, indent=2, sort_keys=True))
return 0
if __name__ == '__main__':
raise SystemExit(main())
@@ -3,13 +3,13 @@ from __future__ import annotations
import json import json
from pathlib import Path from pathlib import Path
ROOT = Path(__file__).parents[2] ROOT = Path(__file__).parents[2]
def test_version_and_candidate_binding(): def test_version_and_candidate_binding():
assert (ROOT / "VERSION").read_text(encoding="utf-8").strip() == "V2R1C7" assert (ROOT / "VERSION").read_text(encoding="utf-8").strip() == "V2R1C6"
metadata = json.loads((ROOT / "versions/V2R1C6.json").read_text(encoding="utf-8")) metadata = json.loads((ROOT / "versions/V2R1C6.json").read_text(encoding="utf-8"))
assert metadata["version"] == "V2R1C6"
assert metadata["base_oid"] == "a33e2593967a180c89d44454350ccaeaf3f79b25" assert metadata["base_oid"] == "a33e2593967a180c89d44454350ccaeaf3f79b25"
assert metadata["candidate_branch"] == "agent/v2r1c6-mainline-reconciliation-20260806" assert metadata["candidate_branch"] == "agent/v2r1c6-mainline-reconciliation-20260806"
assert metadata["production_deployed"] is False assert metadata["production_deployed"] is False
@@ -7,19 +7,17 @@ import pytest
ROOT = Path(__file__).resolve().parents[2] ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "active-runtime" / "app")) sys.path.insert(0, str(ROOT / "active-runtime" / "app"))
from deployment_state import RuntimeDeploymentState
from v2r1c6_privacy_tools import health_payload, serve # noqa: E402 from v2r1c6_privacy_tools import health_payload, serve # noqa: E402
def test_health_is_engineering_only() -> None: def test_health_is_engineering_only() -> None:
result = health_payload(RuntimeDeploymentState("V2R1C7", "a" * 40, "b" * 64, "STAGED")) result = health_payload()
assert result["status"] == "ok" assert result == {
assert result["version"] == "V2R1C7" "status": "ok",
assert result["commit_oid"] == "a" * 40 "version": "V2R1C6",
assert result["artifact_sha256"] == "b" * 64 "production_deployed": False,
assert result["deployment_state"] == "STAGED" "gitops_writes_enabled": False,
assert result["production_deployed"] is False }
assert result["health_timestamp"]
def test_listener_rejects_non_loopback() -> None: def test_listener_rejects_non_loopback() -> None:
-65
View File
@@ -1,65 +0,0 @@
from __future__ import annotations
import importlib.util
import sys
import types
from pathlib import Path
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
TEST_ROOT = REPOSITORY_ROOT / "tests"
SERVICE_PACKAGE_ROOT = REPOSITORY_ROOT / "services" / "aios-autonomous-release-candidate"
ACTIVE_RUNTIME_ROOT = REPOSITORY_ROOT / "active-runtime"
ACTIVE_RUNTIME_APP = ACTIVE_RUNTIME_ROOT / "app"
for path in (TEST_ROOT, SERVICE_PACKAGE_ROOT, ACTIVE_RUNTIME_APP):
value = str(path)
if value not in sys.path:
sys.path.insert(0, value)
def load_module(relative: str):
path = REPOSITORY_ROOT / relative
spec = importlib.util.spec_from_file_location("v2r1c6_privacy_tools", path)
if spec is None or spec.loader is None:
raise RuntimeError("module_load_failed")
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
def _install_active_runtime_namespace() -> None:
package = sys.modules.get("active_runtime")
if package is None:
package = types.ModuleType("active_runtime")
package.__path__ = [str(ACTIVE_RUNTIME_ROOT)]
package.__package__ = "active_runtime"
sys.modules["active_runtime"] = package
app = sys.modules.get("active_runtime.app")
if app is None:
app = types.ModuleType("active_runtime.app")
app.__path__ = [str(ACTIVE_RUNTIME_APP)]
app.__package__ = "active_runtime"
sys.modules["active_runtime.app"] = app
package.app = app
def _install_legacy_test_module(name: str, relative: str) -> None:
if name in sys.modules:
return
path = REPOSITORY_ROOT / relative
spec = importlib.util.spec_from_file_location(name, path)
if spec is None or spec.loader is None:
raise RuntimeError("legacy_test_module_load_failed:" + name)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
_install_active_runtime_namespace()
sys.modules.setdefault("conftest", sys.modules[__name__])
_install_legacy_test_module(
"test_native_adapter_contracts",
"tests/autonomous_release/test_native_adapter_contracts.py",
)
+1 -1
View File
@@ -264,7 +264,7 @@ class TagActionTests(unittest.TestCase):
ROOT / "docs" / "gitops" / "openapi-chatgpt-actions.yaml" ROOT / "docs" / "gitops" / "openapi-chatgpt-actions.yaml"
).read_text(encoding="utf-8") ).read_text(encoding="utf-8")
self.assertIn( self.assertIn(
"required: [version, target_oid, evidence_closure_oid, approval_plan_id]", "required: [version, target_oid, evidence_closure_oid, approval_plan_id, execute]",
schema, schema,
) )
self.assertIn("x-openai-isConsequential: true", schema) self.assertIn("x-openai-isConsequential: true", schema)
+87
View File
@@ -0,0 +1,87 @@
from __future__ import annotations
import hashlib
import json
from pathlib import Path
import tempfile
import pytest
import yaml
from aios_chatgpt_bridge_v2 import (
BRIDGE_OPERATIONS,
BRIDGE_SCHEMA_VERSION,
OPERATION_REQUIRED_FIELDS,
BridgeV2Adapter,
ControlPlaneReleaseManifest,
RuntimeDriftError,
)
ROOT = Path(__file__).parents[1]
def test_immutable_release_identity_accepts_exact_artifact_and_rejects_workspace_drift():
with tempfile.TemporaryDirectory() as directory:
approved = Path(directory) / "releases"
runtime = approved / "release-1"
runtime.mkdir(parents=True)
artifact = runtime / "bridge.pyz"
artifact.write_bytes(b"bridge-v2")
digest = hashlib.sha256(artifact.read_bytes()).hexdigest()
manifest = ControlPlaneReleaseManifest(
"bridge-v2-test", "a" * 40, digest, runtime, BRIDGE_SCHEMA_VERSION,
"aios/aios", Path("/data/aios-gitops/repo.git"), "STAGING",
)
assert manifest.validate(artifact, observed_oid="a" * 40, approved_root=approved)["drift_status"] == "PASS"
with pytest.raises(RuntimeDriftError, match="CONTROL_PLANE_RUNTIME_DRIFT"):
manifest.validate(artifact, observed_oid="b" * 40, approved_root=approved)
mutable = ControlPlaneReleaseManifest(
"bad", "a" * 40, digest, Path("/var/lib/worktrees/dev"), BRIDGE_SCHEMA_VERSION,
"aios/aios", Path("/data/aios-gitops/repo.git"), "STAGING",
)
with pytest.raises(RuntimeDriftError, match="CONTROL_PLANE_RUNTIME_DRIFT"):
mutable.validate(artifact, observed_oid="a" * 40, approved_root=approved)
def test_bridge_capabilities_keep_legacy_closed_and_expose_exact_operations():
adapter = BridgeV2Adapter(runtime_status={"drift_status": "PASS"})
assert adapter.getRuntimeStatus()["bridge_schema_version"] == BRIDGE_SCHEMA_VERSION
capabilities = adapter.getGovernedWriteCapabilities()
assert capabilities["legacy_writes_enabled"] is False
assert capabilities["governed_writes_enabled"] is True
assert tuple(capabilities["operations"]) == BRIDGE_OPERATIONS
assert adapter.legacy_write_disabled() == {
"error": "LEGACY_WRITE_DISABLED",
"replacement": "createGovernedTask",
"governed_writes_available": True,
}
def test_openapi_runtime_and_fragment_required_fields_are_exactly_converged():
canonical = yaml.safe_load((ROOT / "docs/gitops/openapi-chatgpt-actions.yaml").read_text(encoding="utf-8"))
fragment = yaml.safe_load((ROOT / "docs/gitops/openapi-authorized-task-writer-fragment.yaml").read_text(encoding="utf-8"))
operations = {}
for path, methods in canonical["paths"].items():
for method, value in methods.items():
if isinstance(value, dict) and value.get("operationId") in BRIDGE_OPERATIONS:
operations[value["operationId"]] = value
assert set(operations) == set(BRIDGE_OPERATIONS)
for operation, required in OPERATION_REQUIRED_FIELDS.items():
schema = operations[operation]["requestBody"]["content"]["application/json"]["schema"]
assert tuple(schema["required"]) == required
fragment_required = tuple(fragment["components"]["schemas"]["WriterLeaseRequestV2"]["required"])
assert fragment_required == OPERATION_REQUIRED_FIELDS["acquireWriterLease"]
def test_release_manifest_round_trip_contains_only_declared_identity_fields():
manifest = ControlPlaneReleaseManifest(
"v", "a" * 40, "b" * 64, Path("/opt/aios/gitops-control-plane/v"), BRIDGE_SCHEMA_VERSION,
"aios/aios", Path("/data/aios-gitops/repo.git"), "STAGING",
)
value = manifest.as_dict()
assert tuple(value) == (
"control_plane_release_version", "control_plane_target_oid", "artifact_sha256", "runtime_path",
"bridge_schema_version", "repository_identity", "authoritative_git_dir", "deployment_state",
)
assert "credential" not in json.dumps(value).lower()
@@ -1,285 +0,0 @@
from __future__ import annotations
import base64
from datetime import datetime, timedelta, timezone
import json
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import pytest
from aios_existing_branch_approval import (
DurableNonceReplayLedger,
OwnerApprovalEnvelope,
OwnerApprovalRejected,
OwnerApprovalVerifier,
TrustRootEvidence,
)
from aios_existing_branch_publisher import (
ExistingBranchPublicationRejected,
ExistingBranchPublisher,
RemoteBranchObservation,
RemotePublicationEvidence,
)
BASE_OID = "a" * 40
COMMIT_OID = "b" * 40
BRANCH = "agent/owner-approval-contract-20260810"
class TrustRoot:
def __init__(self, public_key: bytes, *, revocation: str = "ACTIVE") -> None:
self.public_key = public_key
self.revocation = revocation
self.calls: list[str] = []
def resolve(self, *, key_id: str, owner_identity: str, trust_domain: str):
self.calls.append("trust-root")
return TrustRootEvidence(
key_id=key_id,
owner_identity=owner_identity,
trust_domain=trust_domain,
public_key=self.public_key,
authority_confirmed=True,
revocation_state=self.revocation,
)
class Credentials:
def __init__(self, events: list[str]) -> None:
self.events = events
def project(self) -> None:
self.events.append("credential-project")
def revoke(self) -> None:
self.events.append("credential-revoke")
class Workspace:
def __init__(self, events: list[str]) -> None:
self.events = events
def head_oid(self) -> str:
self.events.append("workspace-head")
return BASE_OID
def commit_payload(self, payload):
self.events.append("workspace-commit")
return COMMIT_OID
class Workspaces:
def __init__(self, events: list[str]) -> None:
self.events = events
def open_detached(self, expected_branch_oid: str) -> Workspace:
assert expected_branch_oid == BASE_OID
self.events.append("workspace-open")
return Workspace(self.events)
class Remote:
def __init__(self, events: list[str]) -> None:
self.events = events
self.observation = RemoteBranchObservation("PRESENT", BASE_OID, BASE_OID, True)
self.authority_oid = BASE_OID
self.pushes: list[tuple[str, str, str]] = []
def read_branch_oid(self, branch: str) -> str:
self.events.append("authority-observe")
assert branch == BRANCH
return self.authority_oid
def observe(self, branch: str) -> RemoteBranchObservation:
self.events.append("remote-observe")
assert branch == BRANCH
return self.observation
def publish_compare_and_swap(self, branch: str, expected: str, commit: str):
self.events.append("remote-publish")
self.pushes.append((branch, expected, commit))
return RemotePublicationEvidence(COMMIT_OID, COMMIT_OID, COMMIT_OID, True)
class Audit:
def __init__(self) -> None:
self.rows: list[dict] = []
def record(self, event) -> None:
self.rows.append(dict(event))
def request(*, payload=None, branch=BRANCH, expected_oid=BASE_OID):
return {
"schema": "aios.existing-branch-publication.v1",
"repository": "aios/aios",
"branch": branch,
"expected_branch_oid": expected_oid,
"operation": "publishExistingBranchGoverned",
"idempotency_key": "owner-approval-binding-20260810",
"payload": {"files": ["active-runtime/app/example.py"]} if payload is None else payload,
}
def signed_approval(private: Ed25519PrivateKey, request_value, **replacements):
from aios_existing_branch_publisher import ExistingBranchPublicationRequest
parsed = ExistingBranchPublicationRequest.from_mapping(request_value)
now = datetime.now(timezone.utc)
raw = {
"schema": "aios.existing-branch-owner-approval.v1",
"approval_id": "approval-owner-binding-20260810",
"repository": parsed.repository,
"branch": parsed.branch,
"expected_branch_oid": parsed.expected_branch_oid,
"operation": "publishExistingBranchGoverned",
"issued_at": (now - timedelta(seconds=30)).isoformat(),
"not_before": (now - timedelta(seconds=1)).isoformat(),
"expires_at": (now + timedelta(minutes=5)).isoformat(),
"nonce": "nonce-owner-binding-20260810",
"owner_identity": "owner.aios",
"trust_domain": "aios-owner-root",
"key_id": "owner-key-20260810",
"request_digest": parsed.request_digest,
"idempotency_digest": parsed.idempotency_digest,
"signature": "AA==",
}
raw.update(replacements)
envelope = OwnerApprovalEnvelope.from_mapping(raw)
raw["signature"] = base64.b64encode(private.sign(envelope.canonical_bytes())).decode("ascii")
return raw
def service(tmp_path, *, revocation="ACTIVE"):
private = Ed25519PrivateKey.generate()
public_key = private.public_key().public_bytes(
serialization.Encoding.Raw, serialization.PublicFormat.Raw
)
root = TrustRoot(public_key, revocation=revocation)
events: list[str] = []
remote = Remote(events)
audit = Audit()
publisher = ExistingBranchPublisher(
verifier=OwnerApprovalVerifier(root, allowed_trust_domains={"aios-owner-root"}),
replay_ledger=DurableNonceReplayLedger(tmp_path / "replay"),
authority=remote,
remote=remote,
credentials=Credentials(events),
workspaces=Workspaces(events),
audit=audit,
)
return private, root, events, remote, audit, publisher
def test_valid_signed_owner_approval_is_verified_before_capability_projection(tmp_path):
private, root, events, remote, audit, publisher = service(tmp_path)
value = request()
approval = signed_approval(private, value)
result = publisher.publish(value, approval)
assert result["status"] == "PUBLISHED"
assert result["commit_oid"] == COMMIT_OID
assert remote.pushes == [(BRANCH, BASE_OID, COMMIT_OID)]
assert events == [
"authority-observe",
"remote-observe",
"workspace-open",
"workspace-head",
"credential-project",
"workspace-commit",
"remote-publish",
"credential-revoke",
]
assert root.calls == ["trust-root"]
assert approval["signature"] not in json.dumps(audit.rows)
assert "signature" not in audit.rows[-1]
@pytest.mark.parametrize(
"case",
[
"invalid_signature",
"expired",
"revoked",
"missing_key_evidence",
"missing_revocation_evidence",
"wrong_repository",
"wrong_branch",
"wrong_oid",
"wrong_operation",
"arbitrary_reference",
],
)
def test_invalid_owner_approval_inputs_are_rejected_without_publication(tmp_path, case):
private, root, events, remote, _, publisher = service(
tmp_path, revocation="REVOKED" if case == "revoked" else "ACTIVE"
)
value = request()
approval = signed_approval(private, value)
if case == "invalid_signature":
approval["signature"] = "AAAA"
elif case == "expired":
approval = signed_approval(
private,
value,
issued_at="2000-01-01T00:00:00+00:00",
not_before="2000-01-01T00:00:01+00:00",
expires_at="2000-01-01T00:01:00+00:00",
)
elif case == "wrong_repository":
approval = signed_approval(private, value, repository="other/repository")
elif case == "wrong_branch":
approval = signed_approval(private, value, branch="agent/another-approved-branch")
elif case == "wrong_oid":
approval = signed_approval(private, value, expected_branch_oid="c" * 40)
elif case == "wrong_operation":
approval["operation"] = "differentOperation"
elif case == "arbitrary_reference":
approval = "owner-approval-reference-123"
elif case == "missing_key_evidence":
root.public_key = None
elif case == "missing_revocation_evidence":
root.revocation = "UNKNOWN"
with pytest.raises((OwnerApprovalRejected, ExistingBranchPublicationRejected)):
publisher.publish(value, approval)
assert remote.pushes == []
assert "credential-project" not in events
assert "workspace-open" not in events
@pytest.mark.parametrize(
"changed",
[
lambda value: {**value, "branch": "agent/approval-replay-other-branch"},
lambda value: {**value, "expected_branch_oid": "c" * 40},
lambda value: {**value, "payload": {"files": ["other.py"]}},
],
)
def test_signed_approval_cannot_be_replayed_for_another_branch_oid_or_payload(tmp_path, changed):
private, _, events, remote, _, publisher = service(tmp_path)
original = request()
approval = signed_approval(private, original)
with pytest.raises(OwnerApprovalRejected, match="OWNER_APPROVAL_BINDING_REJECTED"):
publisher.publish(changed(original), approval)
assert remote.pushes == []
assert events == []
def test_signed_approval_nonce_is_single_use(tmp_path):
private, _, events, remote, _, publisher = service(tmp_path)
value = request()
approval = signed_approval(private, value)
assert publisher.publish(value, approval)["status"] == "PUBLISHED"
with pytest.raises(OwnerApprovalRejected, match="OWNER_APPROVAL_REPLAY_REJECTED"):
publisher.publish(value, approval)
assert len(remote.pushes) == 1
assert events.count("credential-project") == 1
@@ -1,72 +0,0 @@
from __future__ import annotations
import inspect
from aios_existing_branch_publisher import (
ExistingBranchPublisher,
RemoteBranchObservation,
)
from test_existing_branch_owner_approval import (
BASE_OID,
COMMIT_OID,
request,
service,
signed_approval,
)
def test_remote_oid_conflict_requires_manual_owner_review_before_capability_projection(tmp_path):
private, _, events, remote, _, publisher = service(tmp_path)
remote.observation = RemoteBranchObservation("PRESENT", "c" * 40, "c" * 40, True)
value = request()
result = publisher.publish(value, signed_approval(private, value))
assert result == {"status": "MANUAL_OWNER_REVIEW_REQUIRED"}
assert events == ["authority-observe", "remote-observe"]
assert remote.pushes == []
def test_ambiguous_remote_requires_reconciliation_after_one_observation(tmp_path):
private, _, events, remote, _, publisher = service(tmp_path)
remote.observation = RemoteBranchObservation("AMBIGUOUS", None, None, None)
value = request()
result = publisher.publish(value, signed_approval(private, value))
assert result == {"status": "RECONCILIATION_REQUIRED"}
assert events == ["authority-observe", "remote-observe"]
assert remote.pushes == []
def test_authority_oid_conflict_requires_manual_owner_review(tmp_path):
private, _, events, remote, _, publisher = service(tmp_path)
remote.authority_oid = "c" * 40
value = request()
result = publisher.publish(value, signed_approval(private, value))
assert result == {"status": "MANUAL_OWNER_REVIEW_REQUIRED"}
assert events == ["authority-observe"]
assert remote.pushes == []
def test_success_reports_all_remote_agreement_fields(tmp_path):
private, _, _, _, _, publisher = service(tmp_path)
value = request()
result = publisher.publish(value, signed_approval(private, value))
assert result == {
"status": "PUBLISHED",
"commit_oid": COMMIT_OID,
"authority_oid": COMMIT_OID,
"gitea_git_oid": COMMIT_OID,
"gitea_api_oid": COMMIT_OID,
"commit_visible": True,
}
def test_publisher_exposes_only_compare_and_swap_publication_path():
source = inspect.getsource(ExistingBranchPublisher).lower()
assert "force" not in source
@@ -0,0 +1,283 @@
from __future__ import annotations
from datetime import datetime, timedelta, timezone
from pathlib import Path
import subprocess
import tempfile
import pytest
from aios_continuation_executor import (
ContinuationCommit,
ContinuationExecutionError,
ContinuationExecutor,
ContinuationPermissions,
ContinuationRuntimeBinding,
DetachedGitWorkspace,
GiteaContinuationRemote,
)
from aios_continuation_lease import WriterLeaseRequestV2
from aios_gitops_job_controller import BindingConflict, GitOpsJobController, JobState, JobStore
TASK = "TASK-P0-CHATGPT-BRIDGE-V2-CONTROL-PLANE-CONVERGENCE-20260809"
REPOSITORY = "aios/aios"
BRANCH = "agent/p0-chatgpt-bridge-v2-control-plane-convergence-20260809"
BASE = "2" * 40
HEAD = "8" * 40
NEW = "9" * 40
NOW = datetime(2026, 8, 9, 12, 0, tzinfo=timezone.utc)
class Authority:
def __init__(self, *, head=HEAD, exists=True, descendant=True):
self.head = head
self.exists = exists
self.descendant = descendant
self.cas_calls = []
def branch_exists(self, branch):
return self.exists
def branch_head(self, branch):
return self.head
def is_ancestor(self, older, newer):
if (older, newer) == (BASE, HEAD):
return True
return self.descendant and (older, newer) in {(HEAD, NEW), (BASE, NEW)}
def compare_and_swap_branch(self, branch, expected, new):
self.cas_calls.append((branch, expected, new))
if self.head != expected:
raise RuntimeError("stale")
self.head = new
return new
class Workspace:
def __init__(self, *, detached=True, head=HEAD):
self.detached = detached
self.head = head
self.commits = 0
def is_detached(self):
return self.detached
def head_oid(self):
return self.head
def commit_files(self, files, message):
self.commits += 1
self.head = NEW
return NEW
class Remote:
def __init__(self, *, git=HEAD, api=HEAD, visible=True, repository=REPOSITORY, fail_after_push=False, omit_after_push=False):
self.git = git
self.api = api
self.visible = visible
self.repository = repository
self.fail_after_push = fail_after_push
self.omit_after_push = omit_after_push
self.pushes = 0
def repository_identity(self):
return self.repository
def push_exact(self, branch, expected, new):
self.pushes += 1
if self.git is None:
raise RuntimeError("remote branch missing")
if self.git != expected:
raise RuntimeError("remote conflict")
if not self.omit_after_push:
self.git = self.api = new
else:
self.git = self.api = None
if self.fail_after_push:
raise TimeoutError("response lost")
def read_git_ref(self, branch):
return self.git
def read_api_branch(self, branch):
return self.api
def commit_visible(self, oid):
return self.visible and self.api == oid
class Credential:
def __init__(self):
self.projected = 0
self.revoked = 0
def project(self):
self.projected += 1
def revoke(self):
self.revoked += 1
def lease_request(**changes):
values = dict(task_id=TASK, repository=REPOSITORY, branch_mode="CONTINUE_EXISTING", base_oid=BASE,
expected_branch_oid=HEAD, target_branch=BRANCH, generation=1, lease_seconds=900)
values.update(changes)
return WriterLeaseRequestV2(**values)
def binding(**changes):
values = dict(
request=lease_request(),
workspace_path=Path("/var/lib/aios-task-writer/continuation-worktrees/exact"),
lease_not_before=NOW - timedelta(seconds=1),
lease_expires_at=NOW + timedelta(minutes=15),
original_receipt_valid=True,
original_grant_consumed=True,
permissions=ContinuationPermissions(),
)
values.update(changes)
return ContinuationRuntimeBinding(**values)
def commit(**changes):
values = dict(idempotency_key="first-continuation", files={"active-runtime/app/new.py": b"ok\n"},
message="feat(gitops): add governed continuation executor")
values.update(changes)
return ContinuationCommit(**values)
def make_executor(authority=None, workspace=None, remote=None, credential=None):
temp = tempfile.TemporaryDirectory()
controller = GitOpsJobController(JobStore(Path(temp.name).resolve()))
executor = ContinuationExecutor(
controller, authority or Authority(), workspace or Workspace(), remote or Remote(), credential or Credential(),
now=lambda: NOW,
)
executor._test_temp = temp
return executor
def test_exact_existing_branch_completes_only_after_all_remote_proofs():
authority, remote, credential = Authority(), Remote(), Credential()
result = make_executor(authority, remote=remote, credential=credential).execute(binding(), commit())
assert result["state"] == JobState.COMPLETED.value
assert result["receipt"]["authority_oid"] == result["receipt"]["git_remote_oid"] == NEW
assert result["receipt"]["api_branch_oid"] == NEW
assert result["receipt"]["commit_visible"] is True
assert authority.cas_calls == [(BRANCH, HEAD, NEW)]
assert credential.projected == credential.revoked == 1
assert "credential" not in repr(result).lower()
@pytest.mark.parametrize(
"runtime_binding,authority,workspace,error",
[
(binding(request=lease_request(expected_branch_oid="7" * 40)), Authority(), Workspace(), "EXISTING_BRANCH_OID_CONFLICT"),
(binding(), Authority(exists=False), Workspace(), "EXISTING_BRANCH_MISSING"),
(binding(), Authority(), Workspace(detached=False), "WORKTREE_NOT_DETACHED"),
(binding(), Authority(), Workspace(head="7" * 40), "WORKTREE_HEAD_MISMATCH"),
(binding(lease_expires_at=NOW), Authority(), Workspace(), "LEASE_EXPIRED"),
(binding(request=lease_request(repository="other/repo")), Authority(), Workspace(), "request_identity_invalid"),
(binding(request=lease_request(target_branch="main")), Authority(), Workspace(), "PROTECTED_BRANCH_REJECTED"),
(binding(request=lease_request(generation=1)), Authority(), Workspace(), "GENERATION_NOT_MONOTONIC"),
],
)
def test_pre_side_effect_failures_never_create_or_update_a_branch(runtime_binding, authority, workspace, error):
executor = make_executor(authority, workspace=workspace)
if error == "GENERATION_NOT_MONOTONIC":
executor.observe_generation(BRANCH, 1)
with pytest.raises(Exception, match=error):
executor.execute(runtime_binding, commit())
assert authority.cas_calls == []
assert workspace.commits == 0
@pytest.mark.parametrize("field", ["create_target_branch", "force_push", "tag_write", "baseline_write", "production_write", "main_write"])
def test_forbidden_capabilities_fail_before_credential_projection(field):
credential = Credential()
permissions = ContinuationPermissions(**{field: True})
with pytest.raises(ContinuationExecutionError, match="MUTATION_PERMISSION_DENIED"):
make_executor(credential=credential).execute(binding(permissions=permissions), commit())
assert credential.projected == 0
def test_non_fast_forward_and_concurrent_movement_are_rejected_cas_only():
authority = Authority(descendant=False)
with pytest.raises(ContinuationExecutionError, match="NON_FAST_FORWARD_COMMIT"):
make_executor(authority).execute(binding(), commit())
assert authority.cas_calls == []
def test_authority_success_and_gitea_missing_is_never_completed():
remote = Remote(omit_after_push=True)
result = make_executor(remote=remote).execute(binding(), commit())
assert result["state"] == JobState.RECONCILIATION_REQUIRED.value
assert result["side_effect_state"] == "REMOTE_PUSH_PENDING"
assert result["state"] not in {JobState.REMOTE_VERIFIED.value, JobState.COMPLETED.value}
def test_response_loss_after_remote_success_reconciles_by_observation_without_second_push():
remote = Remote(fail_after_push=True)
executor = make_executor(remote=remote)
first = executor.execute(binding(), commit())
assert first["state"] == JobState.RECONCILIATION_REQUIRED.value
assert remote.pushes == 1
recovered = executor.reconcile(first["job_id"])
assert recovered["state"] == JobState.COMPLETED.value
assert remote.pushes == 1
def test_observation_first_reconcile_retries_only_when_remote_is_exact_expected_old_oid():
remote = Remote(fail_after_push=True)
executor = make_executor(remote=remote)
first = executor.execute(binding(), commit())
assert first["state"] == JobState.RECONCILIATION_REQUIRED.value
remote.git = remote.api = HEAD
remote.visible = True
remote.fail_after_push = False
recovered = executor.reconcile(first["job_id"])
assert recovered["state"] == JobState.COMPLETED.value
assert remote.pushes == 2
def test_duplicate_idempotency_replay_and_conflicting_payload():
executor = make_executor()
first = executor.execute(binding(), commit())
replay = executor.execute(binding(), commit())
assert replay["job_id"] == first["job_id"]
with pytest.raises(BindingConflict, match="BINDING_CONFLICT"):
executor.execute(binding(), commit(files={"active-runtime/app/new.py": b"changed\n"}))
def test_secret_like_payload_fails_before_projection():
credential = Credential()
secret_fixture = b"to" + b"ken=" + b"ghp_" + b"abcdefghijklmnopqrstuvwxyz0123456789"
with pytest.raises(ContinuationExecutionError, match="SECRET_LIKE_PAYLOAD_REJECTED"):
make_executor(credential=credential).execute(binding(), commit(files={"x": secret_fixture}))
assert credential.projected == 0
def test_remote_identity_cannot_alias_the_authority_bare_repo():
with pytest.raises(ContinuationExecutionError, match="GITEA_REMOTE_IDENTITY_INVALID"):
GiteaContinuationRemote.validate_remote_url("/data/aios-gitops/repo.git")
GiteaContinuationRemote.validate_remote_url("aiman@g.cnnetmkt.top:aios/aios.git")
def test_detached_workspace_preserves_porcelain_leading_status_column():
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
subprocess.run(["git", "init", "-q", str(root)], check=True)
subprocess.run(["git", "-C", str(root), "config", "user.name", "test"], check=True)
subprocess.run(["git", "-C", str(root), "config", "user.email", "test@localhost"], check=True)
(root / "tracked.py").write_text("one\n", encoding="utf-8")
subprocess.run(["git", "-C", str(root), "add", "tracked.py"], check=True)
subprocess.run(["git", "-C", str(root), "commit", "-q", "-m", "base"], check=True)
subprocess.run(["git", "-C", str(root), "checkout", "-q", "--detach"], check=True)
(root / "tracked.py").write_text("two\n", encoding="utf-8")
(root / "new.py").write_text("new\n", encoding="utf-8")
workspace = DetachedGitWorkspace(root)
assert workspace.is_detached()
assert workspace._dirty_paths() == {"tracked.py", "new.py"}
+3 -3
View File
@@ -250,7 +250,7 @@ class GovernedLocalWriterTests(unittest.TestCase):
} }
self.assertEqual(service.process_request(secret_request, peer)["status"], "error") self.assertEqual(service.process_request(secret_request, peer)["status"], "error")
def test_idempotent_replay_returns_receipt(self) -> None: def test_one_shot_consumption(self) -> None:
with tempfile.TemporaryDirectory() as root: with tempfile.TemporaryDirectory() as root:
directory = Path(root) directory = Path(root)
auth = self._load_auth(self._make_auth_payload(), directory) auth = self._load_auth(self._make_auth_payload(), directory)
@@ -283,8 +283,8 @@ class GovernedLocalWriterTests(unittest.TestCase):
self.assertEqual(service.process_request(create_request, peer)["status"], "ok") self.assertEqual(service.process_request(create_request, peer)["status"], "ok")
self.assertEqual(service.process_request(append_request, peer)["status"], "ok") self.assertEqual(service.process_request(append_request, peer)["status"], "ok")
self.assertEqual(service.process_request(append_request, peer)["status"], "receipt") self.assertEqual(service.process_request(append_request, peer)["status"], "error")
self.assertEqual(len(sink.records), 2) self.assertEqual(len(sink.records), 3)
self.assertEqual(len(handler.create_calls), 1) self.assertEqual(len(handler.create_calls), 1)
self.assertEqual(len(handler.append_calls), 1) self.assertEqual(len(handler.append_calls), 1)
-35
View File
@@ -1,35 +0,0 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_model_api_source_is_immutable_and_authority_bound():
source = (ROOT / 'active-runtime' / 'app' / 'aios_model_api_staging.py').read_text(encoding='utf-8')
assert 'BaselineAuthority' in source
assert 'BASELINE_AUTHORITY = BaselineAuthority()' in source
assert 'LEGACY_GIT_WRITE_COMMANDS' in source
assert 'BaselineAuthorityError' in source
assert 'IMMUTABLE_STAGING' in source
assert 'LEGACY_GLOBAL_WRITES_DISABLED' in source
assert "'production_deployed': False" in source
assert "'governed_release_routing': 'bridge-v2'" in source
def test_model_api_staging_unit_is_non_production_and_read_only():
unit = (ROOT / 'deploy' / 'systemd' / 'aios-gitops-model-api-v2r2c1-staging.service').read_text(encoding='utf-8')
assert 'aios-gitops-model-api-v2r2c1-staging.service' in unit
assert 'AIOS_GITOPS_WRITES_ENABLED=false' in unit
assert 'AIOS_GITOPS_DURABLE_JOB_EXECUTION_ENABLED=false' in unit
assert 'AIOS_GITOPS_PORT=18893' in unit
assert 'aios_model_api_staging.py' in unit
assert 'production' not in unit.lower().replace('model-api-v2r2c1-staging', '')
def test_model_api_builder_manifest_contract():
builder = (ROOT / 'scripts' / 'build_v2r2c1_model_api_staging.py').read_text(encoding='utf-8')
assert 'aios.v2r2c1.model-api-staging-manifest.v1' in builder
assert "'target_version': 'V2R2C1'" in builder
assert "'repository_identity': 'aios/aios'" in builder
assert "'deployment_state': 'STAGING'" in builder
assert "'legacy_global_writes_enabled': False" in builder
assert 'private marker rejected' in builder
@@ -0,0 +1,37 @@
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
OPENAPI=ROOT/"docs/gitops/openapi-chatgpt-actions.yaml"
ROUTES={
"/v2/task-admission/envelope":"getTaskAdmissionEnvelope",
"/v2/task-admission/authorize":"submitTaskAdmissionAuthorization",
"/v2/task-admission/status":"getTaskAdmissionStatus",
}
def block(text,marker,n):
lines=text.splitlines(); pref=" "*n+marker
start=next((i for i,x in enumerate(lines) if x==pref),None)
assert start is not None, marker
out=[lines[start]]
for line in lines[start+1:]:
if line.strip() and len(line)-len(line.lstrip(" "))<=n: break
out.append(line)
return "\n".join(out)
def test_projected_once():
t=OPENAPI.read_text(encoding="utf-8-sig")
for route,op in ROUTES.items():
assert t.count(f" {route}:")==1
assert t.count(f"operationId: {op}")==1
def test_no_principal_injection():
t=OPENAPI.read_text(encoding="utf-8-sig")
b=block(t,"TaskAdmissionAuthorizationRequest:",4)
assert "\n principal:" not in b
assert "\n _verified_task_principal:" not in b
def test_no_git_write_projection():
t=OPENAPI.read_text(encoding="utf-8-sig")
for route in ("/v2/task-admission/envelope:","/v2/task-admission/authorize:"):
b=block(t,route,2)
assert "x-aios-no-git-write: true" in b
assert "x-aios-no-shell: true" in b
def test_status_read_only():
t=OPENAPI.read_text(encoding="utf-8-sig")
b=block(t,"/v2/task-admission/status:",2)
assert "x-aios-read-only: true" in b