From dbaf80e155229d81399facf0c07785846b185d24 Mon Sep 17 00:00:00 2001 From: orca-bug-scan-bot Date: Sat, 11 Jul 2026 14:41:53 -0700 Subject: [PATCH] fix: address pr-bug-scan validated finding from #7684 Added authoritative dim to resolveMacNotificationPermissionState; a native-readout 'blocked' now maps to 'blocked' instead of softening to 'awaiting-permission' at card:35. --- .../mac-notification-permission-card.tsx | 19 ++++++++++++++++--- .../onboarding/NotificationStep.test.tsx | 7 +++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/components/notifications/mac-notification-permission-card.tsx b/src/renderer/src/components/notifications/mac-notification-permission-card.tsx index 2bc94664d1c..5037f663af2 100644 --- a/src/renderer/src/components/notifications/mac-notification-permission-card.tsx +++ b/src/renderer/src/components/notifications/mac-notification-permission-card.tsx @@ -18,7 +18,8 @@ const MAC_PROBE_POLL_MAX_ATTEMPTS = 72 export function resolveMacNotificationPermissionState( probeState: NotificationDeliveryProbeResult['state'], - promptedBefore: boolean + promptedBefore: boolean, + authoritative: boolean = false ): MacNotificationPermissionState | null { if (probeState === 'unsupported') { return null @@ -29,6 +30,12 @@ export function resolveMacNotificationPermissionState( if (probeState === 'awaiting-decision') { return 'awaiting-permission' } + // Why: an authoritative 'blocked' comes from the native readout reporting + // the permission as denied — it's definitive (no dialog will appear), so + // never soften it to "answer the dialog" via the probe-fallback heuristic. + if (authoritative) { + return 'blocked' + } // Why: probe-fallback hosts can't tell "unanswered dialog" from "denied" — // a first-ever probe is what makes macOS show the permission dialog, so // its rejection means "unanswered", not "denied". @@ -64,7 +71,9 @@ export function useMacNotificationPermissionState( if (cancelled) { return } - setMacPermissionState(resolveMacNotificationPermissionState(probe.state, promptedBefore)) + setMacPermissionState( + resolveMacNotificationPermissionState(probe.state, promptedBefore, probe.authoritative) + ) // Why: authoritative readouts are silent, so keep tracking System // Settings live in every state — flipping the toggle updates the // card within a poll. Probe fallbacks flash a banner when delivery @@ -92,7 +101,11 @@ export function useMacNotificationPermissionState( if (cancelled) { return } - const resolved = resolveMacNotificationPermissionState(probe.state, status.requested) + const resolved = resolveMacNotificationPermissionState( + probe.state, + status.requested, + probe.authoritative + ) setMacPermissionState(resolved) if (resolved !== null && (probe.authoritative || resolved !== 'enabled')) { schedulePoll(status.requested) diff --git a/src/renderer/src/components/onboarding/NotificationStep.test.tsx b/src/renderer/src/components/onboarding/NotificationStep.test.tsx index 04bd27f9833..881eeddc7fd 100644 --- a/src/renderer/src/components/onboarding/NotificationStep.test.tsx +++ b/src/renderer/src/components/onboarding/NotificationStep.test.tsx @@ -86,4 +86,11 @@ describe('resolveMacNotificationPermissionState', () => { it('treats a rejection after a prior prompt as blocked', () => { expect(resolveMacNotificationPermissionState('blocked', true)).toBe('blocked') }) + + it('treats an authoritative blocked readout as blocked even when not prompted before', () => { + // Why: a denied native readout is definitive — no macOS dialog will ever + // appear — so it must not be softened to the "answer the dialog" card just + // because the onboarding permission flag was never stamped. + expect(resolveMacNotificationPermissionState('blocked', false, true)).toBe('blocked') + }) })