diff --git a/README.md b/README.md index 7a392e2..df6887c 100644 --- a/README.md +++ b/README.md @@ -230,9 +230,47 @@ run, so releases cannot loop. For a MINOR or MAJOR release, bump the version yourself (`npm version minor --no-git-tag-version`) and push; the next patch bump continues from there. -macOS builds are unsigned by default. To sign and notarise, set -`CSC_LINK`/`CSC_KEY_PASSWORD` and the notarisation credentials before running -`npm run dist:mac`. +### Unsigned macOS builds + +macOS builds carry no Apple certificate. `electron-builder.yml` sets +`identity: "-"`, and `dist:mac` runs with `CSC_IDENTITY_AUTO_DISCOVERY=false`, so +a certificate sitting in your keychain is never picked up — a build on your +machine is byte-for-byte the same deal as a build in CI. + +`"-"` is an *ad-hoc* signature: no identity, no team, nothing Gatekeeper will +accept — but a structurally valid one. That is the part worth having. Skipping +signing altogether leaves the bundle carrying Electron's original signature over +resources electron-builder has since rewritten, which `codesign --verify` fails: + +``` +code has no resources but signature indicates they must be present +``` + +A quarantined app in that state is not merely refused — Gatekeeper reports it as +"damaged and can't be opened. You should move it to the Trash", and right-click → +*Open* will not get past it. With a valid ad-hoc signature the same app gets the +ordinary unidentified-developer dialog instead, which right-click → *Open* does +clear. + +So the `.app` runs anywhere, but macOS quarantines it the moment it arrives by +download, AirDrop, Slack or email, and an ad-hoc signature does not clear that +quarantine. Whoever you hand the build to has to say so once, either way: + +- **Finder** — right-click the app, choose *Open*, then *Open* in the dialog. + On macOS 15 and newer, open it normally first, then allow it under + *System Settings › Privacy & Security*. +- **Terminal** — strip the quarantine flag outright: + + ```bash + xattr -dr com.apple.quarantine "/Applications/Mongo Explorer.app" + ``` + +Either is needed only once per install, not per launch. + +To ship something that skips all of this, sign and notarise properly: set +`CSC_LINK`/`CSC_KEY_PASSWORD` and the notarisation credentials, drop the +`identity` line from `electron-builder.yml`, and set `hardenedRuntime: true` +(notarisation requires it) before running `npm run dist:mac`. ## Verifying diff --git a/electron-builder.yml b/electron-builder.yml index a7de408..27f0512 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -38,8 +38,15 @@ mac: - target: zip arch: [arm64, x64] darkModeSupport: true - # Unsigned local builds: without this macOS refuses to open the .app because - # the hardened runtime has no signature to validate. + # No Apple certificate is ever used. "-" is an ad-hoc signature: it carries no + # identity, so the app stays unsigned as far as Gatekeeper is concerned, but it + # is a *valid* one. Without it the bundle keeps Electron's own signature over + # resources we have since rewritten, and Gatekeeper calls a quarantined copy of + # that "damaged" — which right-click Open cannot clear, unlike an ad-hoc build. + identity: "-" + # The hardened runtime would validate that signature against an identity there + # isn't one of, and gatekeeperAssess would run the build through spctl, which + # by definition rejects anything unsigned. hardenedRuntime: false gatekeeperAssess: false extendInfo: diff --git a/package.json b/package.json index 4be4418..6cf6c6d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "smoke": "node scripts/build-smoke.mjs && node scripts/with-mongod.mjs electron dist/smoke/smoke.js", "pack": "npm run build && electron-builder --dir", "dist": "npm run build && electron-builder -mwl", - "dist:mac": "npm run build && electron-builder --mac", + "dist:mac": "npm run build && CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --mac", "dist:win": "npm run build && electron-builder --win", "dist:linux": "npm run build && electron-builder --linux", "ui-check": "npm run build && node scripts/build-ui-check.mjs && node scripts/with-mongod.mjs electron dist/smoke/ui-check.js",