diff --git a/config/electron-builder.config.cjs b/config/electron-builder.config.cjs index 50cfe7691e8..192615dea6f 100644 --- a/config/electron-builder.config.cjs +++ b/config/electron-builder.config.cjs @@ -225,6 +225,12 @@ module.exports = { include: resolve(__dirname, 'nsis', 'daemon-host-uninstall.nsh') }, mac: { + // Why: macOS TCC keys permission grants to bundle id + code signature. A + // local build carrying the release appId under a different (ad-hoc/local) + // signature collides with the installed release's grant identity (#9756), + // so non-release packaging gets its own id. Gated on the same env that + // enables release signing/notarization, so release artifacts are untouched. + ...(isMacRelease ? {} : { appId: 'com.stablyai.orca.local' }), icon: 'resources/build/icon.icns', entitlements: 'resources/build/entitlements.mac.plist', entitlementsInherit: 'resources/build/entitlements.mac.plist', diff --git a/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift b/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift index da6c4d34cda..baa8b9ae296 100644 --- a/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift +++ b/native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift @@ -3603,9 +3603,11 @@ private func isTrustedOrcaApplication(_ pid: pid_t) -> Bool { else { return false } - // Why: dev validation runs from per-worktree wrapper apps with stable - // Orca-owned bundle ids; the sidecar peer check must still authorize them. + // Why: dev validation runs from per-worktree wrapper apps and local + // packaging uses its own bundle id (#9756); the sidecar peer check must + // still authorize these Orca-owned identities. return bundleId == "com.stablyai.orca" || + bundleId == "com.stablyai.orca.local" || bundleId.hasPrefix("com.stablyai.orca.dev.") || bundleId == "com.github.Electron" } diff --git a/package.json b/package.json index 02b58ce82ef..6bff416d0c2 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "build:unpack": "pnpm run build && pnpm run ensure:electron-runtime && electron-builder --config config/electron-builder.config.cjs --dir", "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:computer-macos && pnpm run build:notification-status-macos && pnpm run ensure:electron-runtime && electron-builder --config config/electron-builder.config.cjs --mac", + "build:mac": "pnpm run build:desktop && pnpm run build:computer-macos && pnpm run build:notification-status-macos --bundle-id com.stablyai.orca.local && 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: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", diff --git a/src/main/ipc/notifications.test.ts b/src/main/ipc/notifications.test.ts index d7930066ad7..a194e6e295f 100644 --- a/src/main/ipc/notifications.test.ts +++ b/src/main/ipc/notifications.test.ts @@ -238,6 +238,46 @@ describe('registerNotificationHandlers', () => { } }) + it('falls back to the launchd bundle id for packaged local builds', 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' + try { + registerNotificationHandlers({ + getSettings: () => ({ + notifications: { + enabled: true, + agentTaskComplete: true, + terminalBell: true, + suppressWhenFocused: true + } + }) + } as never) + + const handler = getOpenSystemSettingsHandler() + handler({}) + + expect(shellOpenExternalMock).toHaveBeenCalledWith( + 'x-apple.systempreferences:com.apple.Notifications-Settings.extension?id=com.stablyai.orca.local' + ) + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true }) + if (originalDevBundleId === undefined) { + delete process.env.ORCA_DEV_MACOS_BUNDLE_ID + } else { + process.env.ORCA_DEV_MACOS_BUNDLE_ID = originalDevBundleId + } + if (originalLaunchdBundleId === undefined) { + delete process.env.__CFBundleIdentifier + } else { + process.env.__CFBundleIdentifier = originalLaunchdBundleId + } + } + }) + it('opens Windows notification settings', async () => { const originalPlatform = process.platform Object.defineProperty(process, 'platform', { value: 'win32', configurable: true }) diff --git a/src/main/ipc/notifications.ts b/src/main/ipc/notifications.ts index 95e9e3e3a47..bd308cea85b 100644 --- a/src/main/ipc/notifications.ts +++ b/src/main/ipc/notifications.ts @@ -187,7 +187,12 @@ function probeNotificationDelivery(): Promise { } function getMacNotificationSettingsUrl(): string { - const bundleId = process.env.ORCA_DEV_MACOS_BUNDLE_ID ?? MACOS_PACKAGED_BUNDLE_ID + // Why: local packaging uses com.stablyai.orca.local (#9756), so trust the + // launchd-provided id before falling back to the release id. + const bundleId = + process.env.ORCA_DEV_MACOS_BUNDLE_ID ?? + process.env.__CFBundleIdentifier ?? + MACOS_PACKAGED_BUNDLE_ID return `${MACOS_NOTIFICATION_SETTINGS_URL}?id=${encodeURIComponent(bundleId)}` }