Skip to content

land #451: refuse GUI auth dialog off the main thread on macOS - #453

Merged
fu351 merged 2 commits into
mainfrom
land/pr451
Aug 24, 2026
Merged

land #451: refuse GUI auth dialog off the main thread on macOS#453
fu351 merged 2 commits into
mainfrom
land/pr451

Conversation

@fu351

@fu351 fu351 commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Lands #451 with the author's commits unchanged (@harshitagrawal2O keeps authorship; the PR flips to Merged when this lands). The only addition is a merge of current main resolving the CHANGELOG anchor conflict against #452's river bullet. No code differences from #451.

harshitagrawal2O and others added 2 commits August 24, 2026 11:14
Every real caller of the auth-challenge prompter chain runs it on a
background daemon thread: run_auth_challenge dispatches through
_run_with_deadline (a spawned threading.Thread, so a wall-clock deadline
can be enforced on a channel that might never return), and the MCP-proxy
path does the equivalent via asyncio.to_thread. GuiPrompter therefore
always constructs its Tk() root off the process's main thread.

Cocoa's Tk backend requires its NSApplication event loop to start on the
real OS main thread. Constructing Tk() off it is a documented hazard that
does not reliably surface as a catchable TclError the way a missing
$DISPLAY does -- it can silently fail to render, or abort the process --
either of which could leave an AUTH-tier decision recorded as approved
with no human ever having seen a dialog: a fail-closed violation.

_open_root() now refuses (raises PrompterUnavailableError) before ever
importing tkinter when it detects sys.platform == "darwin" and the
current thread is not the main thread. This is exactly the existing
"channel unavailable" contract: FallbackPrompter falls through to the
terminal, and if that is also unavailable, the provider denies. Windows
and Linux are unaffected -- the guard is scoped to the one platform where
this is a documented hazard, and only fires when actually off-main-thread.

9 new tests: the guard fires before tkinter is touched (mocked and via a
real background thread), is inert on the real main thread, is inert on
non-macOS platforms, is reachable through the public GuiPrompter API, and
the full FallbackPrompter/LocalAuthProvider chain still denies (never
approves) when both GUI and terminal are unavailable on macOS.
@fu351
fu351 merged commit 527eb51 into main Aug 24, 2026
10 checks passed
@fu351
fu351 deleted the land/pr451 branch August 24, 2026 20:56
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.

2 participants