from __future__ import annotations import importlib.util import json import subprocess import stat import sys import tempfile import unittest from datetime import datetime from pathlib import Path ROOT = Path(__file__).resolve().parents[1] SCRIPTS = ROOT / "scripts" TESTS = ROOT / "tests" for path in (SCRIPTS, TESTS): if str(path) not in sys.path: sys.path.insert(0, str(path)) from test_custody_contract import projection_contract SPEC = importlib.util.spec_from_file_location( "wp0025_broker_readiness", SCRIPTS / "wp0025-broker-readiness.py" ) assert SPEC and SPEC.loader module = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(module) class BrokerReadinessTests(unittest.TestCase): @staticmethod def engagement_time(contract: dict) -> datetime: return datetime.fromisoformat( contract["window"]["starts_at"].replace("Z", "+00:00") ) def test_show_is_direct_and_authorizes_no_live_mutation(self) -> None: result = module.show(projection_contract()) self.assertEqual("whitehat-security", result["owner"]) self.assertIn("approve", result["approve_command"]) self.assertFalse(result["live_mutation_authorized"]) self.assertFalse(result["secret_values_observed"]) def test_adapter_verification_pins_revision_file_and_focused_test(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) adapter = root / module.DEFAULT_ADAPTER test = root / module.DEFAULT_TEST adapter.parent.mkdir(parents=True) test.parent.mkdir(parents=True) adapter.write_text("class PlatformCustodyBroker: pass\n", encoding="utf-8") test.write_text("def test_adapter(): assert True\n", encoding="utf-8") def runner(command, **kwargs): if command[:2] == ["git", "rev-parse"]: return subprocess.CompletedProcess(command, 0, stdout="a" * 40 + "\n", stderr="") return subprocess.CompletedProcess(command, 0, stdout="1 passed\n", stderr="") result = module.verify_adapter(root, runner=runner) self.assertTrue(result["passed"]) self.assertEqual("a" * 40, result["adapter"]["revision"]) self.assertEqual(64, len(result["adapter"]["sha256"])) self.assertTrue(result["adapter"]["tests_passed"]) def test_missing_adapter_fails_without_running_commands(self) -> None: with tempfile.TemporaryDirectory() as directory: result = module.verify_adapter( Path(directory), runner=lambda *args, **kwargs: self.fail("runner must not execute"), ) self.assertFalse(result["passed"]) self.assertFalse(result["secret_values_observed"]) def test_approval_round_trip_and_change_request(self) -> None: contract = projection_contract() verification = { "passed": True, "adapter": { "repo": "whitehat-security", "revision": "a" * 40, "path": str(module.DEFAULT_ADAPTER), "sha256": "b" * 64, "tests_passed": True, }, "secret_values_observed": False, } now = self.engagement_time(contract) receipt = module.build_approval( contract, "whitehat-owner", verification, now=now ) self.assertEqual("approve", receipt["decision"]) self.assertTrue(receipt["cleanup_request_supported"]) change = module.build_change_request( contract, "whitehat-owner", "Bind cleanup acknowledgement.", now=now, ) self.assertEqual("request-changes", change["decision"]) with self.assertRaises(module.ReadinessError): module.build_change_request(contract, "whitehat-owner", "", now=now) def test_receipt_export_is_raw_canonical_document_with_private_mode(self) -> None: contract = projection_contract() verification = { "passed": True, "adapter": { "repo": "whitehat-security", "revision": "a" * 40, "path": str(module.DEFAULT_ADAPTER), "sha256": "b" * 64, "tests_passed": True, }, "secret_values_observed": False, } receipt = module.build_approval( contract, "whitehat-owner", verification, now=self.engagement_time(contract), ) with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "nested" / "broker.json" module.write_receipt(path, receipt) observed = json.loads(path.read_text(encoding="utf-8")) mode = stat.S_IMODE(path.stat().st_mode) self.assertEqual(receipt, observed) self.assertNotIn("submitted", observed) self.assertEqual(0o600, mode) if __name__ == "__main__": unittest.main()