785 lines
41 KiB
Python
785 lines
41 KiB
Python
#!/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 .private_receipt_io import print_private_receipt_summary
|
|
from .restore_gcp_generated_postgres_snapshot import DEFAULT_RESTORE_SERVICE_ACCOUNT
|
|
from .verify_vps_canonical_snapshot_delta import DELTA_SCHEMA, parse_timestamp, write_private_json
|
|
except ImportError: # pragma: no cover - direct script execution
|
|
from private_receipt_io import print_private_receipt_summary
|
|
from restore_gcp_generated_postgres_snapshot import DEFAULT_RESTORE_SERVICE_ACCOUNT
|
|
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",
|
|
"role_memberships",
|
|
"object_ownership",
|
|
"object_acl",
|
|
}
|
|
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") == [] and details.get("table_hash_problems") == [],
|
|
"structural_hashes": structural_valid,
|
|
"roles": details.get("application_role_mismatches") == {}
|
|
and details.get("target_extra_application_roles") == [],
|
|
"extensions": details.get("required_extension_mismatches") == {}
|
|
and details.get("target_extra_extensions") == [],
|
|
"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 ((invocation.get("database_identity") or {}).get("sslmode") == "verify-full")
|
|
and ((invocation.get("database_identity") or {}).get("server_identity_verified") is True)
|
|
and bool((invocation.get("database_identity") or {}).get("ssl_server_name"))
|
|
and bool(
|
|
SHA256_RE.fullmatch(str((invocation.get("database_identity") or {}).get("ssl_root_cert_sha256") or ""))
|
|
)
|
|
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_manifest_sql_bound": delta_baseline.get("manifest_sql_sha256")
|
|
== (source.get("manifest") or {}).get("manifest_sql_sha256")
|
|
and delta_current.get("manifest_sql_sha256")
|
|
== (current_source.get("manifest") or {}).get("manifest_sql_sha256")
|
|
and delta_baseline.get("manifest_sql_sha256") == delta_current.get("manifest_sql_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 restore_connectivity.get("sslmode") == "verify-full"
|
|
and restore_connectivity.get("server_identity_verified") is True
|
|
and restore_connectivity.get("ssl_server_name") == restore_contract.get("ssl_server_name")
|
|
and restore_connectivity.get("ssl_root_cert_sha256") == restore_contract.get("ssl_root_cert_sha256")
|
|
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 restore_contract.get("restore_service_account") == DEFAULT_RESTORE_SERVICE_ACCOUNT
|
|
and restore_compute.get("service_account") == DEFAULT_RESTORE_SERVICE_ACCOUNT,
|
|
"restore_tls_identity_contract": bool(restore_contract.get("ssl_server_name"))
|
|
and bool(SHA256_RE.fullmatch(str(restore_contract.get("ssl_root_cert_sha256") or ""))),
|
|
"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 parity_connectivity_proof.get("sslmode") == "verify-full"
|
|
and parity_connectivity_proof.get("server_identity_verified") is True
|
|
and parity_connectivity_proof.get("ssl_server_name") == restore_contract.get("ssl_server_name")
|
|
and parity_connectivity_proof.get("ssl_root_cert_sha256") == restore_contract.get("ssl_root_cert_sha256")
|
|
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("existed_before") is True
|
|
and 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)
|
|
structurally_valid = not failed
|
|
return {
|
|
"artifact": "gcp_canonical_snapshot_lifecycle_verification",
|
|
"generated_at_utc": verification_time.isoformat(),
|
|
"status": "prepared_external_attestation_required" if structurally_valid else "fail",
|
|
"current_tier": "T2_structural_receipt_bundle",
|
|
"required_tier": "T3_live_private_gcp_staging",
|
|
"t3_receipt_ready": False,
|
|
"accepted_by_this_api": False,
|
|
"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": (
|
|
"caller-supplied lifecycle receipts are internally consistent; an independently authenticated platform receipt is still required"
|
|
if structurally_valid
|
|
else "lifecycle preparation is 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_private_receipt_summary(args.output, payload)
|
|
return 0 if payload.get("status") == "prepared_external_attestation_required" else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|