git » homepage.git » commit 6b1bac9

Make preservation exports recovery-host portable

author Alan Dipert
2026-08-09 22:04:39 UTC
committer Alan Dipert
2026-08-09 22:04:39 UTC
parent 55bfb26dee49befb2b4a51d36be20bc1dc32c42d

Make preservation exports recovery-host portable

tests/test_archive_techworks.py +29 -0
tools/archive_techworks.py +4 -1

diff --git a/tests/test_archive_techworks.py b/tests/test_archive_techworks.py
index 3fe4d8f..975a2c8 100644
--- a/tests/test_archive_techworks.py
+++ b/tests/test_archive_techworks.py
@@ -3,6 +3,7 @@ import hashlib
 from pathlib import Path
 import tempfile
 import unittest
+import unittest.mock
 
 import archive_techworks
 
@@ -72,6 +73,34 @@ class ArchiveTechWorksTests(unittest.TestCase):
                 (occupied / "file").unlink()
                 occupied.rmdir()
 
+    def test_export_does_not_require_optional_format_tools(self):
+        with tempfile.TemporaryDirectory() as directory:
+            root = Path(directory)
+            artifact = root / "md" / "TechWorks" / "recording.mp4"
+            artifact.parent.mkdir(parents=True)
+            artifact.write_bytes(b"preserved without ffprobe")
+            row = {
+                "work_id": "work",
+                "artifact_id": "work-video",
+                "title": "Work video",
+                "kind": "video",
+                "source_url": "https://example.com/work",
+                "local_path": "md/TechWorks/recording.mp4",
+                "retrieved_utc": "2026-08-09T00:00:00Z",
+                "sha256": hashlib.sha256(b"preserved without ffprobe").hexdigest(),
+                "bytes": str(len(b"preserved without ffprobe")),
+                "visibility": "public",
+                "status": "preserved",
+                "notes": "",
+            }
+            manifest = self.write_manifest(root, [row])
+            with unittest.mock.patch.object(archive_techworks, "run") as run:
+                with self.assertRaisesRegex(
+                    archive_techworks.AuditError, "unsafe export destination"
+                ):
+                    archive_techworks.export(root, manifest, root)
+                run.assert_not_called()
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/archive_techworks.py b/tools/archive_techworks.py
index 99816d4..903db31 100644
--- a/tools/archive_techworks.py
+++ b/tools/archive_techworks.py
@@ -169,7 +169,10 @@ def safe_destination(root: Path, destination: Path) -> Path:
 
 
 def export(root: Path, manifest_path: Path, destination: Path) -> None:
-    rows = audit(root, manifest_path)
+    # Export must remain usable on a recovery host with only Python and Git.
+    # The dedicated archive audit performs the optional ffprobe/pdfinfo checks;
+    # here we still verify every artifact's path, size, and SHA-256 digest.
+    rows = audit(root, manifest_path, verify_formats=False)
     destination = safe_destination(root, destination)
     destination.mkdir(parents=True, exist_ok=True)
     bundle_dir = destination / "git"