#!/usr/bin/env python3 """Verify one bound source-to-GCP restore, reasoning, and cleanup lifecycle.""" from __future__ import annotations import argparse import hashlib import ipaddress import json import re from datetime import UTC, datetime from itertools import pairwise from pathlib import Path from typing import Any try: from .verify_vps_canonical_snapshot_delta import DELTA_SCHEMA, parse_timestamp, write_private_json except ImportError: # pragma: no cover - direct script execution from verify_vps_canonical_snapshot_delta import DELTA_SCHEMA, parse_timestamp, write_private_json SOURCE_SCHEMA = "livingip.sourceSnapshotReceipt.v2" BLIND_REASONING_SCHEMA = "livingip.gcpGeneratedDbBlindClaimCanary.v1" REASONING_COMPUTE_SCHEMA = "livingip.gcpReasoningComputeAttestation.v1" RETRIEVAL_RECEIPT_SCHEMA = "livingip.teleoKbRetrievalReceipt.v1" UUID_RE = re.compile(r"\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b", re.I) SHA256_RE = re.compile(r"[0-9a-f]{64}\Z") FORBIDDEN_HANDLE_RE = re.compile(r"\b(?:cory|m3ta)\b", re.I) EXPECTED_BLIND_ROW_IDS = { "2a7ae257-d01d-46f4-b813-63f81bb9c7c7", "261c3532-fa32-47d8-a5b5-6cc45035c267", "15740795-ecc6-40fa-9a01-3d6bc7c54f79", } def sha256_file(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as handle: for chunk in iter(lambda: handle.read(1024 * 1024), b""): digest.update(chunk) return digest.hexdigest() def load_receipt(path: Path, label: str) -> dict[str, Any]: try: payload = json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError) as exc: raise ValueError(f"{label} is unreadable or invalid JSON") from exc if not isinstance(payload, dict): raise ValueError(f"{label} must be a JSON object") return payload def is_rfc1918(value: Any) -> bool: try: address = ipaddress.ip_address(str(value)) except ValueError: return False return any( address in network for network in ( ipaddress.ip_network("10.0.0.0/8"), ipaddress.ip_network("172.16.0.0/12"), ipaddress.ip_network("192.168.0.0/16"), ) ) def nonempty_all_true(value: Any) -> bool: return isinstance(value, dict) and bool(value) and all(item is True for item in value.values()) def required_true_checks(value: Any, required: set[str]) -> bool: return nonempty_all_true(value) and required <= set(value) def service_healthy(value: Any) -> bool: if not isinstance(value, dict): return False try: main_pid = int(value.get("MainPID") or 0) restarts = int(value.get("NRestarts") or 0) except (TypeError, ValueError): return False return ( value.get("ActiveState") == "active" and value.get("SubState") == "running" and main_pid > 0 and restarts >= 0 ) def parity_evidence(details: dict[str, Any]) -> dict[str, bool]: structural = details.get("structural_hashes") or {} required_structures = { "schemas", "columns", "constraints", "indexes", "sequences", "views", "functions", "triggers", "types", "policies", } structural_valid = required_structures <= set(structural) and all( bool(SHA256_RE.fullmatch(str((structural.get(kind) or {}).get("source") or ""))) and (structural.get(kind) or {}).get("source") == (structural.get(kind) or {}).get("target") for kind in required_structures ) performance = details.get("performance") or [] performance_valid = bool(performance) and all( bool(row.get("query")) and isinstance(row.get("source_ms"), (int, float)) and isinstance(row.get("target_ms"), (int, float)) and isinstance(row.get("source_ratio"), (int, float)) for row in performance ) source_table_count = details.get("source_table_count") target_table_count = details.get("target_table_count") source_total_rows = details.get("source_total_rows") target_total_rows = details.get("target_total_rows") return { "table_counts": isinstance(source_table_count, int) and source_table_count > 0 and source_table_count == target_table_count, "row_counts": isinstance(source_total_rows, int) and source_total_rows > 0 and source_total_rows == target_total_rows, "table_hashes": details.get("table_mismatches") == [], "structural_hashes": structural_valid, "roles": details.get("application_role_mismatches") == {} and details.get("target_extra_application_roles") == [], "extensions": details.get("required_extension_mismatches") == {}, "performance": performance_valid and details.get("performance_problems") == [], } def blind_reasoning_evidence(reasoning: dict[str, Any], target_db: Any) -> dict[str, bool]: result = reasoning.get("result") or {} gateway = result.get("gateway") or {} child = gateway.get("child_process") or {} tool_surface = gateway.get("tool_surface") or {} tool_trace = result.get("database_tool_trace") or {} calls = tool_trace.get("calls") or [] wrapper = reasoning.get("wrapper_tool_proof") or {} invocations = wrapper.get("invocations") or [] prompt = str(reasoning.get("prompt") or "") reply = str(result.get("reply") or "") outcomes = reasoning.get("outcomes") or {} required_outcomes = ( "asks_for_user_iteration_before_live", "challenges_weak_support", "decomposes_the_bundled_legal_claim", "does_not_claim_a_database_change", "proposes_candidate_claims", "uses_only_m3taversal_handle", ) required_subcommands = {"show", "evidence"} discovery_subcommands = {"search", "context"} traced_subcommands = { str(invocation.get("subcommand")) for call in calls for invocation in (call.get("database_invocations") or []) } wrapper_subcommands = {str(invocation.get("subcommand")) for invocation in invocations} retrieved_row_ids = {str(row_id) for call in calls for row_id in ((call.get("result") or {}).get("row_ids") or [])} call_row_ids_valid = bool(calls) and all( isinstance((call.get("result") or {}).get("row_ids"), list) and isinstance((call.get("result") or {}).get("row_id_count"), int) and (call.get("result") or {}).get("row_id_count") >= 0 and (call.get("result") or {}).get("row_id_count") >= len((call.get("result") or {}).get("row_ids") or []) for call in calls ) call_receipts_valid = bool(calls) and all( (call.get("result") or {}).get("nonempty") is True and (call.get("result") or {}).get("error_detected") is False and ((call.get("result") or {}).get("retrieval_receipt") or {}).get("schema") == RETRIEVAL_RECEIPT_SCHEMA and bool( SHA256_RE.fullmatch( str(((call.get("result") or {}).get("retrieval_receipt") or {}).get("semantic_context_sha256") or "") ) ) and bool( SHA256_RE.fullmatch( str(((call.get("result") or {}).get("retrieval_receipt") or {}).get("artifact_state_sha256") or "") ) ) and str( ((call.get("result") or {}).get("retrieval_receipt") or {}).get("read_consistency_status") or "" ).startswith("stable") for call in calls ) wrapper_invocations_valid = bool(invocations) and all( invocation.get("database") == target_db and invocation.get("returncode") == 0 and ((invocation.get("database_identity") or {}).get("transaction_read_only") == "on") and ((invocation.get("database_identity") or {}).get("default_transaction_read_only") == "on") and ((invocation.get("database_identity") or {}).get("ssl") is True) and is_rfc1918((invocation.get("database_identity") or {}).get("server_address")) for invocation in invocations ) return { "mode": reasoning.get("mode") == "gcp_generated_db_gatewayrunner_blind_claim_no_send", "timestamps": bool(reasoning.get("generated_at_utc")) and bool(reasoning.get("completed_at_utc")), "source_compute": bool(reasoning.get("source_compute")), "blind_prompt": bool(prompt) and UUID_RE.search(prompt) is None, "reply_nonempty": bool(reply.strip()), "reply_uses_only_m3taversal_handle": FORBIDDEN_HANDLE_RE.search(reply) is None, "outcomes": all(outcomes.get(name) is True for name in required_outcomes), "gateway": gateway.get("authorized") is True and gateway.get("handler_invoked") is True and gateway.get("model_free_fallback_used") is False and gateway.get("posted_to_telegram") is False, "gateway_cleanup": child.get("exitcode") == 0 and child.get("alive_after_readback") is False and child.get("process_group_alive_after_readback") is False and child.get("timed_out") is False, "send_tool_absent": tool_surface.get("send_message_tool_enabled") is False, "tool_trace": tool_trace.get("schema") == "livingip.leoKbToolTrace.v1" and tool_trace.get("database_tool_call_proven") is True and tool_trace.get("database_retrieval_receipt_proven") is True and tool_trace.get("database_tool_calls_read_only") is True and tool_trace.get("database_tool_call_count") == len(calls) and tool_trace.get("database_tool_completed_count") == len(calls), "tool_receipts": call_receipts_valid, "expected_claim_and_sources_retrieved": call_row_ids_valid and retrieved_row_ids >= EXPECTED_BLIND_ROW_IDS, "required_tool_sequence": required_subcommands <= traced_subcommands and bool(discovery_subcommands & traced_subcommands), "wrapper": wrapper.get("all_bound_to_supplied_target") is True and wrapper.get("all_completed_successfully") is True and wrapper.get("complete_start_end_pairing") is True and wrapper.get("database_read_only_required") is True and wrapper.get("default_read_only_required") is True, "wrapper_invocations": wrapper_invocations_valid and required_subcommands <= wrapper_subcommands and bool(discovery_subcommands & wrapper_subcommands), "canonical_status_unchanged": bool(reasoning.get("canonical_status_before")) and reasoning.get("canonical_status_before") == reasoning.get("canonical_status_after"), "database_identity_unchanged": bool(reasoning.get("database_identity_before")) and reasoning.get("database_identity_before") == reasoning.get("database_identity_after"), "service_unchanged": service_healthy(reasoning.get("service_before")) and reasoning.get("service_before") == reasoning.get("service_after"), "temporary_profile_removed": reasoning.get("temp_profile_absent") is True and reasoning.get("temp_profile_removed") is True, } def verify_lifecycle( *, source_path: Path, current_source_path: Path, source_delta_path: Path, restore_path: Path, parity_path: Path, reasoning_path: Path, reasoning_compute_path: Path, cleanup_path: Path, max_postflight_age_seconds: float = 900.0, max_lifecycle_age_seconds: float = 3600.0, now: datetime | None = None, ) -> dict[str, Any]: if max_postflight_age_seconds <= 0: raise ValueError("max postflight age must be positive") if max_lifecycle_age_seconds <= 0: raise ValueError("max lifecycle age must be positive") verification_time = (now or datetime.now(UTC)).astimezone(UTC) source = load_receipt(source_path, "source receipt") current_source = load_receipt(current_source_path, "current source receipt") source_delta = load_receipt(source_delta_path, "source delta receipt") restore = load_receipt(restore_path, "restore receipt") parity = load_receipt(parity_path, "parity receipt") reasoning = load_receipt(reasoning_path, "reasoning receipt") reasoning_compute_attestation = load_receipt(reasoning_compute_path, "reasoning compute attestation") cleanup = load_receipt(cleanup_path, "cleanup receipt") target_db = restore.get("target_database") run_id = restore.get("run_id") restore_source = restore.get("source") or {} capture_binding = restore_source.get("capture_receipt") or {} restore_target = restore.get("target") or {} restore_connectivity = restore_target.get("connectivity") or {} restore_connectivity_proof = restore_target.get("connectivity_proof") or {} restore_cloudsql = restore_target.get("cloudsql") or {} restore_compute = restore_target.get("compute") or {} restore_parity = restore.get("parity") or {} restore_service = restore.get("live_service") or {} parity_details = parity.get("details") or {} parity_evidence_checks = parity_evidence(parity_details) restore_inline_parity_checks = parity_evidence(restore_parity.get("details") or {}) parity_connectivity = parity.get("private_connectivity") or {} parity_connectivity_proof = parity_connectivity.get("proof") or {} reasoning_checks = reasoning.get("checks") or {} reasoning_parity = reasoning.get("parity_receipt") or {} before_fingerprint = reasoning.get("database_fingerprint_before") or {} after_fingerprint = reasoning.get("database_fingerprint_after") or {} cleanup_database = cleanup.get("database") or {} cleanup_service = cleanup.get("live_service") or {} cleanup_cloudsql = (cleanup.get("target") or {}).get("cloudsql") or {} cleanup_compute = (cleanup.get("target") or {}).get("compute") or {} restore_contract = restore.get("execution_contract") or {} cleanup_contract = cleanup.get("execution_contract") or {} producer_reasoning_checks = blind_reasoning_evidence(reasoning, target_db) reasoning_compute = reasoning_compute_attestation.get("compute") or {} reasoning_compute_checks = reasoning_compute_attestation.get("checks") or {} reasoning_compute_mutation = reasoning_compute_attestation.get("mutation") or {} delta_baseline = source_delta.get("baseline") or {} delta_current = source_delta.get("current") or {} delta_details = source_delta.get("delta") or {} source_snapshot = source.get("snapshot") or {} current_source_snapshot = current_source.get("snapshot") or {} timeline_values = { "source_snapshot": source_snapshot.get("captured_at_utc"), "restore_started": restore.get("generated_at_utc"), "restore_completed": restore.get("completed_at_utc"), "parity_completed": parity.get("completed_at_utc"), "reasoning_started": reasoning.get("generated_at_utc"), "reasoning_completed": reasoning.get("completed_at_utc"), "reasoning_compute_attested": reasoning_compute_attestation.get("generated_at_utc"), "cleanup_started": cleanup.get("generated_at_utc"), "cleanup_completed": cleanup.get("completed_at_utc"), "current_source_snapshot": current_source_snapshot.get("captured_at_utc"), } timeline = [parse_timestamp(value, name) for name, value in timeline_values.items()] lifecycle_chronology = all(earlier <= later for earlier, later in pairwise(timeline)) delta_detected = delta_details.get("delta_detected") delta_change_present = bool( delta_details.get("added_tables") or delta_details.get("removed_tables") or delta_details.get("changed_tables") or delta_details.get("changed_structures") or delta_details.get("total_row_delta") ) current_source_time = parse_timestamp( current_source_snapshot.get("captured_at_utc"), "current source snapshot time" ) restore_started_time = parse_timestamp(restore.get("generated_at_utc"), "restore start time") cleanup_completed_time = parse_timestamp(cleanup.get("completed_at_utc"), "cleanup completion time") postflight_age_seconds = (verification_time - current_source_time).total_seconds() lifecycle_age_seconds = (verification_time - cleanup_completed_time).total_seconds() lifecycle_span_seconds = (current_source_time - restore_started_time).total_seconds() postflight_after_lifecycle = current_source_time >= max( parse_timestamp(reasoning.get("completed_at_utc"), "reasoning completion time"), parse_timestamp(cleanup.get("completed_at_utc"), "cleanup completion time"), ) required_reasoning_checks = ( "exact_blind_prompt_without_ids", "claim_and_sources_retrieved", "discovery_show_evidence_completed", "retrieval_receipts_proven", "private_tls_read_only_target", "generated_database_unchanged", "canonical_counts_unchanged", "database_calls_read_only", "no_database_write", "no_telegram_send", "live_service_unchanged", "live_profile_unchanged", "temporary_profile_removed", ) checks = { "source_schema_v2": source.get("schema") == SOURCE_SCHEMA and source.get("receipt_version") == 2, "source_pass": source.get("status") == "pass" and source.get("snapshot_exported") is True and (source.get("source_service") or {}).get("unchanged") is True and service_healthy((source.get("source_service") or {}).get("before")) and (source.get("source_service") or {}).get("before") == (source.get("source_service") or {}).get("after"), "source_authorized": bool(source.get("capture_authorization_ref")), "source_authorization_bound": capture_binding.get("capture_authorization_ref") == source.get("capture_authorization_ref"), "source_service_unchanged": source.get("service_unchanged") is True, "source_not_mutated": source.get("production_db_mutated") is False, "current_source_schema_v2": current_source.get("schema") == SOURCE_SCHEMA and current_source.get("receipt_version") == 2, "current_source_pass": current_source.get("status") == "pass" and current_source.get("snapshot_exported") is True and current_source.get("service_unchanged") is True and (current_source.get("source_service") or {}).get("unchanged") is True and service_healthy((current_source.get("source_service") or {}).get("before")) and (current_source.get("source_service") or {}).get("before") == (current_source.get("source_service") or {}).get("after") and current_source.get("production_db_mutated") is False, "current_source_identity": current_source.get("source") == source.get("source") and current_source_snapshot.get("system_identifier") == source_snapshot.get("system_identifier"), "source_delta_pass": source_delta.get("artifact") == "vps_canonical_snapshot_postflight_delta" and source_delta.get("schema") == DELTA_SCHEMA and source_delta.get("status") == "pass", "source_delta_receipts_bound": delta_baseline.get("capture_receipt_sha256") == sha256_file(source_path) and delta_current.get("capture_receipt_sha256") == sha256_file(current_source_path), "source_delta_manifests_bound": delta_baseline.get("manifest_sha256") == (source.get("manifest") or {}).get("sha256") and delta_current.get("manifest_sha256") == (current_source.get("manifest") or {}).get("sha256"), "source_delta_authorizations_bound": delta_baseline.get("capture_authorization_ref") == source.get("capture_authorization_ref") and delta_current.get("capture_authorization_ref") == current_source.get("capture_authorization_ref"), "source_delta_explicit": isinstance(delta_details.get("delta_detected"), bool) and isinstance(delta_details.get("added_tables"), list) and isinstance(delta_details.get("removed_tables"), list) and isinstance(delta_details.get("changed_tables"), list) and isinstance(delta_details.get("changed_structures"), list) and isinstance(delta_details.get("total_row_delta"), int), "source_delta_baseline_shape": delta_baseline.get("run_id") == source.get("run_id") and delta_baseline.get("captured_at_utc") == source_snapshot.get("captured_at_utc") and delta_baseline.get("table_count") == (source.get("manifest") or {}).get("table_count") and delta_baseline.get("total_rows") == (source.get("manifest") or {}).get("total_rows") and bool(SHA256_RE.fullmatch(str(delta_baseline.get("table_fingerprint_sha256") or ""))) and bool(SHA256_RE.fullmatch(str(delta_baseline.get("structure_fingerprint_sha256") or ""))), "source_delta_current_shape": delta_current.get("run_id") == current_source.get("run_id") and delta_current.get("captured_at_utc") == current_source_snapshot.get("captured_at_utc") and delta_current.get("table_count") == (current_source.get("manifest") or {}).get("table_count") and delta_current.get("total_rows") == (current_source.get("manifest") or {}).get("total_rows") and bool(SHA256_RE.fullmatch(str(delta_current.get("table_fingerprint_sha256") or ""))) and bool(SHA256_RE.fullmatch(str(delta_current.get("structure_fingerprint_sha256") or ""))), "source_delta_consistent": delta_detected is delta_change_present and delta_details.get("total_row_delta") == (delta_current.get("total_rows") or 0) - (delta_baseline.get("total_rows") or 0) and ( delta_detected is True or ( delta_baseline.get("table_count") == delta_current.get("table_count") and delta_baseline.get("total_rows") == delta_current.get("total_rows") and delta_baseline.get("table_fingerprint_sha256") == delta_current.get("table_fingerprint_sha256") and delta_baseline.get("structure_fingerprint_sha256") == delta_current.get("structure_fingerprint_sha256") ) ), "source_postflight_after_lifecycle": postflight_after_lifecycle, "source_postflight_fresh": 0 <= postflight_age_seconds <= max_postflight_age_seconds, "gcp_lifecycle_fresh": 0 <= lifecycle_age_seconds <= max_lifecycle_age_seconds, "lifecycle_span_bounded": 0 <= lifecycle_span_seconds <= max_lifecycle_age_seconds, "lifecycle_chronology": lifecycle_chronology, "restore_pass": restore.get("artifact") == "gcp_generated_postgres_snapshot_restore" and restore.get("status") == "pass", "restore_target_is_disposable": isinstance(target_db, str) and target_db.startswith("teleo_clone_"), "restore_run_id": isinstance(run_id, str) and run_id.startswith("gcp-restore-"), "source_receipt_hash_bound": capture_binding.get("sha256") == sha256_file(source_path), "source_provenance_bound": capture_binding.get("provenance_binding_sha256") == (source.get("provenance_binding") or {}).get("sha256"), "source_capture_checks": required_true_checks( capture_binding.get("checks"), { "artifact", "schema", "receipt_version", "status", "snapshot_exported", "service_unchanged", "source_service_healthy", "source_not_mutated", "telegram_not_sent", "run_id", "capture_authorization_ref", "source_identity", "source_database", "snapshot_identity", "dump_sha256", "dump_bytes", "source_manifest_sha256", "manifest_sql_sha256", "source_context_sha256", "table_count", "total_rows", "binding_algorithm", "binding_payload", "binding_sha256", }, ), "source_dump_bound": capture_binding.get("dump_sha256") == (source.get("dump") or {}).get("sha256"), "source_execution_contract_bound": restore_contract.get("source") == source.get("source"), "source_manifest_bound": capture_binding.get("manifest_sha256") == (source.get("manifest") or {}).get("sha256"), "restore_manifest_matches_parity_source": capture_binding.get("manifest_sha256") == parity.get("source_manifest_sha256"), "restore_target_manifest_matches_parity": restore_target.get("manifest_sha256") == parity.get("target_manifest_sha256"), "restore_private_tls": restore_connectivity.get("private_connectivity") is True and restore_connectivity.get("ssl") is True and is_rfc1918(restore_connectivity.get("server_address")), "restore_public_ip_disabled": restore_cloudsql.get("public_ip_disabled") is True, "restore_cloudsql_checks": required_true_checks( restore_cloudsql.get("checks"), { "instance", "state", "postgres_16", "public_ip_disabled", "private_network", "expected_private_host", "no_non_private_address", }, ), "restore_compute_checks": required_true_checks( restore_compute.get("checks"), { "project", "project_number", "expected_network_project", "instance", "instance_id", "zone", "network", "private_ip", "service_account", }, ), "restore_compute_contract": restore_compute.get("project") == restore_contract.get("project") and restore_compute.get("instance") == restore_contract.get("compute_instance") and restore_compute.get("zone") == restore_contract.get("compute_zone") and restore_compute.get("expected_private_network") == restore_contract.get("private_network") and bool(restore_compute.get("network_resource")) and is_rfc1918(restore_compute.get("private_ip")) and str(restore_compute.get("service_account") or "").endswith(".iam.gserviceaccount.com"), "restore_connectivity_compute_bound": restore_connectivity.get("source_compute") == restore_compute.get("instance"), "restore_inline_parity": restore_parity.get("status") == "pass" and restore_parity.get("problems") == [], "restore_inline_parity_evidence": all(restore_inline_parity_checks.values()), "restore_service_healthy_unchanged": restore_service.get("unchanged") is True and service_healthy(restore_service.get("before")) and restore_service.get("before") == restore_service.get("after"), "parity_pass": parity.get("artifact") == "canonical_postgres_parity_verification" and parity.get("status") == "pass" and parity.get("scope") == "gcp_staging" and parity.get("problems") == [], "parity_target_bound": parity_details.get("target_database") == target_db, "parity_exact_evidence": all(parity_evidence_checks.values()), "parity_connectivity_hash_bound": restore_connectivity_proof.get("sha256") == parity.get("connectivity_proof_sha256"), "parity_private_proof": parity_connectivity.get("required") is True and parity_connectivity_proof.get("artifact") == "gcp_private_postgres_connectivity" and parity_connectivity_proof.get("status") == "pass" and parity_connectivity_proof.get("schema") == "livingip.gcpPrivatePostgresConnectivity.v2" and parity_connectivity_proof.get("restore_run_id") == run_id and parity_connectivity_proof.get("private_connectivity") is True and parity_connectivity_proof.get("public_ip_disabled") is True and parity_connectivity_proof.get("target_database") == target_db and parity_connectivity_proof.get("project") == restore_cloudsql.get("project") and parity_connectivity_proof.get("cloudsql_instance") == restore_cloudsql.get("instance") and parity_connectivity_proof.get("private_network") == restore_cloudsql.get("private_network") and parity_connectivity_proof.get("source_compute") == reasoning.get("source_compute") and parity_connectivity_proof.get("source_compute_instance_id") == restore_compute.get("instance_id") and parity_connectivity_proof.get("source_compute_zone") == restore_compute.get("zone") and is_rfc1918(parity_connectivity_proof.get("source_compute_private_ip")) and parity_connectivity_proof.get("server_address") == restore_connectivity.get("server_address") and required_true_checks( parity_connectivity_proof.get("cloudsql_control_plane_checks"), { "instance", "state", "postgres_16", "public_ip_disabled", "private_network", "expected_private_host", "no_non_private_address", }, ) and required_true_checks( parity_connectivity_proof.get("compute_identity_checks"), { "project", "project_number", "expected_network_project", "instance", "instance_id", "zone", "network", "private_ip", "service_account", }, ), "reasoning_schema": reasoning.get("schema") == BLIND_REASONING_SCHEMA, "reasoning_pass": reasoning.get("status") == "pass" and not reasoning.get("errors"), "reasoning_target_bound": reasoning.get("target_database") == target_db, "reasoning_compute_bound": reasoning.get("source_compute") == restore_compute.get("instance"), "reasoning_parity_hash_bound": reasoning_parity.get("sha256") == sha256_file(parity_path), "reasoning_required_checks": all(reasoning_checks.get(name) is True for name in required_reasoning_checks), "reasoning_producer_evidence": all(producer_reasoning_checks.values()), "reasoning_compute_attestation": reasoning_compute_attestation.get("artifact") == "gcp_reasoning_compute_attestation" and reasoning_compute_attestation.get("schema") == REASONING_COMPUTE_SCHEMA and reasoning_compute_attestation.get("status") == "pass" and reasoning_compute_attestation.get("method") == "gce_metadata_server_v1" and nonempty_all_true(reasoning_compute_checks) and reasoning_compute_attestation.get("restore_run_id") == run_id and reasoning_compute_attestation.get("target_database") == target_db and all(value is False for value in reasoning_compute_mutation.values()) and { "cloudsql_changed", "compute_changed", "database_changed", "telegram_message_sent", } <= set(reasoning_compute_mutation), "reasoning_compute_receipt_bound": (reasoning_compute_attestation.get("reasoning_receipt") or {}).get("sha256") == sha256_file(reasoning_path), "reasoning_compute_identity_bound": reasoning_compute.get("project") == restore_compute.get("project") and reasoning_compute.get("project_number") == restore_compute.get("project_number") and reasoning_compute.get("instance") == restore_compute.get("instance") and reasoning_compute.get("instance_id") == restore_compute.get("instance_id") and reasoning_compute.get("zone") == restore_compute.get("zone") and reasoning_compute.get("expected_private_network") == restore_compute.get("expected_private_network") and reasoning_compute.get("network_resource") == restore_compute.get("network_resource") and reasoning_compute.get("private_ip") == restore_compute.get("private_ip") and reasoning_compute.get("service_account") == restore_compute.get("service_account") and required_true_checks( reasoning_compute.get("checks"), { "project", "project_number", "expected_network_project", "instance", "instance_id", "zone", "network", "private_ip", "service_account", }, ), "reasoning_no_send_no_write": reasoning.get("posted_to_telegram") is False and reasoning.get("database_write_attempted") is False, "reasoning_fingerprint_unchanged": bool(before_fingerprint.get("sha256")) and before_fingerprint.get("sha256") == after_fingerprint.get("sha256"), "cleanup_pass": cleanup.get("artifact") == "gcp_generated_postgres_snapshot_cleanup" and cleanup.get("status") == "pass", "cleanup_run_bound": cleanup.get("run_id") == run_id and cleanup.get("target_database") == target_db, "cleanup_restore_receipt_bound": (cleanup.get("restore_receipt") or {}).get("sha256") == sha256_file(restore_path), "cleanup_execution_contract_bound": bool(restore_contract) and cleanup_contract == restore_contract, "cleanup_cloudsql_bound": cleanup_cloudsql.get("project") == restore_cloudsql.get("project") and cleanup_cloudsql.get("instance") == restore_cloudsql.get("instance") and cleanup_cloudsql.get("expected_private_host") == restore_cloudsql.get("expected_private_host") and cleanup_cloudsql.get("expected_private_network") == restore_cloudsql.get("expected_private_network") and cleanup_cloudsql.get("public_ip_disabled") is True and required_true_checks( cleanup_cloudsql.get("checks"), { "instance", "state", "postgres_16", "public_ip_disabled", "private_network", "expected_private_host", "no_non_private_address", }, ), "cleanup_compute_bound": cleanup_compute.get("instance_id") == restore_compute.get("instance_id") and cleanup_compute.get("project") == restore_compute.get("project") and cleanup_compute.get("project_number") == restore_compute.get("project_number") and cleanup_compute.get("instance") == restore_compute.get("instance") and cleanup_compute.get("zone") == restore_compute.get("zone") and cleanup_compute.get("expected_private_network") == restore_compute.get("expected_private_network") and cleanup_compute.get("network_resource") == restore_compute.get("network_resource") and cleanup_compute.get("private_ip") == restore_compute.get("private_ip") and cleanup_compute.get("service_account") == restore_compute.get("service_account") and required_true_checks( cleanup_compute.get("checks"), { "project", "project_number", "expected_network_project", "instance", "instance_id", "zone", "network", "private_ip", "service_account", }, ), "clone_absent": cleanup_database.get("clone_database_remaining") == 0, "cleanup_service_unchanged": cleanup_service.get("unchanged") is True and service_healthy(cleanup_service.get("before")) and cleanup_service.get("before") == cleanup_service.get("after"), } failed = sorted(name for name, passed in checks.items() if not passed) return { "artifact": "gcp_canonical_snapshot_lifecycle_verification", "generated_at_utc": verification_time.isoformat(), "status": "pass" if not failed else "fail", "required_tier": "T3_live_private_gcp_staging", "target_database": target_db, "run_id": run_id, "checks": checks, "reasoning_producer_checks": producer_reasoning_checks, "restore_inline_parity_checks": restore_inline_parity_checks, "parity_evidence_checks": parity_evidence_checks, "post_snapshot_source_delta": delta_details, "timeline": timeline_values, "postflight_age_seconds": postflight_age_seconds, "max_postflight_age_seconds": max_postflight_age_seconds, "lifecycle_age_seconds": lifecycle_age_seconds, "lifecycle_span_seconds": lifecycle_span_seconds, "max_lifecycle_age_seconds": max_lifecycle_age_seconds, "failed_checks": failed, "receipt_sha256": { "source": sha256_file(source_path), "current_source": sha256_file(current_source_path), "source_delta": sha256_file(source_delta_path), "restore": sha256_file(restore_path), "parity": sha256_file(parity_path), "reasoning": sha256_file(reasoning_path), "reasoning_compute": sha256_file(reasoning_compute_path), "cleanup": sha256_file(cleanup_path), }, "strongest_claim_allowed": ( ( "current private GCP staging parity, ID-free Leo reasoning, cleanup, and zero post-snapshot VPS delta verified" if delta_details.get("delta_detected") is False else "private GCP staging parity at the declared snapshot boundary, ID-free Leo reasoning, cleanup, and explicit post-snapshot VPS delta verified" ) if not failed else "lifecycle incomplete; failed checks must be repaired" ), "not_proven": ["production cutover", "ongoing replication", "Telegram delivery"], } def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--source-receipt", required=True, type=Path) parser.add_argument("--current-source-receipt", required=True, type=Path) parser.add_argument("--source-delta-receipt", required=True, type=Path) parser.add_argument("--restore-receipt", required=True, type=Path) parser.add_argument("--parity-receipt", required=True, type=Path) parser.add_argument("--reasoning-receipt", required=True, type=Path) parser.add_argument("--reasoning-compute-receipt", required=True, type=Path) parser.add_argument("--cleanup-receipt", required=True, type=Path) parser.add_argument("--output", required=True, type=Path) parser.add_argument("--max-postflight-age-seconds", default=900.0, type=float) parser.add_argument("--max-lifecycle-age-seconds", default=3600.0, type=float) args = parser.parse_args() try: payload = verify_lifecycle( source_path=args.source_receipt, current_source_path=args.current_source_receipt, source_delta_path=args.source_delta_receipt, restore_path=args.restore_receipt, parity_path=args.parity_receipt, reasoning_path=args.reasoning_receipt, reasoning_compute_path=args.reasoning_compute_receipt, cleanup_path=args.cleanup_receipt, max_postflight_age_seconds=args.max_postflight_age_seconds, max_lifecycle_age_seconds=args.max_lifecycle_age_seconds, ) except (OSError, ValueError, KeyError, TypeError) as exc: payload = { "artifact": "gcp_canonical_snapshot_lifecycle_verification", "generated_at_utc": datetime.now(UTC).isoformat(), "status": "fail", "required_tier": "T3_live_private_gcp_staging", "failed_checks": ["receipt_load_or_validation_error"], "error": str(exc), "strongest_claim_allowed": "lifecycle incomplete; receipts could not be validated", } write_private_json(args.output, payload) print(json.dumps(payload, indent=2, sort_keys=True)) return 0 if payload.get("status") == "pass" else 1 if __name__ == "__main__": raise SystemExit(main())