From d330fa490537e62c1d6a0335c1460333eccb5ca8 Mon Sep 17 00:00:00 2001 From: Kai <300677314+kai-openswarm@users.noreply.github.com> Date: Mon, 17 Aug 2026 14:42:03 -0700 Subject: [PATCH] =?UTF-8?q?build(mac):=20an=20unsigned=20local=20build=20l?= =?UTF-8?q?aunches=20=E2=80=94=20dev=20entitlements=20without=20the=20keyc?= =?UTF-8?q?hain=20group,=20no=20profile;=20native=20build=20scripts=20surv?= =?UTF-8?q?ive=20a=20path=20with=20a=20space?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two things stopped 'bash scripts/build-app.sh' (the documented unsigned local build) from producing an app that opens: - electron-builder falls back to an ad-hoc signature but still applied the release entitlements + provisioning profile. keychain-access-groups is a restricted entitlement macOS will not honour on an ad-hoc identity, so the app was SIGKILLed at exec with nothing on stderr and no window (bisected: the same signature minus that one key launches, hardened runtime and all). The unsigned path now packs with --dir, re-signs the outer bundle with build/entitlements.mac.dev.plist (production minus that group) and no profile, then builds the dmg/zip from that app with --prepackaged, so what lands in dist/ is what launches. Signed and publish builds are untouched. - build-mouseclamp.sh / build-haptics.sh invoked $NODE_GYP unquoted; a checkout under a directory with a space split the binary path into two words and the build died before packaging. The command is an array now (the npx fallback is legitimately several words). Co-Authored-By: Claude Opus 5 --- electron/build/entitlements.mac.dev.plist | 28 +++++++++++++++++++++++ electron/scripts/build-haptics.sh | 8 ++++--- electron/scripts/build-mouseclamp.sh | 8 ++++--- scripts/build-app.sh | 17 +++++++++++++- 4 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 electron/build/entitlements.mac.dev.plist diff --git a/electron/build/entitlements.mac.dev.plist b/electron/build/entitlements.mac.dev.plist new file mode 100644 index 000000000..725ff4751 --- /dev/null +++ b/electron/build/entitlements.mac.dev.plist @@ -0,0 +1,28 @@ + + + + + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.allow-jit + + com.apple.security.cs.disable-library-validation + + com.apple.security.network.client + + com.apple.security.network.server + + com.apple.security.files.user-selected.read-write + + com.apple.security.inherit + + com.apple.security.device.audio-input + + + diff --git a/electron/scripts/build-haptics.sh b/electron/scripts/build-haptics.sh index 33389992f..d9b1cf024 100755 --- a/electron/scripts/build-haptics.sh +++ b/electron/scripts/build-haptics.sh @@ -11,13 +11,15 @@ HERE="$(cd "$(dirname "$0")/.." && pwd)" # electron/ ELECTRON_TARGET="$(node -p "require('$HERE/node_modules/electron/package.json').version.split('+')[0]" 2>/dev/null || echo '42.3.3')" SRC="$HERE/native/haptics" OUT="$HERE/build-staging/haptics/$ARCH" -NODE_GYP="$HERE/node_modules/.bin/node-gyp" -[[ -x "$NODE_GYP" ]] || NODE_GYP="npx --yes node-gyp" # transitive dep usually, npx if not +# An array, not a string: the local binary path can contain spaces (a checkout under "Projects Claude/" +# split it into two words), while the npx fallback is legitimately several words. +NODE_GYP=("$HERE/node_modules/.bin/node-gyp") +[[ -x "${NODE_GYP[0]}" ]] || NODE_GYP=(npx --yes node-gyp) # transitive dep usually, npx if not echo "[haptics] building for arch=$ARCH (electron $ELECTRON_TARGET)" cd "$SRC" rm -rf build -$NODE_GYP rebuild \ +"${NODE_GYP[@]}" rebuild \ --target="$ELECTRON_TARGET" \ --arch="$ARCH" \ --dist-url=https://electronjs.org/headers diff --git a/electron/scripts/build-mouseclamp.sh b/electron/scripts/build-mouseclamp.sh index 403a4be33..5e94845db 100755 --- a/electron/scripts/build-mouseclamp.sh +++ b/electron/scripts/build-mouseclamp.sh @@ -11,13 +11,15 @@ HERE="$(cd "$(dirname "$0")/.." && pwd)" # electron/ ELECTRON_TARGET="$(node -p "require('$HERE/node_modules/electron/package.json').version.split('+')[0]" 2>/dev/null || echo '42.3.3')" SRC="$HERE/native/mouseclamp" OUT="$HERE/build-staging/mouseclamp/$ARCH" -NODE_GYP="$HERE/node_modules/.bin/node-gyp" -[[ -x "$NODE_GYP" ]] || NODE_GYP="npx --yes node-gyp" # transitive dep usually, npx if not +# An array, not a string: the local binary path can contain spaces (a checkout under "Projects Claude/" +# split it into two words), while the npx fallback is legitimately several words. +NODE_GYP=("$HERE/node_modules/.bin/node-gyp") +[[ -x "${NODE_GYP[0]}" ]] || NODE_GYP=(npx --yes node-gyp) # transitive dep usually, npx if not echo "[mouseclamp] building for arch=$ARCH (electron $ELECTRON_TARGET)" cd "$SRC" rm -rf build -$NODE_GYP rebuild \ +"${NODE_GYP[@]}" rebuild \ --target="$ELECTRON_TARGET" \ --arch="$ARCH" \ --dist-url=https://electronjs.org/headers diff --git a/scripts/build-app.sh b/scripts/build-app.sh index c8f6e2e38..768d55f76 100755 --- a/scripts/build-app.sh +++ b/scripts/build-app.sh @@ -550,8 +550,23 @@ if $PUBLISH_MODE; then elif $SIGN_MODE; then npx electron-builder --mac "${EB_ARCH_FLAGS[@]}" --publish never else + # Unsigned local build. electron-builder falls back to an ad-hoc signature but still applies the + # release entitlements + provisioning profile; the restricted keychain-access-groups entitlement + # is not honoured for an ad-hoc identity, so macOS SIGKILLs the app at exec (silently: no + # window, nothing on stderr). Pack first, then re-sign the outer bundle with the same + # entitlements minus that group and no profile (passkeys stay off in a dev build anyway), then + # build the dmg/zip from the app that actually launches. export CSC_IDENTITY_AUTO_DISCOVERY=false - npx electron-builder --mac "${EB_ARCH_FLAGS[@]}" --publish never + npx electron-builder --mac "${EB_ARCH_FLAGS[@]}" --dir --publish never + for A in "${BUILD_ARCHS[@]}"; do + APP_DIR="dist/mac-$A" + [[ "$A" == "x64" && ! -d "$APP_DIR" ]] && APP_DIR="dist/mac" + APP="$APP_DIR/OpenSwarm.app" + [[ -d "$APP" ]] || { echo "ERROR: packed app not found at $APP" >&2; exit 1; } + rm -f "$APP/Contents/embedded.provisionprofile" + codesign --force --sign - --options runtime --entitlements build/entitlements.mac.dev.plist "$APP" + npx electron-builder --mac "--$A" --prepackaged "$APP" --publish never + done fi rm -rf "$PROJECT_ROOT/electron/build-staging"