Merge pull request 'fix(release): close owner auth bootstrap and production executor' (#51) from agent/v2r1c7-production-executor-bootstrap-20260807-r2 into main

Reviewed-on: #51
This commit was merged in pull request #51.
This commit is contained in:
2026-08-07 17:36:41 +08:00
11 changed files with 3119 additions and 0 deletions
+652
View File
@@ -0,0 +1,652 @@
#!/usr/bin/env python3
"""One-shot governed executor for an already approved exact release binding.
This module deliberately does not build release artifacts. The build/staging
evidence is completed before Owner production approval. Production execution
consumes that immutable binding, revalidates it, and performs narrow
side-effects through adapters in a durable fail-closed order.
Adapter protocol:
stdin: JSON request with operation = "probe" | "apply" | "rollback"
stdout: one JSON object on the final non-empty line
shell: never used
The executor never rewrites tags, never writes refs/heads/main, and records
Baseline last.
"""
from __future__ import annotations
import argparse
import dataclasses
import fcntl
import hashlib
import json
import os
import re
import stat
import subprocess
import sys
import tempfile
import time
from pathlib import Path
from typing import Any, Mapping, Sequence
OID_RE = re.compile(r"^[0-9a-f]{40}$")
SHA_RE = re.compile(r"^[0-9a-f]{64}$")
PLAN_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
REQUIRED_V2R1C7_MEMBERS = {
"payload/VERSION",
"payload/active-runtime/app/deployment_state.py",
"payload/active-runtime/app/v2r1c6_privacy_tools.py",
"payload/active-runtime/app/v2r1c7_health_service.py",
"payload/deploy/aios-v2/systemd/aios-v2r1c7-production.service",
"payload/deploy/aios-v2/v2r1c7-runtime-config.json",
"payload/deploy/aios-v2/v2r1c7-rollback.json",
"payload/scripts/probe_v2r1c7_health.py",
"payload/scripts/rollback_v2r1c7_release.sh",
"payload/BUILD-METADATA.json",
"payload/ARTIFACT-MANIFEST.json",
"payload/ROLLBACK-METADATA.json",
}
class ReleaseBlocked(RuntimeError):
pass
class ManualOwnerReviewRequired(ReleaseBlocked):
pass
class ReconciliationRequired(ReleaseBlocked):
pass
@dataclasses.dataclass(frozen=True)
class Binding:
version: str
target_oid: str
evidence_closure_oid: str
artifact_sha256: str
approval_plan_id: str
artifact_path: str
artifact_size: int
production_service: str
production_port: int
repository_identity: str = "aios/aios"
def __post_init__(self) -> None:
if not self.version or not OID_RE.fullmatch(self.target_oid):
raise ValueError("invalid release target binding")
if not OID_RE.fullmatch(self.evidence_closure_oid):
raise ValueError("invalid evidence closure OID")
if not SHA_RE.fullmatch(self.artifact_sha256):
raise ValueError("invalid artifact SHA-256")
if not PLAN_RE.fullmatch(self.approval_plan_id):
raise ValueError("invalid approval plan id")
if self.artifact_size <= 0:
raise ValueError("invalid artifact size")
if not self.production_service:
raise ValueError("production service is required")
if not 1024 <= self.production_port <= 65535:
raise ValueError("invalid production port")
if self.repository_identity != "aios/aios":
raise ValueError("unexpected repository identity")
@property
def tag(self) -> str:
return self.version
@property
def fingerprint(self) -> str:
payload = {
"version": self.version,
"target_oid": self.target_oid,
"evidence_closure_oid": self.evidence_closure_oid,
"artifact_sha256": self.artifact_sha256,
"approval_plan_id": self.approval_plan_id,
"artifact_size": self.artifact_size,
"production_service": self.production_service,
"production_port": self.production_port,
"repository_identity": self.repository_identity,
}
return hashlib.sha256(canonical_json(payload)).hexdigest()
def request(self, operation: str) -> dict[str, Any]:
return {
"schema": "aios.production-executor-request.v1",
"operation": operation,
"binding_fingerprint": self.fingerprint,
"version": self.version,
"tag": self.tag,
"target_oid": self.target_oid,
"evidence_closure_oid": self.evidence_closure_oid,
"artifact_sha256": self.artifact_sha256,
"artifact_path": self.artifact_path,
"artifact_size": self.artifact_size,
"approval_plan_id": self.approval_plan_id,
"production_service": self.production_service,
"production_port": self.production_port,
"repository_identity": self.repository_identity,
}
def canonical_json(value: object) -> bytes:
return (json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n").encode("utf-8")
def secure_json(path: Path) -> dict[str, Any]:
st = path.lstat()
if not stat.S_ISREG(st.st_mode) or path.is_symlink():
raise ReleaseBlocked(f"non-regular authorization file: {path}")
if st.st_uid != 0:
raise ReleaseBlocked(f"authorization file must be root-owned: {path}")
if st.st_mode & 0o022:
raise ReleaseBlocked(f"authorization file is group/world writable: {path}")
data = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(data, dict):
raise ReleaseBlocked("authorization receipt must be a JSON object")
return data
def sha256_file(path: Path) -> str:
if path.is_symlink() or not path.is_file():
raise ReleaseBlocked("artifact must be a regular non-symlink file")
digest = hashlib.sha256()
with path.open("rb") as source:
for block in iter(lambda: source.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def run_git(git_dir: Path, *args: str, check: bool = True) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["git", f"--git-dir={git_dir}", *args],
check=check,
capture_output=True,
text=True,
timeout=30,
env={"PATH": os.environ.get("PATH", "")},
)
def verify_git_lineage(git_dir: Path, binding: Binding) -> dict[str, Any]:
authority_main = run_git(git_dir, "rev-parse", "refs/heads/main").stdout.strip()
if not OID_RE.fullmatch(authority_main):
raise ReleaseBlocked("Authority main OID is invalid")
target_type = run_git(git_dir, "cat-file", "-t", binding.target_oid).stdout.strip()
if target_type != "commit":
raise ReleaseBlocked("target_oid is not a commit")
evidence_type = run_git(
git_dir, "cat-file", "-t", binding.evidence_closure_oid
).stdout.strip()
if evidence_type != "commit":
raise ReleaseBlocked("evidence_closure_oid is not a commit")
# A control-plane-only patch may advance main after release approval.
# The approved release target remains valid only while it is still on main.
target_on_main = run_git(
git_dir,
"merge-base",
"--is-ancestor",
binding.target_oid,
authority_main,
check=False,
).returncode == 0
if not target_on_main:
raise ManualOwnerReviewRequired(
"approved target is no longer an ancestor of Authority main"
)
target_in_evidence = run_git(
git_dir,
"merge-base",
"--is-ancestor",
binding.target_oid,
binding.evidence_closure_oid,
check=False,
).returncode == 0
if not target_in_evidence:
raise ReleaseBlocked("approved target is not an ancestor of evidence closure")
return {
"authority_main_oid": authority_main,
"target_oid": binding.target_oid,
"target_is_ancestor_of_main": True,
"evidence_closure_oid": binding.evidence_closure_oid,
"evidence_object_type": evidence_type,
"target_is_ancestor_of_evidence": True,
}
def verify_artifact(binding: Binding) -> dict[str, Any]:
path = Path(binding.artifact_path)
if path.stat().st_size != binding.artifact_size:
raise ReleaseBlocked("artifact size mismatch")
actual = sha256_file(path)
if actual != binding.artifact_sha256:
raise ReleaseBlocked("artifact SHA-256 mismatch")
if binding.version == "V2R1C7":
# Python tarfile may not have zstd support on the target host, so
# decompress into a private temporary tar and inspect it there.
with tempfile.TemporaryDirectory(prefix="aios-artifact-verify-") as temp_dir:
tar_path = Path(temp_dir) / "release.tar"
with tar_path.open("wb") as output:
completed = subprocess.run(
["zstd", "-dc", str(path)],
check=False,
stdout=output,
stderr=subprocess.PIPE,
timeout=60,
env={"PATH": os.environ.get("PATH", "")},
)
if completed.returncode != 0:
raise ReleaseBlocked("artifact zstd decompression failed")
import tarfile
with tarfile.open(tar_path, "r:") as archive:
names: set[str] = set()
for member in archive.getmembers():
candidate = Path(member.name)
if (
candidate.is_absolute()
or ".." in candidate.parts
or member.issym()
or member.islnk()
or not (member.isfile() or member.isdir())
):
raise ReleaseBlocked(f"unsafe artifact member: {member.name}")
names.add(member.name)
missing = sorted(REQUIRED_V2R1C7_MEMBERS - names)
if missing:
raise ReleaseBlocked(
"artifact missing required members: " + ",".join(missing)
)
return {
"artifact_path": str(path),
"artifact_sha256": actual,
"artifact_size": binding.artifact_size,
"verified": True,
}
def verify_authorization(receipt: Mapping[str, Any], binding: Binding) -> dict[str, Any]:
if receipt.get("accepted") is not True:
raise ReleaseBlocked("Owner production authorization is not accepted")
if receipt.get("binding_replaced") not in (None, False):
raise ManualOwnerReviewRequired("Owner binding was replaced")
expected = {
"version": binding.version,
"target_oid": binding.target_oid,
"evidence_closure_oid": binding.evidence_closure_oid,
"artifact_sha256": binding.artifact_sha256,
"approval_plan_id": binding.approval_plan_id,
}
for key, value in expected.items():
if receipt.get(key) != value:
raise ManualOwnerReviewRequired(f"Owner authorization mismatch: {key}")
return {"accepted": True, **expected}
class DurableState:
def __init__(self, root: Path, binding: Binding):
self.root = root
self.root.mkdir(parents=True, exist_ok=True)
os.chmod(self.root, 0o700)
self.path = self.root / "execution.json"
self.binding = binding
self.value: dict[str, Any]
if self.path.exists():
existing = json.loads(self.path.read_text(encoding="utf-8"))
if existing.get("binding_fingerprint") != binding.fingerprint:
raise ManualOwnerReviewRequired(
"state root contains a different production binding"
)
self.value = existing
else:
self.value = {
"schema": "aios.production-execution-state.v1",
"binding_fingerprint": binding.fingerprint,
"version": binding.version,
"target_oid": binding.target_oid,
"state": "AUTHORIZED",
"completed": {},
"history": [],
}
self.save()
def save(self) -> None:
temporary = self.path.with_suffix(".tmp")
temporary.write_bytes(canonical_json(self.value))
os.chmod(temporary, 0o600)
os.replace(temporary, self.path)
def record(self, state: str, step: str, result: Mapping[str, Any]) -> None:
now = time.time()
sanitized = json.loads(json.dumps(result))
self.value["state"] = state
self.value["completed"][step] = sanitized
self.value["history"].append(
{"at": now, "state": state, "step": step, "result": sanitized}
)
self.save()
def fail(self, state: str, reason: str) -> None:
self.value["state"] = state
self.value["history"].append(
{"at": time.time(), "state": state, "reason": reason}
)
self.save()
class FileLock:
def __init__(self, path: Path):
self.path = path
self.handle = None
def __enter__(self) -> "FileLock":
self.path.parent.mkdir(parents=True, exist_ok=True)
self.handle = self.path.open("a+", encoding="utf-8")
os.chmod(self.path, 0o600)
try:
fcntl.flock(
self.handle.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB
)
except BlockingIOError as exc:
raise ReleaseBlocked("production executor is already running") from exc
return self
def __exit__(self, exc_type, exc, tb) -> None:
if self.handle is not None:
fcntl.flock(self.handle.fileno(), fcntl.LOCK_UN)
self.handle.close()
def parse_command(values: Sequence[str]) -> list[str]:
command = [str(x) for x in values if str(x)]
if not command:
raise ValueError("adapter command is required")
if not os.path.isabs(command[0]):
raise ValueError("adapter executable must be an absolute path")
return command
def run_adapter(command: Sequence[str], request: Mapping[str, Any]) -> dict[str, Any]:
completed = subprocess.run(
list(command),
input=canonical_json(request),
check=False,
capture_output=True,
timeout=180,
env={"PATH": os.environ.get("PATH", "")},
)
if completed.returncode != 0:
raise ReleaseBlocked(
f"adapter failed: {Path(command[0]).name} rc={completed.returncode}"
)
lines = [line for line in completed.stdout.decode("utf-8").splitlines() if line.strip()]
if not lines:
raise ReleaseBlocked("adapter returned no JSON result")
try:
value = json.loads(lines[-1])
except ValueError as exc:
raise ReleaseBlocked("adapter returned invalid JSON") from exc
if not isinstance(value, dict):
raise ReleaseBlocked("adapter result must be an object")
return value
def require_exact_response(result: Mapping[str, Any], binding: Binding) -> None:
for key, expected in {
"version": binding.version,
"target_oid": binding.target_oid,
"evidence_closure_oid": binding.evidence_closure_oid,
"artifact_sha256": binding.artifact_sha256,
"approval_plan_id": binding.approval_plan_id,
}.items():
if key in result and result[key] != expected:
raise ManualOwnerReviewRequired(f"adapter binding mismatch: {key}")
def tag_step(command: Sequence[str], binding: Binding) -> dict[str, Any]:
request = binding.request("probe")
probe = run_adapter(command, request)
require_exact_response(probe, binding)
state = probe.get("status")
if state == "CONFLICT":
raise ManualOwnerReviewRequired("same-name tag conflicts with approved binding")
if state == "INDETERMINATE":
raise ReconciliationRequired("tag publication state is indeterminate")
if state not in {"APPLIED_VERIFIED", "NOT_APPLIED", "PARTIAL_LOCAL"}:
raise ReleaseBlocked(f"unsupported tag probe status: {state}")
if state != "APPLIED_VERIFIED":
applied = run_adapter(command, binding.request("apply"))
require_exact_response(applied, binding)
if applied.get("status") == "CONFLICT":
raise ManualOwnerReviewRequired("tag conflict during publication")
probe = run_adapter(command, request)
require_exact_response(probe, binding)
if probe.get("status") != "APPLIED_VERIFIED":
raise ReconciliationRequired("tag was not independently verified")
if probe.get("peeled_target_oid") != binding.target_oid:
raise ManualOwnerReviewRequired("published tag peeled target mismatch")
tag_oid = probe.get("tag_oid")
if not isinstance(tag_oid, str) or not OID_RE.fullmatch(tag_oid):
raise ReleaseBlocked("verified annotated tag object OID missing")
return dict(probe)
def deploy_step(command: Sequence[str], binding: Binding) -> dict[str, Any]:
probe = run_adapter(command, binding.request("probe"))
require_exact_response(probe, binding)
if probe.get("status") == "ACTIVE_VERIFIED":
return dict(probe)
if probe.get("status") == "CONFLICT":
raise ManualOwnerReviewRequired("production runtime has conflicting binding")
applied = run_adapter(command, binding.request("apply"))
require_exact_response(applied, binding)
probe = run_adapter(command, binding.request("probe"))
require_exact_response(probe, binding)
if probe.get("status") != "ACTIVE_VERIFIED":
try:
run_adapter(command, binding.request("rollback"))
except Exception:
pass
raise ReconciliationRequired("production runtime did not verify after apply")
if (
probe.get("deployment_state") != "ACTIVE"
or probe.get("production_deployed") is not True
):
raise ReconciliationRequired("production health contract is not ACTIVE")
return dict(probe)
def finalize_step(
command: Sequence[str],
binding: Binding,
*,
name: str,
tag_oid: str,
) -> dict[str, Any]:
request = binding.request("probe")
request["tag_oid"] = tag_oid
probe = run_adapter(command, request)
require_exact_response(probe, binding)
if probe.get("status") == "CONFLICT":
raise ManualOwnerReviewRequired(f"{name} has conflicting release binding")
if probe.get("status") != "VERIFIED":
apply_request = binding.request("apply")
apply_request["tag_oid"] = tag_oid
applied = run_adapter(command, apply_request)
require_exact_response(applied, binding)
probe = run_adapter(command, request)
require_exact_response(probe, binding)
if probe.get("status") != "VERIFIED":
raise ReconciliationRequired(f"{name} did not verify after apply")
if probe.get("tag_oid") not in (None, tag_oid):
raise ManualOwnerReviewRequired(f"{name} tag object mismatch")
return dict(probe)
def execute(
*,
binding: Binding,
authorization_path: Path,
repository: Path,
state_root: Path,
tag_command: Sequence[str],
deploy_command: Sequence[str],
registry_command: Sequence[str],
baseline_command: Sequence[str],
) -> dict[str, Any]:
authorization = verify_authorization(secure_json(authorization_path), binding)
lineage = verify_git_lineage(repository, binding)
artifact = verify_artifact(binding)
state = DurableState(state_root, binding)
with FileLock(state_root / "executor.lock"):
state.record(
"PREFLIGHT_VERIFIED",
"preflight",
{"authorization": authorization, "lineage": lineage, "artifact": artifact},
)
tag: dict[str, Any] | None = None
runtime: dict[str, Any] | None = None
try:
tag = tag_step(tag_command, binding)
state.record("TAG_VERIFIED", "tag", tag)
runtime = deploy_step(deploy_command, binding)
state.record("RUNTIME_VERIFIED", "runtime", runtime)
registry = finalize_step(
registry_command,
binding,
name="registry",
tag_oid=tag["tag_oid"],
)
state.record("REGISTRY_VERIFIED", "registry", registry)
baseline = finalize_step(
baseline_command,
binding,
name="baseline",
tag_oid=tag["tag_oid"],
)
state.record("BASELINE_VERIFIED", "baseline", baseline)
# Final readback: no mutation, all four planes must still agree.
final_tag = tag_step(tag_command, binding)
final_runtime = run_adapter(deploy_command, binding.request("probe"))
final_registry_request = binding.request("probe")
final_registry_request["tag_oid"] = tag["tag_oid"]
final_registry = run_adapter(registry_command, final_registry_request)
final_baseline_request = binding.request("probe")
final_baseline_request["tag_oid"] = tag["tag_oid"]
final_baseline = run_adapter(baseline_command, final_baseline_request)
for value in (final_runtime, final_registry, final_baseline):
require_exact_response(value, binding)
if final_runtime.get("status") != "ACTIVE_VERIFIED":
raise ReconciliationRequired("final runtime readback failed")
if final_registry.get("status") != "VERIFIED":
raise ReconciliationRequired("final Registry readback failed")
if final_baseline.get("status") != "VERIFIED":
raise ReconciliationRequired("final Baseline readback failed")
final = {
"status": "PRODUCTION_ACCEPTED",
"version": binding.version,
"target_oid": binding.target_oid,
"evidence_closure_oid": binding.evidence_closure_oid,
"artifact_sha256": binding.artifact_sha256,
"approval_plan_id": binding.approval_plan_id,
"tag_oid": tag["tag_oid"],
"tag": final_tag,
"runtime": final_runtime,
"registry": final_registry,
"baseline": final_baseline,
"force_push_used": False,
"tag_rewritten": False,
"direct_main_push": False,
"secrets_committed": False,
}
state.record("COMPLETED", "final_consistency", final)
return final
except ManualOwnerReviewRequired as exc:
state.fail("MANUAL_OWNER_REVIEW_REQUIRED", str(exc))
raise
except ReconciliationRequired as exc:
state.fail("RECONCILIATION_REQUIRED", str(exc))
raise
except Exception as exc:
# Once a formal tag has been verified, no later error is a clean
# pre-side-effect failure. Preserve the tag and require idempotent
# reconciliation rather than pretending the release never started.
if tag is not None:
reason = f"{type(exc).__name__}: {exc}"
state.fail("RECONCILIATION_REQUIRED", reason)
raise ReconciliationRequired(reason) from exc
state.fail("FAIL_CLOSED", f"{type(exc).__name__}: {exc}")
raise
def parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser()
p.add_argument("--authorization", required=True, type=Path)
p.add_argument("--repository", required=True, type=Path)
p.add_argument("--state-root", required=True, type=Path)
p.add_argument("--artifact", required=True, type=Path)
p.add_argument("--artifact-size", required=True, type=int)
p.add_argument("--version", required=True)
p.add_argument("--target-oid", required=True)
p.add_argument("--evidence-closure-oid", required=True)
p.add_argument("--artifact-sha256", required=True)
p.add_argument("--approval-plan-id", required=True)
p.add_argument("--production-service", required=True)
p.add_argument("--production-port", required=True, type=int)
p.add_argument("--repository-identity", default="aios/aios")
p.add_argument("--tag-adapter", required=True, nargs="+")
p.add_argument("--deploy-adapter", required=True, nargs="+")
p.add_argument("--registry-adapter", required=True, nargs="+")
p.add_argument("--baseline-adapter", required=True, nargs="+")
return p
def main() -> int:
args = parser().parse_args()
binding = Binding(
version=args.version,
target_oid=args.target_oid,
evidence_closure_oid=args.evidence_closure_oid,
artifact_sha256=args.artifact_sha256,
approval_plan_id=args.approval_plan_id,
artifact_path=str(args.artifact),
artifact_size=args.artifact_size,
production_service=args.production_service,
production_port=args.production_port,
repository_identity=args.repository_identity,
)
try:
result = execute(
binding=binding,
authorization_path=args.authorization,
repository=args.repository,
state_root=args.state_root,
tag_command=parse_command(args.tag_adapter),
deploy_command=parse_command(args.deploy_adapter),
registry_command=parse_command(args.registry_adapter),
baseline_command=parse_command(args.baseline_adapter),
)
print(json.dumps(result, sort_keys=True))
return 0
except ManualOwnerReviewRequired as exc:
print(json.dumps({"status": "MANUAL_OWNER_REVIEW_REQUIRED", "reason": str(exc)}, sort_keys=True))
return 20
except ReconciliationRequired as exc:
print(json.dumps({"status": "RECONCILIATION_REQUIRED", "reason": str(exc)}, sort_keys=True))
return 21
except Exception as exc:
print(json.dumps({"status": "FAIL_CLOSED", "error": type(exc).__name__, "reason": str(exc)}, sort_keys=True))
return 22
if __name__ == "__main__":
raise SystemExit(main())
+293
View File
@@ -0,0 +1,293 @@
#!/usr/bin/env python3
"""Thin production tag adapter over AIOS's existing mature TagPublisher.
This adapter deliberately does not call TagPublisher.publish(), because that
legacy method also mutates Registry/Baseline. The production executor requires:
Tag -> runtime ACTIVE -> Registry -> Baseline.
`apply` reuses TagPublisher._verify_publication() under the publisher's durable
per-version lock. That method performs the existing fail-closed annotated-tag,
network remote, Gitea API, peeled-target and listing verification, but stops
before Registry/Baseline mutation.
`probe` is read-only.
"""
from __future__ import annotations
import argparse
import json
import os
import re
import sys
from pathlib import Path
from typing import Any, Mapping
from gitea_tag_publication import (
GiteaTagClient,
GitTagBackend,
PublicationConflict,
PublicationManualOwnerReviewRequired,
PublicationPending,
PublicationReconciliationRequired,
PublicationRequest,
PublicationState,
TagPublisher,
)
OID_RE = re.compile(r"^[0-9a-f]{40}$")
PLAN_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
def load_request() -> dict[str, Any]:
value = json.load(sys.stdin)
if not isinstance(value, dict):
raise ValueError("request_object_required")
if value.get("schema") != "aios.production-executor-request.v1":
raise ValueError("request_schema_invalid")
if not re.fullmatch(r"V\d+R\d+C\d+(?:-[A-Za-z0-9_.-]+)?", str(value.get("version", ""))):
raise ValueError("version_invalid")
for name in ("target_oid", "evidence_closure_oid"):
if not OID_RE.fullmatch(str(value.get(name, ""))):
raise ValueError(f"{name}_invalid")
if not PLAN_RE.fullmatch(str(value.get("approval_plan_id", ""))):
raise ValueError("approval_plan_id_invalid")
if value.get("repository_identity") != "aios/aios":
raise ValueError("repository_identity_invalid")
return value
def publication_request(value: Mapping[str, Any]) -> PublicationRequest:
return PublicationRequest(
str(value["version"]),
str(value["target_oid"]),
str(value["evidence_closure_oid"]),
str(value["approval_plan_id"]),
)
def response(value: Mapping[str, Any], status: str, **extra: Any) -> dict[str, Any]:
return {
"status": status,
"version": value["version"],
"target_oid": value["target_oid"],
"evidence_closure_oid": value["evidence_closure_oid"],
"artifact_sha256": value["artifact_sha256"],
"approval_plan_id": value["approval_plan_id"],
**extra,
}
def build(args: argparse.Namespace) -> tuple[TagPublisher, GitTagBackend, GiteaTagClient]:
git = GitTagBackend(args.workspace, authoritative_repo=args.repository)
gitea = GiteaTagClient(
args.gitea_api,
args.gitea_repo,
args.gitea_token_file,
token_line=args.gitea_token_line,
)
publisher = TagPublisher(
args.workspace,
git,
gitea,
args.remote,
state_root=args.state_root,
)
return publisher, git, gitea
def _gitea_lookup(gitea: GiteaTagClient, version: str) -> tuple[str, str] | None:
try:
return gitea.lookup_tag(version)
except RuntimeError as exc:
if "HTTP 404" in str(exc):
return None
raise
def probe(
args: argparse.Namespace,
value: Mapping[str, Any],
publisher: TagPublisher,
git: GitTagBackend,
gitea: GiteaTagClient,
) -> dict[str, Any]:
request = publication_request(value)
request.validate()
git.validate_evidence_lineage(request)
local_oid = git._rev(f"refs/tags/{request.version}")
local_target = git._rev(f"refs/tags/{request.version}^{{commit}}")
remote = git.remote_tag(args.remote, request.version)
api = _gitea_lookup(gitea, request.version)
listing = False
if api is not None:
listing = gitea.tag_visible_in_listing(request.version, request.target_oid)
if local_oid is None and remote is None and api is None:
return response(value, "NOT_APPLIED")
if local_oid is not None:
if local_target is None or local_oid == local_target:
return response(value, "CONFLICT", reason="local_tag_not_annotated")
if local_target != request.target_oid:
return response(
value,
"CONFLICT",
reason="local_peeled_target_mismatch",
tag_oid=local_oid,
peeled_target_oid=local_target,
)
# A remote/Gitea tag without the Authority tag object is not safe to
# recreate, because a new annotated tag would have a different object OID.
if local_oid is None and (remote is not None or api is not None):
return response(
value,
"INDETERMINATE",
reason="remote_or_gitea_tag_exists_without_authority_tag_object",
)
if remote is not None:
if remote[0] != local_oid or remote[1] != request.target_oid:
return response(
value,
"CONFLICT",
reason="network_remote_tag_mismatch",
tag_oid=local_oid,
peeled_target_oid=local_target,
remote_tag_oid=remote[0],
remote_peeled_target_oid=remote[1],
)
if api is not None:
if api[0] != local_oid or api[1] != request.target_oid:
return response(
value,
"CONFLICT",
reason="gitea_api_tag_mismatch",
tag_oid=local_oid,
peeled_target_oid=local_target,
gitea_tag_oid=api[0],
gitea_peeled_target_oid=api[1],
)
if (
local_oid is not None
and remote is not None
and api is not None
and listing
):
return response(
value,
"APPLIED_VERIFIED",
tag_oid=local_oid,
peeled_target_oid=local_target,
remote_tag_oid=remote[0],
remote_peeled_target_oid=remote[1],
gitea_tag_oid=api[0],
gitea_peeled_target_oid=api[1],
gitea_listing_visible=True,
)
if local_oid is not None and remote is None and api is None:
return response(
value,
"PARTIAL_LOCAL",
tag_oid=local_oid,
peeled_target_oid=local_target,
)
return response(
value,
"INDETERMINATE",
reason="tag_visibility_partial",
tag_oid=local_oid,
peeled_target_oid=local_target,
)
def apply(
args: argparse.Namespace,
value: Mapping[str, Any],
publisher: TagPublisher,
git: GitTagBackend,
gitea: GiteaTagClient,
) -> dict[str, Any]:
before = probe(args, value, publisher, git, gitea)
if before["status"] in {"APPLIED_VERIFIED", "CONFLICT", "INDETERMINATE"}:
return before
request = publication_request(value)
with publisher.store.lock(request.version):
request.validate()
publisher._assert_fingerprint(request)
publisher.store.record(request, PublicationState.PENDING)
publisher._verify_publication(
request,
allow_push=True,
previously_deployed=False,
)
return probe(args, value, publisher, git, gitea)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--workspace", type=Path, default=Path(os.environ["AIOS_GITOPS_CONTROLLER_WORKSPACE"]))
parser.add_argument("--repository", type=Path, default=Path(os.environ["AIOS_GITOPS_AUTHORITATIVE_GIT_DIR"]))
parser.add_argument("--remote", default=os.getenv("AIOS_GITOPS_GITEA_REMOTE", "gitea"))
parser.add_argument("--gitea-api", default=os.getenv("AIOS_GITOPS_GITEA_API_URL", ""))
parser.add_argument("--gitea-repo", default=os.getenv("AIOS_GITOPS_GITEA_REPOSITORY", ""))
parser.add_argument(
"--gitea-token-file",
type=Path,
default=Path(os.getenv("AIOS_GITOPS_GITEA_TOKEN_FILE", "")),
)
parser.add_argument(
"--gitea-token-line",
type=int,
default=int(os.getenv("AIOS_GITOPS_GITEA_TOKEN_LINE", "1")),
)
parser.add_argument(
"--state-root",
type=Path,
default=Path(
os.getenv(
"AIOS_GITOPS_PUBLICATION_STATE_DIR",
"/var/lib/aios-gitops/tag-publications",
)
),
)
args = parser.parse_args()
value = load_request()
publisher, git, gitea = build(args)
operation = value.get("operation")
if operation == "probe":
result = probe(args, value, publisher, git, gitea)
elif operation == "apply":
result = apply(args, value, publisher, git, gitea)
else:
raise ValueError("unsupported_operation")
print(json.dumps(result, sort_keys=True))
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except PublicationManualOwnerReviewRequired as exc:
print(json.dumps({"status": "CONFLICT", "reason": str(exc)}, sort_keys=True))
raise SystemExit(20)
except PublicationConflict as exc:
print(json.dumps({"status": "CONFLICT", "reason": str(exc)}, sort_keys=True))
raise SystemExit(20)
except (PublicationPending, PublicationReconciliationRequired) as exc:
print(json.dumps({"status": "INDETERMINATE", "reason": str(exc)}, sort_keys=True))
raise SystemExit(21)
except Exception as exc:
print(
json.dumps(
{"status": "INDETERMINATE", "error": type(exc).__name__, "reason": str(exc)},
sort_keys=True,
)
)
raise SystemExit(22)
+642
View File
@@ -0,0 +1,642 @@
#!/usr/bin/env python3
"""One-shot local Owner authentication ingress for AIOS.
This module deliberately does not mint a reusable Owner token.
Authentication is based on a real local login session:
- a root-run one-shot server owns a Unix socket;
- the client must run as the configured Owner OS account;
- the server validates SO_PEERCRED, Linux audit loginuid and the controlling TTY;
- the Owner must interactively confirm the exact task/branch/base request;
- the server constructs a narrow OwnerPrincipal and invokes the existing
OwnerAuthorizationBroker;
- one successful authorization consumes the service lifetime.
The resulting principal is fixed to one non-wildcard intake scope
(`commit:create` for the current deployment) and cannot carry production,
tag, baseline, main or history-rewrite capability.
This is a trust-root ingress, not a Git writer and not a production executor.
"""
from __future__ import annotations
import argparse
import fcntl
import hashlib
import json
import os
from pathlib import Path
import pwd
import re
import secrets
import socket
import stat
import struct
import sys
import tempfile
import time
from typing import Any, Mapping
BINDING_SCHEMA = "aios.local-owner-auth-ingress.v1"
CLIENT_BEGIN_SCHEMA = "aios.local-owner-auth-client-begin.v1"
CHALLENGE_SCHEMA = "aios.local-owner-auth-challenge.v1"
CLIENT_CONFIRM_SCHEMA = "aios.local-owner-auth-client-confirm.v1"
RESULT_SCHEMA = "aios.local-owner-auth-result.v1"
ACTION = "AUTHORIZE_TASK_WRITER_PROVISIONING"
OID_RE = re.compile(r"^[0-9a-f]{40}$")
IDENTITY_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._@:+/-]{1,254}$")
SCOPE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{1,127}$")
TASK_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:-]{1,255}$")
BRANCH_RE = re.compile(r"^agent/[A-Za-z0-9._/-]{1,220}$")
MAX_FRAME = 64 * 1024
CHALLENGE_TTL_SECONDS = 120
EXPECTED_ALLOWED_OPERATIONS = frozenset(
{
"create_worktree",
"create_target_branch_if_absent",
"commit_to_target_branch",
"push_target_branch",
}
)
EXPECTED_DENIED_OPERATIONS = frozenset(
{
"direct_main_push",
"force_push",
"tag_create",
"tag_update",
"tag_delete",
"branch_delete",
"repository_admin",
"baseline_write",
"production_deploy",
"production_marker_write",
"history_rewrite",
}
)
SENSITIVE_FRAGMENTS = (
"authorization_header",
"bearer",
"client_secret",
"password",
"private_key",
"raw_secret",
"raw_token",
"secret_value",
)
class BootstrapError(RuntimeError):
def __init__(self, code: str, status: int = 1) -> None:
super().__init__(code)
self.code = code
self.status = status
def canonical_json(value: Any) -> bytes:
return (
json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False)
+ "\n"
).encode("utf-8")
def sha256_json(value: Any) -> str:
return hashlib.sha256(canonical_json(value)).hexdigest()
def atomic_json(path: Path, value: Mapping[str, Any], mode: int = 0o600) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
if path.parent.is_symlink() or path.is_symlink():
raise BootstrapError("STATE_SYMLINK_REJECTED")
fd, name = tempfile.mkstemp(prefix=f".{path.name}.", dir=str(path.parent))
try:
os.fchmod(fd, mode)
with os.fdopen(fd, "wb", closefd=True) as stream:
stream.write(canonical_json(dict(value)))
stream.flush()
os.fsync(stream.fileno())
os.replace(name, path)
os.chmod(path, mode)
dfd = os.open(path.parent, os.O_RDONLY | getattr(os, "O_DIRECTORY", 0))
try:
os.fsync(dfd)
finally:
os.close(dfd)
finally:
try:
os.unlink(name)
except FileNotFoundError:
pass
def secure_root_file(path: Path) -> dict[str, Any]:
if path.is_symlink() or not path.is_file():
raise BootstrapError("BINDING_FILE_INVALID")
st = path.lstat()
if st.st_uid != 0:
raise BootstrapError("BINDING_FILE_ROOT_OWNER_REQUIRED")
if stat.S_IMODE(st.st_mode) & 0o077:
raise BootstrapError("BINDING_FILE_PERMISSIONS_INVALID")
if st.st_size <= 0 or st.st_size > 1_048_576:
raise BootstrapError("BINDING_FILE_SIZE_INVALID")
try:
value = json.loads(path.read_text(encoding="utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise BootstrapError("BINDING_JSON_INVALID") from exc
if not isinstance(value, dict):
raise BootstrapError("BINDING_JSON_INVALID")
return value
def validate_binding(value: Mapping[str, Any]) -> dict[str, Any]:
if set(value) != {
"schema",
"owner_identity",
"owner_role",
"authenticated_scope",
"request",
}:
raise BootstrapError("BINDING_FIELDS_REJECTED")
if value["schema"] != BINDING_SCHEMA:
raise BootstrapError("BINDING_SCHEMA_REJECTED")
identity = value["owner_identity"]
if not isinstance(identity, str) or not IDENTITY_RE.fullmatch(identity):
raise BootstrapError("OWNER_IDENTITY_INVALID")
if value["owner_role"] != "owner":
raise BootstrapError("OWNER_ROLE_INVALID")
scope = value["authenticated_scope"]
if (
not isinstance(scope, str)
or not SCOPE_RE.fullmatch(scope)
or scope == "writer:provision"
or scope == "*"
or scope.endswith(":*")
):
raise BootstrapError("OWNER_SCOPE_INVALID")
request = value["request"]
if not isinstance(request, dict):
raise BootstrapError("REQUEST_INVALID")
expected_fields = {
"action",
"task_id",
"repository",
"base_ref",
"base_oid",
"target_branch",
"one_time_use",
"expires_in_seconds",
"production_change_authorized",
"tag_change_authorized",
"baseline_change_authorized",
"main_write_authorized",
"allowed_operations",
"denied_operations",
}
if set(request) != expected_fields:
raise BootstrapError("REQUEST_FIELDS_REJECTED")
if request["action"] != ACTION:
raise BootstrapError("REQUEST_ACTION_REJECTED")
if request["repository"] != "aios/aios":
raise BootstrapError("REPOSITORY_REJECTED")
if request["base_ref"] != "refs/heads/main":
raise BootstrapError("BASE_REF_REJECTED")
if not isinstance(request["base_oid"], str) or not OID_RE.fullmatch(request["base_oid"]):
raise BootstrapError("BASE_OID_REJECTED")
if (
not isinstance(request["target_branch"], str)
or not BRANCH_RE.fullmatch(request["target_branch"])
):
raise BootstrapError("TARGET_BRANCH_REJECTED")
if (
not isinstance(request["task_id"], str)
or not TASK_RE.fullmatch(request["task_id"])
):
raise BootstrapError("TASK_ID_REJECTED")
if request["one_time_use"] is not True:
raise BootstrapError("ONE_TIME_USE_REQUIRED")
expiry = request["expires_in_seconds"]
if (
not isinstance(expiry, int)
or isinstance(expiry, bool)
or not 60 <= expiry <= 900
):
raise BootstrapError("EXPIRY_REJECTED")
for field in (
"production_change_authorized",
"tag_change_authorized",
"baseline_change_authorized",
"main_write_authorized",
):
if request[field] is not False:
raise BootstrapError("CONSEQUENTIAL_CAPABILITY_REJECTED")
if (
not isinstance(request["allowed_operations"], list)
or frozenset(request["allowed_operations"]) != EXPECTED_ALLOWED_OPERATIONS
):
raise BootstrapError("ALLOWED_OPERATIONS_MISMATCH")
if (
not isinstance(request["denied_operations"], list)
or frozenset(request["denied_operations"]) != EXPECTED_DENIED_OPERATIONS
):
raise BootstrapError("DENIED_OPERATIONS_MISMATCH")
return {
"schema": BINDING_SCHEMA,
"owner_identity": identity,
"owner_role": "owner",
"authenticated_scope": scope,
"request": dict(request),
}
def _status_uids(pid: int) -> tuple[int, int, int, int]:
try:
lines = Path(f"/proc/{pid}/status").read_text(encoding="utf-8").splitlines()
except OSError as exc:
raise BootstrapError("PEER_STATUS_UNAVAILABLE") from exc
for line in lines:
if line.startswith("Uid:"):
fields = line.split()[1:]
if len(fields) != 4:
break
return tuple(int(item) for item in fields) # type: ignore[return-value]
raise BootstrapError("PEER_UID_STATUS_INVALID")
def _loginuid(pid: int) -> int:
try:
raw = Path(f"/proc/{pid}/loginuid").read_text(encoding="ascii").strip()
value = int(raw)
except (OSError, ValueError) as exc:
raise BootstrapError("PEER_LOGINUID_UNAVAILABLE") from exc
if value == 4294967295:
raise BootstrapError("PEER_LOGIN_SESSION_REQUIRED")
return value
def _tty_path(pid: int) -> Path:
try:
value = os.readlink(f"/proc/{pid}/fd/0")
except OSError as exc:
raise BootstrapError("PEER_INTERACTIVE_TTY_REQUIRED") from exc
if not (value.startswith("/dev/pts/") or value.startswith("/dev/tty")):
raise BootstrapError("PEER_INTERACTIVE_TTY_REQUIRED")
path = Path(value)
try:
if not stat.S_ISCHR(path.stat().st_mode):
raise BootstrapError("PEER_INTERACTIVE_TTY_REQUIRED")
except OSError as exc:
raise BootstrapError("PEER_INTERACTIVE_TTY_REQUIRED") from exc
return path
def verify_peer_session(pid: int, uid: int, gid: int, owner_identity: str) -> dict[str, Any]:
try:
owner = pwd.getpwnam(owner_identity)
except KeyError as exc:
raise BootstrapError("OWNER_OS_ACCOUNT_MISSING") from exc
if uid != owner.pw_uid:
raise BootstrapError("PEER_OWNER_UID_MISMATCH")
uids = _status_uids(pid)
if any(item != owner.pw_uid for item in uids):
raise BootstrapError("PEER_UID_TRANSITION_REJECTED")
loginuid = _loginuid(pid)
if loginuid != owner.pw_uid:
# This deliberately rejects sudo/runuser from another authenticated
# account; the session itself must have logged in as the Owner.
raise BootstrapError("PEER_LOGINUID_OWNER_MISMATCH")
tty = _tty_path(pid)
if tty.stat().st_uid != owner.pw_uid:
raise BootstrapError("PEER_TTY_OWNER_MISMATCH")
return {
"pid": pid,
"uid": uid,
"gid": gid,
"loginuid": loginuid,
"tty": str(tty),
"owner_identity": owner_identity,
}
def read_frame(connection: socket.socket) -> dict[str, Any]:
data = bytearray()
while len(data) <= MAX_FRAME:
block = connection.recv(4096)
if not block:
break
data.extend(block)
if b"\n" in block:
break
if not data or len(data) > MAX_FRAME:
raise BootstrapError("PROTOCOL_FRAME_INVALID")
raw = bytes(data).split(b"\n", 1)[0]
try:
value = json.loads(raw)
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise BootstrapError("PROTOCOL_JSON_INVALID") from exc
if not isinstance(value, dict):
raise BootstrapError("PROTOCOL_JSON_INVALID")
return value
def write_frame(connection: socket.socket, value: Mapping[str, Any]) -> None:
connection.sendall(canonical_json(dict(value)))
def safe_result(value: Mapping[str, Any]) -> dict[str, Any]:
for key in value:
lowered = str(key).lower()
if any(fragment in lowered for fragment in SENSITIVE_FRAGMENTS):
raise BootstrapError("BROKER_RESPONSE_SENSITIVE_DATA_REJECTED")
allowed = {
"status",
"approval_plan_id",
"grant_id",
"grant_digest_sha256",
"branch_oid",
"branch_ref_created",
"grant_consumed",
"owner_authorization_event_id",
"owner_authorization_reference",
"owner_authorization_digest_sha256",
"owner_authorization_consumed",
"owner_authorization_idempotent",
}
return {key: value.get(key) for key in sorted(allowed) if key in value}
def request_summary(binding: Mapping[str, Any]) -> dict[str, Any]:
request = binding["request"]
return {
"owner_identity": binding["owner_identity"],
"authenticated_scope": binding["authenticated_scope"],
"task_id": request["task_id"],
"repository": request["repository"],
"base_ref": request["base_ref"],
"base_oid": request["base_oid"],
"target_branch": request["target_branch"],
"expires_in_seconds": request["expires_in_seconds"],
"allowed_operations": sorted(request["allowed_operations"]),
"denied_operations": sorted(request["denied_operations"]),
"production_change_authorized": False,
"tag_change_authorized": False,
"baseline_change_authorized": False,
"main_write_authorized": False,
}
def _ensure_runtime_paths(socket_path: Path, state_root: Path, owner_identity: str) -> None:
if os.geteuid() != 0:
raise BootstrapError("SERVER_ROOT_REQUIRED")
owner = pwd.getpwnam(owner_identity)
for directory, mode, uid, gid in (
(socket_path.parent, 0o750, 0, owner.pw_gid),
(state_root, 0o700, 0, 0),
):
if directory.is_symlink():
raise BootstrapError("RUNTIME_DIRECTORY_SYMLINK_REJECTED")
directory.mkdir(parents=True, exist_ok=True)
os.chown(directory, uid, gid)
os.chmod(directory, mode)
if socket_path.exists() or socket_path.is_symlink():
raise BootstrapError("SOCKET_ALREADY_EXISTS")
def _lock(path: Path):
path.parent.mkdir(parents=True, exist_ok=True)
fd = os.open(path, os.O_RDWR | os.O_CREAT | getattr(os, "O_NOFOLLOW", 0), 0o600)
os.fchmod(fd, 0o600)
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
return fd
def invoke_broker(binding: Mapping[str, Any]) -> dict[str, Any]:
# Import only on the root server side. The bootstrap package does not carry
# a second broker/provisioner implementation; it reuses current main.
from owner_authorization_broker import ( # type: ignore
OwnerAuthorizationBroker,
OwnerAuthorizationBrokerConfig,
OwnerPrincipal,
)
config = OwnerAuthorizationBrokerConfig.from_environment()
identity = str(binding["owner_identity"])
scope = str(binding["authenticated_scope"])
if identity not in config.allowed_owner_identities:
raise BootstrapError("OWNER_IDENTITY_NOT_ALLOWED_BY_LIVE_BROKER")
if scope not in config.allowed_intake_scopes:
raise BootstrapError("OWNER_SCOPE_NOT_ALLOWED_BY_LIVE_BROKER")
if config.max_expiry_seconds < int(binding["request"]["expires_in_seconds"]):
raise BootstrapError("LIVE_BROKER_EXPIRY_TOO_SMALL")
principal = OwnerPrincipal(
identity=identity,
role="owner",
authenticated_scope=scope,
token_scopes=frozenset({scope}),
credential_id="",
)
return OwnerAuthorizationBroker(config=config).authorize_and_provision(
binding["request"], principal
)
def serve(binding_path: Path, socket_path: Path, state_root: Path, timeout: int) -> int:
binding = validate_binding(secure_root_file(binding_path))
identity = str(binding["owner_identity"])
_ensure_runtime_paths(socket_path, state_root, identity)
lock_fd = _lock(state_root / "bootstrap.lock")
listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
listener.bind(str(socket_path))
owner = pwd.getpwnam(identity)
os.chown(socket_path, 0, owner.pw_gid)
os.chmod(socket_path, 0o660)
listener.listen(1)
listener.settimeout(timeout)
connection, _ = listener.accept()
with connection:
raw_peer = connection.getsockopt(
socket.SOL_SOCKET, socket.SO_PEERCRED, struct.calcsize("3i")
)
pid, uid, gid = struct.unpack("3i", raw_peer)
session = verify_peer_session(pid, uid, gid, identity)
begin = read_frame(connection)
if begin != {"schema": CLIENT_BEGIN_SCHEMA, "action": "BEGIN"}:
raise BootstrapError("CLIENT_BEGIN_REJECTED")
challenge = secrets.token_hex(12)
challenge_issued = time.monotonic()
summary = request_summary(binding)
write_frame(
connection,
{
"schema": CHALLENGE_SCHEMA,
"challenge": challenge,
"expires_in_seconds": CHALLENGE_TTL_SECONDS,
"request_digest_sha256": sha256_json(binding["request"]),
"summary": summary,
},
)
confirm = read_frame(connection)
expected_confirmation = f"AUTHORIZE {challenge}"
if (
confirm.get("schema") != CLIENT_CONFIRM_SCHEMA
or confirm.get("challenge") != challenge
or confirm.get("confirmation") != expected_confirmation
):
raise BootstrapError("OWNER_INTERACTIVE_CONFIRMATION_REJECTED")
if time.monotonic() - challenge_issued > CHALLENGE_TTL_SECONDS:
raise BootstrapError("OWNER_CONFIRMATION_EXPIRED")
result = safe_result(invoke_broker(binding))
receipt = {
"schema": "aios.local-owner-auth-ingress-receipt.v1",
"status": "CONSUMED",
"owner_identity": identity,
"owner_role": "owner",
"authenticated_scope": binding["authenticated_scope"],
"peer": session,
"request_digest_sha256": sha256_json(binding["request"]),
"binding_digest_sha256": sha256_json(binding),
"challenge_digest_sha256": hashlib.sha256(
challenge.encode("ascii")
).hexdigest(),
"broker": result,
"completed_at_unix": int(time.time()),
}
event_id = str(
result.get("owner_authorization_event_id")
or hashlib.sha256(
canonical_json(
{
"peer": session,
"request": sha256_json(binding["request"]),
}
)
).hexdigest()[:32]
)
atomic_json(state_root / "events" / f"{event_id}.json", receipt)
write_frame(
connection,
{
"schema": RESULT_SCHEMA,
"ok": True,
"result": result,
},
)
return 0
except (BootstrapError, TimeoutError, socket.timeout) as exc:
code = exc.code if isinstance(exc, BootstrapError) else "OWNER_BOOTSTRAP_TIMEOUT"
try:
if "connection" in locals():
write_frame(
connection,
{
"schema": RESULT_SCHEMA,
"ok": False,
"error": code,
},
)
except Exception:
pass
atomic_json(
state_root / "last-failure.json",
{
"schema": "aios.local-owner-auth-ingress-failure.v1",
"status": "FAILED",
"error": code,
"binding_digest_sha256": sha256_json(binding),
"failed_at_unix": int(time.time()),
},
)
return 2
finally:
listener.close()
try:
socket_path.unlink()
except FileNotFoundError:
pass
try:
fcntl.flock(lock_fd, fcntl.LOCK_UN)
finally:
os.close(lock_fd)
def client(socket_path: Path) -> int:
# The server performs the authoritative peer/session checks. The client
# also refuses non-interactive execution to make accidental automation hard.
if not sys.stdin.isatty() or not sys.stdout.isatty():
raise BootstrapError("CLIENT_INTERACTIVE_TTY_REQUIRED")
connection = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
connection.connect(str(socket_path))
with connection:
write_frame(connection, {"schema": CLIENT_BEGIN_SCHEMA, "action": "BEGIN"})
challenge = read_frame(connection)
if challenge.get("schema") != CHALLENGE_SCHEMA:
raise BootstrapError("CHALLENGE_INVALID")
summary = challenge.get("summary")
if not isinstance(summary, dict):
raise BootstrapError("CHALLENGE_INVALID")
print("\nAIOS one-shot Owner authorization request:")
print(json.dumps(summary, indent=2, sort_keys=True))
print("\nThis authorizes only the task writer shown above.")
phrase = f"AUTHORIZE {challenge['challenge']}"
typed = input(f"Type exactly:\n{phrase}\n> ").strip()
if typed != phrase:
raise BootstrapError("OWNER_CONFIRMATION_MISMATCH")
write_frame(
connection,
{
"schema": CLIENT_CONFIRM_SCHEMA,
"challenge": challenge["challenge"],
"confirmation": typed,
},
)
result = read_frame(connection)
print(json.dumps(result, indent=2, sort_keys=True))
return 0 if result.get("ok") is True else 3
def parser() -> argparse.ArgumentParser:
value = argparse.ArgumentParser()
mode = value.add_mutually_exclusive_group(required=True)
mode.add_argument("--serve", action="store_true")
mode.add_argument("--client", action="store_true")
value.add_argument("--binding", type=Path)
value.add_argument(
"--socket",
type=Path,
default=Path("/run/aios-owner-bootstrap/owner.sock"),
)
value.add_argument(
"--state-root",
type=Path,
default=Path("/var/lib/aios-gitops/owner-local-auth-ingress"),
)
value.add_argument("--timeout", type=int, default=300)
return value
def main(argv: list[str] | None = None) -> int:
args = parser().parse_args(argv)
if args.serve:
if args.binding is None:
raise SystemExit("--binding is required with --serve")
return serve(args.binding, args.socket, args.state_root, args.timeout)
return client(args.socket)
if __name__ == "__main__":
try:
raise SystemExit(main())
except BootstrapError as exc:
print(json.dumps({"status": "BLOCKED", "error": exc.code}), file=sys.stderr)
raise SystemExit(exc.status)
+410
View File
@@ -0,0 +1,410 @@
#!/usr/bin/env python3
"""Atomic Registry/Baseline finalizer for an already ACTIVE exact release.
This adapter never writes Git refs. It is intended for the AIOS runtime
Registry and authoritative runtime-anchor Baseline only.
Registry is finalized before Baseline. Baseline apply independently verifies:
- exact Authority annotated tag and peeled target
- exact ACTIVE production health
- exact V2R1C7 Registry record
- exact previous Baseline file SHA-256 (CAS)
"""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import re
import stat
import subprocess
import sys
import tempfile
import time
import urllib.error
import urllib.request
from pathlib import Path
from typing import Any, Mapping
OID_RE = re.compile(r"^[0-9a-f]{40}$")
SHA_RE = re.compile(r"^[0-9a-f]{64}$")
PLAN_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
def sha256_file(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as source:
for block in iter(lambda: source.read(1024 * 1024), b""):
digest.update(block)
return digest.hexdigest()
def atomic_json(path: Path, value: Mapping[str, Any], mode: int = 0o640) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
# Existing runtime-authority files may be root:gitops and read-only to
# non-root readers. Preserve their owner/group/mode across os.replace().
if path.exists():
metadata = path.lstat()
if not stat.S_ISREG(metadata.st_mode) or path.is_symlink():
raise RuntimeError("ATOMIC_TARGET_NOT_REGULAR")
target_mode = stat.S_IMODE(metadata.st_mode)
target_uid = metadata.st_uid
target_gid = metadata.st_gid
else:
parent = path.parent.stat()
target_mode = mode
target_uid = 0 if os.geteuid() == 0 else os.geteuid()
target_gid = parent.st_gid
fd, name = tempfile.mkstemp(prefix=f".{path.name}.", dir=str(path.parent))
try:
with os.fdopen(fd, "w", encoding="utf-8") as output:
json.dump(dict(value), output, sort_keys=True, indent=2)
output.write("\n")
output.flush()
os.fsync(output.fileno())
os.chmod(name, target_mode)
if os.geteuid() == 0:
os.chown(name, target_uid, target_gid)
os.replace(name, path)
dfd = os.open(path.parent, os.O_RDONLY | os.O_DIRECTORY)
try:
os.fsync(dfd)
finally:
os.close(dfd)
finally:
try:
os.unlink(name)
except FileNotFoundError:
pass
def load_request() -> dict[str, Any]:
value = json.load(sys.stdin)
if not isinstance(value, dict) or value.get("schema") != "aios.production-executor-request.v1":
raise ValueError("request_schema_invalid")
if value.get("repository_identity") != "aios/aios":
raise ValueError("repository_identity_invalid")
if not re.fullmatch(r"V\d+R\d+C\d+(?:-[A-Za-z0-9_.-]+)?", str(value.get("version", ""))):
raise ValueError("version_invalid")
for name in ("target_oid", "evidence_closure_oid"):
if not OID_RE.fullmatch(str(value.get(name, ""))):
raise ValueError(f"{name}_invalid")
if not SHA_RE.fullmatch(str(value.get("artifact_sha256", ""))):
raise ValueError("artifact_sha256_invalid")
if not PLAN_RE.fullmatch(str(value.get("approval_plan_id", ""))):
raise ValueError("approval_plan_id_invalid")
if "tag_oid" in value and not OID_RE.fullmatch(str(value["tag_oid"])):
raise ValueError("tag_oid_invalid")
return value
def exact_response(value: Mapping[str, Any], status: str, **extra: Any) -> dict[str, Any]:
return {
"status": status,
"version": value["version"],
"target_oid": value["target_oid"],
"evidence_closure_oid": value["evidence_closure_oid"],
"artifact_sha256": value["artifact_sha256"],
"approval_plan_id": value["approval_plan_id"],
**extra,
}
def git(repository: Path, *args: str, check: bool = True) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["git", f"--git-dir={repository}", *args],
check=check,
capture_output=True,
text=True,
timeout=30,
env={"PATH": os.environ.get("PATH", "")},
)
def verify_local_tag(repository: Path, value: Mapping[str, Any]) -> tuple[str, str]:
tag_oid = git(repository, "rev-parse", "--verify", f"refs/tags/{value['version']}").stdout.strip()
peeled = git(repository, "rev-parse", "--verify", f"refs/tags/{value['version']}^{{commit}}").stdout.strip()
if tag_oid == peeled or peeled != value["target_oid"]:
raise RuntimeError("FORMAL_TAG_BINDING_MISMATCH")
requested = value.get("tag_oid")
if requested and requested != tag_oid:
raise RuntimeError("FORMAL_TAG_OBJECT_MISMATCH")
return tag_oid, peeled
def health(url: str, value: Mapping[str, Any]) -> dict[str, Any]:
try:
with urllib.request.urlopen(url, timeout=5) as response:
body = json.loads(response.read().decode("utf-8"))
status = response.status
except (urllib.error.URLError, TimeoutError, ValueError) as exc:
raise RuntimeError("PRODUCTION_HEALTH_UNAVAILABLE") from exc
if not (
status == 200
and body.get("version") == value["version"]
and body.get("commit_oid") == value["target_oid"]
and body.get("artifact_sha256") == value["artifact_sha256"]
and body.get("deployment_state") == "ACTIVE"
and body.get("production_deployed") is True
):
raise RuntimeError("PRODUCTION_HEALTH_BINDING_MISMATCH")
return body
def registry_record(value: Mapping[str, Any], tag_oid: str, production_health: Mapping[str, Any]) -> dict[str, Any]:
return {
"schema": "aios.production-registry.v2",
"version": value["version"],
"repository": "aios/aios",
"target_oid": value["target_oid"],
"tag": value["version"],
"tag_oid": tag_oid,
"tag_object": tag_oid,
"peeled_target_oid": value["target_oid"],
"evidence_closure_oid": value["evidence_closure_oid"],
"artifact_sha256": value["artifact_sha256"],
"approval_plan_id": value["approval_plan_id"],
"production_service": value["production_service"],
"production_port": value["production_port"],
"registered": True,
"enabled": True,
"production_deployed": True,
"status": "PRODUCTION_DEPLOYED",
"deployment_state": production_health["deployment_state"],
"updated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
}
def registry_matches(record: Mapping[str, Any], value: Mapping[str, Any], tag_oid: str) -> bool:
return all(
record.get(key) == expected
for key, expected in {
"version": value["version"],
"target_oid": value["target_oid"],
"tag_oid": tag_oid,
"evidence_closure_oid": value["evidence_closure_oid"],
"artifact_sha256": value["artifact_sha256"],
"approval_plan_id": value["approval_plan_id"],
"production_service": value["production_service"],
"production_port": value["production_port"],
"production_deployed": True,
}.items()
) and record.get("registered") is True and record.get("enabled") is True
def baseline_matches(record: Mapping[str, Any], value: Mapping[str, Any], tag_oid: str) -> bool:
current = record.get("current_baseline") or record.get("version")
return current == value["version"] and all(
record.get(key) == expected
for key, expected in {
"target_oid": value["target_oid"],
"tag_oid": tag_oid,
"evidence_closure_oid": value["evidence_closure_oid"],
"artifact_sha256": value["artifact_sha256"],
"approval_plan_id": value["approval_plan_id"],
"production_service": value["production_service"],
"production_port": value["production_port"],
"status": "PRODUCTION_DEPLOYED",
}.items()
)
def registry_probe(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Any]:
tag_oid, _ = verify_local_tag(args.repository, value)
path = args.registry_root / f"{value['version']}.json"
if not path.exists():
return exact_response(value, "NOT_APPLIED", tag_oid=tag_oid)
record = json.loads(path.read_text(encoding="utf-8"))
if registry_matches(record, value, tag_oid):
return exact_response(
value,
"VERIFIED",
tag_oid=tag_oid,
registry_path=str(path),
registry_sha256=sha256_file(path),
)
return exact_response(value, "CONFLICT", tag_oid=tag_oid, reason="registry_binding_mismatch")
def registry_apply(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Any]:
existing = registry_probe(args, value)
if existing["status"] in {"VERIFIED", "CONFLICT"}:
return existing
tag_oid, _ = verify_local_tag(args.repository, value)
production_health = health(args.health_url, value)
path = args.registry_root / f"{value['version']}.json"
atomic_json(path, registry_record(value, tag_oid, production_health))
return registry_probe(args, value)
def secure_baseline_authority_file(path: Path) -> None:
if not path.is_file() or path.is_symlink():
raise RuntimeError("BASELINE_AUTHORITY_FILE_INVALID")
baseline_stat = path.lstat()
if baseline_stat.st_uid != 0 or baseline_stat.st_mode & 0o022:
raise RuntimeError("BASELINE_AUTHORITY_PERMISSIONS_INVALID")
def baseline_probe(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Any]:
tag_oid, _ = verify_local_tag(args.repository, value)
secure_baseline_authority_file(args.baseline_path)
record = json.loads(args.baseline_path.read_text(encoding="utf-8"))
if baseline_matches(record, value, tag_oid):
return exact_response(
value,
"VERIFIED",
tag_oid=tag_oid,
baseline_path=str(args.baseline_path),
baseline_sha256=sha256_file(args.baseline_path),
)
current = record.get("current_baseline") or record.get("version")
current_sha = sha256_file(args.baseline_path)
if (
current == args.expected_previous_baseline
and current_sha == args.expected_previous_baseline_sha256
):
return exact_response(
value,
"NOT_APPLIED",
tag_oid=tag_oid,
previous_baseline=current,
previous_baseline_sha256=current_sha,
)
return exact_response(
value,
"CONFLICT",
tag_oid=tag_oid,
reason="baseline_precondition_or_binding_mismatch",
observed_baseline=current,
observed_sha256=current_sha,
)
def baseline_apply(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Any]:
existing = baseline_probe(args, value)
if existing["status"] in {"VERIFIED", "CONFLICT"}:
return existing
tag_oid, _ = verify_local_tag(args.repository, value)
production_health = health(args.health_url, value)
registry_path = args.registry_root / f"{value['version']}.json"
if not registry_path.is_file():
raise RuntimeError("REGISTRY_NOT_FINALIZED")
registry = json.loads(registry_path.read_text(encoding="utf-8"))
if not registry_matches(registry, value, tag_oid):
raise RuntimeError("REGISTRY_BINDING_NOT_VERIFIED")
previous = json.loads(args.baseline_path.read_text(encoding="utf-8"))
if sha256_file(args.baseline_path) != args.expected_previous_baseline_sha256:
raise RuntimeError("BASELINE_CAS_MISMATCH")
generation = max(
int(previous.get("generation", 0) or 0),
int(previous.get("authority_generation", 0) or 0),
) + 1
record = {
"schema": "aios.production-baseline.v2",
"source_identity": "aios-gitops-runtime-anchor-baseline-authority-v1",
"current_baseline": value["version"],
"version": value["version"],
"previous_baseline": args.expected_previous_baseline,
"previous_version": args.expected_previous_baseline,
"status": "PRODUCTION_DEPLOYED",
"target_oid": value["target_oid"],
"peeled_target_oid": value["target_oid"],
"tag_oid": tag_oid,
"evidence_closure_oid": value["evidence_closure_oid"],
"approval_plan_id": value["approval_plan_id"],
"artifact_sha256": value["artifact_sha256"],
"production_artifact_sha256": value["artifact_sha256"],
"production_service": value["production_service"],
"production_port": value["production_port"],
"production_deployed": True,
"deployment_state": production_health["deployment_state"],
"registry_digest": sha256_file(registry_path),
"registry_source": str(registry_path),
"generation": generation,
"authority_generation": generation,
# The actual previously deployed production baseline is the rollback
# target. V2R1C6 has a formal tag but was never production-deployed.
"rollback_version": args.expected_previous_baseline,
"rollback_tag_oid": previous.get("tag_oid"),
"rollback_target_oid": previous.get("target_oid"),
"promoted_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"promoted_by": "aios-approved-production-release-executor",
}
atomic_json(args.baseline_path, record)
return baseline_probe(args, value)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument(
"--mode",
choices=("registry", "baseline"),
default=os.environ.get("AIOS_RELEASE_METADATA_MODE"),
required=os.environ.get("AIOS_RELEASE_METADATA_MODE") is None,
)
parser.add_argument(
"--repository",
type=Path,
default=Path(os.environ["AIOS_GITOPS_AUTHORITATIVE_GIT_DIR"]),
)
parser.add_argument(
"--registry-root",
type=Path,
default=Path(os.environ["AIOS_RUNTIME_REGISTRY_ROOT"]),
)
parser.add_argument(
"--baseline-path",
type=Path,
default=Path(os.environ["AIOS_RUNTIME_BASELINE_PATH"]),
)
parser.add_argument(
"--expected-previous-baseline",
default=os.environ.get("AIOS_PREVIOUS_BASELINE", "V2R1C5"),
)
parser.add_argument(
"--expected-previous-baseline-sha256",
default=os.environ.get("AIOS_PREVIOUS_BASELINE_SHA256"),
required=os.environ.get("AIOS_PREVIOUS_BASELINE_SHA256") is None,
)
parser.add_argument(
"--health-url",
default=os.environ.get("AIOS_RELEASE_HEALTH_URL", "http://127.0.0.1:18927/health"),
)
args = parser.parse_args()
value = load_request()
operation = value.get("operation")
if args.mode == "registry":
if operation == "probe":
result = registry_probe(args, value)
elif operation == "apply":
result = registry_apply(args, value)
else:
raise ValueError("unsupported_operation")
else:
if operation == "probe":
result = baseline_probe(args, value)
elif operation == "apply":
result = baseline_apply(args, value)
else:
raise ValueError("unsupported_operation")
print(json.dumps(result, sort_keys=True))
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as exc:
print(
json.dumps(
{"status": "FAIL_CLOSED", "error": type(exc).__name__, "reason": str(exc)},
sort_keys=True,
)
)
raise SystemExit(2)
+455
View File
@@ -0,0 +1,455 @@
#!/usr/bin/env python3
"""Concrete V2R1C7 production deployment adapter.
The adapter consumes only an already approved immutable artifact. It never
writes Git refs, Registry, or Baseline. A rollback only tears down the V2R1C7
runtime and leaves V2R1C5/V2R1C6 untouched.
"""
from __future__ import annotations
import argparse
import grp
import hashlib
import json
import os
import pwd
import shutil
import stat
import subprocess
import sys
import tarfile
import tempfile
import time
import urllib.error
import urllib.request
from pathlib import Path
from typing import Any, Mapping
VERSION = "V2R1C7"
SERVICE = "aios-v2r1c7-production.service"
PORT = 18927
RUNTIME_USER = "aios-v2r1c7"
RUNTIME_GROUP = "aios-v2r1c7"
REQUIRED_MEMBERS = {
"payload/VERSION",
"payload/active-runtime/app/deployment_state.py",
"payload/active-runtime/app/v2r1c6_privacy_tools.py",
"payload/active-runtime/app/v2r1c7_health_service.py",
"payload/deploy/aios-v2/systemd/aios-v2r1c7-production.service",
"payload/deploy/aios-v2/v2r1c7-runtime-config.json",
"payload/deploy/aios-v2/v2r1c7-rollback.json",
"payload/scripts/probe_v2r1c7_health.py",
"payload/scripts/rollback_v2r1c7_release.sh",
"payload/BUILD-METADATA.json",
"payload/ARTIFACT-MANIFEST.json",
"payload/ROLLBACK-METADATA.json",
}
def load_request() -> dict[str, Any]:
value = json.load(sys.stdin)
if not isinstance(value, dict):
raise ValueError("request_object_required")
if value.get("schema") != "aios.production-executor-request.v1":
raise ValueError("request_schema_invalid")
if value.get("version") != VERSION:
raise ValueError("version_mismatch")
if value.get("production_service") != SERVICE:
raise ValueError("service_mismatch")
if int(value.get("production_port", -1)) != PORT:
raise ValueError("port_mismatch")
return value
def sha256_file(path: Path) -> str:
if path.is_symlink() or not path.is_file():
raise ValueError("artifact_regular_file_required")
digest = hashlib.sha256()
with path.open("rb") as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def atomic_json(path: Path, value: Mapping[str, Any], *, mode: int, gid: int | None = None) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_name(path.name + ".tmp")
temporary.write_text(
json.dumps(dict(value), sort_keys=True, separators=(",", ":")) + "\n",
encoding="utf-8",
)
os.chmod(temporary, mode)
if gid is not None:
os.chown(temporary, 0, gid)
os.replace(temporary, path)
def atomic_text(path: Path, text: str, *, mode: int, gid: int | None = None) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_name(path.name + ".tmp")
temporary.write_text(text, encoding="utf-8")
os.chmod(temporary, mode)
if gid is not None:
os.chown(temporary, 0, gid)
os.replace(temporary, path)
def systemctl(*args: str, check: bool = True) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["systemctl", *args],
check=check,
capture_output=True,
text=True,
timeout=45,
env={"PATH": os.environ.get("PATH", "")},
)
def identity() -> tuple[int, int]:
try:
user = pwd.getpwnam(RUNTIME_USER)
group = grp.getgrnam(RUNTIME_GROUP)
except KeyError as exc:
raise RuntimeError("RUNTIME_IDENTITY_MISSING") from exc
if user.pw_gid != group.gr_gid:
raise RuntimeError("RUNTIME_IDENTITY_GROUP_MISMATCH")
return user.pw_uid, group.gr_gid
def safe_extract(artifact: Path, destination: Path) -> set[str]:
with tempfile.TemporaryDirectory(prefix="aios-v2r1c7-unpack-") as temp:
tar_path = Path(temp) / "release.tar"
with tar_path.open("wb") as output:
completed = subprocess.run(
["zstd", "-dc", str(artifact)],
check=False,
stdout=output,
stderr=subprocess.PIPE,
timeout=60,
env={"PATH": os.environ.get("PATH", "")},
)
if completed.returncode != 0:
raise RuntimeError("ARTIFACT_DECOMPRESSION_FAILED")
with tarfile.open(tar_path, "r:") as archive:
members = archive.getmembers()
names = {m.name for m in members}
missing = REQUIRED_MEMBERS - names
if missing:
raise RuntimeError("ARTIFACT_MEMBERS_MISSING:" + ",".join(sorted(missing)))
for member in members:
relative = Path(member.name)
if (
relative.is_absolute()
or ".." in relative.parts
or member.issym()
or member.islnk()
or not (member.isfile() or member.isdir())
):
raise RuntimeError("UNSAFE_ARTIFACT_MEMBER:" + member.name)
if not member.name.startswith("payload/"):
raise RuntimeError("UNEXPECTED_ARTIFACT_ROOT:" + member.name)
payload = destination
payload.mkdir(parents=True, exist_ok=True)
for member in members:
rel = Path(member.name).relative_to("payload")
if str(rel) == ".":
continue
target = payload / rel
resolved_parent = target.parent.resolve()
resolved_parent.relative_to(payload.resolve())
if member.isdir():
target.mkdir(parents=True, exist_ok=True)
os.chmod(target, 0o755)
continue
target.parent.mkdir(parents=True, exist_ok=True)
source = archive.extractfile(member)
if source is None:
raise RuntimeError("ARTIFACT_MEMBER_READ_FAILED")
with target.open("wb") as output:
shutil.copyfileobj(source, output)
# Scripts must be executable; all other payload files are read-only.
mode = 0o755 if rel.parts and rel.parts[0] == "scripts" else 0o644
os.chmod(target, mode)
return names
def health(url: str, expected: Mapping[str, Any]) -> dict[str, Any]:
try:
with urllib.request.urlopen(url, timeout=5) as response:
body = json.loads(response.read().decode("utf-8"))
status = response.status
except (urllib.error.URLError, TimeoutError, ValueError):
return {"status": "UNAVAILABLE"}
exact = (
status == 200
and body.get("version") == expected["version"]
and body.get("commit_oid") == expected["target_oid"]
and body.get("artifact_sha256") == expected["artifact_sha256"]
and body.get("deployment_state") == "ACTIVE"
and body.get("production_deployed") is True
)
if not exact:
return {
"status": "CONFLICT",
"http_status": status,
"version": body.get("version"),
"target_oid": body.get("commit_oid"),
"artifact_sha256": body.get("artifact_sha256"),
"deployment_state": body.get("deployment_state"),
"production_deployed": body.get("production_deployed"),
}
return {
"status": "ACTIVE_VERIFIED",
"http_status": 200,
"version": body["version"],
"target_oid": body["commit_oid"],
"artifact_sha256": body["artifact_sha256"],
"deployment_state": body["deployment_state"],
"production_deployed": True,
}
def paths(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Path]:
release_id = (
f"{VERSION}-{str(value['target_oid'])[:12]}-"
f"{str(value['artifact_sha256'])[:12]}"
)
return {
"release_dir": args.release_root / release_id,
"current_link": args.current_link,
"env_file": args.env_file,
"state_file": args.state_file,
"unit_file": args.unit_file,
}
def probe(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Any]:
p = paths(args, value)
url = f"http://127.0.0.1:{PORT}/health"
active = systemctl("is-active", "--quiet", SERVICE, check=False).returncode == 0
if not active:
# A stale exact release directory is safe to reuse; it is not a deployment.
return {
"status": "NOT_APPLIED",
"version": VERSION,
"target_oid": value["target_oid"],
"artifact_sha256": value["artifact_sha256"],
"production_deployed": False,
"deployment_state": "ROLLED_BACK"
if p["state_file"].exists()
and "ROLLED_BACK" in p["state_file"].read_text(encoding="utf-8")
else "ABSENT",
}
result = health(url, value)
if result["status"] == "UNAVAILABLE":
return {
"status": "CONFLICT",
"version": VERSION,
"target_oid": value["target_oid"],
"artifact_sha256": value["artifact_sha256"],
"reason": "service_active_health_unavailable",
}
return result
def install_release(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Any]:
_, gid = identity()
artifact = Path(str(value["artifact_path"]))
if artifact.stat().st_size != int(value["artifact_size"]):
raise RuntimeError("ARTIFACT_SIZE_MISMATCH")
if sha256_file(artifact) != value["artifact_sha256"]:
raise RuntimeError("ARTIFACT_DIGEST_MISMATCH")
p = paths(args, value)
release_dir = p["release_dir"]
marker = release_dir / "DEPLOYMENT-BINDING.json"
marker_value = {
"schema": "aios.runtime-release-binding.v1",
"version": VERSION,
"target_oid": value["target_oid"],
"artifact_sha256": value["artifact_sha256"],
"approval_plan_id": value["approval_plan_id"],
}
if release_dir.exists():
if not marker.is_file():
raise RuntimeError("EXISTING_RELEASE_DIR_UNTRUSTED")
current_marker = json.loads(marker.read_text(encoding="utf-8"))
if current_marker != marker_value:
raise RuntimeError("EXISTING_RELEASE_DIR_BINDING_CONFLICT")
else:
release_dir.parent.mkdir(parents=True, exist_ok=True)
temp_dir = Path(
tempfile.mkdtemp(prefix=release_dir.name + ".", dir=str(release_dir.parent))
)
try:
safe_extract(artifact, temp_dir)
atomic_json(
temp_dir / "DEPLOYMENT-BINDING.json",
marker_value,
mode=0o644,
)
os.rename(temp_dir, release_dir)
except Exception:
shutil.rmtree(temp_dir, ignore_errors=True)
raise
if (release_dir / "VERSION").read_text(encoding="utf-8").strip() != VERSION:
raise RuntimeError("RELEASE_VERSION_FILE_MISMATCH")
# Only replace our dedicated V2R1C7 link. Never touch previous versions.
current_link = p["current_link"]
if current_link.exists() and not current_link.is_symlink():
raise RuntimeError("CURRENT_RELEASE_PATH_NOT_SYMLINK")
if current_link.is_symlink():
existing = current_link.resolve()
if existing != release_dir.resolve():
raise RuntimeError("CURRENT_RELEASE_LINK_CONFLICT")
else:
current_link.parent.mkdir(parents=True, exist_ok=True)
new_link = current_link.with_name(current_link.name + ".new")
try:
new_link.unlink()
except FileNotFoundError:
pass
new_link.symlink_to(release_dir)
os.replace(new_link, current_link)
state_value = {
"version": VERSION,
"commit_oid": value["target_oid"],
"artifact_sha256": value["artifact_sha256"],
"deployment_state": "ACTIVE",
}
atomic_json(p["state_file"], state_value, mode=0o640, gid=gid)
env = (
f"RELEASE_VERSION={VERSION}\n"
f"TARGET_OID={value['target_oid']}\n"
f"ARTIFACT_SHA256={value['artifact_sha256']}\n"
"DEPLOYMENT_STATE=ACTIVE\n"
f"AIOS_V2R1C7_PORT={PORT}\n"
f"DEPLOYMENT_STATE_FILE={p['state_file']}\n"
"AIOS_GITOPS_WRITES_ENABLED=false\n"
)
atomic_text(p["env_file"], env, mode=0o640, gid=gid)
unit_source = (
release_dir
/ "deploy"
/ "aios-v2"
/ "systemd"
/ "aios-v2r1c7-production.service"
)
unit_text = unit_source.read_text(encoding="utf-8")
if "aios-v2r1c7-production.service" in unit_text:
# Description text is irrelevant; service identity is the destination.
pass
atomic_text(p["unit_file"], unit_text, mode=0o644)
verify = subprocess.run(
["systemd-analyze", "verify", str(p["unit_file"])],
check=False,
capture_output=True,
text=True,
timeout=30,
env={"PATH": os.environ.get("PATH", "")},
)
if verify.returncode != 0:
raise RuntimeError("PRODUCTION_SYSTEMD_VERIFY_FAILED")
systemctl("daemon-reload")
systemctl("enable", SERVICE)
systemctl("restart", SERVICE)
deadline = time.time() + args.health_timeout
result = {"status": "UNAVAILABLE"}
while time.time() < deadline:
result = health(f"http://127.0.0.1:{PORT}/health", value)
if result["status"] == "ACTIVE_VERIFIED":
break
if result["status"] == "CONFLICT":
break
time.sleep(1)
if result["status"] != "ACTIVE_VERIFIED":
raise RuntimeError("PRODUCTION_HEALTH_VERIFY_FAILED")
# Restart recovery is part of production acceptance, not just staging.
systemctl("restart", SERVICE)
deadline = time.time() + args.health_timeout
while time.time() < deadline:
result = health(f"http://127.0.0.1:{PORT}/health", value)
if result["status"] == "ACTIVE_VERIFIED":
break
if result["status"] == "CONFLICT":
break
time.sleep(1)
if result["status"] != "ACTIVE_VERIFIED":
raise RuntimeError("PRODUCTION_RESTART_RECOVERY_FAILED")
return result
def rollback(args: argparse.Namespace, value: Mapping[str, Any]) -> dict[str, Any]:
_, gid = identity()
p = paths(args, value)
systemctl("stop", SERVICE, check=False)
systemctl("disable", SERVICE, check=False)
state = {
"version": VERSION,
"commit_oid": value["target_oid"],
"artifact_sha256": value["artifact_sha256"],
"deployment_state": "ROLLED_BACK",
}
atomic_json(p["state_file"], state, mode=0o640, gid=gid)
return {
"status": "ROLLED_BACK",
"version": VERSION,
"target_oid": value["target_oid"],
"artifact_sha256": value["artifact_sha256"],
"deployment_state": "ROLLED_BACK",
"production_deployed": False,
}
def main() -> int:
p = argparse.ArgumentParser()
p.add_argument("--release-root", type=Path, default=Path("/opt/aios/releases"))
p.add_argument("--current-link", type=Path, default=Path("/opt/aios/v2r1c7"))
p.add_argument("--env-file", type=Path, default=Path("/etc/aios/aios-v2r1c7.env"))
p.add_argument(
"--state-file",
type=Path,
default=Path("/var/lib/aios/v2r1c7/deployment-state.json"),
)
p.add_argument(
"--unit-file",
type=Path,
default=Path("/etc/systemd/system/aios-v2r1c7-production.service"),
)
p.add_argument("--health-timeout", type=int, default=30)
args = p.parse_args()
value = load_request()
operation = value.get("operation")
if operation == "probe":
result = probe(args, value)
elif operation == "apply":
result = install_release(args, value)
elif operation == "rollback":
result = rollback(args, value)
else:
raise ValueError("unsupported_operation")
print(json.dumps(result, sort_keys=True))
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as exc:
print(
json.dumps(
{"status": "FAIL_CLOSED", "error": type(exc).__name__, "reason": str(exc)},
sort_keys=True,
)
)
raise SystemExit(2)
@@ -0,0 +1,38 @@
[Unit]
Description=AIOS governed approved production release executor
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=root
Group=root
UMask=0077
Environment=PYTHONDONTWRITEBYTECODE=1
Environment=AIOS_GITOPS_WRITES_ENABLED=false
EnvironmentFile=/etc/aios-gitops/approved-release-executor.env
ExecStart=/usr/bin/python3 /usr/libexec/aios-approved-release-executor/current/active-runtime/app/approved_release_executor.py \
--authorization ${AIOS_RELEASE_AUTHORIZATION} \
--repository ${AIOS_GITOPS_AUTHORITATIVE_GIT_DIR} \
--state-root ${AIOS_RELEASE_EXECUTION_STATE_ROOT} \
--artifact ${AIOS_RELEASE_ARTIFACT} \
--artifact-size ${AIOS_RELEASE_ARTIFACT_SIZE} \
--version ${AIOS_RELEASE_VERSION} \
--target-oid ${AIOS_RELEASE_TARGET_OID} \
--evidence-closure-oid ${AIOS_RELEASE_EVIDENCE_CLOSURE_OID} \
--artifact-sha256 ${AIOS_RELEASE_ARTIFACT_SHA256} \
--approval-plan-id ${AIOS_RELEASE_APPROVAL_PLAN_ID} \
--production-service aios-v2r1c7-production.service \
--production-port 18927 \
--tag-adapter /usr/bin/python3 /usr/libexec/aios-approved-release-executor/current/active-runtime/app/governed_tag_adapter.py \
--deploy-adapter /usr/bin/python3 /usr/libexec/aios-approved-release-executor/current/active-runtime/app/v2r1c7_production_adapter.py \
--registry-adapter /usr/bin/env AIOS_RELEASE_METADATA_MODE=registry /usr/bin/python3 /usr/libexec/aios-approved-release-executor/current/active-runtime/app/release_metadata_adapter.py \
--baseline-adapter /usr/bin/env AIOS_RELEASE_METADATA_MODE=baseline /usr/bin/python3 /usr/libexec/aios-approved-release-executor/current/active-runtime/app/release_metadata_adapter.py
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
ReadWritePaths=/etc/aios /etc/systemd/system /opt/aios /var/lib/aios /var/lib/aios-gitops /var/lib/aios-gitops-runtime-anchor /data/aios-gitops
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,63 @@
# AIOS Approved Production Release Executor
Status: implementation artifact for governed protected-PR integration.
## Why this exists
The deployed `aios-silent-release-controller` is intentionally shadow-only.
It rejects production execution unless a trusted builder/orchestrator factory is
wired. V2R1C7 already completed post-merge deterministic build, staging,
rollback, evidence closure and exact Owner approval, so rebuilding inside the
production executor is both unnecessary and a deadlock source.
This patch adds a separate one-shot production executor. It **does not turn the
shadow controller into a production service**.
## Exact V2R1C7 binding
- target: `c7adece1cc8beffe7c718d53c775898b45d6c7f8`
- evidence: `8c2898baf07195b9861ed2ff74f03a71674ec9e9`
- artifact: `ce09a46f28b453634784abceda4597fd51c3aa0838e72a5ad5fefd03d58b949e`
- approval plan: `sha256:c8199d638c2bb2e4896ca9b219ca52db79713bee007df05653ab348905d6cf28`
The executor requires a root-owned accepted authorization receipt that matches
all five fields. It does not accept caller-supplied replacement evidence.
## Execution order
1. exact authorization + artifact + Git lineage preflight
2. annotated V2R1C7 Tag publication and Authority/network/Gitea verification
3. deploy exact artifact; health must report ACTIVE and exact target/digest
4. Registry atomic finalization
5. authoritative Production Baseline CAS finalization **last**
6. read back Tag/runtime/Registry/Baseline and require exact consistency
## Tag implementation
`governed_tag_adapter.py` is a thin adapter over the repository's existing
`gitea_tag_publication.TagPublisher`. It intentionally calls only the existing
tag verification/publication subroutine and never calls legacy
`TagPublisher.publish()` because that legacy operation finalizes Baseline before
the product runtime is ACTIVE.
## Runtime finalization
`release_metadata_adapter.py` writes no Git refs. Registry and Baseline are
runtime state only and are atomic/CAS guarded. Baseline apply independently
requires exact ACTIVE health, exact formal tag, exact Registry, and the exact
previous Baseline SHA-256.
For this release the previous **production** baseline is V2R1C5. V2R1C6 has a
formal tag but was never deployed, so rollback must return to V2R1C5.
## Governance
- force push: forbidden
- tag rewrite/delete: forbidden
- direct main push: forbidden
- V2R1C5/V2R1C6 mutation: forbidden
- plaintext secrets in Git: forbidden
- exact binding replacement: manual Owner review required
- after a verified Tag, uncertain errors become reconciliation-required
- global `AIOS_GITOPS_WRITES_ENABLED` stays false; this executor is a narrow,
separately installed production capability.
+53
View File
@@ -0,0 +1,53 @@
# AIOS Local Owner Authentication Ingress
This component closes the Owner authentication bootstrap gap without creating a
long-lived Owner PAT.
## Trust model
The ingress is deliberately one-shot and local-only.
1. A root-run server creates a Unix socket.
2. The peer must be the configured OS Owner account (`aiman`).
3. The server verifies Unix `SO_PEERCRED`, all four process UIDs, Linux audit
`loginuid`, and ownership of the controlling TTY.
4. A `sudo -u aiman` / `runuser` process from another authenticated login is
rejected because its audit `loginuid` does not equal the Owner UID.
5. The human Owner sees the exact task/base/branch/capability request and types
a random one-time challenge.
6. The server constructs only:
- identity: `aiman`
- role: `owner`
- authenticated scope: `commit:create`
- token scopes: [`commit:create`]
7. It calls the existing `OwnerAuthorizationBroker`; it does not call the
provisioner directly.
8. It exits and removes the socket after the single authorization attempt.
No reusable token is minted and no production/tag/baseline/main capability is
granted.
## Current V2R1C7 bootstrap binding
The bootstrap request is expected to authorize only:
- task: `V2R1C7_PRODUCTION_EXECUTOR_BOOTSTRAP`
- branch: `agent/v2r1c7-production-executor-bootstrap-20260807-r2`
- base: exact live `refs/heads/main`
- repository: `aios/aios`
- scope: `commit:create`
- TTL: <= 900 seconds
- production/tag/baseline/main write: false
## Installation model
For the current trust-root bootstrap, the exact SHA-verified script may be
staged under `/run/aios-owner-bootstrap/` and run by a transient root systemd
service. This staging step has no Git/Tag/Registry/Baseline side effect.
The Owner must connect from a real interactive login session as the OS account
`aiman`.
After the governed writer is issued, the same module and tests are committed
through the resulting protected engineering PR so future bootstrap uses code
from main rather than an out-of-band artifact.
+245
View File
@@ -0,0 +1,245 @@
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "active-runtime" / "app"))
from approved_release_executor import (
Binding,
DurableState,
ManualOwnerReviewRequired,
ReconciliationRequired,
deploy_step,
execute,
tag_step,
verify_authorization,
)
TARGET = "c7adece1cc8beffe7c718d53c775898b45d6c7f8"
EVIDENCE = "8c2898baf07195b9861ed2ff74f03a71674ec9e9"
ARTIFACT = "ce09a46f28b453634784abceda4597fd51c3aa0838e72a5ad5fefd03d58b949e"
PLAN = "sha256:c8199d638c2bb2e4896ca9b219ca52db79713bee007df05653ab348905d6cf28"
TAG_OID = "1" * 40
def binding(tmp_path: Path) -> Binding:
artifact = tmp_path / "release.tar.zst"
artifact.write_bytes(b"x")
return Binding(
version="VTEST",
target_oid=TARGET,
evidence_closure_oid=EVIDENCE,
artifact_sha256=ARTIFACT,
approval_plan_id=PLAN,
artifact_path=str(artifact),
artifact_size=1,
production_service="test.service",
production_port=18927,
)
def authorization(value: Binding) -> dict:
return {
"accepted": True,
"binding_replaced": False,
"version": value.version,
"target_oid": value.target_oid,
"evidence_closure_oid": value.evidence_closure_oid,
"artifact_sha256": value.artifact_sha256,
"approval_plan_id": value.approval_plan_id,
}
def test_owner_authorization_is_exact(tmp_path):
value = binding(tmp_path)
assert verify_authorization(authorization(value), value)["accepted"] is True
wrong = authorization(value)
wrong["artifact_sha256"] = "0" * 64
with pytest.raises(ManualOwnerReviewRequired):
verify_authorization(wrong, value)
def test_durable_state_rejects_different_binding(tmp_path):
first = binding(tmp_path)
DurableState(tmp_path / "state", first)
second = Binding(
**{
**first.__dict__,
"approval_plan_id": "sha256:" + "2" * 64,
}
)
with pytest.raises(ManualOwnerReviewRequired):
DurableState(tmp_path / "state", second)
def test_tag_conflict_never_applies(monkeypatch, tmp_path):
value = binding(tmp_path)
calls = []
def fake(command, request):
calls.append(request["operation"])
return {
"status": "CONFLICT",
"version": value.version,
"target_oid": value.target_oid,
"artifact_sha256": value.artifact_sha256,
}
monkeypatch.setattr("approved_release_executor.run_adapter", fake)
with pytest.raises(ManualOwnerReviewRequired):
tag_step(["/tag"], value)
assert calls == ["probe"]
def test_runtime_failure_attempts_rollback_after_apply(monkeypatch, tmp_path):
value = binding(tmp_path)
calls = []
probes = 0
def fake(command, request):
nonlocal probes
calls.append(request["operation"])
if request["operation"] == "probe":
probes += 1
if probes == 1:
return {
"status": "NOT_APPLIED",
"version": value.version,
"target_oid": value.target_oid,
"artifact_sha256": value.artifact_sha256,
}
return {
"status": "NOT_APPLIED",
"version": value.version,
"target_oid": value.target_oid,
"artifact_sha256": value.artifact_sha256,
}
if request["operation"] == "rollback":
return {
"status": "ROLLED_BACK",
"version": value.version,
"target_oid": value.target_oid,
"artifact_sha256": value.artifact_sha256,
}
return {
"status": "APPLY_STARTED",
"version": value.version,
"target_oid": value.target_oid,
"artifact_sha256": value.artifact_sha256,
}
monkeypatch.setattr("approved_release_executor.run_adapter", fake)
with pytest.raises(ReconciliationRequired):
deploy_step(["/deploy"], value)
assert calls == ["probe", "apply", "probe", "rollback"]
def test_execute_orders_registry_before_baseline_and_baseline_last(
monkeypatch, tmp_path
):
value = binding(tmp_path)
auth_path = tmp_path / "authorization.json"
auth_path.write_text(json.dumps(authorization(value)))
auth_path.chmod(0o600)
monkeypatch.setattr(
"approved_release_executor.secure_json",
lambda path: json.loads(path.read_text(encoding="utf-8")),
)
monkeypatch.setattr(
"approved_release_executor.verify_git_lineage",
lambda repo, binding: {"verified": True},
)
monkeypatch.setattr(
"approved_release_executor.verify_artifact",
lambda binding: {"verified": True},
)
calls = []
tag_applied = False
runtime_applied = False
registry_applied = False
baseline_applied = False
def fake(command, request):
nonlocal tag_applied, runtime_applied, registry_applied, baseline_applied
name = command[0]
operation = request["operation"]
calls.append((name, operation))
common = {
"version": value.version,
"target_oid": value.target_oid,
"artifact_sha256": value.artifact_sha256,
}
if name == "/tag":
if operation == "apply":
tag_applied = True
if tag_applied:
return {
**common,
"status": "APPLIED_VERIFIED",
"tag_oid": TAG_OID,
"peeled_target_oid": value.target_oid,
}
return {**common, "status": "NOT_APPLIED"}
if name == "/deploy":
if operation == "apply":
runtime_applied = True
if operation == "rollback":
return {**common, "status": "ROLLED_BACK"}
if runtime_applied:
return {
**common,
"status": "ACTIVE_VERIFIED",
"deployment_state": "ACTIVE",
"production_deployed": True,
}
return {**common, "status": "NOT_APPLIED"}
if name == "/registry":
if operation == "apply":
registry_applied = True
return {
**common,
"status": "VERIFIED" if registry_applied else "NOT_APPLIED",
"tag_oid": TAG_OID if registry_applied else None,
}
if name == "/baseline":
if operation == "apply":
assert registry_applied is True
assert runtime_applied is True
baseline_applied = True
return {
**common,
"status": "VERIFIED" if baseline_applied else "NOT_APPLIED",
"tag_oid": TAG_OID if baseline_applied else None,
}
raise AssertionError(name)
monkeypatch.setattr("approved_release_executor.run_adapter", fake)
result = execute(
binding=value,
authorization_path=auth_path,
repository=tmp_path / "repo.git",
state_root=tmp_path / "state",
tag_command=["/tag"],
deploy_command=["/deploy"],
registry_command=["/registry"],
baseline_command=["/baseline"],
)
assert result["status"] == "PRODUCTION_ACCEPTED"
assert calls.index(("/registry", "apply")) < calls.index(("/baseline", "apply"))
assert calls.index(("/deploy", "apply")) < calls.index(("/registry", "apply"))
state = json.loads((tmp_path / "state" / "execution.json").read_text())
assert state["state"] == "COMPLETED"
+152
View File
@@ -0,0 +1,152 @@
from __future__ import annotations
import json
import os
from pathlib import Path
import sys
import types
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "active-runtime" / "app"))
import owner_local_auth_ingress as ingress
TARGET = "c7adece1cc8beffe7c718d53c775898b45d6c7f8"
def binding():
return {
"schema": ingress.BINDING_SCHEMA,
"owner_identity": "aiman",
"owner_role": "owner",
"authenticated_scope": "commit:create",
"request": {
"action": ingress.ACTION,
"task_id": "V2R1C7_PRODUCTION_EXECUTOR_BOOTSTRAP",
"repository": "aios/aios",
"base_ref": "refs/heads/main",
"base_oid": TARGET,
"target_branch": "agent/v2r1c7-production-executor-bootstrap-20260807-r2",
"one_time_use": True,
"expires_in_seconds": 300,
"production_change_authorized": False,
"tag_change_authorized": False,
"baseline_change_authorized": False,
"main_write_authorized": False,
"allowed_operations": sorted(ingress.EXPECTED_ALLOWED_OPERATIONS),
"denied_operations": sorted(ingress.EXPECTED_DENIED_OPERATIONS),
},
}
def test_exact_binding_passes():
result = ingress.validate_binding(binding())
assert result["owner_identity"] == "aiman"
assert result["authenticated_scope"] == "commit:create"
@pytest.mark.parametrize(
("path", "value", "error"),
[
(("owner_identity",), "owner", None),
(("authenticated_scope",), "*", "OWNER_SCOPE_INVALID"),
(("request", "target_branch"), "patch/not-allowed", "TARGET_BRANCH_REJECTED"),
(("request", "production_change_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
(("request", "tag_change_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
(("request", "baseline_change_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
(("request", "main_write_authorized"), True, "CONSEQUENTIAL_CAPABILITY_REJECTED"),
(("request", "expires_in_seconds"), 901, "EXPIRY_REJECTED"),
],
)
def test_negative_binding_contract(path, value, error):
payload = binding()
target = payload
for item in path[:-1]:
target = target[item]
target[path[-1]] = value
if error is None:
# Structurally valid but not the deployment allowlisted identity;
# the live Broker performs that final allowlist check.
assert ingress.validate_binding(payload)["owner_identity"] == "owner"
else:
with pytest.raises(ingress.BootstrapError, match=error):
ingress.validate_binding(payload)
def test_request_summary_never_grants_consequential_capability():
summary = ingress.request_summary(ingress.validate_binding(binding()))
assert summary["production_change_authorized"] is False
assert summary["tag_change_authorized"] is False
assert summary["baseline_change_authorized"] is False
assert summary["main_write_authorized"] is False
def test_safe_result_rejects_secret_material():
with pytest.raises(ingress.BootstrapError, match="SENSITIVE_DATA"):
ingress.safe_result({"status": "READY", "raw_token": "secret"})
def test_safe_result_keeps_only_allowlisted_fields():
result = ingress.safe_result(
{
"status": "READY_FOR_CODE_AUTHORING",
"grant_id": "grant-1",
"some_untrusted_extra": "drop-me",
}
)
assert result == {
"grant_id": "grant-1",
"status": "READY_FOR_CODE_AUTHORING",
}
def test_invoke_broker_constructs_narrow_principal(monkeypatch):
captured = {}
class Config:
allowed_owner_identities = frozenset({"aiman"})
allowed_intake_scopes = frozenset({"commit:create"})
max_expiry_seconds = 900
@classmethod
def from_environment(cls):
return cls()
class Principal:
def __init__(self, **kwargs):
captured["principal"] = kwargs
class Broker:
def __init__(self, config):
captured["config"] = config
def authorize_and_provision(self, request, principal):
captured["request"] = request
return {
"status": "READY_FOR_CODE_AUTHORING",
"grant_id": "grant-test",
}
module = types.SimpleNamespace(
OwnerAuthorizationBroker=Broker,
OwnerAuthorizationBrokerConfig=Config,
OwnerPrincipal=Principal,
)
monkeypatch.setitem(sys.modules, "owner_authorization_broker", module)
result = ingress.invoke_broker(ingress.validate_binding(binding()))
assert result["status"] == "READY_FOR_CODE_AUTHORING"
assert captured["principal"] == {
"identity": "aiman",
"role": "owner",
"authenticated_scope": "commit:create",
"token_scopes": frozenset({"commit:create"}),
"credential_id": "",
}
def test_confirmation_phrase_is_exact():
challenge = "abc123"
assert f"AUTHORIZE {challenge}" == "AUTHORIZE abc123"
+116
View File
@@ -0,0 +1,116 @@
from __future__ import annotations
import hashlib
import json
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "active-runtime" / "app"))
import release_metadata_adapter as adapter
TARGET = "c7adece1cc8beffe7c718d53c775898b45d6c7f8"
EVIDENCE = "8c2898baf07195b9861ed2ff74f03a71674ec9e9"
ARTIFACT = "ce09a46f28b453634784abceda4597fd51c3aa0838e72a5ad5fefd03d58b949e"
PLAN = "sha256:c8199d638c2bb2e4896ca9b219ca52db79713bee007df05653ab348905d6cf28"
TAG = "1" * 40
def value():
return {
"version": "V2R1C7",
"target_oid": TARGET,
"evidence_closure_oid": EVIDENCE,
"artifact_sha256": ARTIFACT,
"approval_plan_id": PLAN,
"production_service": "aios-v2r1c7-production.service",
"production_port": 18927,
}
def old_baseline(path: Path) -> str:
data = {
"current_baseline": "V2R1C5",
"version": "V2R1C5",
"target_oid": "a" * 40,
"tag_oid": "b" * 40,
"generation": 2,
"authority_generation": 2,
"status": "PRODUCTION_DEPLOYED",
}
path.write_text(json.dumps(data, sort_keys=True) + "\n", encoding="utf-8")
return adapter.sha256_file(path)
def test_baseline_record_uses_real_previous_production_baseline(tmp_path, monkeypatch):
baseline = tmp_path / "baseline.json"
previous_sha = old_baseline(baseline)
registry_root = tmp_path / "versions"
registry_root.mkdir()
args = type("A", (), {
"repository": tmp_path / "repo.git",
"registry_root": registry_root,
"baseline_path": baseline,
"expected_previous_baseline": "V2R1C5",
"expected_previous_baseline_sha256": previous_sha,
"health_url": "http://127.0.0.1:18927/health",
})()
monkeypatch.setattr(adapter, "verify_local_tag", lambda *a: (TAG, TARGET))
monkeypatch.setattr(adapter, "secure_baseline_authority_file", lambda path: None)
monkeypatch.setattr(adapter, "health", lambda *a: {
"deployment_state": "ACTIVE",
"production_deployed": True,
})
registry = adapter.registry_record(value(), TAG, {"deployment_state": "ACTIVE"})
adapter.atomic_json(registry_root / "V2R1C7.json", registry)
result = adapter.baseline_apply(args, value())
assert result["status"] == "VERIFIED"
current = json.loads(baseline.read_text())
assert current["previous_baseline"] == "V2R1C5"
assert current["rollback_version"] == "V2R1C5"
assert current["rollback_target_oid"] == "a" * 40
assert current["status"] == "PRODUCTION_DEPLOYED"
def test_baseline_cas_conflict_fails_closed(tmp_path, monkeypatch):
baseline = tmp_path / "baseline.json"
previous_sha = old_baseline(baseline)
baseline.write_text('{"current_baseline":"OTHER"}\n', encoding="utf-8")
args = type("A", (), {
"repository": tmp_path / "repo.git",
"registry_root": tmp_path / "versions",
"baseline_path": baseline,
"expected_previous_baseline": "V2R1C5",
"expected_previous_baseline_sha256": previous_sha,
"health_url": "http://127.0.0.1:18927/health",
})()
monkeypatch.setattr(adapter, "verify_local_tag", lambda *a: (TAG, TARGET))
monkeypatch.setattr(adapter, "secure_baseline_authority_file", lambda path: None)
result = adapter.baseline_probe(args, value())
assert result["status"] == "CONFLICT"
def test_registry_record_binds_all_exact_release_fields():
record = adapter.registry_record(value(), TAG, {"deployment_state": "ACTIVE"})
assert record["target_oid"] == TARGET
assert record["artifact_sha256"] == ARTIFACT
assert record["evidence_closure_oid"] == EVIDENCE
assert record["approval_plan_id"] == PLAN
assert record["tag_oid"] == TAG
assert record["production_deployed"] is True
def test_atomic_json_preserves_existing_mode(tmp_path):
target = tmp_path / "current.json"
target.write_text('{"old":true}\n', encoding="utf-8")
target.chmod(0o440)
before = target.stat()
adapter.atomic_json(target, {"new": True})
after = target.stat()
assert after.st_mode & 0o777 == 0o440
assert after.st_uid == before.st_uid
assert after.st_gid == before.st_gid