#!/usr/bin/env python3 """Independently verify an external MCP protocol/schema replay receipt. This standalone verifier intentionally does not import the replay controller. It revalidates the committed policy and artifact receipt chain, rematerializes the immutable bundle, and repeats initialize plus tools/list in a fresh offline container. No browser or MCP tool is invoked. """ from __future__ import annotations import argparse import hashlib import json import os import re import select import shutil import subprocess import sys import tarfile import tempfile import uuid from datetime import datetime, timezone from pathlib import Path, PurePosixPath from typing import Any POLICY_SCHEMA = "awoooi_external_mcp_replay_policy_v1" CONTROLLER_SCHEMA = "awoooi_external_mcp_replay_receipt_v1" VERIFIER_SCHEMA = "awoooi_external_mcp_replay_verifier_receipt_v1" ARTIFACT_CONTROLLER_SCHEMA = "awoooi_external_mcp_artifact_receipt_v1" ARTIFACT_VERIFIER_SCHEMA = "awoooi_external_mcp_artifact_verifier_receipt_v1" ARTIFACT_BUNDLE_SCHEMA = "awoooi_external_mcp_artifact_bundle_v1" SHA256_PATTERN = re.compile(r"^[0-9a-f]{64}$") SHA512_PATTERN = re.compile(r"^[0-9a-f]{128}$") OCI_REF_PATTERN = re.compile( r"^[a-z0-9.-]+(?::[0-9]+)?/[a-z0-9._/-]+@sha256:[0-9a-f]{64}$" ) MAX_JSON_BYTES = 4 * 1024 * 1024 MAX_PROTOCOL_LINE_BYTES = 2 * 1024 * 1024 MAX_FILES = 4_096 MAX_UNPACKED_BYTES = 40 * 1024 * 1024 EXPECTED_RUNTIME_ARGUMENTS = [ "--headless", "--isolated", "--allowed-origins", "https://awoooi.wooo.work", "--output-dir", "/tmp/mcp-output", "--executable-path", "/nonexistent/browser", ] class VerifierError(RuntimeError): """Fail-closed public-safe verifier error class.""" def _canonical(payload: Any) -> bytes: return json.dumps( payload, ensure_ascii=False, sort_keys=True, separators=(",", ":"), ).encode("utf-8") def _sha256(data: bytes) -> str: return hashlib.sha256(data).hexdigest() def _read_json(path: Path, error: str) -> tuple[bytes, dict[str, Any]]: try: raw = path.read_bytes() except OSError as exc: raise VerifierError(error) from exc if not raw or len(raw) > MAX_JSON_BYTES: raise VerifierError(error) try: payload = json.loads(raw) except json.JSONDecodeError as exc: raise VerifierError(error) from exc if not isinstance(payload, dict): raise VerifierError(error) return raw, payload def _dict(value: Any, error: str) -> dict[str, Any]: if not isinstance(value, dict): raise VerifierError(error) return value def _text(value: Any, error: str) -> str: if not isinstance(value, str) or not value.strip(): raise VerifierError(error) return value.strip() def _exact_digest(value: Any, error: str, *, prefixed: bool = False) -> str: text = _text(value, error) digest = text.removeprefix("sha256:") if prefixed else text if not SHA256_PATTERN.fullmatch(digest): raise VerifierError(error) if prefixed and not text.startswith("sha256:"): raise VerifierError(error) return text def _oci_ref(value: Any, error: str) -> str: ref = _text(value, error) if not OCI_REF_PATTERN.fullmatch(ref): raise VerifierError(error) return ref def load_and_validate_policy(path: Path) -> tuple[dict[str, Any], str]: _, policy = _read_json(path, "policy_unreadable") if ( policy.get("schema_version") != POLICY_SCHEMA or policy.get("policy_version") != "1.0.0" or policy.get("risk_class") != "high" or policy.get("scope") != "offline_protocol_and_tool_schema_compatibility_only" or policy.get("work_item_id") != "MCP-REPLAY-PLAYWRIGHT-001" or policy.get("candidate_id") != "external.playwright-verifier" or policy.get("adapter_id") != "playwright_public_accessibility_verifier_v1" or policy.get("owner_lane") != "awoooi_mcp_supply_chain" ): raise VerifierError("policy_contract_invalid") try: expires = datetime.fromisoformat(_text(policy.get("expires_at"), "policy_expiry_invalid")) except ValueError as exc: raise VerifierError("policy_expiry_invalid") from exc if expires.tzinfo is None or expires <= datetime.now(timezone.utc): raise VerifierError("policy_expired") artifact = _dict(policy.get("artifact_source"), "artifact_source_invalid") runtime = _dict(policy.get("runtime"), "runtime_invalid") protocol = _dict(policy.get("protocol_contract"), "protocol_invalid") boundaries = _dict(policy.get("execution_boundaries"), "boundaries_invalid") if any(value is not False for value in boundaries.values()): raise VerifierError("boundary_must_remain_false") if ( runtime.get("network_mode") != "none" or runtime.get("read_only_root") is not True or runtime.get("no_new_privileges") is not True or runtime.get("cap_drop") != ["ALL"] or runtime.get("user") != "65534:65534" or runtime.get("platform") != "linux/amd64" or runtime.get("pids_limit") != 64 or runtime.get("memory_limit") != "384m" or runtime.get("cpu_limit") != "0.5" or runtime.get("tmpfs") != "/tmp:rw,noexec,nosuid,size=32m" or runtime.get("startup_timeout_seconds") != 20 or runtime.get("shutdown_timeout_seconds") != 5 or runtime.get("entrypoint") != ["node", "node_modules/@playwright/mcp/cli.js"] or runtime.get("arguments") != EXPECTED_RUNTIME_ARGUMENTS ): raise VerifierError("runtime_isolation_invalid") artifact_ref = _oci_ref(artifact.get("artifact_ref"), "artifact_ref_invalid") runtime_ref = _oci_ref(runtime.get("image_ref"), "runtime_ref_invalid") artifact_runtime_ref = _oci_ref( artifact.get("artifact_runtime_ref"), "artifact_runtime_ref_invalid" ) if ( artifact_ref == runtime_ref or not artifact_ref.startswith( "registry.wooo.work/awoooi/mcp-artifacts/playwright-mcp@" ) or not artifact_runtime_ref.startswith( "192.168.0.110:5000/awoooi/mcp-artifacts/playwright-mcp@" ) or not runtime_ref.startswith("registry.wooo.work/awoooi/ci-runner@") or artifact.get("audit_branch") != "mcp-artifact-receipts" ): raise VerifierError("artifact_runtime_repository_contract_invalid") for field in ( "controller_receipt_sha256", "verifier_receipt_sha256", "bundle_manifest_sha256", "cyclonedx_sbom_sha256", "tool_name_set_sha256", "tool_schema_manifest_sha256", ): source = artifact if field in artifact else protocol _exact_digest(source.get(field), f"{field}_invalid") _exact_digest(artifact.get("policy_checksum"), "artifact_policy_checksum_invalid", prefixed=True) integrities = _dict(artifact.get("package_integrities"), "integrities_invalid") if len(integrities) != 3: raise VerifierError("integrities_invalid") for digest in integrities.values(): if not isinstance(digest, str) or not SHA512_PATTERN.fullmatch(digest): raise VerifierError("integrities_invalid") allowed = protocol.get("adapter_allowed_tools") denied = protocol.get("adapter_denied_tools") if ( not isinstance(allowed, list) or not isinstance(denied, list) or len(allowed) != 4 or len(denied) != 20 or set(allowed) & set(denied) or set(allowed) != { "browser_close", "browser_navigate", "browser_snapshot", "browser_take_screenshot", } or "browser_run_code_unsafe" not in denied or "browser_file_upload" not in denied ): raise VerifierError("adapter_tool_partition_invalid") return policy, f"sha256:{_sha256(_canonical(policy))}" def validate_controller_receipt( policy: dict[str, Any], policy_checksum: str, path: Path ) -> tuple[dict[str, Any], str]: raw, receipt = _read_json(path, "controller_receipt_unreadable") if ( receipt.get("schema_version") != CONTROLLER_SCHEMA or receipt.get("status") != "completed_protocol_schema_replay_pending_independent_verifier" or receipt.get("mode") != "apply" or receipt.get("policy_checksum") != policy_checksum or receipt.get("work_item_id") != policy.get("work_item_id") or receipt.get("candidate_id") != policy.get("candidate_id") or receipt.get("adapter_id") != policy.get("adapter_id") ): raise VerifierError("controller_receipt_terminal_invalid") try: normalized_run_id = str(uuid.UUID(_text(receipt.get("run_id"), "run_id_invalid"))) except ValueError as exc: raise VerifierError("run_id_invalid") from exc if ( receipt.get("run_id") != normalized_run_id or receipt.get("trace_id") != f"mcp-replay-{normalized_run_id}" ): raise VerifierError("run_trace_identity_invalid") for field in ( "direct_gateway_registration_allowed", "adapter_registration_allowed", "browser_started", "tool_call_performed", "navigation_performed", "raw_request_or_response_body_stored", "external_rag_write_performed", "production_write_performed", "shadow_allowed", "canary_allowed", "promotion_allowed", ): if receipt.get(field) is not False: raise VerifierError("controller_boundary_invalid") artifact = _dict(policy.get("artifact_source"), "artifact_source_invalid") runtime = _dict(policy.get("runtime"), "runtime_invalid") if ( receipt.get("artifact_ref") != artifact.get("artifact_ref") or receipt.get("runtime_image_ref") != runtime.get("image_ref") or receipt.get("artifact_audit_commit") != artifact.get("audit_commit") ): raise VerifierError("controller_source_identity_invalid") protocol = _dict(policy.get("protocol_contract"), "protocol_invalid") observed = _dict(receipt.get("protocol_observation"), "protocol_observation_invalid") expected = { "protocol_version": protocol.get("protocol_version"), "server_name": protocol.get("server_name"), "server_version": protocol.get("server_version"), "tool_count": protocol.get("tool_count"), "tool_name_set_sha256": protocol.get("tool_name_set_sha256"), "tool_schema_manifest_sha256": protocol.get("tool_schema_manifest_sha256"), } if any(observed.get(field) != value for field, value in expected.items()): raise VerifierError("controller_protocol_observation_mismatch") if observed.get("shutdown_mode") != "stdin_eof_clean_exit": raise VerifierError("controller_shutdown_terminal_invalid") stages = _dict(receipt.get("stage_receipts"), "controller_stages_invalid") rollback = _dict( stages.get("rollback_or_no_write_terminal"), "controller_rollback_invalid" ) if ( rollback.get("status") != "mcp_process_terminated_and_ephemeral_container_removed" or rollback.get("ephemeral_container_removed") is not True or rollback.get("production_route_changed") is not False ): raise VerifierError("controller_rollback_invalid") return receipt, _sha256(raw) def validate_artifact_receipt_chain( policy: dict[str, Any], controller_path: Path, verifier_path: Path ) -> tuple[str, str]: artifact = _dict(policy.get("artifact_source"), "artifact_source_invalid") controller_raw, controller = _read_json( controller_path, "artifact_controller_receipt_unreadable" ) verifier_raw, verifier = _read_json( verifier_path, "artifact_verifier_receipt_unreadable" ) controller_sha = _sha256(controller_raw) verifier_sha = _sha256(verifier_raw) if ( controller_sha != artifact.get("controller_receipt_sha256") or verifier_sha != artifact.get("verifier_receipt_sha256") or controller.get("schema_version") != ARTIFACT_CONTROLLER_SCHEMA or controller.get("status") != "completed_internal_mirror_pending_independent_verifier" or verifier.get("schema_version") != ARTIFACT_VERIFIER_SCHEMA or verifier.get("status") != "completed_internal_mirror_verified" or verifier.get("controller_receipt_sha256") != controller_sha ): raise VerifierError("artifact_receipt_chain_invalid") post = _dict(verifier.get("independent_post_verifier"), "artifact_verifier_invalid") if ( post.get("status") != "passed" or post.get("container_or_mcp_started") is not False or controller.get("run_id") != verifier.get("run_id") or controller.get("trace_id") != verifier.get("trace_id") ): raise VerifierError("artifact_independent_verifier_invalid") for receipt in (controller, verifier): if ( receipt.get("internal_mirror_ref") != artifact.get("artifact_ref") or receipt.get("policy_checksum") != artifact.get("policy_checksum") or any( receipt.get(field) is not False for field in ( "promotion_allowed", "replay_allowed", "shadow_allowed", "canary_allowed", ) ) ): raise VerifierError("artifact_receipt_boundary_invalid") return controller_sha, verifier_sha def _docker() -> str: executable = shutil.which("docker") if not executable: raise VerifierError("docker_cli_unavailable") return executable def _run(command: list[str], *, timeout: int, error: str) -> str: try: result = subprocess.run( command, check=False, capture_output=True, text=True, timeout=timeout, ) except (OSError, subprocess.TimeoutExpired) as exc: raise VerifierError(error) from exc if result.returncode != 0: raise VerifierError(error) return result.stdout def _pull_and_readback(docker: str, ref: str, platform: str) -> None: _run( [docker, "pull", "--platform", platform, ref], timeout=300, error="image_pull_failed", ) output = _run( [docker, "image", "inspect", "--format", "{{json .RepoDigests}}", ref], timeout=30, error="image_readback_failed", ) try: digests = json.loads(output.strip()) except json.JSONDecodeError as exc: raise VerifierError("image_readback_invalid") from exc if not isinstance(digests, list) or ref not in digests: raise VerifierError("image_digest_readback_mismatch") def _safe_member(name: str) -> Path | None: pure = PurePosixPath(name) if pure.is_absolute() or not pure.parts or ".." in pure.parts: raise VerifierError("archive_path_invalid") if pure.parts[0] != "package": raise VerifierError("archive_root_invalid") if len(pure.parts) == 1: return None return Path(*pure.parts[1:]) def _unpack(tarball: Path, destination: Path) -> tuple[int, int]: files = 0 size = 0 try: archive = tarfile.open(tarball, "r:gz") except (OSError, tarfile.TarError) as exc: raise VerifierError("tarball_invalid") from exc with archive: for member in archive.getmembers(): relative = _safe_member(member.name) if relative is None: continue target = destination / relative if member.isdir(): target.mkdir(parents=True, exist_ok=True) continue if not member.isfile() or member.issym() or member.islnk(): raise VerifierError("archive_member_type_invalid") files += 1 size += member.size if files > MAX_FILES or size > MAX_UNPACKED_BYTES: raise VerifierError("archive_limits_exceeded") source = archive.extractfile(member) if source is None: raise VerifierError("archive_member_unreadable") content = source.read(member.size + 1) if len(content) != member.size: raise VerifierError("archive_member_size_mismatch") target.parent.mkdir(parents=True, exist_ok=True) target.write_bytes(content) return files, size def independently_materialize( policy: dict[str, Any], directory: Path ) -> tuple[Path, int, int]: artifact = _dict(policy.get("artifact_source"), "artifact_source_invalid") runtime = _dict(policy.get("runtime"), "runtime_invalid") docker = _docker() artifact_ref = _oci_ref(artifact.get("artifact_ref"), "artifact_ref_invalid") platform = _text(runtime.get("platform"), "platform_invalid") _pull_and_readback(docker, artifact_ref, platform) bundle = directory / "bundle" modules = directory / "node_modules" bundle.mkdir() modules.mkdir() container = f"awoooi-mcp-verifier-artifact-{uuid.uuid4().hex[:16]}" try: _run( [ docker, "create", "--platform", platform, "--name", container, artifact_ref, "/nonexistent/no-start", ], timeout=60, error="artifact_container_create_failed", ) _run( [docker, "cp", f"{container}:/artifact/.", str(bundle)], timeout=60, error="artifact_copy_failed", ) finally: subprocess.run( [docker, "rm", "-f", container], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=30, ) manifest_raw, manifest = _read_json( bundle / "bundle-manifest.json", "bundle_manifest_invalid" ) sbom_raw, sbom = _read_json(bundle / "sbom.cdx.json", "bundle_sbom_invalid") if ( _sha256(manifest_raw) != artifact.get("bundle_manifest_sha256") or _sha256(sbom_raw) != artifact.get("cyclonedx_sbom_sha256") or manifest.get("schema_version") != ARTIFACT_BUNDLE_SCHEMA or manifest.get("candidate_id") != policy.get("candidate_id") or manifest.get("policy_checksum") != artifact.get("policy_checksum") or sbom.get("bomFormat") != "CycloneDX" or sbom.get("specVersion") != "1.5" ): raise VerifierError("bundle_identity_invalid") bundle_boundaries = _dict( manifest.get("operation_boundaries"), "bundle_boundaries_invalid" ) if any( bundle_boundaries.get(field) is not False for field in ( "mcp_server_started", "browser_started", "external_tool_call_performed", "external_rag_write_performed", "production_write_performed", "runtime_request_or_response_body_stored", ) ): raise VerifierError("bundle_boundary_invalid") integrities = _dict(artifact.get("package_integrities"), "integrities_invalid") rows = manifest.get("packages") if not isinstance(rows, list) or len(rows) != 3: raise VerifierError("bundle_package_set_invalid") observed: set[str] = set() total_files = 0 total_size = 0 for row in rows: if not isinstance(row, dict): raise VerifierError("bundle_package_set_invalid") name = _text(row.get("name"), "package_name_invalid") version = _text(row.get("version"), "package_version_invalid") key = f"{name}@{version}" tarball = bundle / _text(row.get("tarball_path"), "tarball_path_invalid") try: raw = tarball.read_bytes() except OSError as exc: raise VerifierError("tarball_unreadable") from exc if ( key in observed or integrities.get(key) != row.get("tarball_sha512_hex") or hashlib.sha512(raw).hexdigest() != integrities.get(key) ): raise VerifierError("tarball_integrity_mismatch") observed.add(key) destination = ( modules / "@playwright" / "mcp" if name == "@playwright/mcp" else modules / name ) destination.mkdir(parents=True) files, size = _unpack(tarball, destination) total_files += files total_size += size _, package_json = _read_json(destination / "package.json", "package_json_invalid") if package_json.get("name") != name or package_json.get("version") != version: raise VerifierError("package_json_identity_mismatch") if observed != set(integrities): raise VerifierError("bundle_package_set_mismatch") for path in modules.rglob("*"): path.chmod(0o755 if path.is_dir() else 0o444) modules.chmod(0o755) directory.chmod(0o755) return modules, total_files, total_size def _send(process: subprocess.Popen[str], payload: dict[str, Any]) -> None: if process.stdin is None: raise VerifierError("mcp_stdin_unavailable") try: process.stdin.write(_canonical(payload).decode("utf-8") + "\n") process.stdin.flush() except (BrokenPipeError, OSError) as exc: raise VerifierError("mcp_write_failed") from exc def _receive( process: subprocess.Popen[str], timeout_seconds: int, expected_id: int ) -> dict[str, Any]: if process.stdout is None: raise VerifierError("mcp_stdout_unavailable") ready, _, _ = select.select([process.stdout], [], [], timeout_seconds) if not ready: raise VerifierError("mcp_response_timeout") line = process.stdout.readline(MAX_PROTOCOL_LINE_BYTES + 1) if not line or len(line.encode("utf-8")) > MAX_PROTOCOL_LINE_BYTES: raise VerifierError("mcp_response_invalid") try: response = json.loads(line) except json.JSONDecodeError as exc: raise VerifierError("mcp_response_invalid") from exc if ( not isinstance(response, dict) or response.get("jsonrpc") != "2.0" or response.get("id") != expected_id or "error" in response or not isinstance(response.get("result"), dict) ): raise VerifierError("mcp_response_invalid") return response["result"] def _independent_tool_hashes(tools: Any) -> tuple[int, str, str, set[str]]: if not isinstance(tools, list): raise VerifierError("tool_list_invalid") names: list[str] = [] schema_rows: list[dict[str, Any]] = [] for tool in tools: if not isinstance(tool, dict): raise VerifierError("tool_schema_invalid") name = _text(tool.get("name"), "tool_name_invalid") schema = tool.get("inputSchema") if not isinstance(schema, dict): raise VerifierError("tool_schema_invalid") row: dict[str, Any] = {"name": name, "inputSchema": schema} if "annotations" in tool: annotations = tool["annotations"] if not isinstance(annotations, dict): raise VerifierError("tool_annotations_invalid") row["annotations"] = annotations names.append(name) schema_rows.append(row) if len(names) != len(set(names)): raise VerifierError("tool_names_not_unique") schema_rows.sort(key=lambda row: row["name"]) return ( len(tools), _sha256(_canonical(sorted(names))), _sha256(_canonical(schema_rows)), set(names), ) def independently_replay( policy: dict[str, Any], modules: Path ) -> dict[str, Any]: runtime = _dict(policy.get("runtime"), "runtime_invalid") protocol = _dict(policy.get("protocol_contract"), "protocol_invalid") docker = _docker() runtime_ref = _oci_ref(runtime.get("image_ref"), "runtime_ref_invalid") platform = _text(runtime.get("platform"), "platform_invalid") _pull_and_readback(docker, runtime_ref, platform) container = f"awoooi-mcp-replay-verifier-{uuid.uuid4().hex[:16]}" command = [ docker, "run", "--rm", "--platform", platform, "--name", container, "--network", "none", "--read-only", "--security-opt", "no-new-privileges", "--cap-drop", "ALL", "--pids-limit", str(runtime.get("pids_limit")), "--memory", _text(runtime.get("memory_limit"), "memory_limit_invalid"), "--cpus", _text(runtime.get("cpu_limit"), "cpu_limit_invalid"), "--user", _text(runtime.get("user"), "runtime_user_invalid"), "--env", "HOME=/tmp", "--env", "CI=1", "--tmpfs", _text(runtime.get("tmpfs"), "tmpfs_invalid"), "--stop-timeout", str(runtime.get("shutdown_timeout_seconds")), "-i", "-v", f"{modules.resolve()}:/work/node_modules:ro", "-w", "/work", runtime_ref, *runtime.get("entrypoint", []), *runtime.get("arguments", []), ] stderr_file = tempfile.TemporaryFile(mode="w+t", encoding="utf-8") process: subprocess.Popen[str] | None = None try: try: process = subprocess.Popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr_file, text=True, bufsize=1, env={**os.environ, "DOCKER_CLI_HINTS": "false"}, ) except OSError as exc: raise VerifierError("mcp_process_start_failed") from exc _send( process, { "jsonrpc": "2.0", "id": 41, "method": "initialize", "params": { "protocolVersion": protocol.get("protocol_version"), "capabilities": {}, "clientInfo": { "name": "awoooi-external-mcp-replay-verifier", "version": "1", }, }, }, ) timeout = int(runtime.get("startup_timeout_seconds")) initialized = _receive(process, timeout, 41) server = _dict(initialized.get("serverInfo"), "server_info_invalid") if ( initialized.get("protocolVersion") != protocol.get("protocol_version") or server.get("name") != protocol.get("server_name") or server.get("version") != protocol.get("server_version") ): raise VerifierError("initialize_contract_mismatch") _send( process, { "jsonrpc": "2.0", "method": "notifications/initialized", "params": {}, }, ) _send( process, {"jsonrpc": "2.0", "id": 42, "method": "tools/list", "params": {}}, ) listed = _receive(process, timeout, 42) count, names_hash, schemas_hash, names = _independent_tool_hashes( listed.get("tools") ) if ( count != protocol.get("tool_count") or names_hash != protocol.get("tool_name_set_sha256") or schemas_hash != protocol.get("tool_schema_manifest_sha256") or names != set(protocol.get("adapter_allowed_tools", [])) | set(protocol.get("adapter_denied_tools", [])) ): raise VerifierError("tool_contract_mismatch") if process.stdin is None: raise VerifierError("mcp_stdin_unavailable") process.stdin.close() try: exit_code = process.wait(timeout=int(runtime.get("shutdown_timeout_seconds"))) except subprocess.TimeoutExpired as exc: raise VerifierError("mcp_shutdown_timeout") from exc if exit_code != 0: raise VerifierError("mcp_exit_invalid") finally: if process is not None and process.poll() is None: process.terminate() try: process.wait(timeout=int(runtime.get("shutdown_timeout_seconds", 5))) except subprocess.TimeoutExpired: process.kill() process.wait(timeout=5) subprocess.run( [docker, "rm", "-f", container], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=30, ) stderr_file.close() inspect = subprocess.run( [docker, "container", "inspect", container], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=30, ) if inspect.returncode == 0: raise VerifierError("container_cleanup_failed") return { "protocol_version": protocol.get("protocol_version"), "server_name": protocol.get("server_name"), "server_version": protocol.get("server_version"), "tool_count": count, "tool_name_set_sha256": names_hash, "tool_schema_manifest_sha256": schemas_hash, "process_exit_code": 0, "shutdown_mode": "stdin_eof_clean_exit", "ephemeral_container_removed": True, } def build_verifier_receipt( *, policy: dict[str, Any], policy_checksum: str, controller: dict[str, Any], controller_sha256: str, artifact_controller_sha256: str, artifact_verifier_sha256: str, observation: dict[str, Any], package_file_count: int, package_unpacked_bytes: int, ) -> dict[str, Any]: artifact = _dict(policy.get("artifact_source"), "artifact_source_invalid") runtime = _dict(policy.get("runtime"), "runtime_invalid") return { "schema_version": VERIFIER_SCHEMA, "run_id": controller["run_id"], "trace_id": controller["trace_id"], "work_item_id": controller["work_item_id"], "candidate_id": controller["candidate_id"], "adapter_id": controller["adapter_id"], "risk_class": "high", "status": "completed_protocol_schema_replay_verified", "observed_at": datetime.now(timezone.utc).isoformat(), "policy_checksum": policy_checksum, "controller_receipt_sha256": controller_sha256, "artifact_controller_receipt_sha256": artifact_controller_sha256, "artifact_verifier_receipt_sha256": artifact_verifier_sha256, "artifact_ref": artifact.get("artifact_ref"), "runtime_image_ref": runtime.get("image_ref"), "independent_post_verifier": { "status": "passed", "implementation": "standalone_no_controller_import", "fresh_artifact_digest_readback": True, "fresh_runtime_digest_readback": True, "fresh_protocol_replay": True, "package_file_count": package_file_count, "package_unpacked_bytes": package_unpacked_bytes, **observation, }, "direct_gateway_registration_allowed": False, "adapter_registration_allowed": False, "browser_started": False, "tool_call_performed": False, "navigation_performed": False, "raw_request_or_response_body_stored": False, "external_rag_write_performed": False, "production_write_performed": False, "shadow_allowed": False, "canary_allowed": False, "promotion_allowed": False, "promotion_blockers": policy.get("promotion_blockers_after_replay"), "rollback_terminal": { "status": "mcp_process_terminated_and_ephemeral_container_removed", "candidate_registration_state": "disabled", "ephemeral_container_removed": True, "production_route_changed": False, }, "learning_writeback": { "status": "verified_receipt_ready_for_gitea_audit_branch_writeback", "external_rag_write_performed": False, "km_write_performed": False, }, } def _write(path: Path, payload: dict[str, Any]) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_bytes(_canonical(payload) + b"\n") def _failure_receipt( policy: dict[str, Any], controller: dict[str, Any], error: str ) -> dict[str, Any]: return { "schema_version": VERIFIER_SCHEMA, "run_id": controller.get("run_id"), "trace_id": controller.get("trace_id"), "work_item_id": policy.get("work_item_id"), "candidate_id": policy.get("candidate_id"), "status": "blocked_with_safe_next_action", "error_class": error, "observed_at": datetime.now(timezone.utc).isoformat(), "browser_started": False, "tool_call_performed": False, "external_rag_write_performed": False, "production_write_performed": False, "promotion_allowed": False, "rollback_terminal": { "status": "candidate_disabled_ephemeral_process_cleanup_attempted", "candidate_registration_state": "disabled", "production_route_changed": False, }, } def _parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--policy", type=Path, required=True) parser.add_argument("--artifact-controller-receipt", type=Path, required=True) parser.add_argument("--artifact-verifier-receipt", type=Path, required=True) parser.add_argument("--controller-receipt", type=Path, required=True) parser.add_argument("--verifier-receipt", type=Path, required=True) return parser def main(argv: list[str] | None = None) -> int: args = _parser().parse_args(argv) policy, policy_checksum = load_and_validate_policy(args.policy) controller: dict[str, Any] = {} try: controller, controller_sha256 = validate_controller_receipt( policy, policy_checksum, args.controller_receipt ) artifact_controller_sha256, artifact_verifier_sha256 = ( validate_artifact_receipt_chain( policy, args.artifact_controller_receipt, args.artifact_verifier_receipt, ) ) with tempfile.TemporaryDirectory(prefix="awoooi-mcp-replay-verifier-") as temp: modules, file_count, unpacked_bytes = independently_materialize( policy, Path(temp) ) observation = independently_replay(policy, modules) receipt = build_verifier_receipt( policy=policy, policy_checksum=policy_checksum, controller=controller, controller_sha256=controller_sha256, artifact_controller_sha256=artifact_controller_sha256, artifact_verifier_sha256=artifact_verifier_sha256, observation=observation, package_file_count=file_count, package_unpacked_bytes=unpacked_bytes, ) except VerifierError as exc: _write(args.verifier_receipt, _failure_receipt(policy, controller, str(exc))) raise _write(args.verifier_receipt, receipt) print(json.dumps(receipt, ensure_ascii=False, sort_keys=True)) return 0 if __name__ == "__main__": try: raise SystemExit(main()) except VerifierError as exc: print( json.dumps( { "schema_version": VERIFIER_SCHEMA, "status": "blocked_with_safe_next_action", "error_class": str(exc), }, sort_keys=True, ), file=sys.stderr, ) raise SystemExit(1) from None