#!/usr/bin/env python3 """Full release-manifest CLI; synthetic inert artifacts, never installed.""" import io import json import os from pathlib import Path import resource import shutil import subprocess import sys import tarfile import unittest SOURCE = Path(os.environ['PACKAGER_SOURCE']).resolve() WORK = Path(os.environ['PACKAGER_WORK']).resolve() WORK.mkdir(parents=True, exist_ok=True) RECEIPTS = [] REQUIRED = ( 'scripts/ota-crash-guard.sh', 'image-recipe/configs/prepare-terminal-workspace.sh', 'scripts/d09-lifecycle-client.py', 'scripts/d09-lifecycle-owner.py', 'scripts/provision-d09-lifecycle.py', 'scripts/d09_wire.py', 'scripts/d09_store.py', 'scripts/d09_worker.py', 'scripts/d09-wire-schema.json', 'image-recipe/configs/archipelago-d09-lifecycle.service', 'image-recipe/configs/50-d09-lifecycle.conf', 'image-recipe/configs/60-terminal-workspace.conf', ) def limits(): resource.setrlimit(resource.RLIMIT_CPU, (15, 15)) resource.setrlimit(resource.RLIMIT_AS, (256 * 1024**2, 256 * 1024**2)) resource.setrlimit(resource.RLIMIT_FSIZE, (8 * 1024**2, 8 * 1024**2)) class Packager(unittest.TestCase): def setUp(self): self.root = WORK / self._testMethodName self.root.mkdir() self.project = self.root / 'project' shutil.copytree(SOURCE, self.project) cargo = self.project / 'core/archipelago/Cargo.toml' cargo.parent.mkdir(parents=True, exist_ok=True) cargo.write_text('[package]\nversion = "1.9.2"\n') self.backend = self.root / 'inert-backend' self.backend.write_bytes(b'fixture only; not executable\n') self.archive = self.root / 'frontend.tar.gz' self.output = self.root / 'manifest.json' def make_archive(self, omit=(), changed=None, mode=0o644, member_type=tarfile.REGTYPE, duplicate=False, bad_parent=False, alias=False): with tarfile.open(self.archive, 'w:gz') as tf: for path in REQUIRED: if path in omit: continue data = (self.project / path).read_bytes() if path == REQUIRED[1] and changed is not None: data = changed m = tarfile.TarInfo('./archipelago-runtime/' + path) m.mode = mode if path == REQUIRED[1] else 0o644 m.type = member_type if path == REQUIRED[1] else tarfile.REGTYPE if m.type in (tarfile.SYMTYPE, tarfile.LNKTYPE): m.linkname = 'foreign-helper' m.size = len(data) if m.isreg() else 0 tf.addfile(m, io.BytesIO(data) if m.isreg() else None) if duplicate and path == REQUIRED[1]: m.name = m.name.removeprefix('./') tf.addfile(m, io.BytesIO(data) if m.isreg() else None) if bad_parent: m = tarfile.TarInfo('./archipelago-runtime/image-recipe') m.type = tarfile.SYMTYPE; m.linkname = 'foreign-directory' tf.addfile(m) if alias: data = b'wrong helper behind alias' m = tarfile.TarInfo('./archipelago-runtime/image-recipe/configs/./prepare-terminal-workspace.sh') m.mode = 0o644; m.size = len(data) tf.addfile(m, io.BytesIO(data)) data = b'Synthetic fixture' m = tarfile.TarInfo('./index.html'); m.mode = 0o644; m.size = len(data) tf.addfile(m, io.BytesIO(data)) def invoke(self): cmd = ['/bin/bash', str(self.project / 'scripts/create-release-manifest.sh'), '--version', '1.9.2', '--date', '2026-10-25', '--backend', str(self.backend), '--frontend', str(self.archive), '--output', str(self.output), '--base-url', 'https://invalid.example/fixture'] env = {'PATH': '/usr/bin:/bin', 'HOME': str(self.root), 'TMPDIR': str(self.root), 'LANG': 'C', 'PYTHONDONTWRITEBYTECODE': '1'} p = subprocess.run(cmd, cwd=self.root, env=env, capture_output=True, text=True, timeout=10, preexec_fn=limits) RECEIPTS.append({'case': self._testMethodName, 'command': cmd, 'exit': p.returncode, 'stdout': p.stdout, 'stderr': p.stderr, 'manifest_exists': self.output.exists()}) return p def test_exact_helpers_emit_manifest(self): self.make_archive() p = self.invoke() self.assertEqual(p.returncode, 0, p.stderr) manifest = json.loads(self.output.read_text()) self.assertEqual(len(manifest['components']), 2) import hashlib self.assertEqual(manifest['components'][1]['sha256'], hashlib.sha256(self.archive.read_bytes()).hexdigest()) def test_gnu_tar_runtime_layout_emits_manifest(self): staging = self.root / 'staging' for path in REQUIRED: dest = staging / 'archipelago-runtime' / path dest.parent.mkdir(parents=True, exist_ok=True) shutil.copyfile(self.project / path, dest); dest.chmod(0o644) (staging / 'index.html').write_text('synthetic frontend') staging.chmod(0o755) for p in staging.rglob('*'): if p.is_dir(): p.chmod(0o755) cmd = ['/usr/bin/tar', '--owner=0', '--group=0', '--mode=u=rwX,go=rX', '-czf', str(self.archive), '-C', str(staging), '.'] subprocess.run(cmd, check=True, timeout=10, preexec_fn=limits) p = self.invoke() self.assertEqual(p.returncode, 0, p.stderr) self.assertTrue(self.output.exists()) def test_changed_helper_refuses_manifest(self): original = (self.project / REQUIRED[1]).read_bytes() self.make_archive(changed=bytes([original[0] ^ 1]) + original[1:]) p = self.invoke() self.assertNotEqual(p.returncode, 0, 'real packager accepted wrong helper bytes') self.assertIn('source mismatch', p.stderr) self.assertFalse(self.output.exists()) def test_truncated_helper_refuses(self): self.make_archive(changed=b'# truncated helper\n') self.assert_refused() def assert_refused(self): p = self.invoke() self.assertNotEqual(p.returncode, 0, 'real packager emitted invalid lifecycle payload') self.assertIn('Error:', p.stderr) self.assertFalse(self.output.exists()) def test_nonreadable_helper_refuses(self): self.make_archive(mode=0o600) self.assert_refused() def test_duplicate_helper_refuses(self): self.make_archive(duplicate=True) self.assert_refused() def test_link_helper_refuses(self): self.make_archive(member_type=tarfile.SYMTYPE) self.assert_refused() def test_source_symlink_refuses(self): self.make_archive() src = self.project / REQUIRED[1] other = src.with_name('foreign-helper'); src.rename(other); src.symlink_to(other.name) self.assert_refused() def test_missing_crash_guard_refuses(self): self.make_archive(omit=(REQUIRED[0],)) self.assert_refused() def test_ancestor_link_refuses(self): self.make_archive(bad_parent=True) self.assert_refused() def test_helper_path_alias_refuses(self): self.make_archive(alias=True) self.assert_refused() def test_source_fifo_refuses_without_blocking(self): self.make_archive() src = self.project / REQUIRED[1]; src.unlink(); os.mkfifo(src) self.assert_refused() def test_missing_terminal_helper_refuses_manifest(self): self.make_archive(omit=(REQUIRED[1],)) p = self.invoke() self.assertNotEqual(p.returncode, 0, 'real packager accepted missing OTA helper') self.assertFalse(self.output.exists()) def test_missing_shared_schema_refuses_manifest(self): self.make_archive(omit=('scripts/d09-wire-schema.json',)) self.assert_refused() if __name__ == '__main__': try: unittest.main(verbosity=2) finally: (WORK / 'commands.json').write_text(json.dumps(RECEIPTS, indent=2) + '\n')