"""ISO smoke must bind exact signed APK bytes, not Gradle's base version.""" import hashlib import importlib.util import json from pathlib import Path import tempfile import unittest from unittest import mock MODULE = Path(__file__).resolve().parents[1] / 'iso_companion_check.py' spec = importlib.util.spec_from_file_location('iso_companion_check', MODULE) check = importlib.util.module_from_spec(spec) spec.loader.exec_module(check) COMMIT = 'a' * 40 class IsoCompanionCheck(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.addCleanup(self.temp.cleanup) self.web = Path(self.temp.name) (self.web / 'packages').mkdir() self.apk = self.web / 'packages/archipelago-companion.apk' self.meta = self.web / 'packages/archipelago-companion.json' self.apk.write_bytes(b'synthetic signed APK fixture') self.qualified = { 'sha256': hashlib.sha256(self.apk.read_bytes()).hexdigest(), 'certificate_sha256': 'b' * 64, 'package_name': 'com.archipelago.app.debug', 'versionName': '0.5.40-bump28-debug', 'versionCode': 60, } self.meta.write_text(json.dumps({'versionName': '0.5.40-bump28-debug', 'versionCode': 60})) def test_accepts_qualified_variant_suffix_and_exact_apk(self): result = check.check(self.web, COMMIT, self.qualified) self.assertEqual(result['versionName'], '0.5.40-bump28-debug') self.assertEqual(result['apk_sha256'], self.qualified['sha256']) def test_rejects_swapped_apk_even_with_matching_metadata(self): self.apk.write_bytes(b'different APK with same claimed metadata') with self.assertRaisesRegex(ValueError, 'differs from signed source APK'): check.check(self.web, COMMIT, self.qualified) def test_rejects_metadata_disagreeing_with_qualified_apk(self): self.meta.write_text(json.dumps({'versionName': '0.5.40', 'versionCode': 60})) with self.assertRaisesRegex(ValueError, 'metadata differs'): check.check(self.web, COMMIT, self.qualified) self.meta.write_text(json.dumps({'versionName': '0.5.40-bump28-debug', 'versionCode': 61})) with self.assertRaisesRegex(ValueError, 'metadata differs'): check.check(self.web, COMMIT, self.qualified) def test_rejects_symlink_apk_and_unqualified_identity(self): self.apk.unlink() self.apk.symlink_to(self.meta) with self.assertRaisesRegex(ValueError, 'unsafe Companion file'): check.check(self.web, COMMIT, self.qualified) self.apk.unlink() self.apk.write_bytes(b'synthetic signed APK fixture') with self.assertRaisesRegex(ValueError, 'package differs'): check.check(self.web, COMMIT, dict(self.qualified, package_name='other.app')) with self.assertRaisesRegex(ValueError, 'version missing'): check.check(self.web, COMMIT, dict(self.qualified, versionCode=None)) def test_qualify_calls_release_source_and_signed_apk_verifier(self): responses = [COMMIT + '\n', json.dumps(self.qualified)] with mock.patch.object(check.subprocess, 'check_output', side_effect=responses) as call: source, identity = check.qualify(Path('/qualified/repo'), '2.1.3-beta') self.assertEqual(source, COMMIT) self.assertEqual(identity, self.qualified) self.assertEqual(call.call_count, 2) self.assertEqual(call.call_args_list[0].args[0][-5:], ['source', '--version', '2.1.3-beta', '--root', '/qualified/repo']) self.assertEqual(call.call_args_list[1].args[0][-3:], ['companion', '--root', '/qualified/repo']) self.assertEqual([item.kwargs['cwd'] for item in call.call_args_list], [Path('/qualified/repo'), Path('/qualified/repo')]) if __name__ == '__main__': unittest.main()