Recognize macOS extraction helper staging and verify release resources
This commit is contained in:
1 parent
f1028e2689
commit
d41c5b5e98
4 files changed
+44
-4
No files matched your search
@@ -53,10 +53,17 @@ def identity(path):
|
||||
machine = struct.unpack_from('<H', signature, 4)[0] if signature[:4] == b'PE\0\0' else 0
|
||||
arch = {0x8664: 'x86_64', 0xAA64: 'aarch64'}.get(machine)
|
||||
platform = 'windows'
|
||||
elif header[:6] == b'\x7fELF\x02\x01':
|
||||
elif len(header) == 64 and header[:6] == b'\x7fELF\x02\x01':
|
||||
machine = struct.unpack_from('<H', header, 18)[0]
|
||||
arch = {62: 'x86_64', 183: 'aarch64'}.get(machine)
|
||||
platform = 'linux'
|
||||
elif len(header) >= 32 and header[:4] == b'\xcf\xfa\xed\xfe':
|
||||
# Apple's mach_header_64: thin little-endian native executable.
|
||||
cpu, _, filetype, commands, command_bytes = struct.unpack_from('<IIIII', header, 4)
|
||||
if filetype != 2 or not 0 < commands <= 8192 or not commands * 8 <= command_bytes <= path.stat().st_size - 32:
|
||||
raise ValueError('Invalid extraction Mach-O executable header')
|
||||
arch = {0x01000007: 'x86_64', 0x0100000c: 'aarch64'}.get(cpu)
|
||||
platform = 'macos'
|
||||
else:
|
||||
raise ValueError('Unsupported extraction executable format')
|
||||
if arch is None:
|
||||
@@ -106,7 +113,7 @@ def stage(binary, provenance, destination, root=ROOT):
|
||||
try:
|
||||
if target == name and hashlib.sha256(data).hexdigest() != record['sha256']:
|
||||
raise ValueError('Extraction binary changed while staging')
|
||||
if target == name and platform == 'linux':
|
||||
if target == name and platform != 'windows':
|
||||
temporary.chmod(0o755)
|
||||
os.replace(temporary, destination / target)
|
||||
finally:
|
||||
@@ -119,7 +126,7 @@ def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--destination', type=Path, default=ROOT / 'apps/desktop/src-tauri/resources')
|
||||
parser.add_argument('--verify-only', action='store_true')
|
||||
parser.add_argument('--platform', choices=['windows', 'linux'], default='windows' if os.name == 'nt' else 'linux')
|
||||
parser.add_argument('--platform', choices=['windows', 'linux', 'macos'], default='windows' if os.name == 'nt' else ('macos' if host_platform.system() == 'Darwin' else 'linux'))
|
||||
parser.add_argument('--architecture', choices=['x86_64', 'aarch64'], default='aarch64' if host_platform.machine().lower() in {'aarch64', 'arm64'} else 'x86_64')
|
||||
args = parser.parse_args()
|
||||
if args.verify_only:
|
||||
|
||||
@@ -56,6 +56,26 @@ class ExtractionStageTests(unittest.TestCase):
|
||||
worker.stage(binary, before, resources, root)
|
||||
self.assertEqual((resources / 'searchi-extract-worker.exe').read_bytes(), binary.read_bytes())
|
||||
|
||||
def test_macos_thin_headers_and_staging(self):
|
||||
import struct
|
||||
for cpu, arch in [(0x01000007, 'x86_64'), (0x0100000c, 'aarch64')]:
|
||||
with self.subTest(architecture=arch), tempfile.TemporaryDirectory() as directory:
|
||||
root, binary, resources = self.fixture(directory)
|
||||
data = struct.pack('<8I', 0xfeedfacf, cpu, 0, 2, 1, 8, 0, 0) + struct.pack('<2I', 0, 8)
|
||||
binary.write_bytes(data)
|
||||
worker.stage(binary, worker.fingerprint(root), resources, root)
|
||||
records = worker.verify(resources, root, 'macos', arch)
|
||||
self.assertIn('searchi-extract-worker', records)
|
||||
for invalid in [data[:31], data[:12] + struct.pack('<I', 6) + data[16:], data[:4] + struct.pack('<I', 7) + data[8:], data[:20] + struct.pack('<I', 9999) + data[24:]]:
|
||||
binary.write_bytes(invalid)
|
||||
with self.assertRaises(ValueError):
|
||||
worker.identity(binary)
|
||||
|
||||
def test_darwin_default_uses_macos_and_arm64(self):
|
||||
with patch.object(worker.os, 'name', 'posix'), patch.object(worker.host_platform, 'system', return_value='Darwin'), patch.object(worker.host_platform, 'machine', return_value='arm64'), patch.object(worker, 'verify') as verify, patch('sys.argv', ['stage_extraction_worker.py', '--verify-only']):
|
||||
worker.main()
|
||||
self.assertEqual(verify.call_args.args[2:], ('macos', 'aarch64'))
|
||||
|
||||
def test_failed_build_never_stages_existing_binary(self):
|
||||
with patch.object(worker.subprocess, 'run', side_effect=RuntimeError('cargo failed')), patch.object(worker, 'stage') as stage, patch('sys.argv', ['stage_extraction_worker.py']):
|
||||
with self.assertRaises(RuntimeError):
|
||||
|
||||
Reference in new issue
Block a user