From 7ead8837b89e62e62c8b8f2a8314751c19cb1ed5 Mon Sep 17 00:00:00 2001 From: Francesco Bonacci Date: Tue, 26 May 2026 15:13:57 +0200 Subject: [PATCH] fix(cua-driver-rs)(install): _install-local-rust.sh symlink swap + macOS 26 codesign MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two install-script bugs surfaced by today's macOS 26.4 + slow-path re-install. 1) Atomic symlink swap was broken on macOS ================================================ Previous code: TMP_LINK="$CURRENT_LINK.new" rm -f "$TMP_LINK" ln -s "$VERSIONED_DIR" "$TMP_LINK" mv -Tf "$TMP_LINK" "$CURRENT_LINK" 2>/dev/null \ || mv -f "$TMP_LINK" "$CURRENT_LINK" `mv -T` is GNU-only. On macOS BSD coreutils the `-Tf` form silently errors (redirected to /dev/null), then the fallback `mv -f` fires. When the destination is a symlink-to-directory (which `$CURRENT_LINK` is on re-install), BSD `mv -f` *follows the symlink* and drops the temp symlink INSIDE the directory as `current/current.new`, leaving stale `current.new` orphans at both the packages/ level AND inside the versioned release dir, and the actual `current` symlink untouched. Replacement: `ln -sfn` — POSIX, atomic on POSIX-compliant filesystems, works identically on macOS BSD and Linux GNU. No temp file, no orphan to sweep on partial failure. Also adds an `rm -f "$CURRENT_LINK.new"` to clean up any orphan that a previous (pre-fix) run might've left. User-facing repro: $ ./install-local.sh ... Staging into ... mv: ...current.new and .../current/current.new are identical [exit 1, broken state on disk] 2) macOS 26 Taskgated rejects linker-emitted adhoc signatures after cp ======================================================================== macOS 26.4 (the user's host) enforces CODESIGNING-namespace verification stricter than 14.x and earlier. After `cp` planted the new binary at the versioned release dir, the kernel's cached signature for the new inode didn't match the embedded linker-emitted ad-hoc signature strictly enough, and Taskgated SIGKILLed the binary on first launch with no stderr output. Exit code 137. Only diagnostic was buried in ~/Library/Logs/DiagnosticReports/cua-driver-*.ips: "type": "EXC_CRASH", "signal": "SIGKILL (Code Signature Invalid)" "namespace": "CODESIGNING", "indicator": "Taskgated Invalid Signature" Fix: re-sign in place with `codesign --force --sign -` immediately after the `cp`. The fresh embedded ad-hoc signature is keyed to the on-disk bytes Taskgated will subsequently verify. Cheap (~50ms on a 40MB binary). macOS-only — guarded with `command -v codesign` so Linux + minimal macOS shells don't blow up if codesign is missing. If codesign fails for any reason (rare — would need a corrupted dev toolchain), prints a yellow warning rather than failing the install, so users on older macOS where the issue doesn't manifest aren't blocked. The warning text names the symptom (SIGKILL on first run) so anyone hitting it can correlate. Test plan ========= - [x] `bash -n` clean - [x] Live test on macOS 26.4.1: install-local.sh end-to-end completes, no orphan files, `~/.local/bin/cua-driver --version` exits 0 - [ ] Linux verification (the codesign step is guarded; symlink fix applies on both) --- .../cua-driver/scripts/_install-local-rust.sh | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/libs/cua-driver/scripts/_install-local-rust.sh b/libs/cua-driver/scripts/_install-local-rust.sh index b2d6dd2f2d..b98ef20572 100755 --- a/libs/cua-driver/scripts/_install-local-rust.sh +++ b/libs/cua-driver/scripts/_install-local-rust.sh @@ -205,6 +205,24 @@ mkdir -p "$VERSIONED_DIR" cp "$BUILT_BINARY" "$VERSIONED_DIR/cua-driver" chmod +x "$VERSIONED_DIR/cua-driver" +# Re-sign with a fresh ad-hoc signature. +# +# macOS 26+ Taskgated rejects the linker-emitted ad-hoc signature once +# the binary has been copied (the kernel's cached signature for the new +# inode doesn't match the embedded one strictly enough for the newer +# CODESIGNING namespace). Result is `SIGKILL (Code Signature Invalid) +# — Taskgated Invalid Signature` on first run, no stderr output, exit +# code 137 — extremely confusing without a diagnostic-report dig. The +# fix: re-sign in place. `codesign --force --sign -` emits a fresh +# ad-hoc signature keyed to the new on-disk bytes, which Taskgated +# accepts. Cheap (~50ms on a 40MB binary). macOS-only — no-op on Linux. +if [ "$OS" = "Darwin" ]; then + if command -v codesign >/dev/null 2>&1; then + codesign --force --sign - "$VERSIONED_DIR/cua-driver" 2>/dev/null \ + || echo "${YELLOW}warning: codesign --force --sign - failed; first run may fail with SIGKILL on macOS 26+${NORMAL}" >&2 + fi +fi + # Skill pack — stage from the repo so the `current` symlink below # transparently exposes it to agents. Mirrors what install.sh does # from a release tarball. @@ -217,12 +235,24 @@ if [ -d "$SOURCE_SKILLS" ]; then echo "${GREEN}staged skill pack at $STAGED_SKILLS${NORMAL}" fi -# Atomic-ish swap of the `current` symlink. +# Atomically point `current` at the new versioned release dir. +# +# Previous version used `ln -s … current.new` + `mv -Tf current.new current` +# with a BSD `mv -f` fallback. The BSD fallback path is broken: when the +# destination is a symlink-to-directory, BSD `mv` *follows* it and drops +# the temp symlink INSIDE the directory as `current/current.new`, leaving +# stale `current.new` orphans at both levels and the actual `current` +# symlink untouched. macOS doesn't ship GNU `mv` so the `-Tf` path never +# fires on this host. +# +# `ln -sfn` is the POSIX primitive that does what we wanted from the +# start: replace the existing symlink atomically, without dereferencing. +# Works the same on macOS BSD and Linux GNU coreutils. No temp file +# means no orphan to clean up on partial failure. mkdir -p "$HOME_DIR/packages" -TMP_LINK="$CURRENT_LINK.new" -rm -f "$TMP_LINK" -ln -s "$VERSIONED_DIR" "$TMP_LINK" -mv -Tf "$TMP_LINK" "$CURRENT_LINK" 2>/dev/null || mv -f "$TMP_LINK" "$CURRENT_LINK" +# Sweep any orphan temp from a previous (pre-fix) run before re-creating. +rm -f "$CURRENT_LINK.new" +ln -sfn "$VERSIONED_DIR" "$CURRENT_LINK" echo "${GREEN}current -> $VERSIONED_DIR${NORMAL}" echo ""