Bundle and re-sign libusb for the signed macOS CLI#6
Merged
Conversation
The released MCCOutletCLI linked libusb by absolute Homebrew path. Once the CLI is Developer-ID signed with the hardened runtime it is subject to library validation and may only load dylibs signed by Apple or the same Team ID. Homebrew's libusb bottle is signed by a different team, so dyld refused it unconditionally and the shipped CLI was unrunnable on every machine (including ones with `brew install libusb`). CI missed this because the smoke test runs in the build job, before the sign-macos job adds the hardened runtime, on a runner that has brew libusb. Fix, in the sign-macos job before the CLI is signed: treat libusb exactly like lsl.framework. Copy the dylib into the CLI's Frameworks/ dir (preferring the macdeployqt'd app copy, falling back to the CLI's current reference so it works on both /opt/homebrew and /usr/local runners), normalize its install name to @rpath, repoint the CLI, and sign the dylib with the Developer ID before the CLI (dependency before dependent). The dylib ships automatically since Frameworks is already in the tarball. Also add a guardrail: after signing, fail the build if the CLI still links any absolute brew dylib. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The released
MCCOutletCLIfrom the signed macOS tarball is dead on arrival on every machine — even ones withbrew install libusb:The GUI app is fine; only the CLI is broken.
Root cause
Two facts combine:
otool -Lshows/opt/homebrew/opt/libusb/lib/libusb-1.0.0.dylib).lsl.frameworkgets bundled +@rpath-fixed-up correctly, but libusb had no equivalent bundling step.brew installcan fix it — the binary is unrunnable by construction.Why CI didn't catch it
The
MCCOutletCLI --helpsmoke tests run in the build job, before thesign-macosjob adds the hardened runtime, on a runner that has brew libusb. Unsigned/non-hardened binaries can load cross-team dylibs, so the pre-signing test passes, then signing silently breaks the shipped artifact.Fix
In the
sign-macosjob, beforesign_and_notarize.shruns on the CLI, treat libusb exactly likelsl.framework:libusb-1.0.0.dylibinto the CLI'sFrameworks/dir — preferring the copy macdeployqt already placed inMCCOutlet.app, falling back to whatever reference the CLI currently links (handles arm64/opt/homebrewvs x86_64/usr/local).@rpath/libusb-1.0.0.dylib(resolved via the CLI's existing@executable_path/Frameworksrpath).install_name_tool -change, resolving the current reference dynamically.The dylib ships automatically —
Frameworksis already in the release tarball.Verification
Manually validated the equivalent steps against the v3.2.0 asset on both a dev Mac and a deployed study computer: after the repoint + re-sign the CLI runs and enumerates an attached USB-1608FS-Plus. Once this ships, the downstream brnbci-deploy workaround that repoints + re-signs the binary post-download becomes a no-op.
🤖 Generated with Claude Code