import hashlib import json import tempfile import unittest from pathlib import Path from scripts.prepare_m1_acceptance_kit import ( KIT_FILES, EXPECTED_ADDON_FILES, RAYFORGE_COMMIT, REPORT_TEMPLATE, ROOT, create_kit, ) class M1AcceptanceKitTests(unittest.TestCase): @staticmethod def _artifact_pair(root: Path, status="passed"): checkpoint = { "schema_version": 2, "checkpoint": "Rayforge Windows no-device bundle", "addon": "the_pirate_ray_jcz", "rayforge_commit": RAYFORGE_COMMIT, "bundle": {"sha256": "1" * 64}, "installer": {"sha256": "2" * 64}, } checkpoint_path = root / "rayforge-windows-checkpoint.json" checkpoint_path.write_text(json.dumps(checkpoint), encoding="utf-8") verification = { "schema_version": 1, "verification": "Rayforge Windows no-device artifact verification", "status": status, "hardware_access": False, "executed_binaries": False, "manual_interaction_required": True, "rayforge_commit": RAYFORGE_COMMIT, "bundle_sha256": "1" * 64, "installer_sha256": "2" * 64, "verified_addon_files": EXPECTED_ADDON_FILES, "addon": "the_pirate_ray_jcz", "checkpoint_manifest": { "path": checkpoint_path.name, "sha256": hashlib.sha256(checkpoint_path.read_bytes()).hexdigest(), }, } verification_path = root / "verification.json" verification_path.write_text(json.dumps(verification), encoding="utf-8") return verification_path, checkpoint_path def test_kit_contains_only_allowlisted_public_inputs(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: output = Path(directory) / "kit" manifest = create_kit(output, repository_commit="a" * 40) self.assertFalse(manifest["hardware_access_authorized"]) self.assertFalse(manifest["contains_private_evidence"]) self.assertEqual(2, manifest["schema_version"]) self.assertEqual( hashlib.sha256((ROOT / REPORT_TEMPLATE).read_bytes()).hexdigest(), manifest["report_template"]["sha256"], ) self.assertEqual( {record["path"] for record in manifest["files"]}, set(KIT_FILES), ) for record in manifest["files"]: path = output / record["path"] self.assertEqual(record["bytes"], path.stat().st_size) self.assertEqual(record["sha256"], hashlib.sha256(path.read_bytes()).hexdigest()) self.assertEqual(record["classification"], "synthetic-public") report = json.loads((output / "manual-report.json").read_text(encoding="utf-8")) self.assertEqual("a" * 40, report["acceptance_kit"]["repository_commit"]) self.assertEqual( hashlib.sha256((output / "kit-manifest.json").read_bytes()).hexdigest(), report["acceptance_kit"]["manifest_sha256"], ) def test_manifest_is_reproducible_for_same_commit(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: root = Path(directory) create_kit(root / "one", repository_commit="b" * 40) create_kit(root / "two", repository_commit="b" * 40) one = (root / "one" / "kit-manifest.json").read_bytes() two = (root / "two" / "kit-manifest.json").read_bytes() self.assertEqual(one, two) def test_nonempty_output_is_not_overwritten(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: output = Path(directory) / "kit" output.mkdir() sentinel = output / "keep.txt" sentinel.write_text("keep", encoding="utf-8") with self.assertRaisesRegex(ValueError, "not empty"): create_kit(output, repository_commit="c" * 40) self.assertEqual(sentinel.read_text(encoding="utf-8"), "keep") def test_manifest_on_disk_matches_returned_data(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: output = Path(directory) / "kit" expected = create_kit(output, repository_commit="d" * 40) actual = json.loads((output / "kit-manifest.json").read_text(encoding="utf-8")) self.assertEqual(actual, expected) def test_passing_artifact_verification_is_bound_into_report(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: root = Path(directory) verification, checkpoint = self._artifact_pair(root) output = root / "kit" create_kit( output, repository_commit="e" * 40, artifact_verification=verification, checkpoint_manifest=checkpoint, ) copied = output / "artifact-verification.json" report = json.loads((output / "manual-report.json").read_text(encoding="utf-8")) copied_digest = hashlib.sha256(copied.read_bytes()).hexdigest() self.assertEqual("passed", report["artifact_verification"]["status"]) self.assertEqual( copied_digest, report["artifact_verification"]["report_sha256"], ) def test_failed_artifact_verification_is_rejected(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: root = Path(directory) verification, checkpoint = self._artifact_pair(root, status="failed") with self.assertRaisesRegex(ValueError, "did not pass"): create_kit( root / "kit", repository_commit="f" * 40, artifact_verification=verification, checkpoint_manifest=checkpoint, ) def test_wrong_rayforge_pin_or_missing_hashes_are_rejected(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: root = Path(directory) verification, checkpoint = self._artifact_pair(root) result = json.loads(verification.read_text(encoding="utf-8")) result["rayforge_commit"] = "0" * 40 result["bundle_sha256"] = "not-a-hash" verification.write_text(json.dumps(result), encoding="utf-8") with self.assertRaisesRegex(ValueError, "did not pass"): create_kit( root / "kit", repository_commit="f" * 40, artifact_verification=verification, checkpoint_manifest=checkpoint, ) def test_changed_checkpoint_manifest_is_rejected(self): with tempfile.TemporaryDirectory(dir=ROOT / ".build") as directory: root = Path(directory) verification, checkpoint = self._artifact_pair(root) checkpoint.write_text("{}", encoding="utf-8") with self.assertRaisesRegex(ValueError, "did not pass"): create_kit( root / "kit", repository_commit="f" * 40, artifact_verification=verification, checkpoint_manifest=checkpoint, ) if __name__ == "__main__": unittest.main()