"""Offline fail-closed helper checks; does not download/install/build.""" import hashlib import io import pathlib import tarfile import tempfile import unittest import json from unittest import mock import stage_app import prepare class Contracts(unittest.TestCase): def test_hash_and_size(self): with tempfile.TemporaryDirectory() as directory: path = pathlib.Path(directory) / "artifact" path.write_bytes(b"candidate") item = {"size": 9, "checksum": {"sha256": hashlib.sha256(b"candidate").hexdigest()}} prepare.verify(path, item) path.write_bytes(b"Candidate") with self.assertRaises(ValueError): prepare.verify(path, item) path.write_bytes(b"candidate-extra") with self.assertRaises(ValueError): prepare.verify(path, item) def test_network_allowlist(self): prepare.check_url("https://dl.registry.platformio.org/download/a") prepare.check_url("https://dl.registry.nm1.platformio.org/download/a") for url in ("http://dl.registry.platformio.org/a", "https://example.com/a", "https://dl.registry.platformio.org.evil/a"): with self.assertRaises(ValueError): prepare.check_url(url) def test_contract_failure(self): with self.assertRaises(ValueError): prepare.require(False) def test_member_ambiguity(self): stream = io.BytesIO() with tarfile.open(fileobj=stream, mode="w") as archive: for name in ("package.json", "./package.json"): entry = tarfile.TarInfo(name) entry.size = 2 archive.addfile(entry, io.BytesIO(b"{}")) stream.seek(0) with tarfile.open(fileobj=stream) as archive: with self.assertRaises(ValueError): prepare.member(archive, "package.json") with self.assertRaises(ValueError): prepare.member(archive, "missing") class Staging(unittest.TestCase): def test_fresh_snapshot_and_manifest(self): with tempfile.TemporaryDirectory() as directory: root = pathlib.Path(directory) base = root / ".pio/idf-candidate-5.5.3" base.mkdir(parents=True) (base / "app").mkdir() (base / "app/sentinel").write_text("old") (root / "platformio.ini").write_text("[platformio]\nplatform = platformio/espressif32@6.13.0\n") (root / "src").mkdir() (root / "src/main.c").write_text("modified working tree") (root / "src/secret").write_text("never copy") ws = root / "tests/sdk_security_overrides/ws.c" ws.parent.mkdir(parents=True) ws.write_text("explicit fixture") items = [{"package": "platformio/platform/espressif32", "version": "6.13.0", "name": "platform.tar.gz"}] with mock.patch.object(stage_app.subprocess, "check_output", return_value=b"platformio.ini\0src/main.c\0"): dest = stage_app.stage("app-validated", root, base, items) manifest = json.loads((dest / "app-source-manifest.json").read_text()) for name, digest in manifest.items(): self.assertEqual(hashlib.sha256((dest / name).read_bytes()).hexdigest(), digest) self.assertIn(str(base / "core"), (dest / "platformio.ini").read_text()) self.assertEqual((dest / "src/main.c").read_text(), "modified working tree") self.assertTrue((dest / "tests/sdk_security_overrides/ws.c").exists()) self.assertFalse((dest / "src/secret").exists()) self.assertEqual((base / "app/sentinel").read_text(), "old") for name in ("app", "app-validated"): with self.assertRaises(FileExistsError): stage_app.stage(name, root, base, items) for name in ("../escape", "/tmp/escape", "", ".", "..", "app/nested"): with self.assertRaises(ValueError): stage_app.stage(name, root, base, items) (base / "linked").symlink_to(root, target_is_directory=True) with self.assertRaises(ValueError): stage_app.stage("linked", root, base, items) (root / "src/main.c").unlink() (root / "src/main.c").symlink_to(root / "platformio.ini") with self.assertRaises(ValueError): stage_app.stage("unsafe", root, base, items) self.assertFalse((base / "unsafe").exists()) if __name__ == "__main__": unittest.main()