"""Pure inventory fixtures: no application imports, network, installs or builds.""" import json from pathlib import Path import subprocess import sys import tempfile import unittest SCRIPT = Path(__file__).resolve().parents[1] / 'security-dependency-inventory.py' class PythonInventoryTests(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.addCleanup(self.tmp.cleanup) self.root = Path(self.tmp.name) for path in ['core/Cargo.lock', 'Android/rust/archy-fips-core/Cargo.lock']: self.write(path, 'version = 3\npackage = []\n') for path in ['neode-ui/package-lock.json', 'apps/router/package-lock.json', 'examples/archipelago-app-starter/package-lock.json']: self.write(path, '{"packages": {}}') for path in ['aiui/pnpm-lock.yaml', 'docker/gashboard/pnpm-lock.yaml']: self.write(path, 'packages: {}\n') self.write('reticulum-daemon/requirements.txt', 'rns==1.3.5\nlxmf==1.0.1\n') self.write('reticulum-daemon/requirements-build.txt', 'pyinstaller==6.21.0\n') for path in ['reticulum-daemon/build.sh', 'reticulum-daemon/build-esptool.sh']: self.write(path, ".venv/bin/pip install 'esptool==4.8.1'\n") self.report = {'version': '1', 'environment': {'python_version': '3.13', 'sys_platform': 'linux'}, 'install': []} for name, version in [('rns', '1.3.5'), ('lxmf', '1.0.1'), ('pyinstaller', '6.21.0'), ('esptool', '4.8.1'), ('PyYAML', '6.0.3')]: self.report['install'].append({ 'metadata': {'name': name, 'version': version, 'license': 'Reticulum License' if name == 'rns' else 'MIT'}, 'requested': name != 'PyYAML', 'download_info': {'url': 'https://example.invalid/' + name + '.whl', 'archive_info': {'hashes': {'sha256': 'a' * 64}}}, }) def write(self, path, content): target = self.root / path target.parent.mkdir(parents=True, exist_ok=True) target.write_text(content) def run_inventory(self, with_report=True): command = [sys.executable, str(SCRIPT), '--repo', str(self.root), '--output', str(self.root / 'out')] if with_report: self.write('pip-report.json', json.dumps(self.report)) command += ['--python-report', str(self.root / 'pip-report.json')] return subprocess.run(command, capture_output=True, text=True) def test_exact_transitives_hashes_and_custom_license_names(self): result = self.run_inventory() self.assertEqual(result.returncode, 0, result.stderr) bom = json.loads((self.root / 'out/source-bom.cdx.json').read_text()) components = {item['purl']: item for item in bom['components']} self.assertEqual(len(components), 5) self.assertIn('pkg:pypi/pyyaml@6.0.3', components) rns = components['pkg:pypi/rns@1.3.5'] self.assertEqual(rns['licenses'], [{'license': {'name': 'Reticulum License'}}]) self.assertEqual(rns['hashes'], [{'alg': 'SHA-256', 'content': 'a' * 64}]) summary = json.loads((self.root / 'out/source-inventory.json').read_text()) self.assertEqual(summary['python_resolution']['components'], 5) self.assertIn('esptool==4.8.1', summary['python_resolution']['roots']) self.assertTrue(any('other-platform graph' in entry['reason'] for entry in summary['unresolved'])) def test_stale_report_rejected_after_build_pin_changes(self): self.write('reticulum-daemon/build-esptool.sh', "pip install 'esptool==5.0.0'\n") result = self.run_inventory() self.assertNotEqual(result.returncode, 0) self.assertIn('does not match reticulum-daemon/build-esptool.sh', result.stderr) self.assertFalse((self.root / 'out/source-bom.cdx.json').exists()) def test_missing_artifact_hash_is_not_exact_evidence(self): self.report['install'][0]['download_info']['archive_info']['hashes'] = {} result = self.run_inventory() self.assertNotEqual(result.returncode, 0) self.assertIn('lacks exact SHA-256 artifact evidence', result.stderr) def test_without_report_build_only_root_remains_unresolved(self): result = self.run_inventory(with_report=False) self.assertEqual(result.returncode, 0, result.stderr) summary = json.loads((self.root / 'out/source-inventory.json').read_text()) esptool = [x for x in summary['unresolved'] if x.get('constraint') == 'esptool==4.8.1'] self.assertEqual({x['input'] for x in esptool}, {'reticulum-daemon/build.sh', 'reticulum-daemon/build-esptool.sh'}) if __name__ == '__main__': unittest.main()