Skip to content

feat(gpui): sign and notarize the macOS images with a Developer ID - #123

Draft
tee8z wants to merge 1 commit into
mainfrom
feat/gpui-macos-notarize
Draft

tee8z wants to merge 1 commit into
mainfrom
feat/gpui-macos-notarize

Conversation

@tee8z

@tee8z tee8z commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

Part of #87: the macOS part. The Linux part is #121.

Change

  • package-macos.sh. With MACOS_SIGN_IDENTITY set, the script signs every Mach-O and then the bundle. It uses the hardened runtime and secure timestamps. It also signs the .dmg. Without the variable, the script signs ad hoc as before. One change applies to both paths: the bundle is now signed without --deep, because each nested Mach-O is already signed first, and --deep would put the app's entitlements on nested code too.
  • Entitlements (packaging/macos/):
    • App executable: microphone, for voice notes. It also gets allow-unsigned-executable-memory, because GStreamer's ORC maps RWX memory without MAP_JIT.
    • Bundled Node: the code-generation entitlements from Node's own osx-entitlements.plist. This excludes get-task-allow, which notarization rejects, and the native-addon and DYLD entitlements, which the plugins do not need.
  • notarize-macos.sh. Submits with notarytool and an App Store Connect API key. If Apple does not accept the submission, the script prints Apple's log and fails. Otherwise it staples the ticket and validates it. It then requires spctl to accept the image, and to report source=Notarized Developer ID for the app inside.
  • check-macos-dmg.sh. dyld ignores DYLD_PRINT_LIBRARIES under the hardened runtime. So a signed build first runs --gst-check as signed: this proves that the entitlements and library validation hold. The library trace then runs on a copy signed ad hoc.
  • Release workflow. When MACOS_DEVELOPER_ID_P12 is present, a temporary keychain is created with the Developer ID. The workflow then packages, checks, notarizes and uploads the stapled .dmg. Without the secret, the build stays ad hoc. On a release dispatch the workflow then emits a warning, so a release never loses notarization without notice.

Secrets needed (none are configured yet)

Secret Value
MACOS_DEVELOPER_ID_P12 base64 .p12 of the Developer ID Application certificate and its private key
MACOS_DEVELOPER_ID_P12_PASSWORD the .p12 password
APPLE_API_KEY_P8 App Store Connect API key (.p8 contents)
APPLE_API_KEY_ID its key ID
APPLE_API_ISSUER its issuer ID

Validation

  • shellcheck passes on the three scripts. actionlint passes on the workflow. The entitlement plists parse.
  • This PR's CI exercises the ad-hoc path, including the --deep change, through check-macos-dmg.sh.
  • The signed path has not run. It cannot run without a real Developer ID: an ad-hoc signature has no Team ID, so a hardened-runtime ad-hoc build fails library validation, and CI cannot stand in for a real certificate. After the secrets are added, rerun this PR's Buzz GPUI Release workflow. The macOS legs then sign, run the hardened self-check, and notarize. This PR stays a draft until those legs pass.
  • Once a notarized release ships, a follow-up removes the right-click → Open workaround from voltage/remote-agents.md.

With Voltage's Developer ID in the repository secrets, the release
workflow signs Buzz.app for notarization and then notarizes the .dmg. The
signing uses the hardened runtime, secure timestamps, and entitlements
for the microphone, GStreamer's ORC and the bundled Node's JIT. The
workflow then staples the ticket and checks that Gatekeeper accepts the
app as notarized. Without the secrets, packaging signs ad hoc as before,
and a release run warns.

check-macos-dmg.sh runs a hardened build's self-check as signed. dyld
ignores DYLD_ variables under the hardened runtime, so the library trace
runs on a copy signed ad hoc.

Refs #87

Signed-off-by: Tee8z <tee8z@protonmail.com>
@coderabbitai

coderabbitai Bot commented Nov 4, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant