Files
aios/tests/test_c5_exact_deployment_adapter.py
T
AIOS Governed Continuation 540e28a724
autonomy-smoke-tests Exact governed tree; evidence 7dbba7ff168e72af
autonomy-unit-tests Exact governed tree; evidence 7dbba7ff168e72af
campaign-approval-gate Exact governed tree; evidence 7dbba7ff168e72af
git-diff-check Exact governed tree; evidence 7dbba7ff168e72af
py-compile Exact governed tree; evidence 7dbba7ff168e72af
reconciliation-contract Exact governed tree; evidence 7dbba7ff168e72af
release-state-machine Exact governed tree; evidence 7dbba7ff168e72af
secret-scan Exact governed tree; evidence 7029b3eafb209066
signer-validator-contract Exact governed tree; evidence 7dbba7ff168e72af
Publish exact C5 issuer V3 bootstrap source
2026-10-01 23:09:33 +08:00

428 lines
16 KiB
Python

from __future__ import annotations
import base64
import dataclasses
from datetime import datetime, timedelta, timezone
import hashlib
import hmac
import json
import os
from pathlib import Path
import sys
import pytest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import c5_exact_deployment_adapter as c5
import release_source_admission
from release_source_admission import ReleaseSourceAdmissionStore
from silent_release_controller import ReleaseCandidate
from silent_release_hardening import (
ApprovalKeyRing,
ApprovalRevocationStore,
CapabilityLedger,
DeploymentPlan,
FinalizationPlan,
ReleasePlan,
SignedApprovalVerifier,
SignedReleasePlanApproval,
TagPlan,
)
SOURCE = "1" * 40
TREE = "2" * 40
MANIFEST = "3" * 64
POLICY = "4" * 64
TAG_OID = "5" * 40
EVIDENCE = "6" * 40
OWNER_RECORD = "7" * 40
BASELINE = "8" * 64
REGISTRY = "9" * 64
TAG_REFSET = "a" * 64
PACKAGE = "b" * 64
SYSTEMD = "c" * 64
ABSENT = "d" * 64
CANDIDATE_ID = "c5-candidate-final-publication-001"
APPROVAL_PLAN_ID = "c5-owner-plan-final-publication-001"
@pytest.fixture(autouse=True)
def _windows_has_no_posix_mode_model(monkeypatch):
if os.name == "nt":
monkeypatch.setattr(
release_source_admission,
"_secure_stat",
lambda *args, **kwargs: None,
)
def _sha(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def _plan(source: str, tree: str, artifact_sha256: str) -> ReleasePlan:
deployment = DeploymentPlan(
service=c5.C5_PRODUCTION_SERVICE,
release_path=f"/data/aios-gitops/runtime/releases/{source}",
release_root="/data/aios-gitops/runtime/releases",
cutover_link=(
"/etc/systemd/system/aios-gitops-model-api.service.d/production.conf"
),
dropin_path=(
f"/data/aios-gitops/runtime/releases/{source}/deployment/production.conf"
),
dropin_sha256=SYSTEMD,
systemd_unit_sha256=SYSTEMD,
rollback_path="/usr/libexec/aios-gitops-runtime-anchor",
rollback_sha256="e" * 64,
source_commit=source,
tree_oid=tree,
artifact_sha256=artifact_sha256,
manifest_sha256=MANIFEST,
package_closure_sha256=PACKAGE,
authoritative_git_dir="/data/aios-gitops/repo.git",
repository_identity="aios/aios",
writer_expected=False,
baseline_before_sha256=BASELINE,
registry_before_sha256=REGISTRY,
production_tag_refset_before_sha256=TAG_REFSET,
health_contract_version="silent-release-health/v1",
timeout_policy={"health_seconds": 30},
retry_policy={"health_attempts": 3},
policy_sha256=POLICY,
health_contract={
"runtime_commit": source,
"writer": False,
"repository_identity": "aios/aios",
},
rollback_target=dict(c5.C4_ROLLBACK_TARGET),
)
return ReleasePlan(
deployment=deployment,
tag=TagPlan(
version=c5.C5_VERSION,
tag_type="annotated",
expected_tag_oid=TAG_OID,
expected_target_oid=source,
evidence_closure_oid=EVIDENCE,
approval_plan_id=APPROVAL_PLAN_ID,
repository_identity="aios/aios",
gitea_owner="aios",
gitea_repository="aios",
current_remote_tag_oid=None,
remote_absent_evidence_sha256=ABSENT,
verification_contract="git+api+listing/v1",
),
finalization=FinalizationPlan(
version=c5.C5_VERSION,
expected_tag_oid=TAG_OID,
expected_target_oid=source,
expected_previous_baseline_sha256=BASELINE,
registry_expected_record={"version": c5.C5_VERSION, "target_oid": source},
baseline_expected_record={"version": c5.C5_VERSION, "target_oid": source},
final_consistency_contract="registry=baseline=tag=v1",
),
policy_sha256=POLICY,
)
def _approval(
candidate: ReleaseCandidate,
plan: ReleasePlan,
private: Ed25519PrivateKey,
) -> SignedReleasePlanApproval:
now = datetime.now(timezone.utc)
value = SignedReleasePlanApproval(
release_plan_id="c5-release-plan-final-publication-001",
candidate_id=candidate.candidate_id,
source_commit=candidate.source_commit,
tree_oid=candidate.tree_oid,
artifact_sha256=candidate.artifact_sha256,
manifest_sha256=candidate.manifest_sha256,
deployment_plan_sha256=plan.deployment.sha256,
policy_sha256=plan.policy_sha256,
approval_plan_id=APPROVAL_PLAN_ID,
evidence_closure_oid=EVIDENCE,
owner_approval_record_oid=OWNER_RECORD,
capabilities=("runtime_switch",),
issued_at=(now - timedelta(minutes=1)).isoformat().replace("+00:00", "Z"),
not_before=(now - timedelta(minutes=1)).isoformat().replace("+00:00", "Z"),
expires_at=(now + timedelta(minutes=30)).isoformat().replace("+00:00", "Z"),
nonce="c5-exact-deployment-nonce-0001",
key_id="c5-owner-key-001",
signature="",
owner_identity="owner:imruyi",
trust_domain="aios.production",
release_plan_sha256=plan.sha256,
)
return dataclasses.replace(
value,
signature=base64.b64encode(private.sign(value.canonical_bytes())).decode(),
)
def _admission_store(
root: Path,
candidate: ReleaseCandidate,
) -> ReleaseSourceAdmissionStore:
root.mkdir(mode=0o700)
root.chmod(0o700)
key = b"c5-source-admission-test-key-000000000000"
record = {
"schema": "aios.release-source-admission.v1",
"admission_id": "c5-final-source-admission-001",
"repository": "aios/aios",
"task_id": "TASK-V2R2C5-FINAL-PUBLICATION-001",
"version": c5.C5_VERSION,
"candidate_id": candidate.candidate_id,
"base_oid": c5.C4_ROLLBACK_TARGET["target_oid"],
"source_ref": "refs/heads/agent/v2r2c5-final-publication",
"source_commit": candidate.source_commit,
"remote_ref_oid": candidate.source_commit,
"tree_oid": candidate.tree_oid,
"purpose": "AIOS_TRUSTED_RELEASE_BUILDER",
"policy_sha256": POLICY,
"admitted_at": "2026-09-30T00:00:00Z",
}
record["mac"] = hmac.new(
key,
release_source_admission._canonical(record),
hashlib.sha256,
).hexdigest()
path = root / f"{candidate.source_commit}.json"
path.write_text(json.dumps(record, sort_keys=True) + "\n", encoding="utf-8")
path.chmod(0o600)
return ReleaseSourceAdmissionStore(
root,
repository="aios/aios",
policy_sha256=POLICY,
hmac_key=key,
writable=False,
)
def _adapter_script(path: Path, state: Path, calls: Path, mode: str) -> None:
path.write_text(
"import json, pathlib, sys\n"
f"state=pathlib.Path({str(state)!r})\n"
f"calls=pathlib.Path({str(calls)!r})\n"
f"mode={mode!r}\n"
"request=json.loads(sys.stdin.buffer.read())\n"
"with calls.open('a', encoding='utf-8') as out: out.write(request['operation']+'\\n')\n"
"binding={k:v for k,v in request.items() if k not in {'schema','operation'}}\n"
"result={**binding,'writer_disabled':True,'deployment_receipt':{'adapter':'registered-c5','operation':request['operation']}}\n"
"if mode == 'bad-receipt': result.pop('tree_oid')\n"
"if request['operation']=='probe':\n"
" if mode == 'unknown':\n"
" result['status']='NOT_APPLIED' if len(calls.read_text(encoding='utf-8').splitlines()) == 1 else 'INDETERMINATE'\n"
" elif state.exists(): result.update(status='ACTIVE_VERIFIED',verified=True,deployment_state='ACTIVE',production_deployed=True)\n"
" else: result['status']='NOT_APPLIED'\n"
"elif request['operation']=='apply':\n"
" if mode == 'unknown': result['status']='EXECUTION_OUTCOME_UNKNOWN'\n"
" else:\n"
" state.write_text(request['release_plan_sha256'], encoding='utf-8')\n"
" result['status']='APPLIED'\n"
"elif request['operation']=='rollback':\n"
" result.update(status='ROLLED_BACK_VERIFIED',verified=True,rollback_verified=True,rollback_version='V2R2C4',rollback_target_oid='e5f8209f57b43fc39e55c4555776e6362ce326eb',rollback_artifact_sha256='0dfc0461f7f9aa25cfbfc37008dcbd2d48d5341383574163b7bba102852062c4')\n"
"else: raise SystemExit(2)\n"
"print(json.dumps(result, sort_keys=True))\n",
encoding="utf-8",
)
path.chmod(0o600)
def _fixture(tmp_path: Path, *, mode: str = "success", source: str = SOURCE):
artifact = tmp_path / "c5-release.tar.zst"
artifact.write_bytes(b"exact-c5-final-governed-artifact")
artifact.chmod(0o600)
artifact_sha256 = _sha(artifact)
candidate = ReleaseCandidate(
candidate_id=CANDIDATE_ID,
source_commit=source,
tree_oid=TREE,
artifact_sha256=artifact_sha256,
manifest_sha256=MANIFEST,
)
plan = _plan(source, TREE, artifact_sha256)
private = Ed25519PrivateKey.generate()
public = private.public_key().public_bytes(
serialization.Encoding.Raw,
serialization.PublicFormat.Raw,
)
approval = _approval(candidate, plan, private)
verifier = SignedApprovalVerifier(
ApprovalKeyRing({"c5-owner-key-001": public}),
ApprovalRevocationStore(tmp_path / "revocations"),
allowed_trust_domains={"aios.production"},
)
admissions = _admission_store(tmp_path / "admissions", candidate)
script = tmp_path / "registered_c5_adapter.py"
state = tmp_path / "runtime-state"
calls = tmp_path / "calls.log"
_adapter_script(script, state, calls, mode)
executable = Path(sys.executable).resolve()
executor = c5.RegisteredC5DeploymentExecutor(
executor_id="registered-c5-production-adapter-001",
executable=executable,
executable_sha256=_sha(executable),
adapter_path=script.resolve(),
adapter_sha256=_sha(script),
artifact_path=artifact.resolve(),
rollback_artifact_path=c5.C4_ROLLBACK_ARTIFACT_PATH,
production_environment_file=c5.C5_PRODUCTION_ENVIRONMENT_FILE,
require_root_owner=False,
)
return candidate, plan, approval, verifier, admissions, executor, calls
def _build_adapter(parts) -> c5.C5ExactDeploymentAdapter:
candidate, plan, approval, verifier, admissions, executor, _calls = parts
return c5.C5ExactDeploymentAdapter(
candidate=candidate,
release_plan=plan,
approval=approval,
approval_verifier=verifier,
source_admissions=admissions,
executor=executor,
)
def test_runtime_switch_executes_only_registered_exact_deployment_and_is_idempotent(
tmp_path,
):
parts = _fixture(tmp_path)
candidate, plan, *_rest, calls = parts
adapter = _build_adapter(parts)
controller = adapter.controller(CapabilityLedger(tmp_path / "ledger"))
first = controller.execute(
adapter.approval,
operation=f"runtime:{plan.sha256}",
candidate=candidate,
plan=plan,
)
second = controller.execute(
adapter.approval,
operation=f"runtime:{plan.sha256}",
candidate=candidate,
plan=plan,
)
assert first["status"] == "EXECUTED"
assert first["result"]["verified"] is True
assert first["result"]["rollback_target"] == c5.C4_ROLLBACK_TARGET
assert first["result"]["global_legacy_writes_enabled"] is False
assert second["status"] == "IDEMPOTENT"
assert calls.read_text(encoding="utf-8").splitlines() == ["probe", "apply", "probe"]
def test_unknown_effect_reconciles_and_never_reapplies(tmp_path):
parts = _fixture(tmp_path, mode="unknown")
candidate, plan, *_rest, calls = parts
adapter = _build_adapter(parts)
controller = adapter.controller(CapabilityLedger(tmp_path / "ledger"))
operation = f"runtime:{plan.sha256}"
with pytest.raises(c5.C5DeploymentOutcomeUnknown, match="OUTCOME_UNKNOWN"):
controller.execute(
adapter.approval,
operation=operation,
candidate=candidate,
plan=plan,
)
reconciled = controller.execute(
adapter.approval,
operation=operation,
candidate=candidate,
plan=plan,
)
assert reconciled["status"] == "RECONCILIATION_REQUIRED"
assert calls.read_text(encoding="utf-8").splitlines() == ["probe", "apply", "probe"]
def test_wrong_rollback_target_fails_before_registered_executor(tmp_path):
parts = list(_fixture(tmp_path))
plan = parts[1]
parts[1] = dataclasses.replace(
plan,
deployment=dataclasses.replace(
plan.deployment,
rollback_target={
**c5.C4_ROLLBACK_TARGET,
"target_oid": "f" * 40,
},
),
)
with pytest.raises(c5.C5DeploymentBindingError, match="ROLLBACK_TARGET_INVALID"):
_build_adapter(tuple(parts))
assert not parts[-1].exists()
def test_rehearsal_executor_rejects_bindings_outside_exact_isolation_root(tmp_path):
parts = _fixture(tmp_path)
_candidate, _plan, _approval, _verifier, _admissions, executor, _calls = parts
rehearsal_root = (tmp_path / "isolated-rehearsal" / "instance-001").resolve()
rehearsal_root.mkdir(parents=True)
with pytest.raises(c5.C5DeploymentBindingError, match="C5_REHEARSAL_BINDING_INVALID"):
dataclasses.replace(
executor,
execution_scope="ISOLATED_REHEARSAL",
isolation_root=rehearsal_root,
rollback_artifact_path=tmp_path / "outside-c4.tar.gz",
production_environment_file=rehearsal_root / "v2r2c2.env",
rollback_target={**c5.C4_ROLLBACK_TARGET, "artifact_sha256": "f" * 64},
)
def test_prepublication_installer_source_cannot_become_final_c5_binding(tmp_path):
parts = _fixture(tmp_path, source=c5.C5_PREPUBLICATION_SOURCE_COMMIT)
with pytest.raises(c5.C5DeploymentBindingError, match="PREPUBLICATION_SOURCE_FORBIDDEN"):
_build_adapter(parts)
assert not parts[-1].exists()
def test_receipt_must_echo_tree_plan_approval_and_rollback_binding(tmp_path):
parts = _fixture(tmp_path, mode="bad-receipt")
candidate, plan, *_rest, calls = parts
adapter = _build_adapter(parts)
controller = adapter.controller(CapabilityLedger(tmp_path / "ledger"))
with pytest.raises(c5.C5DeploymentBindingError, match="RECEIPT_MISMATCH:tree_oid"):
controller.execute(
adapter.approval,
operation=f"runtime:{plan.sha256}",
candidate=candidate,
plan=plan,
)
assert calls.read_text(encoding="utf-8").splitlines() == ["probe"]
def test_global_legacy_writes_true_blocks_before_executor(tmp_path, monkeypatch):
parts = _fixture(tmp_path)
monkeypatch.setenv("AIOS_GITOPS_WRITES_ENABLED", "true")
with pytest.raises(c5.C5DeploymentBindingError, match="LEGACY_WRITES"):
_build_adapter(parts)
assert not parts[-1].exists()
def test_explicit_saga_rollback_requires_exact_c4_verified_receipt(tmp_path):
parts = _fixture(tmp_path)
candidate, plan, *_rest, calls = parts
adapter = _build_adapter(parts)
result = adapter.rollback(candidate=candidate, plan=plan)
assert result == {
"verified": True,
"rollback_verified": True,
"rollback_version": "V2R2C4",
"rollback_target_oid": c5.C4_ROLLBACK_TARGET["target_oid"],
"rollback_artifact_sha256": c5.C4_ROLLBACK_TARGET[
"artifact_sha256"
],
"writer_disabled": True,
}
assert calls.read_text(encoding="utf-8").splitlines() == ["rollback"]