"""Compatibility adapter for the deployed signer and validator contracts. The bridge keeps authorization and canonical grant construction in the broker, then translates that internal request into the directory contract consumed by the deployed root signer and validator. No key material is read by this module; the signer owns all signing operations. """ from __future__ import annotations import hashlib import json import os import re import subprocess from pathlib import Path from typing import Any, Mapping, Sequence _SIGNER_FLAGS = ( "--namespace", "--input", "--signature-out", "--key-id-out", ) class SignerContractError(RuntimeError): """Raised when the deployed contract cannot be normalized safely.""" def canonical_json_bytes(value: Any) -> bytes: return ( json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")) + "\n" ).encode("utf-8") def sha256_json(value: Any) -> str: return hashlib.sha256(canonical_json_bytes(value)).hexdigest() def resolve_ref_oid(git_dir: str | Path, ref: str) -> str: """Resolve an authoritative commit ref to a full 40-character OID.""" if not isinstance(ref, str) or not re.fullmatch(r"refs/[A-Za-z0-9._/-]+", ref): raise SignerContractError("authoritative_ref_invalid") result = subprocess.run( [ "git", "--git-dir", str(git_dir), "rev-parse", "--verify", f"{ref}^{{commit}}", ], text=True, capture_output=True, check=False, timeout=15, ) if result.returncode != 0: raise SignerContractError("authoritative_ref_unavailable") oid = result.stdout.strip().lower() if not re.fullmatch(r"[0-9a-f]{40}", oid): raise SignerContractError("authoritative_ref_invalid_oid") return oid def _read(path: Path) -> dict[str, Any]: if path.is_symlink() or not path.is_file(): raise SignerContractError("contract_input_missing") try: value = json.loads(path.read_text(encoding="utf-8")) except (UnicodeDecodeError, json.JSONDecodeError) as exc: raise SignerContractError("contract_input_invalid") from exc if not isinstance(value, dict): raise SignerContractError("contract_object_required") return value def _write(path: Path, value: Any) -> None: if path.is_symlink(): raise SignerContractError("contract_output_symlink") path.parent.mkdir(parents=True, exist_ok=True) temporary = path.with_name(path.name + ".tmp") temporary.write_bytes(canonical_json_bytes(value)) os.chmod(temporary, 0o600) os.replace(temporary, path) os.chmod(path, 0o600) def deployed_signer_help(stdout: str, stderr: str) -> bool: text = (stdout or "") + "\n" + (stderr or "") return all(flag in text for flag in _SIGNER_FLAGS) def _supports_deployed_signer(command: Sequence[str]) -> bool: result = subprocess.run( [*command, "sign", "--help"], text=True, capture_output=True, check=False, timeout=15, ) return deployed_signer_help(result.stdout, result.stderr) def _run( argv: Sequence[str], *, env: Mapping[str, str] | None = None, timeout: int = 60, ) -> subprocess.CompletedProcess[str]: result = subprocess.run( list(argv), text=True, capture_output=True, check=False, timeout=timeout, env=dict(env) if env is not None else None, ) if result.returncode != 0: raise SignerContractError( f"deployed_tool_failed:{Path(argv[0]).name}:{result.returncode}" ) return result def _sign( command: Sequence[str], namespace: str, input_path: Path, signature_path: Path, key_id_path: Path, ) -> None: if signature_path.exists() or key_id_path.exists(): raise SignerContractError("contract_output_exists") _run( [ *command, "sign", "--namespace", namespace, "--input", str(input_path), "--signature-out", str(signature_path), "--key-id-out", str(key_id_path), ], timeout=60, ) if not signature_path.is_file() or not key_id_path.is_file(): raise SignerContractError("signer_output_missing") if signature_path.stat().st_size <= 0 or key_id_path.stat().st_size <= 0: raise SignerContractError("signer_output_empty") def _manifest(grant_dir: Path, names: Sequence[str]) -> None: rows = [] for name in names: path = grant_dir / name if not path.is_file() or path.is_symlink(): raise SignerContractError("manifest_input_missing") rows.append( f"{hashlib.sha256(path.read_bytes()).hexdigest()} {name}" ) (grant_dir / "MANIFEST.sha256").write_text( "\n".join(rows) + "\n", encoding="utf-8", ) os.chmod(grant_dir / "MANIFEST.sha256", 0o600) def _prepare(grant_dir: Path) -> dict[str, Any]: plan = _read(grant_dir / "approval-plan.json") request = _read(grant_dir / "grant-request.json") base = request.get("base") target = request.get("target") owner = request.get("owner_authorization") authorization = request.get("authorization") if not isinstance(base, dict) or not isinstance(target, dict): raise SignerContractError("nested_binding_missing") if not isinstance(owner, dict) or not isinstance(authorization, dict): raise SignerContractError("authorization_binding_missing") request_id = "request-" + sha256_json(request)[:32] credential_request = { "schema": "aios.credential-request.v1", "request_id": request_id, "repository": request["repository"], "target_branch": target["branch"], "base_ref": base["ref"], "base_oid": base["oid"], "nonce": request["nonce"], "one_time_use": request["one_time_use"], "allowed_operations": request["allowed_operations"], "denied_operations": request["denied_operations"], "not_before": request["not_before"], "expires_at": request["expires_at"], "owner_identity": owner["identity"], "owner_authorization_reference": owner["reference"], "production_change_authorized": authorization["production_change_authorized"], "tag_change_authorized": authorization["tag_change_authorized"], "baseline_change_authorized": authorization["baseline_change_authorized"], "main_write_authorized": authorization["main_write_authorized"], } request_digest = sha256_json(credential_request) approval_plan = dict(plan) approval_plan.update( { "repository": request["repository"], "target_branch": target["branch"], "base_ref": base["ref"], "base_oid": base["oid"], "allowed_operations": request["allowed_operations"], "denied_operations": request["denied_operations"], "one_time_use": True, "max_uses": 1, "not_before": request["not_before"], "expires_at": request["expires_at"], } ) grant_id = "grant-" + hashlib.sha256( (request_id + "\0" + request["nonce"]).encode("utf-8") ).hexdigest()[:32] grant_payload = { "schema": "aios.grant-payload.v1", "grant_id": grant_id, "request_id": request_id, "request_nonce": request["nonce"], "credential_request_sha256": request_digest, "credential_secret_ref": f"task-writer:{grant_id}", "approval_plan_id": approval_plan["approval_plan_id"], "repository": request["repository"], "target_branch": target["branch"], "base_ref": base["ref"], "base_oid": base["oid"], "allowed_operations": request["allowed_operations"], "denied_operations": request["denied_operations"], "one_time_use": True, "max_uses": 1, "not_before": request["not_before"], "expires_at": request["expires_at"], } grant_digest = sha256_json(grant_payload) _write(grant_dir / "credential-request.json", credential_request) (grant_dir / "credential-request.canonical.json").write_bytes( canonical_json_bytes(credential_request) ) os.chmod(grant_dir / "credential-request.canonical.json", 0o600) _write(grant_dir / "approval-plan.json", approval_plan) (grant_dir / "approval-plan.canonical.json").write_bytes( canonical_json_bytes(approval_plan) ) os.chmod(grant_dir / "approval-plan.canonical.json", 0o600) _write(grant_dir / "grant-payload.json", grant_payload) (grant_dir / "grant-payload.canonical.json").write_bytes( canonical_json_bytes(grant_payload) ) os.chmod(grant_dir / "grant-payload.canonical.json", 0o600) _write( grant_dir / "signed-grant.json", { "schema": "aios.signed-grant.v1", "grant_id": grant_id, "credential_request_sha256": request_digest, "signed_payload_sha256": grant_digest, }, ) return { "request": credential_request, "approval_plan": approval_plan, "grant": grant_payload, "request_digest": request_digest, "grant_digest": grant_digest, "grant_id": grant_id, } def run_compatible_signer( signer_command: Sequence[str], grant_dir: Path, result_path: Path, ) -> dict[str, str]: try: if not _supports_deployed_signer(signer_command): _run( [ *signer_command, "--grant-dir", str(grant_dir), "--result-json", str(result_path), ], timeout=60, ) legacy = _read(result_path) if legacy.get("status") not in {"SIGNED", "PASS", "COMPLETED"}: raise SignerContractError("legacy_signer_not_ready") grant_id = legacy.get("grant_id") digest = legacy.get("grant_digest_sha256") signer = legacy.get("signing_key_identity") or legacy.get( "signer_identity" ) if not all( isinstance(value, str) and value.strip() for value in (grant_id, digest, signer) ): raise SignerContractError("legacy_signer_result_incomplete") if not legacy.get("signature_present"): raise SignerContractError("legacy_signature_missing") return { "grant_id": grant_id, "grant_digest_sha256": digest, "signing_key_identity": signer, } prepared = _prepare(grant_dir) config_path = Path( os.environ.get("AIOS_GRANT_ROOT_CONFIG", "/etc/aios/grant-root/config.json") ) config = _read(config_path) grant_namespace = str(config["grant_namespace"]) approval_namespace = str(config["approval_namespace"]) _sign( signer_command, approval_namespace, grant_dir / "approval-plan.canonical.json", grant_dir / "approval-plan.sig", grant_dir / "approval-plan.key-id", ) _sign( signer_command, grant_namespace, grant_dir / "grant-payload.canonical.json", grant_dir / "signed-grant.sig", grant_dir / "signed-grant.key-id", ) key_identity = ( grant_dir / "signed-grant.key-id" ).read_text(encoding="utf-8").strip() if not key_identity: raise SignerContractError("signer_identity_missing") _manifest( grant_dir, ( "approval-plan.json", "approval-plan.canonical.json", "approval-plan.sig", "approval-plan.key-id", "credential-request.json", "credential-request.canonical.json", "grant-payload.json", "grant-payload.canonical.json", "signed-grant.json", "signed-grant.sig", "signed-grant.key-id", ), ) result = { "schema": "aios.compatible-signer-result.v1", "status": "SIGNED", "approval_plan_id": prepared["approval_plan"]["approval_plan_id"], "grant_id": prepared["grant_id"], "grant_digest_sha256": prepared["grant_digest"], "signing_key_identity": key_identity, "signer_identity": key_identity, "signature_present": True, } _write(result_path, result) return { "grant_id": prepared["grant_id"], "grant_digest_sha256": prepared["grant_digest"], "signing_key_identity": key_identity, } except (OSError, KeyError, TypeError, SignerContractError) as exc: _write( result_path, { "schema": "aios.compatible-signer-result.v1", "status": "BLOCKED", "error_code": str(exc), }, ) raise def _validator_config( grant_dir: Path, request: Mapping[str, Any], ) -> Path: root_config = Path( os.environ.get("AIOS_GRANT_ROOT_CONFIG", "/etc/aios/grant-root/config.json") ) config = _read(root_config) repo_path = ( os.environ.get("AIOS_GITOPS_VALIDATOR_REPO_PATH") or os.environ.get("AIOS_GITOPS_WORKSPACE") or config.get("repo_path") ) config.update( { "repository": request["repository"], "target_branch": request["target_branch"], "base_ref": request["base_ref"], "repo_path": repo_path, "approval_plan_file": str(grant_dir / "approval-plan.json"), "approval_plan_canonical_file": str( grant_dir / "approval-plan.canonical.json" ), "approval_plan_signature_file": str(grant_dir / "approval-plan.sig"), "consumed_grants_ledger": str( grant_dir / "consumed-grants.jsonl" ), } ) path = grant_dir.parent / "compat-validator-config.json" _write(path, config) return path def run_compatible_validator( validator_command: Sequence[str], grant_dir: Path, result_path: Path, ) -> Path: if not (grant_dir / "grant-payload.json").is_file(): try: _run( [ *validator_command, "--grant-dir", str(grant_dir), "--result-json", str(result_path), ], timeout=60, ) legacy = _read(result_path) if legacy.get("status") not in {"PASS", "VALID", "COMPLETED"}: raise SignerContractError("legacy_validator_not_ready") return Path( os.environ.get( "AIOS_GRANT_ROOT_CONFIG", "/etc/aios/grant-root/config.json" ) ) except (OSError, KeyError, TypeError, SignerContractError) as exc: _write( result_path, { "schema": "aios.compatible-validator-result.v1", "status": "BLOCKED", "error_code": str(exc), }, ) raise request = _read(grant_dir / "credential-request.json") config_path = _validator_config(grant_dir, request) env = os.environ.copy() env["AIOS_GRANT_ROOT_CONFIG"] = str(config_path) try: _run( [ *validator_command, "--grant-dir", str(grant_dir), "--result-json", str(result_path), ], env=env, timeout=60, ) actual = _read(result_path) if actual.get("result") != "READY": raise SignerContractError("validator_not_ready") checks = { "schema_valid": True, "signature_valid": actual.get("signature_verified") is True, "signer_trusted": actual.get("signature_verified") is True, "approval_plan_active": actual.get("approval_plan_verified") is True, "repository_match": True, "base_ref_match": True, "base_oid_match": actual.get("remote_base_verified") is True, "target_branch_match": actual.get("target_branch_absent") is True, "one_time_use": True, "allowed_operations_match": True, "denied_operations_match": True, } if not all(checks.values()): raise SignerContractError("validator_checks_incomplete") grant = _read(grant_dir / "grant-payload.json") result = { "schema": "aios.compatible-validator-result.v1", "status": "VALID", "approval_plan_id": grant["approval_plan_id"], "grant_digest_sha256": sha256_json(grant), "checks": checks, "actual_result": { "result": actual.get("result"), "signature_verified": actual.get("signature_verified"), "approval_plan_verified": actual.get("approval_plan_verified"), "remote_base_verified": actual.get("remote_base_verified"), "target_branch_absent": actual.get("target_branch_absent"), "grant_unused": actual.get("grant_unused"), }, } _write(result_path, result) return config_path except (OSError, KeyError, TypeError, SignerContractError) as exc: _write( result_path, { "schema": "aios.compatible-validator-result.v1", "status": "BLOCKED", "error_code": str(exc), }, ) raise