test_ffi_installed.py (5140B)
1 from __future__ import annotations 2 3 import copy 4 import shutil 5 import sys 6 import tempfile 7 import unittest 8 from pathlib import Path 9 from unittest.mock import patch 10 11 SCRIPTS = Path(__file__).resolve().parent 12 if str(SCRIPTS) not in sys.path: 13 sys.path.insert(0, str(SCRIPTS)) 14 15 import ffi_artifacts as artifacts # noqa: E402 16 import ffi_installed as installed # noqa: E402 17 import ffi_provenance as provenance # noqa: E402 18 import ffi_source as source # noqa: E402 19 import test_ffi_artifacts as fixtures # noqa: E402 20 21 22 class InstalledArtifactTests(unittest.TestCase): 23 def setUp(self) -> None: 24 fixture = fixtures.NativeArtifactTests() 25 fixture.setUp() 26 self.addCleanup(fixture.doCleanups) 27 temporary = tempfile.TemporaryDirectory() 28 self.addCleanup(temporary.cleanup) 29 self.root = Path(temporary.name).resolve() 30 self.manifest = installed.installed_manifest( 31 artifacts.check(fixture.root, fixture.records) 32 ) 33 for relative, destination in installed.installed_paths().items(): 34 path = self.root / destination 35 path.parent.mkdir(parents=True, exist_ok=True) 36 shutil.copyfile(fixture.root / relative, path) 37 (self.root / installed.MANIFEST).write_bytes(provenance.encoded(self.manifest)) 38 39 def test_installed_inventory_retains_exact_candidate_file_identities(self) -> None: 40 installed.verify_files(self.root, self.manifest) 41 self.assertEqual(len(self.manifest["files"]), 13) 42 self.assertEqual( 43 self.manifest["disposition"], "local_installed_not_release_qualified" 44 ) 45 46 def test_missing_or_tampered_installed_library_is_rejected(self) -> None: 47 library = ( 48 self.root / "Tera/Frameworks/TeraFFI.xcframework/ios-arm64/libtera_ffi.a" 49 ) 50 library.write_bytes(b"tampered synthetic verifier fixture") 51 with self.assertRaisesRegex(source.ProvenanceError, "bytes are stale"): 52 installed.verify_files(self.root, self.manifest) 53 library.unlink() 54 with self.assertRaisesRegex(source.ProvenanceError, "missing"): 55 installed.verify_files(self.root, self.manifest) 56 57 def test_extra_generated_source_cannot_survive_an_install(self) -> None: 58 (self.root / "Tera/Generated/LegacyBindings.swift").write_text("// synthetic\n") 59 with self.assertRaisesRegex(source.ProvenanceError, "inventory differs"): 60 installed.verify_files(self.root, self.manifest) 61 62 def test_manifest_cannot_substitute_an_installed_file_hash(self) -> None: 63 changed = copy.deepcopy(self.manifest) 64 changed["files"][0]["sha256"] = "f" * 64 65 with self.assertRaisesRegex(source.ProvenanceError, "manifest differs"): 66 installed.verify_files(self.root, changed) 67 68 def test_symlinked_installed_source_is_rejected(self) -> None: 69 path = self.root / "Tera/Generated/TeraKitBindings.swift" 70 path.unlink() 71 path.symlink_to(self.root / installed.MANIFEST) 72 with self.assertRaisesRegex(source.ProvenanceError, "symlink"): 73 installed.verify_files(self.root, self.manifest) 74 75 def test_symlinked_parent_is_rejected_before_any_installation_swap(self) -> None: 76 with tempfile.TemporaryDirectory() as temporary: 77 outside = Path(temporary) / "Tera" 78 (self.root / "Tera").rename(outside) 79 (self.root / "Tera").symlink_to(outside, target_is_directory=True) 80 original = (outside / "Generated/TeraKitBindings.swift").read_bytes() 81 previous = self.root / "previous-unused" 82 with self.assertRaisesRegex( 83 source.ProvenanceError, "path contains a symlink" 84 ): 85 installed.replace_installation( 86 self.root, self.root / "stage-unused", previous 87 ) 88 self.assertFalse(previous.exists()) 89 self.assertEqual( 90 (outside / "Generated/TeraKitBindings.swift").read_bytes(), original 91 ) 92 93 def test_failed_final_source_check_restores_the_prior_installation(self) -> None: 94 staging = self.root / "stage" 95 previous = self.root / "previous" 96 before = { 97 p.relative_to(self.root): p.read_bytes() 98 for p in self.root.rglob("*") 99 if p.is_file() 100 } 101 for relative, data in before.items(): 102 path = staging / relative 103 path.parent.mkdir(parents=True, exist_ok=True) 104 path.write_bytes(data + b"new synthetic generation") 105 (staging / installed.LOCK).write_text("new lock\n") 106 with patch.object( 107 installed, "check", side_effect=source.ProvenanceError("source changed") 108 ): 109 with self.assertRaisesRegex(source.ProvenanceError, "source changed"): 110 installed.replace_installation(self.root, staging, previous) 111 for relative, data in before.items(): 112 self.assertEqual((self.root / relative).read_bytes(), data) 113 self.assertFalse((self.root / installed.LOCK).exists()) 114 115 116 if __name__ == "__main__": 117 unittest.main()