fix(release): ad-hoc sign macOS .app before DMG sealing#57
Merged
Conversation
Published macOS DMGs through v0.14.1 contained an entirely unsigned .app (`codesign -dvvv` reported "code object is not signed at all"), so users had to manually clear quarantine and could hit AMFI/'Team IDs differ' errors on macOS 14+. Root cause: `electron-builder.yml` set `identity: null` (disabling electron-builder's signing path entirely), and the release workflow's `Ad-hoc sign macOS app` step ran AFTER `--publish always` had already uploaded the unsigned DMG — so the post-build codesign was applied to a file no one downloads. Move the ad-hoc signing into an electron-builder `afterPack` hook so it runs after pack but BEFORE DMG sealing. Using a single recursive `codesign --deep --sign -` against the fully-packed .app signs the main binary, helpers, and the bundled Electron Framework with the same (empty) ad-hoc identity — avoiding the per-component 'Team IDs differ' issue that originally motivated `identity: null`. When CSC_LINK is set in CI, the hook is a no-op and the real Developer ID path takes over. Verified locally on a Calculator.app stand-in: before: 'code object is not signed at all' after: flags=0x2(adhoc), satisfies its Designated Requirement Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.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.
Follow-up to #45 / #56 — addresses the unsigned-bundle issue raised by @raphapizzi.
Problem
Published macOS DMGs through v0.14.1 ship an entirely unsigned
.app:This forces users to manually
xattr -dr com.apple.quarantineon first launch and can trigger AMFI / "Team IDs differ" errors on macOS 14+.Root cause
Two things compound:
identity: nullinelectron-builder.ymldisables electron-builder's signing path entirely. The existing comment explains the original motivation: when electron-builder did partial ad-hoc signing, the bundledElectron Framework.frameworkended up with a different Team ID than the main binary, breaking the load on macOS 14+.Ad-hoc sign macOS appstep is dead code. It runs afternpm run build:mac:ci -- --publish always, by which point electron-builder has already created and uploaded the DMG containing the unsigned.app. The post-buildcodesignis applied to a file on the runner that nothing downloads.Fix
Move the ad-hoc signing into an electron-builder
afterPackhook that runs after pack but before DMG sealing:scripts/mac-adhoc-sign.mjs— runscodesign --force --deep --sign - <.app>. A single recursive call signs every nested Mach-O (main binary, helpers, framework, dylibs) with the same empty/ad-hoc identity, so the "Team IDs differ" mismatch never arises. No-op on Windows/Linux; no-op on macOS whenCSC_LINKis set so real Developer ID signing can take over later.electron-builder.yml— wires the hook viaafterPack:, and rewrites theidentity: nullcomment to explain why we still disable electron-builder's own broken per-component path..github/workflows/release.yml— removes the dead post-buildAd-hoc sign macOS appstep (its job is now handled correctly by the hook).package.json/CHANGELOG.md— patch bump tov0.14.2+ customer-facing changelog entry.What this gets us
codesign -dvvvreports a valid ad-hoc signature on the published.appWhat this does NOT get us
Still not signed by a Developer ID, so:
xattr -dr com.apple.quarantine /Applications/DPlex.appBoth are unavoidable until we add a paid Developer ID + notarization.
Local verification
Smoke-tested the hook against a real
.app(Calculator stand-in):Pre-release verification
Same recipe as #56 — dry-run the release workflow on this PR, download the macOS artifact, and run:
Tests
npm run lint— no new issuesnpm run typecheck— cleannpm run test:unit— 325/325 passcodesignsmoke test (above)Diff
+90 / −26 across 5 files (~30 lines of actual hook logic, the rest is comment, workflow cleanup, version bump, changelog entry).