From 4ece493b077c7f77d33adf37ebf8a4e4db60f4cc Mon Sep 17 00:00:00 2001 From: Darien Hernandez Date: Thu, 9 Jul 2026 18:40:57 +0200 Subject: [PATCH 1/2] =?UTF-8?q?fix(modules):=20platform-check=20existing?= =?UTF-8?q?=20executor=20in=20post-install=20=F0=9F=90=9B=F0=9F=94=92?= =?UTF-8?q?=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A linux-amd64 node tarball shipped a Mach-O arm64 executor; post-install only downloaded when the binary was absent, so it patched the wrong-platform binary in place and it failed at runtime with an opaque exec format error. Now an existing executor is magic-byte-checked against --os/--arch: on mismatch it is deleted and re-downloaded, or fails loud when downloads are disabled. Co-Authored-By: Claude Fable 5 --- .../lib/python/post-install/__main__.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/modules/install/lib/python/post-install/__main__.py b/modules/install/lib/python/post-install/__main__.py index 75ee22ab..629464ef 100644 --- a/modules/install/lib/python/post-install/__main__.py +++ b/modules/install/lib/python/post-install/__main__.py @@ -3,6 +3,8 @@ import shlex import argparse import platform +import shutil +import struct import tarfile import io import traceback @@ -491,6 +493,34 @@ def parse_executor_version(executor_version: str) -> tuple[int, int, int]: all_executor_version_tuples.add(parse_executor_version(v)) +_ELF_MACHINE_TO_ARCH = {0x3E: 'amd64', 0xB7: 'arm64'} +_MACHO_CPUTYPE_TO_ARCH = {0x01000007: 'amd64', 0x0100000C: 'arm64'} + + +def detect_executable_platform(path: Path) -> tuple[str, str] | None: + """Detect (os, arch) of an executable from magic bytes, e.g. ('linux', 'amd64'). + + Returns None if the file is not a recognized ELF or 64-bit Mach-O binary, + or its architecture is not one we distribute (amd64/arm64). + """ + with open(path, 'rb') as f: + header = f.read(20) + if len(header) < 20: + return None + if header[:4] == b'\x7fELF': + endian = '>' if header[5] == 2 else '<' + (e_machine,) = struct.unpack_from(endian + 'H', header, 18) + arch = _ELF_MACHINE_TO_ARCH.get(e_machine) + return ('linux', arch) if arch else None + (magic,) = struct.unpack_from('' + (cputype,) = struct.unpack_from(endian + 'I', header, 4) + arch = _MACHO_CPUTYPE_TO_ARCH.get(cputype) + return ('macos', arch) if arch else None + return None + + def process_executor_version(executor_version: str): logger.info(f'Examining executor version {executor_version}') @@ -506,6 +536,27 @@ def process_executor_version(executor_version: str): executor_executable = executor_root_dir.joinpath('bin', 'genvm') if args.executor_download or args.bin_patch or args.bin_check: + if executor_executable.exists(): + found = detect_executable_platform(executor_executable) + expected = (args.os, args.arch) + if found != expected: + found_str = f'{found[0]}/{found[1]}' if found else 'unrecognized binary format' + mismatch_msg = ( + f'Existing executor {executor_executable} does not match the target platform: ' + f'found {found_str}, expected {expected[0]}/{expected[1]}' + ) + if args.executor_download: + logger.warning( + f'{mismatch_msg}; removing {executor_root_dir} and re-downloading' + ) + shutil.rmtree(executor_root_dir) + else: + logger.error(mismatch_msg) + raise RuntimeError( + mismatch_msg + + ' (enable the executor-download step to replace it, or remove ' + + f'{executor_root_dir} manually)' + ) if not executor_executable.exists() and args.executor_download: import lzma From 5d5cb5be0d50d9b9d2a4ca65f9277b0a0d0ec6b5 Mon Sep 17 00:00:00 2001 From: Darien Hernandez Date: Thu, 9 Jul 2026 18:41:15 +0200 Subject: [PATCH 2/2] =?UTF-8?q?fix(modules):=20define=20next=5Fversion=20i?= =?UTF-8?q?n=20post-install=20skip=20log=20=F0=9F=90=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- modules/install/lib/python/post-install/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/install/lib/python/post-install/__main__.py b/modules/install/lib/python/post-install/__main__.py index 629464ef..22fd772b 100644 --- a/modules/install/lib/python/post-install/__main__.py +++ b/modules/install/lib/python/post-install/__main__.py @@ -528,7 +528,7 @@ def process_executor_version(executor_version: str): major, minor, patch = parse_executor_version(executor_version) if (major, minor, patch + 1) in all_executor_version_tuples: logger.info( - f'Skipping executor version {executor_version} because a newer version {next_version} exists' + f'Skipping executor version {executor_version} because a newer version v{major}.{minor}.{patch + 1} exists' ) return