vignette/scripts/check-g7-external-proof.py
2026-08-09 18:22:03 +09:00

1022 lines
38 KiB
Python

#!/usr/bin/env python3
"""Fail-closed validator for the complete G7 external evidence gate.
All four artifacts are required: authenticated public physical-microphone soak,
process-local voice runtime sampling, pinned deployment topology sampling, and
an independent human-held-out voice-gain pack. No artifact may contain raw audio
or transcripts, and synthetic evidence cannot satisfy this gate.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import math
import ntpath
import sys
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
REPO_ROOT = Path(__file__).resolve().parents[1]
API_ROOT = REPO_ROOT / "apps/api"
if str(API_ROOT) not in sys.path:
sys.path.insert(0, str(API_ROOT))
from app.contracts.g7_external_evidence import G7HumanVoiceGainEvidencePack # noqa: E402
from app.services.g7_voice_gain_evidence import evaluate_human_voice_gain # noqa: E402
MINIMUM_SOAK_SECONDS = 3_000.0
PINNED_PSUTIL_VERSION = "6.1.1"
# 이 게이트는 특정 벤더가 아니라 **운영하기로 결정한 provider** 를 강제한다.
# 2026-08-08 소유자 결정: STT 는 노트북 상주 faster-whisper(`local_whisper`),
# TTS 는 노트북 MeloTTS(`melotts`). 둘 다 MIT 라 운영 사용 제약이 없다.
# 이전 값은 벤더 하나(`deepgram`/`openai`)가 하드코딩돼 있었을 뿐 결정 기록이 아니었다.
# 근거는 docs/decisions/local-voice-stack.md.
#
# 목록은 닫혀 있다. 배치 STT(`openai`)는 interim/final 계약을 만족할 수 없어
# 여기 들어오지 못한다. 어떤 경우에도 `expected_* == ready_*` 결속은 유지되므로
# 선언한 provider 와 실제로 돈 provider 가 다르면 계속 실패한다.
ALLOWED_STT_PROVIDERS = ("local_whisper", "deepgram")
ALLOWED_TTS_PROVIDERS = ("melotts", "higgs", "openai")
def load_json(path: Path, errors: list[str], label: str) -> dict[str, Any]:
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except FileNotFoundError:
errors.append(f"{label}:missing")
return {}
except (OSError, UnicodeError, json.JSONDecodeError):
errors.append(f"{label}:unreadable")
return {}
if not isinstance(payload, dict):
errors.append(f"{label}:invalid_shape")
return {}
return payload
def _number(value: object) -> float | None:
if isinstance(value, bool) or not isinstance(value, (int, float)):
return None
result = float(value)
return result if math.isfinite(result) else None
def _require(errors: list[str], condition: bool, code: str) -> None:
if not condition:
errors.append(code)
def _iso(value: object) -> datetime | None:
if not isinstance(value, str) or not value:
return None
try:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError:
return None
if parsed.tzinfo is None:
parsed = parsed.replace(tzinfo=UTC)
return parsed.astimezone(UTC)
def _lower_hex(value: object, lengths: set[int]) -> bool:
return (
isinstance(value, str)
and len(value) in lengths
and value == value.lower()
and all(character in "0123456789abcdef" for character in value)
)
def validate_public_soak(payload: dict[str, Any], errors: list[str]) -> None:
prefix = "voice_soak"
_require(
errors,
payload.get("schema_version") == "vignette.g7-public-voice-soak.v4",
f"{prefix}:schema",
)
_require(errors, payload.get("mode") == "public_soak", f"{prefix}:mode")
_require(errors, payload.get("status") == "passed", f"{prefix}:status")
requested = _number(payload.get("requested_duration_seconds"))
elapsed = _number(payload.get("elapsed_seconds"))
_require(
errors,
requested is not None and requested >= MINIMUM_SOAK_SECONDS,
f"{prefix}:duration_requested",
)
_require(
errors,
elapsed is not None and requested is not None and elapsed >= requested,
f"{prefix}:duration_elapsed",
)
for field in (
"microphone_device_enumerated",
"physical_capture_confirmed",
"physical_microphone_used",
"public_wss_used",
"authenticated_public_wss_ready",
"real_database_session_binding_required",
"ready_provider_metadata_validated",
"cookie_present",
"session_id_present",
"cloudflare_ray_present",
"unauthenticated_handshake_accepted",
):
_require(errors, payload.get(field) is True, f"{prefix}:{field}")
for field in (
"raw_audio_retained",
"provider_overrides_used",
"cookie_value_logged",
):
_require(errors, payload.get(field) is False, f"{prefix}:{field}")
_require(errors, payload.get("tls_version") == "TLSv1.3", f"{prefix}:tls")
_require(
errors,
payload.get("unauthenticated_close_code") == 1008,
f"{prefix}:unauth_close",
)
_require(errors, payload.get("close_code") == 1000, f"{prefix}:auth_close")
_require(
errors,
payload.get("expected_stt_provider") in ALLOWED_STT_PROVIDERS,
f"{prefix}:stt_provider_not_operated",
)
_require(
errors,
payload.get("expected_tts_provider") in ALLOWED_TTS_PROVIDERS,
f"{prefix}:tts_provider_not_operated",
)
for expected, ready in (
("expected_stt_provider", "ready_stt_provider"),
("expected_stt_model", "ready_stt_model"),
("expected_tts_provider", "ready_tts_provider"),
("expected_tts_model", "ready_tts_model"),
):
_require(
errors,
bool(payload.get(expected)) and payload.get(expected) == payload.get(ready),
f"{prefix}:{ready}_mismatch",
)
attempted = payload.get("turns_attempted")
succeeded = payload.get("turns_succeeded")
metrics = payload.get("turn_transcript_metrics")
_require(
errors,
isinstance(attempted, int) and attempted >= 10,
f"{prefix}:turns_attempted",
)
_require(errors, succeeded == attempted, f"{prefix}:turns_succeeded")
_require(
errors,
isinstance(metrics, list) and len(metrics) == succeeded,
f"{prefix}:turn_metrics_count",
)
if isinstance(metrics, list):
interim_total = 0
final_total = 0
seen_turns: set[int] = set()
for item in metrics:
if not isinstance(item, dict):
errors.append(f"{prefix}:turn_metric_shape")
continue
turn = item.get("turn_number")
interim = item.get("interim_transcript_frames")
final = item.get("speech_final_transcript_frames")
_require(
errors,
isinstance(turn, int) and turn > 0 and turn not in seen_turns,
f"{prefix}:turn_number",
)
if isinstance(turn, int):
seen_turns.add(turn)
_require(
errors,
isinstance(interim, int) and interim >= 1,
f"{prefix}:interim_missing",
)
_require(errors, final == 1, f"{prefix}:speech_final_not_exact")
_require(
errors,
_number(item.get("first_interim_latency_ms")) is not None,
f"{prefix}:interim_latency",
)
_require(
errors,
_number(item.get("speech_final_latency_ms")) is not None,
f"{prefix}:final_latency",
)
interim_total += interim if isinstance(interim, int) else 0
final_total += final if isinstance(final, int) else 0
_require(
errors,
payload.get("interim_transcript_frames") == interim_total,
f"{prefix}:interim_total",
)
_require(
errors,
payload.get("speech_final_transcript_frames") == final_total,
f"{prefix}:final_total",
)
_require(
errors,
isinstance(succeeded, int) and payload.get("reply_frames", 0) >= succeeded,
f"{prefix}:reply_frames",
)
_require(
errors,
isinstance(succeeded, int) and payload.get("tts_end_frames", 0) >= succeeded,
f"{prefix}:tts_end_frames",
)
_require(errors, payload.get("tts_binary_bytes", 0) > 0, f"{prefix}:tts_audio")
_require(errors, payload.get("captured_pcm_bytes", 0) > 0, f"{prefix}:captured_pcm")
_require(errors, not payload.get("blockers"), f"{prefix}:blockers")
_require(errors, payload.get("failure_type") is None, f"{prefix}:failure")
def validate_runtime(payload: dict[str, Any], errors: list[str]) -> None:
prefix = "runtime"
_require(
errors,
payload.get("schema_version") == "vignette.g7-runtime-sampling.v1",
f"{prefix}:schema",
)
_require(errors, payload.get("status") == "passed", f"{prefix}:status")
_require(
errors,
payload.get("privacy_boundary")
== "metadata_only_no_audio_transcript_session_or_cookie_values",
f"{prefix}:privacy",
)
_require(
errors,
payload.get("cookie_present") is True
and payload.get("cookie_value_logged") is False,
f"{prefix}:cookie_boundary",
)
requested = payload.get("requested_samples")
completed = payload.get("samples_completed")
interval = _number(payload.get("interval_seconds"))
_require(
errors,
isinstance(requested, int) and requested == completed and requested > 1,
f"{prefix}:sample_count",
)
_require(
errors,
interval is not None
and isinstance(completed, int)
and (completed - 1) * interval >= MINIMUM_SOAK_SECONDS,
f"{prefix}:coverage",
)
samples = payload.get("samples")
_require(
errors,
isinstance(samples, list) and len(samples) == completed,
f"{prefix}:samples",
)
high = payload.get("high_water")
_require(errors, isinstance(high, dict), f"{prefix}:high_water")
if isinstance(high, dict):
for field in (
"process_peak_rss_bytes",
"process_threads_max",
"websocket_high_water",
"streaming_provider_session_high_water",
"route_audio_buffer_high_water_bytes",
"streaming_event_queue_high_water_items",
):
_require(errors, (_number(high.get(field)) or 0) > 0, f"{prefix}:{field}")
capture_started = _iso(payload.get("started_at_utc"))
worker_started = _iso(payload.get("worker_started_at_utc"))
_require(
errors,
capture_started is not None
and worker_started is not None
and 0 <= (capture_started - worker_started).total_seconds() <= 120,
f"{prefix}:fresh_worker_required",
)
if isinstance(samples, list) and samples:
final = samples[-1].get("snapshot") if isinstance(samples[-1], dict) else None
counters = final.get("counters") if isinstance(final, dict) else None
limits = final.get("limits") if isinstance(final, dict) else None
_require(
errors,
isinstance(final, dict)
and final.get("schema_version") == "vignette.voice-runtime.v1",
f"{prefix}:snapshot_schema",
)
_require(
errors,
isinstance(final, dict) and final.get("scope") == "single_api_worker",
f"{prefix}:snapshot_scope",
)
_require(
errors,
isinstance(final, dict)
and final.get("privacy_boundary")
== "metadata_only_no_audio_transcript_or_session_ids",
f"{prefix}:snapshot_privacy",
)
_require(errors, isinstance(counters, dict), f"{prefix}:final_counters")
_require(
errors,
isinstance(limits, dict) and limits.get("uvicorn_ws_max_queue") == 4,
f"{prefix}:uvicorn_queue_cap",
)
if isinstance(counters, dict):
for field in (
"provider_fallback_total",
"websocket_error_total",
"audio_overflow_rejections_total",
):
_require(errors, counters.get(field) == 0, f"{prefix}:{field}")
def _validate_linux_compose_topology(
payload: dict[str, Any],
errors: list[str],
) -> None:
prefix = "topology"
targets = payload.get("targets")
_require(
errors,
isinstance(targets, dict) and set(targets) == {"api", "caddy"},
f"{prefix}:targets",
)
if isinstance(targets, dict):
capture_started = _iso(payload.get("started_at_utc"))
for role in ("api", "caddy"):
target = targets.get(role)
_require(errors, isinstance(target, dict), f"{prefix}:{role}_target")
if isinstance(target, dict):
_require(
errors,
isinstance(target.get("container_id"), str)
and len(target["container_id"]) == 64,
f"{prefix}:{role}_container",
)
digest = target.get("image_digest")
_require(
errors,
isinstance(digest, str)
and digest.startswith("sha256:")
and len(digest) == 71,
f"{prefix}:{role}_image",
)
target_started = _iso(target.get("started_at"))
_require(
errors,
capture_started is not None
and target_started is not None
and 0 <= (capture_started - target_started).total_seconds() <= 120,
f"{prefix}:{role}_fresh_container_required",
)
summary = payload.get("summary")
_require(errors, isinstance(summary, dict), f"{prefix}:summary")
if isinstance(summary, dict):
containers = summary.get("containers")
host_tcp = summary.get("host_tcp")
_require(errors, isinstance(containers, dict), f"{prefix}:container_summary")
if isinstance(containers, dict):
for role in ("api", "caddy"):
values = containers.get(role)
_require(errors, isinstance(values, dict), f"{prefix}:{role}_summary")
if isinstance(values, dict):
for field in (
"cgroup_memory_peak_bytes_max",
"cgroup_cpu_usage_usec_max",
"cgroup_pids_current_max",
"proc_vm_hwm_bytes_max",
"proc_threads_max",
"proc_fd_count_max",
):
_require(
errors,
(_number(values.get(field)) or 0) > 0,
f"{prefix}:{role}_{field}",
)
_require(
errors,
isinstance(host_tcp, dict)
and (_number(host_tcp.get("connections_max")) or 0) > 0,
f"{prefix}:host_tcp",
)
def _validate_windows_topology(
payload: dict[str, Any],
errors: list[str],
) -> None:
prefix = "topology"
requested = payload.get("requested")
_require(errors, isinstance(requested, dict), f"{prefix}:windows_requested")
if not isinstance(requested, dict):
return
expected_git_sha = requested.get("git_sha")
_require(
errors,
_lower_hex(expected_git_sha, {40, 64}),
f"{prefix}:windows_git_sha",
)
source_pin = requested.get("source_pin")
_require(
errors,
isinstance(source_pin, dict),
f"{prefix}:windows_source_pin",
)
expected_tree_sha = (
source_pin.get("git_tree_sha") if isinstance(source_pin, dict) else None
)
expected_scripts = (
source_pin.get("script_sha256") if isinstance(source_pin, dict) else None
)
expected_dependencies = (
source_pin.get("runtime_dependencies") if isinstance(source_pin, dict) else None
)
_require(
errors,
_lower_hex(expected_tree_sha, {40, 64}),
f"{prefix}:windows_git_tree_sha_pin",
)
_require(
errors,
isinstance(expected_scripts, dict)
and set(expected_scripts) == {"runner", "collector", "checker"}
and all(_lower_hex(value, {64}) for value in expected_scripts.values()),
f"{prefix}:windows_script_sha256_pin",
)
_require(
errors,
isinstance(expected_dependencies, dict)
and expected_dependencies == {"psutil": PINNED_PSUTIL_VERSION},
f"{prefix}:windows_psutil_version_pin",
)
source_provenance = payload.get("source_provenance")
_require(
errors,
isinstance(source_provenance, dict),
f"{prefix}:windows_source_provenance",
)
if isinstance(source_provenance, dict):
observed_scripts = source_provenance.get("script_sha256")
observed_dependencies = source_provenance.get("runtime_dependencies")
_require(
errors,
source_provenance.get("detached_head") is True,
f"{prefix}:windows_detached_head",
)
_require(
errors,
source_provenance.get("tracked_clean") is True,
f"{prefix}:windows_tracked_clean",
)
_require(
errors,
source_provenance.get("git_sha") == expected_git_sha,
f"{prefix}:windows_source_git_sha",
)
_require(
errors,
source_provenance.get("git_tree_sha") == expected_tree_sha,
f"{prefix}:windows_source_git_tree_sha",
)
_require(
errors,
isinstance(observed_scripts, dict)
and isinstance(expected_scripts, dict)
and observed_scripts == expected_scripts,
f"{prefix}:windows_source_script_sha256",
)
_require(
errors,
isinstance(observed_dependencies, dict)
and isinstance(expected_dependencies, dict)
and observed_dependencies == expected_dependencies,
f"{prefix}:windows_source_psutil_version",
)
repo_root = requested.get("repo_root")
_require(
errors,
isinstance(repo_root, str) and ntpath.isabs(repo_root),
f"{prefix}:windows_repo_root",
)
api_listen_port = requested.get("api_listen_port")
_require(
errors,
isinstance(api_listen_port, int)
and not isinstance(api_listen_port, bool)
and 1 <= api_listen_port <= 65_535,
f"{prefix}:windows_api_listen_port",
)
requested_roles = requested.get("roles")
_require(
errors,
isinstance(requested_roles, dict)
and set(requested_roles) == {"api", "cloudflared"},
f"{prefix}:windows_requested_roles",
)
targets = payload.get("targets")
_require(
errors,
isinstance(targets, dict) and set(targets) == {"api", "cloudflared"},
f"{prefix}:targets",
)
capture_started = _iso(payload.get("started_at_utc"))
target_pids: list[int] = []
if isinstance(targets, dict) and isinstance(requested_roles, dict):
for role in ("api", "cloudflared"):
target = targets.get(role)
expectation = requested_roles.get(role)
_require(errors, isinstance(target, dict), f"{prefix}:{role}_target")
_require(
errors,
isinstance(expectation, dict),
f"{prefix}:{role}_expectation",
)
if not isinstance(target, dict) or not isinstance(expectation, dict):
continue
_require(
errors,
target.get("role") == role,
f"{prefix}:{role}_role",
)
pid = target.get("pid")
_require(
errors,
isinstance(pid, int) and not isinstance(pid, bool) and pid > 0,
f"{prefix}:{role}_pid",
)
if isinstance(pid, int) and not isinstance(pid, bool):
target_pids.append(pid)
_require(
errors,
pid == expectation.get("pid"),
f"{prefix}:{role}_pid_pin",
)
executable_sha256 = target.get("executable_sha256")
_require(
errors,
_lower_hex(executable_sha256, {64})
and executable_sha256 == expectation.get("expected_executable_sha256"),
f"{prefix}:{role}_executable_sha256",
)
_require(
errors,
_lower_hex(target.get("command_line_sha256"), {64}),
f"{prefix}:{role}_command_line_sha256",
)
executable_name = target.get("executable_name")
expected_name = expectation.get("expected_executable_name")
_require(
errors,
isinstance(executable_name, str)
and isinstance(expected_name, str)
and executable_name.casefold() == expected_name.casefold(),
f"{prefix}:{role}_executable_name",
)
cwd = target.get("cwd")
expected_cwd = expectation.get("expected_cwd")
_require(
errors,
isinstance(cwd, str)
and isinstance(expected_cwd, str)
and ntpath.normcase(ntpath.normpath(cwd))
== ntpath.normcase(ntpath.normpath(expected_cwd)),
f"{prefix}:{role}_cwd",
)
_require(
errors,
target.get("git_sha") == expected_git_sha,
f"{prefix}:{role}_git_sha",
)
target_started = _iso(target.get("started_at"))
_require(
errors,
capture_started is not None
and target_started is not None
and target_started <= capture_started,
f"{prefix}:{role}_process_start",
)
_require(
errors,
len(target_pids) == 2 and len(set(target_pids)) == 2,
f"{prefix}:windows_distinct_pids",
)
completed = payload.get("samples_completed")
samples = payload.get("samples")
_require(
errors,
isinstance(samples, list)
and isinstance(completed, int)
and len(samples) == completed,
f"{prefix}:windows_samples",
)
capture_ended = _iso(payload.get("ended_at_utc"))
metric_values: dict[str, dict[str, list[float]]] = {
role: {
field: []
for field in (
"rss_bytes",
"peak_rss_bytes",
"cpu_time_seconds",
"cpu_percent",
"handles",
"threads",
)
}
for role in ("api", "cloudflared")
}
tcp_values: dict[str, dict[str, list[int]]] = {
role: {field: [] for field in ("connections", "established", "listeners")}
for role in ("api", "cloudflared")
}
listener_owned: list[int] = []
listener_conflicts: list[int] = []
host_connections: list[int] = []
if isinstance(samples, list):
previous_cpu: dict[str, float] = {}
for index, sample in enumerate(samples, start=1):
if not isinstance(sample, dict):
errors.append(f"{prefix}:windows_sample_shape")
continue
_require(
errors,
sample.get("sequence") == index,
f"{prefix}:windows_sample_sequence",
)
observed_at = _iso(sample.get("observed_at_utc"))
_require(
errors,
capture_started is not None
and capture_ended is not None
and observed_at is not None
and capture_started <= observed_at <= capture_ended,
f"{prefix}:windows_sample_time",
)
processes = sample.get("processes")
process_tcp = sample.get("process_tcp")
_require(
errors,
isinstance(processes, dict)
and set(processes) == {"api", "cloudflared"},
f"{prefix}:windows_sample_processes",
)
_require(
errors,
isinstance(process_tcp, dict)
and set(process_tcp) == {"api", "cloudflared"},
f"{prefix}:windows_sample_process_tcp",
)
for role in ("api", "cloudflared"):
metrics = processes.get(role) if isinstance(processes, dict) else None
tcp = process_tcp.get(role) if isinstance(process_tcp, dict) else None
_require(
errors,
isinstance(metrics, dict),
f"{prefix}:{role}_sample_metrics",
)
_require(
errors,
isinstance(tcp, dict),
f"{prefix}:{role}_sample_tcp",
)
if isinstance(metrics, dict):
for field in metric_values[role]:
numeric = _number(metrics.get(field))
positive = field != "cpu_percent"
_require(
errors,
numeric is not None
and numeric >= 0
and (not positive or numeric > 0),
f"{prefix}:{role}_{field}_sample",
)
if numeric is not None:
metric_values[role][field].append(numeric)
cpu_time = _number(metrics.get("cpu_time_seconds"))
if cpu_time is not None:
_require(
errors,
cpu_time >= previous_cpu.get(role, 0.0),
f"{prefix}:{role}_cpu_time_monotonic",
)
previous_cpu[role] = cpu_time
if isinstance(tcp, dict):
for field in tcp_values[role]:
value = tcp.get(field)
_require(
errors,
isinstance(value, int)
and not isinstance(value, bool)
and value >= 0,
f"{prefix}:{role}_tcp_{field}_sample",
)
if isinstance(value, int) and not isinstance(value, bool):
tcp_values[role][field].append(value)
if role == "api":
_require(
errors,
(_number(tcp.get("listeners")) or 0) > 0,
f"{prefix}:api_listener_sample",
)
else:
_require(
errors,
(_number(tcp.get("established")) or 0) > 0,
f"{prefix}:cloudflared_tunnel_sample",
)
listener = sample.get("api_listener")
host_tcp = sample.get("host_tcp")
_require(errors, isinstance(listener, dict), f"{prefix}:listener_sample")
_require(errors, isinstance(host_tcp, dict), f"{prefix}:host_tcp_sample")
if isinstance(listener, dict):
owned = listener.get("owned_listener_count")
conflicts = listener.get("conflicting_listener_count")
_require(
errors,
listener.get("port") == api_listen_port,
f"{prefix}:listener_port_sample",
)
_require(
errors,
isinstance(owned, int) and not isinstance(owned, bool) and owned > 0,
f"{prefix}:listener_owner_sample",
)
_require(
errors,
isinstance(conflicts, int)
and not isinstance(conflicts, bool)
and conflicts == 0,
f"{prefix}:listener_conflict_sample",
)
if isinstance(owned, int) and not isinstance(owned, bool):
listener_owned.append(owned)
if isinstance(conflicts, int) and not isinstance(conflicts, bool):
listener_conflicts.append(conflicts)
if isinstance(host_tcp, dict):
connections = host_tcp.get("connections")
_require(
errors,
isinstance(connections, int)
and not isinstance(connections, bool)
and connections > 0,
f"{prefix}:host_tcp_connections_sample",
)
if isinstance(connections, int) and not isinstance(connections, bool):
host_connections.append(connections)
summary = payload.get("summary")
_require(errors, isinstance(summary, dict), f"{prefix}:summary")
if isinstance(summary, dict):
process_summary = summary.get("processes")
listener_summary = summary.get("api_listener")
host_summary = summary.get("host_tcp")
_require(
errors,
isinstance(process_summary, dict)
and set(process_summary) == {"api", "cloudflared"},
f"{prefix}:windows_process_summary",
)
if isinstance(process_summary, dict):
for role in ("api", "cloudflared"):
values = process_summary.get(role)
_require(
errors,
isinstance(values, dict),
f"{prefix}:{role}_summary",
)
if not isinstance(values, dict):
continue
for field, observations in metric_values[role].items():
_require(
errors,
bool(observations)
and _number(values.get(f"{field}_max")) == max(observations),
f"{prefix}:{role}_{field}_max",
)
for field, observations in tcp_values[role].items():
_require(
errors,
bool(observations)
and _number(values.get(f"tcp_{field}_max"))
== max(observations),
f"{prefix}:{role}_tcp_{field}_max",
)
_require(
errors,
isinstance(listener_summary, dict)
and listener_summary.get("port") == api_listen_port
and bool(listener_owned)
and listener_summary.get("owned_listener_count_min")
== min(listener_owned)
and bool(listener_conflicts)
and listener_summary.get("conflicting_listener_count_max")
== max(listener_conflicts),
f"{prefix}:windows_listener_summary",
)
_require(
errors,
isinstance(host_summary, dict)
and bool(host_connections)
and host_summary.get("connections_max") == max(host_connections),
f"{prefix}:host_tcp",
)
def validate_topology(payload: dict[str, Any], errors: list[str]) -> None:
prefix = "topology"
_require(
errors,
payload.get("schema_version") == "vignette.g7-topology-evidence.v1",
f"{prefix}:schema",
)
_require(errors, payload.get("status") == "passed", f"{prefix}:status")
scope = payload.get("scope")
_require(
errors,
isinstance(scope, dict) and scope.get("metadata_only") is True,
f"{prefix}:privacy",
)
if isinstance(scope, dict):
for field in (
"raw_command_output_retained",
"socket_endpoints_retained",
"request_payloads_retained",
"audio_retained",
"transcripts_retained",
):
_require(errors, scope.get(field) is False, f"{prefix}:{field}")
edge = scope.get("cloudflare_edge")
_require(
errors,
isinstance(edge, dict)
and edge.get("internal_queue_measured") is False
and edge.get("evidence_boundary") == "separate_external_artifact_required",
f"{prefix}:edge_boundary",
)
requested = payload.get("requested")
completed = payload.get("samples_completed")
_require(errors, isinstance(requested, dict), f"{prefix}:requested")
if isinstance(requested, dict):
sample_count = requested.get("samples")
interval = _number(requested.get("interval_seconds"))
_require(
errors,
isinstance(sample_count, int)
and sample_count == completed
and sample_count > 1,
f"{prefix}:sample_count",
)
_require(
errors,
interval is not None
and isinstance(completed, int)
and (completed - 1) * interval >= MINIMUM_SOAK_SECONDS,
f"{prefix}:coverage",
)
topology_mode = payload.get("topology_mode")
_require(
errors,
topology_mode in (None, "linux_compose", "windows_host"),
f"{prefix}:mode",
)
if topology_mode == "windows_host":
_require(
errors,
isinstance(scope, dict)
and scope.get("topology_boundary")
== "windows_host_api_and_cloudflared_processes"
and scope.get("configured_listener_port_retained") is True,
f"{prefix}:windows_scope",
)
_validate_windows_topology(payload, errors)
elif topology_mode in (None, "linux_compose"):
_validate_linux_compose_topology(payload, errors)
_require(errors, payload.get("failure_type") is None, f"{prefix}:failure")
def validate_human_gain(payload: dict[str, Any], errors: list[str]) -> dict[str, Any]:
try:
pack = G7HumanVoiceGainEvidencePack.model_validate(payload)
result = evaluate_human_voice_gain(pack)
except Exception as exc:
errors.append(f"human_gain:invalid:{type(exc).__name__}")
return {}
if not result.passed:
errors.extend(f"human_gain:{reason}" for reason in result.failure_reasons)
return result.model_dump(mode="json")
def validate_binding(
voice: dict[str, Any],
runtime: dict[str, Any],
topology: dict[str, Any],
errors: list[str],
) -> None:
voice_host = voice.get("target_host")
runtime_host = runtime.get("target_host")
requested = topology.get("requested")
topology_host = (
requested.get("public_host") if isinstance(requested, dict) else None
)
_require(
errors,
bool(voice_host) and voice_host == runtime_host == topology_host,
"binding:public_host",
)
windows = []
for label, payload in (
("voice", voice),
("runtime", runtime),
("topology", topology),
):
start, end = (
_iso(payload.get("started_at_utc")),
_iso(payload.get("ended_at_utc")),
)
if start is None or end is None or end < start:
errors.append(f"binding:{label}_time")
else:
windows.append((start, end))
if len(windows) == 3:
overlap_started = max(start for start, _ in windows)
overlap_ended = min(end for _, end in windows)
_require(
errors,
overlap_started <= overlap_ended,
"binding:no_concurrent_overlap",
)
if overlap_started <= overlap_ended:
_require(
errors,
(overlap_ended - overlap_started).total_seconds()
>= MINIMUM_SOAK_SECONDS,
"binding:concurrent_overlap_below_3000_seconds",
)
def artifact_sha256(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def parser() -> argparse.ArgumentParser:
result = argparse.ArgumentParser(description=__doc__)
result.add_argument("--voice-soak", type=Path, required=True)
result.add_argument("--runtime", type=Path, required=True)
result.add_argument("--topology", type=Path, required=True)
result.add_argument("--human-voice-gain", type=Path, required=True)
result.add_argument("--json", action="store_true")
return result
def main() -> int:
args = parser().parse_args()
errors: list[str] = []
paths = {
"voice_soak": args.voice_soak,
"runtime": args.runtime,
"topology": args.topology,
"human_voice_gain": args.human_voice_gain,
}
payloads = {label: load_json(path, errors, label) for label, path in paths.items()}
if payloads["voice_soak"]:
validate_public_soak(payloads["voice_soak"], errors)
if payloads["runtime"]:
validate_runtime(payloads["runtime"], errors)
if payloads["topology"]:
validate_topology(payloads["topology"], errors)
gain_result = (
validate_human_gain(payloads["human_voice_gain"], errors)
if payloads["human_voice_gain"]
else {}
)
if all(payloads[label] for label in ("voice_soak", "runtime", "topology")):
validate_binding(
payloads["voice_soak"], payloads["runtime"], payloads["topology"], errors
)
report = {
"schema_version": "vignette.g7-external-proof-result.v1",
"passed": not errors,
"clinical_claim_allowed": False,
"artifact_sha256": {
label: artifact_sha256(path)
for label, path in paths.items()
if path.is_file()
},
"human_voice_gain_result": gain_result,
"errors": errors,
}
print(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True))
return 0 if not errors else 1
if __name__ == "__main__":
raise SystemExit(main())