From 26676975eace77d95e67114bbf504cf67830fefe Mon Sep 17 00:00:00 2001 From: Teodor Calin Date: Thu, 28 May 2026 23:50:04 -0700 Subject: [PATCH] fix(sdk-python): version ldflag + wrong-platform validation (PILOT-208 side fixes) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two of three sub-fixes from PILOT-208. The third (CI publish-pipeline single-arch upload) remains blocked on the .github/workflows/ policy decision tracked in PILOT-113. Fix A: build-binaries.sh missing version ldflag `go build -ldflags="-s -w"` produced binaries that report "dev" for their version string at runtime. Added `-X main.Version=$SDK_VERSION` (SDK_VERSION is already parsed from pyproject.toml earlier in the script) so the four CLI binaries embed the wheel's version. The CGO binding doesn't have a main package — left alone. Fix B: _runtime.py wrong-platform validation Wheel bundled binaries get exec'd by cli.py / loaded by client.py. If pip installed a wrong-platform wheel (e.g. linux wheel on macOS), the failure surfaces as opaque "Exec format error" at first exec with no actionable diagnostic. Added _validate_binary_platform that sniffs the first 4 bytes of pilotctl for ELF / Mach-O / PE magic, compares to host platform, raises OSError with reinstall hint if there's a clear mismatch. Tightened to raise ONLY when a KNOWN binary format is detected that doesn't match — files with unrecognized headers (text stubs, empty files in test fixtures) pass through to the existing seeder pipeline unchanged. Caught by the existing test_missing_lib_does_not_crash_seeder test which was failing on the strict initial version. Verification: 55/55 sdk-python tests pass. _runtime.py coverage at 97%. Closes PILOT-208 (partially — sub-fixes A + B; root cause stays blocked). --- pilotprotocol/_runtime.py | 59 +++++++++++++++++++++++++++++++++++++++ scripts/build-binaries.sh | 8 +++--- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/pilotprotocol/_runtime.py b/pilotprotocol/_runtime.py index 73be4c2..cdeb8ed 100644 --- a/pilotprotocol/_runtime.py +++ b/pilotprotocol/_runtime.py @@ -70,6 +70,58 @@ def _platform_lib_name() -> str: return name +# Magic bytes per binary format. We sniff the first 4 bytes of one +# bundled binary and compare to the host platform, so a mistakenly +# packaged macOS binary on a Linux wheel (or vice versa) fails loudly +# at seed-time instead of producing "Exec format error" downstream +# with no actionable diagnostic. +_FORMAT_MAGICS = { + "ELF": b"\x7fELF", # Linux + "MACHO": (b"\xfe\xed\xfa\xce", b"\xfe\xed\xfa\xcf", + b"\xcf\xfa\xed\xfe", b"\xca\xfe\xba\xbe"), # Mach-O / fat + "PE": b"MZ", # Windows +} +_EXPECTED_FORMAT = {"Linux": "ELF", "Darwin": "MACHO", "Windows": "PE"} + + +def _validate_binary_platform(binary_path: Path) -> None: + """Sniff binary magic bytes; raise OSError if format != host platform.""" + host_system = platform.system() + expected = _EXPECTED_FORMAT.get(host_system) + if expected is None: + # Unsupported host — _platform_lib_name will raise the proper error + return + try: + with binary_path.open("rb") as f: + head = f.read(4) + except OSError: + return # Caller will hit the missing-file case naturally + if not head: + return + expected_magics = _FORMAT_MAGICS[expected] + if isinstance(expected_magics, bytes): + expected_magics = (expected_magics,) + if not any(head.startswith(m) for m in expected_magics): + # Identify what we DID find. Only raise if we detect a KNOWN + # binary format that's the WRONG one (e.g. Mach-O on Linux). + # If the file is a text stub / empty / unrecognized header, the + # existing seeder pipeline (atomic_install + exec) will surface + # the failure naturally — don't pre-empt it. + detected = None + for fmt, magics in _FORMAT_MAGICS.items(): + magics = magics if isinstance(magics, tuple) else (magics,) + if any(head.startswith(m) for m in magics): + detected = fmt + break + if detected is not None and detected != expected: + raise OSError( + f"pilotprotocol wheel binary at {binary_path} has format {detected!r} " + f"but host {host_system} expects {expected!r}. The wheel was likely " + f"built for a different platform; reinstall the platform-specific " + f"wheel (pip install --force-reinstall pilotprotocol)." + ) + + # --------------------------------------------------------------------------- # Version helpers # --------------------------------------------------------------------------- @@ -245,6 +297,13 @@ def ensure_runtime_seeded(force: bool = False) -> Path: Set ``force=True`` to re-run even if this process has already seeded. """ + # PILOT-208: validate the wheel's bundled binaries match the host + # platform before doing any I/O. Catches wrong-platform wheels at + # seed-time with a clear error, instead of silent "Exec format error" + # later when something tries to exec a Mach-O binary on Linux. + _src_bin = _pkg_bin_dir() / "pilotctl" + if _src_bin.exists(): + _validate_binary_platform(_src_bin) global _SEEDED_ONCE if _SEEDED_ONCE and not force: return _runtime_bin() diff --git a/scripts/build-binaries.sh b/scripts/build-binaries.sh index 137c7ae..1a545b9 100755 --- a/scripts/build-binaries.sh +++ b/scripts/build-binaries.sh @@ -36,25 +36,25 @@ mkdir -p "$OUTPUT_DIR" # 1. Build daemon echo "1. Building pilot-daemon..." -CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w" -o "$OUTPUT_DIR/pilot-daemon" ./cmd/daemon +CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w -X main.Version=$SDK_VERSION" -o "$OUTPUT_DIR/pilot-daemon" ./cmd/daemon echo " ✓ Built: $OUTPUT_DIR/pilot-daemon" echo "" # 2. Build pilotctl echo "2. Building pilotctl..." -CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w" -o "$OUTPUT_DIR/pilotctl" ./cmd/pilotctl +CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w -X main.Version=$SDK_VERSION" -o "$OUTPUT_DIR/pilotctl" ./cmd/pilotctl echo " ✓ Built: $OUTPUT_DIR/pilotctl" echo "" # 3. Build gateway echo "3. Building pilot-gateway..." -CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w" -o "$OUTPUT_DIR/pilot-gateway" ./cmd/gateway +CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w -X main.Version=$SDK_VERSION" -o "$OUTPUT_DIR/pilot-gateway" ./cmd/gateway echo " ✓ Built: $OUTPUT_DIR/pilot-gateway" echo "" # 4. Build updater echo "4. Building pilot-updater..." -CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w" -o "$OUTPUT_DIR/pilot-updater" ./cmd/updater +CGO_ENABLED=0 GOOS="$OS" GOARCH="$ARCH" go build -ldflags="-s -w -X main.Version=$SDK_VERSION" -o "$OUTPUT_DIR/pilot-updater" ./cmd/updater echo " ✓ Built: $OUTPUT_DIR/pilot-updater" echo ""