unbreak macOS Apple Silicon install, atomic Linux install, real version smoke test#11
Open
staylor wants to merge 1 commit into
Open
unbreak macOS Apple Silicon install, atomic Linux install, real version smoke test#11staylor wants to merge 1 commit into
staylor wants to merge 1 commit into
Conversation
400500e to
b0501d6
Compare
d99615d to
6fcd30f
Compare
…on smoke test Three independently-motivated bug fixes in scripts/install.sh: 1. macOS Apple Silicon: AMFI rejects the release Mach-O at exec The lightpanda-aarch64-macos asset has a linker-signed ad-hoc signature without a CMS blob (`codesign -dv` shows flags=0x20002(adhoc,linker-signed)). AMFI on Apple Silicon enforces stricter requirements outside trusted prefixes; from /tmp or ~/.local/bin the kernel rejects it as 'Unrecoverable CT signature issue, bailing out' and SIGKILLs at exec. Re-signing locally with `codesign -s -` adds a CMS blob but AMFI then rejects with error -423 (adhoc signed by unknown chain). Verified empirically: same byte-identical Mach-O runs from /opt/homebrew/Cellar/lightpanda/.../bin/lightpanda but is SIGKILLed from /tmp/. Copying the broken curl-downloaded bytes INTO the brew path makes them run. So the trust is path-based, not byte-based. The Lightpanda brew formula does NOT build from source (verified via `brew cat`) — it just downloads the same Mach-O and runs `bin.install` to place it at /opt/homebrew/Cellar/.../bin/lightpanda, which AMFI exempts from the strict ad-hoc signature check. Reproducing on M3 Pro / macOS 14.x; should be uniform across Apple Silicon but not directly tested on M1/M2/M4. Intel macOS keeps the GitHub Release Mach-O path — Apple Silicon's stricter AMFI enforcement is arm64-specific and I don't have an Intel Mac to test. 2. Failed reruns destroy existing working binary SKILL.md documents reruns as the update path, but curl -L -o "$INSTALL_DIR/$BINARY_NAME" overwrites the install target during download. Atomic install via mktemp + verify + smoke-test + mv preserves the existing binary on any failure. 3. --version smoke test silently accepts broken binaries Lightpanda's CLI has no --version flag; running it logs '$msg=exit err=UnknownCommand' and exits 1. The current 2>/dev/null + --help fallback masks this, and the head -1 pipe at the end means it succeeds on broken binaries that produce no output. Use the 'version' subcommand and capture stderr to surface real diagnostics like 'GLIBC_2.32 not found' on failure. Smaller adjacent changes, each tightly motivated by the three above: - set -euo pipefail (was set -e); curl -fSL (was -sL/-L). pipefail + -f propagate curl HTTP errors through curl | jq, replacing the misleading 'could not retrieve checksum' message. - chmod 0755 instead of chmod a+x. Required because fix lightpanda-io#2 uses mktemp (0600); chmod a+x on top yields 0711 (owner-only readable). - Apple Silicon PATH-shadow warning. A user upgrading from a pre- this-PR version still has the rejected ~/.local/bin/lightpanda (the linker-signed Mach-O) which shadows the new working brew binary in PATH — without the warning they still get SIGKILL after a successful brew install. - LIGHTPANDA_DIR warning on Apple Silicon (brew owns the install path; the variable is silently ignored without this). - SKILL.md Install section: per-OS callout describing the flow split. Better long-term fix (out of scope for this PR): upstream-side, the build pipeline producing the GitHub Release assets should apply a proper ad-hoc signature with a CMS blob (or, better, Developer ID + notarization). The release Mach-O would then run from anywhere and this workaround wouldn't be needed. Intentionally not included (offered as follow-ups): - Optional $GITHUB_TOKEN for API quota - PATH-shadow check on the shared download flow - Upstream-side signing fix (separate repo)
6fcd30f to
ef4e6cd
Compare
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.
What & why
Three fixes in
scripts/install.sh. Each is independently a bug; grouped because they all sit in the same script and #1 motivates the diagnostic improvements in #2 and #3.1. macOS Apple Silicon install produces a binary the kernel kills at exec
The nightly Mach-O
lightpanda-aarch64-macosgets SIGKILLed at exec when run from arbitrary user paths (/tmp,~/.local/bin/, etc.) on Apple Silicon. The kernel log line is:Root cause
The Mach-O's
codesign -dvshowsflags=0x20002 (adhoc, linker-signed)— the build linker emitted a minimal ad-hoc signature with aCodeDirectoryand page hashes but no CMS (Cryptographic Message Syntax) blob. AMFI on Apple Silicon enforces stricter requirements on ad-hoc signatures outside certain trusted prefixes; without the CMS blob, AMFI rejects the binary at exec from arbitrary paths.I verified empirically:
f7acdfdd...) runs fine from/opt/homebrew/Cellar/lightpanda/.../bin/lightpanda, gets SIGKILLed from/tmp/lightpanda-aarch64-macos./opt/homebrew/Cellar/...makes them run.codesign -s -adds a CMS blob but AMFI then rejects with error-423 "adhoc signed or signed by an unknown certificate chain".So ad-hoc re-signing genuinely doesn't help; the actual fix is either (a) upstream-side proper signing or (b) installing to a path AMFI exempts.
What this PR does
Routes Apple Silicon only through
brew install lightpanda-io/browser/lightpanda. The brew formula'sbin.installstep places the same byte-identical Mach-O at/opt/homebrew/Cellar/lightpanda/.../bin/lightpanda, an AMFI-exempt path, where it runs.Important honesty note: I previously assumed the brew tap built from source. It does not. The formula is:
The "fix" is purely about install path, not about how the binary was produced. The install script is using brew as a way to land the binary at an AMFI-exempt location.
Better long-term fix (out of scope for this PR)
The proper fix is upstream-side: the build pipeline that produces the GitHub Release assets should apply a proper ad-hoc signature with a CMS blob (or, better, a Developer ID signature + notarization). Then the release Mach-O would run from anywhere and this brew workaround wouldn't be needed.
Intel macOS
Left on the GitHub Release Mach-O path. I don't have an Intel Mac to test, but Apple Silicon's stricter AMFI signature enforcement is a known arm64-specific behavior (the kernel signature path was tightened around macOS 11 / Apple Silicon transition); the same Mach-O may well run fine from
~/.local/bin/on Intel. Happy to widen the brew routing if you have data showing Intel needs it too.Test environment
Reproducing on M3 Pro / macOS 14.x. The kernel-signing path is uniform across Apple Silicon hardware, so this should affect all M-series Macs, but I haven't directly tested M1/M2/M4 or older macOS versions.
2. Linux (and Intel macOS) install destroys an existing working binary on any failed rerun
SKILL.md documents reruns of this script as the update path:
But
curl -L -o "$INSTALL_DIR/$BINARY_NAME"overwrites the install target during download. A failed download (network drop, checksum mismatch, unrunnable replacement) leaves the user with no binary or a broken one — even though they had a working one before.This PR downloads to a
mktempfile in the same directory, verifies checksum + smoke-tests, then atomicallymvs into place. The existing binary is preserved on any failure.3. The
--versionsmoke test silently accepts broken binariesCurrent test:
Lightpanda's CLI doesn't have a
--versionflag. Running it logs$msg=exit err=UnknownCommandto stderr and exits 1. The2>/dev/nullmasks this and the script falls through to the--helpbranch. On a binary that crashes at exec,--helpalso fails, but the surroundingif ... | head -1; thenconstruction still ends in the success branch becauseheadexits 0 on empty stdin. Result:Lightpanda installed successfully!for an unrunnable binary.This PR uses the actual
versionsubcommand, captures stderr to a tempfile, and fails hard with the binary's stderr surfaced so users see real diagnostics likeGLIBC_2.32 not foundon incompatible systems.Live reproduction of the broken
--version:Smaller adjacent changes
These are tightly motivated by the three fixes above:
set -euo pipefail(wasset -e).pipefailpropagates a failing curl throughcurl | jq(jq exits 0 on empty input, otherwise hiding network errors behind a misleading "could not retrieve checksum").curl -fSL(was-sL/-L) makes curl exit non-zero on HTTP errors soset -ecatches them.chmod 0755instead ofchmod a+x. Only relevant because of fix update metadata and move install into scripts dir #2'smktemp, which creates 0600;a+xon top of that yields 0711 (owner-only readable).~/.local/bin/lightpanda(the linker-signed Mach-O) which shadows the new working brew binary in PATH — so they'd runlightpandaand still get SIGKILL even though the brew install succeeded.LIGHTPANDA_DIRwarning on Apple Silicon (brew owns the install path; the variable is silently ignored without this).Out of scope (intentionally not included)
$GITHUB_TOKENto raise the GitHub API quota from 60→5000/hr.lightpanda-io/browserfor the linker-signed Mach-O. That's the real long-term solution.Verified
End-to-end run on Apple Silicon: brew install/upgrade succeeds,
versionsubcommand prints1.0.0-nightly.6051+d360fcc0, PATH-shadow warning fires when a stale binary is present,LIGHTPANDA_DIRwarning fires when the variable is set. Smoke-test stderr capture exercised by deliberately corrupting the temp binary. The byte-identical-bytes-in-different-paths claim verified by direct test (broken curl bytes → AMFI-exempt brew path → runs; working brew bytes → /tmp → SIGKILL).Intel macOS path is structurally identical to the Linux flow — same shared download/verify/smoke-test/mv code. Linux is what the existing script's tests have always exercised.
Stack
Independent of #12 (docs corrections including #10 point 2) and #13 (
--block-private-networksdefaults). All three branch offmaindirectly.