From 682d336cb91e0b61fb30aa38debc7a158c6cafeb Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Wed, 22 Jul 2026 16:14:42 -0700 Subject: [PATCH] fix(macos): harden package identity selection --- .../scripts/package-electron-runtime-contract.test.mjs | 3 +++ package.json | 2 +- src/main/ipc/notifications.test.ts | 9 +++++++-- src/main/ipc/notifications.ts | 4 ++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/config/scripts/package-electron-runtime-contract.test.mjs b/config/scripts/package-electron-runtime-contract.test.mjs index 256c898d5f6..2801f105c4e 100644 --- a/config/scripts/package-electron-runtime-contract.test.mjs +++ b/config/scripts/package-electron-runtime-contract.test.mjs @@ -101,6 +101,9 @@ describe('Electron runtime package contract', () => { expect(scripts['build:linux']).not.toContain('build:computer-macos') expect(scripts['build:unpack']).toContain('pnpm run build:native') expect(scripts['build:mac']).toContain('pnpm run build:native') + expect(scripts['build:mac:release']).toContain('ORCA_MAC_RELEASE=1 pnpm run build:native') + expect(scripts['build:mac:release']).not.toContain('pnpm run build:computer-macos') + expect(scripts['build:mac:release']).not.toContain('pnpm run build:notification-status-macos') expect(scripts['build:mac:release']).not.toContain('com.stablyai.orca.local') expect(scripts['build:release']).toContain('pnpm run build:native') expect(scripts['build:release']).not.toContain('build:computer-macos') diff --git a/package.json b/package.json index 8e989fcb4db..ffbeebafd32 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "build:win": "pnpm run build:desktop && pnpm run ensure:electron-runtime && electron-builder --config config/electron-builder.config.cjs --win", "build:icons": "bash resources/icon-source/generate.sh", "build:mac": "pnpm run build:desktop && pnpm run build:native && pnpm run ensure:electron-runtime && electron-builder --config config/electron-builder.config.cjs --mac", - "build:mac:release": "node config/scripts/verify-macos-release-env.mjs && ORCA_MAC_RELEASE=1 pnpm run build:desktop && ORCA_MAC_RELEASE=1 pnpm run build:computer-macos && ORCA_MAC_RELEASE=1 pnpm run build:notification-status-macos && pnpm run ensure:electron-runtime && ORCA_MAC_RELEASE=1 electron-builder --config config/electron-builder.config.cjs --mac", + "build:mac:release": "node config/scripts/verify-macos-release-env.mjs && ORCA_MAC_RELEASE=1 pnpm run build:desktop && ORCA_MAC_RELEASE=1 pnpm run build:native && pnpm run ensure:electron-runtime && ORCA_MAC_RELEASE=1 electron-builder --config config/electron-builder.config.cjs --mac", "build:linux": "pnpm run build:desktop && pnpm run ensure:electron-runtime && electron-builder --config config/electron-builder.config.cjs --linux AppImage deb", "test:e2e": "pnpm run ensure:electron-runtime && npx playwright test --config tests/playwright.config.ts --project=electron-headless", "test:e2e:multi-client-navigation": "node config/scripts/run-multi-client-navigation-e2e.mjs", diff --git a/src/main/ipc/notifications.test.ts b/src/main/ipc/notifications.test.ts index 3e819ba354c..6392eac25c9 100644 --- a/src/main/ipc/notifications.test.ts +++ b/src/main/ipc/notifications.test.ts @@ -252,13 +252,16 @@ describe('registerNotificationHandlers', () => { } }) - it('falls back to the launchd bundle id for packaged local builds', async () => { + it('prefers the packaged bundle id over an inherited launchd bundle id', async () => { const originalPlatform = process.platform const originalDevBundleId = process.env.ORCA_DEV_MACOS_BUNDLE_ID const originalLaunchdBundleId = process.env.__CFBundleIdentifier Object.defineProperty(process, 'platform', { value: 'darwin', configurable: true }) delete process.env.ORCA_DEV_MACOS_BUNDLE_ID - process.env.__CFBundleIdentifier = 'com.stablyai.orca.local' + process.env.__CFBundleIdentifier = 'com.stablyai.orca' + electronAppMock.isPackaged = true + electronAppMock.getPath.mockReturnValue('/Applications/Orca Local.app/Contents/MacOS/Orca') + execFileSyncMock.mockReturnValue('com.stablyai.orca.local\n') try { registerNotificationHandlers({ getSettings: () => ({ @@ -277,8 +280,10 @@ describe('registerNotificationHandlers', () => { expect(shellOpenExternalMock).toHaveBeenCalledWith( 'x-apple.systempreferences:com.apple.Notifications-Settings.extension?id=com.stablyai.orca.local' ) + expect(execFileSyncMock).toHaveBeenCalledOnce() } finally { Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true }) + electronAppMock.isPackaged = false if (originalDevBundleId === undefined) { delete process.env.ORCA_DEV_MACOS_BUNDLE_ID } else { diff --git a/src/main/ipc/notifications.ts b/src/main/ipc/notifications.ts index 6478f3bc629..544c26bc7bb 100644 --- a/src/main/ipc/notifications.ts +++ b/src/main/ipc/notifications.ts @@ -205,8 +205,8 @@ function readPackagedMacBundleId(): string | null { } function getMacNotificationSettingsUrl(): string { - // Why: direct executable launches do not reliably receive launchd's private - // bundle-id environment variable, so packaged apps read their own plist. + // Why: direct launches can inherit another app's private bundle-id variable, + // so packaged apps read their own plist before trusting the environment. const bundleId = process.env.ORCA_DEV_MACOS_BUNDLE_ID ?? readPackagedMacBundleId() ??