G7 증명과 G8 clean-head 승격 준비

This commit is contained in:
Yun Chan 2026-08-09 18:22:03 +09:00
parent 94c681d450
commit 5221f79e3f
52 changed files with 6876 additions and 506 deletions

View file

@ -265,6 +265,153 @@ def topology() -> dict[str, object]:
}
def windows_topology() -> dict[str, object]:
process_metrics = {
"api": {
"rss_bytes": 200_000,
"peak_rss_bytes": 240_000,
"cpu_time_seconds": 2.0,
"cpu_percent": 3.0,
"handles": 40,
"threads": 8,
},
"cloudflared": {
"rss_bytes": 100_000,
"peak_rss_bytes": 120_000,
"cpu_time_seconds": 1.0,
"cpu_percent": 1.5,
"handles": 20,
"threads": 4,
},
}
process_tcp = {
"api": {"connections": 2, "established": 1, "listeners": 1},
"cloudflared": {"connections": 4, "established": 4, "listeners": 0},
}
samples = [
{
"sequence": index + 1,
"observed_at_utc": "2026-08-07T00:30:00Z",
"processes": copy.deepcopy(process_metrics),
"process_tcp": copy.deepcopy(process_tcp),
"host_tcp": {"connections": 20},
"api_listener": {
"port": 8001,
"owned_listener_count": 1,
"conflicting_listener_count": 0,
},
}
for index in range(31)
]
return {
"schema_version": "vignette.g7-topology-evidence.v1",
"topology_mode": "windows_host",
"status": "passed",
"started_at_utc": "2026-08-07T00:00:00Z",
"ended_at_utc": "2026-08-07T01:00:00Z",
"scope": {
"metadata_only": True,
"raw_command_output_retained": False,
"socket_endpoints_retained": False,
"request_payloads_retained": False,
"audio_retained": False,
"transcripts_retained": False,
"topology_boundary": "windows_host_api_and_cloudflared_processes",
"configured_listener_port_retained": True,
"cloudflare_edge": {
"internal_queue_measured": False,
"evidence_boundary": "separate_external_artifact_required",
},
},
"requested": {
"public_host": "api.example.test",
"repo_root": r"D:\workspace\vignette",
"git_sha": "5" * 40,
"source_pin": {
"git_tree_sha": "8" * 40,
"script_sha256": {
"runner": "9" * 64,
"collector": "a" * 64,
"checker": "b" * 64,
},
"runtime_dependencies": {"psutil": "6.1.1"},
},
"samples": 31,
"interval_seconds": 100.0,
"api_listen_port": 8001,
"roles": {
"api": {
"pid": 301,
"expected_executable_name": "python.exe",
"expected_executable_sha256": "3" * 64,
"expected_cwd": r"D:\workspace\vignette\apps\api",
},
"cloudflared": {
"pid": 302,
"expected_executable_name": "cloudflared.exe",
"expected_executable_sha256": "4" * 64,
"expected_cwd": r"D:\workspace\vignette",
},
},
},
"source_provenance": {
"detached_head": True,
"tracked_clean": True,
"git_sha": "5" * 40,
"git_tree_sha": "8" * 40,
"script_sha256": {
"runner": "9" * 64,
"collector": "a" * 64,
"checker": "b" * 64,
},
"runtime_dependencies": {"psutil": "6.1.1"},
},
"samples_completed": 31,
"targets": {
"api": {
"role": "api",
"pid": 301,
"started_at": "2026-08-06T00:00:00Z",
"executable_name": "python.exe",
"executable_sha256": "3" * 64,
"command_line_sha256": "6" * 64,
"git_sha": "5" * 40,
"cwd": r"D:\workspace\vignette\apps\api",
},
"cloudflared": {
"role": "cloudflared",
"pid": 302,
"started_at": "2026-08-06T00:00:00Z",
"executable_name": "cloudflared.exe",
"executable_sha256": "4" * 64,
"command_line_sha256": "7" * 64,
"git_sha": "5" * 40,
"cwd": r"D:\workspace\vignette",
},
},
"samples": samples,
"summary": {
"processes": {
role: {
**{f"{field}_max": value for field, value in metrics.items()},
**{
f"tcp_{field}_max": value
for field, value in process_tcp[role].items()
},
}
for role, metrics in process_metrics.items()
},
"api_listener": {
"port": 8001,
"owned_listener_count_min": 1,
"conflicting_listener_count_max": 0,
},
"host_tcp": {"connections_max": 20},
},
"failure_type": None,
}
class G7ExternalProofTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
@ -286,6 +433,97 @@ class G7ExternalProofTests(unittest.TestCase):
self.assertTrue(gain["passed"])
self.assertGreaterEqual(gain["held_out_participants"], 30)
def test_windows_host_topology_passes_without_weakening_compose(self) -> None:
errors: list[str] = []
payload = windows_topology()
compose_payload = topology()
compose_payload["topology_mode"] = "linux_compose"
self.checker.validate_topology(payload, errors)
self.checker.validate_topology(compose_payload, errors)
self.checker.validate_binding(public_soak(), runtime(), payload, errors)
self.assertEqual([], errors)
def test_windows_host_identity_listener_and_summary_fail_closed(self) -> None:
cases = (
(
lambda payload: payload["targets"]["api"].__setitem__("pid", 999),
"topology:api_pid_pin",
),
(
lambda payload: payload["samples"][0]["api_listener"].__setitem__(
"owned_listener_count", 0
),
"topology:listener_owner_sample",
),
(
lambda payload: payload["summary"]["processes"]["api"].__setitem__(
"rss_bytes_max", 1
),
"topology:api_rss_bytes_max",
),
)
for mutate, failure in cases:
with self.subTest(failure=failure):
payload = windows_topology()
mutate(payload)
errors: list[str] = []
self.checker.validate_topology(payload, errors)
self.assertIn(failure, errors)
def test_windows_source_and_toolchain_provenance_fail_closed(self) -> None:
cases = (
(
lambda payload: payload["source_provenance"].__setitem__(
"detached_head", False
),
"topology:windows_detached_head",
),
(
lambda payload: payload["source_provenance"].__setitem__(
"tracked_clean", False
),
"topology:windows_tracked_clean",
),
(
lambda payload: payload["source_provenance"].__setitem__(
"git_tree_sha", "c" * 40
),
"topology:windows_source_git_tree_sha",
),
(
lambda payload: payload["source_provenance"]["script_sha256"].__setitem__(
"runner", "c" * 64
),
"topology:windows_source_script_sha256",
),
(
lambda payload: payload["source_provenance"][
"runtime_dependencies"
].__setitem__("psutil", "6.1.0"),
"topology:windows_source_psutil_version",
),
)
for mutate, failure in cases:
with self.subTest(failure=failure):
payload = windows_topology()
mutate(payload)
errors: list[str] = []
self.checker.validate_topology(payload, errors)
self.assertIn(failure, errors)
unpinned_version = windows_topology()
unpinned_version["requested"]["source_pin"]["runtime_dependencies"][
"psutil"
] = "6.1.0"
unpinned_version["source_provenance"]["runtime_dependencies"][
"psutil"
] = "6.1.0"
errors = []
self.checker.validate_topology(unpinned_version, errors)
self.assertIn("topology:windows_psutil_version_pin", errors)
def test_decided_local_stack_is_accepted(self) -> None:
"""2026-08-08 소유자 결정: 노트북 faster-whisper STT + MeloTTS TTS (둘 다 MIT)."""
@ -353,6 +591,44 @@ class G7ExternalProofTests(unittest.TestCase):
self.assertIn("voice_soak:physical_microphone_used", errors)
self.assertIn("binding:no_concurrent_overlap", errors)
def test_concurrent_window_requires_full_3000_second_intersection(self) -> None:
exact_errors: list[str] = []
exact_voice = public_soak()
exact_voice["ended_at_utc"] = "2026-08-07T00:50:00Z"
exact_runtime = runtime()
exact_runtime["ended_at_utc"] = "2026-08-07T00:50:00Z"
exact_topology = topology()
exact_topology["ended_at_utc"] = "2026-08-07T00:50:00Z"
self.checker.validate_binding(
exact_voice,
exact_runtime,
exact_topology,
exact_errors,
)
self.assertEqual([], exact_errors)
short_errors: list[str] = []
short_voice = public_soak()
short_voice["ended_at_utc"] = "2026-08-07T00:50:00Z"
short_runtime = runtime()
short_runtime["started_at_utc"] = "2026-08-07T00:00:01Z"
short_runtime["ended_at_utc"] = "2026-08-07T00:50:00Z"
short_topology = topology()
short_topology["ended_at_utc"] = "2026-08-07T00:50:00Z"
self.checker.validate_binding(
short_voice,
short_runtime,
short_topology,
short_errors,
)
self.assertIn(
"binding:concurrent_overlap_below_3000_seconds",
short_errors,
)
def test_runtime_fallback_and_short_topology_fail(self) -> None:
errors: list[str] = []
runtime_payload = runtime()