fix(cua-driver-rs)(macos): bind serve socket before the permissions gate (#1761) - #1773
Conversation
…ate (#1761) On first launch with `com.trycua.driver` ungranted, the macOS `Serve` arm ran the blocking permissions gate BEFORE `run_serve_cmd` bound the Unix socket. While the gate sat in `wait_for_grants` (prompting + re-exec looping), the socket never appeared, so a daemon launched via `open -n -g -a CuaDriver --args serve` was unreachable for minutes — `permissions grant` and MCP clients couldn't even get a "pending" answer. Reorder the macOS serve arm: run serve on a background thread first (it binds the socket — a Unix socket + tokio accept loop has no main-thread requirement) and run the gate on the main thread (its prompt APIs and the NSPanel must stay on main). The daemon is reachable within ~1s while the gate works toward the grant. On grant the gate's `reexec_self()` restarts the whole daemon cleanly; `run_serve` already unlinks the stale socket file before re-binding, so the rebind is fast. Because serve now runs concurrently, each re-exec restarts the daemon and flaps the socket. Raise `EXEC_AFTER_POLLS` 5 -> 25 (~25s between re-execs) to trade grant-detection latency for socket stability, and log "restarting daemon" before each re-exec. The re-exec stays — it's the only way to pick up an Accessibility grant (`AXIsProcessTrusted` is cached per process). `permissions grant` now polls `check_permissions` via the daemon every 2s up to 180s (tolerating transient failures during a re-exec restart) until both grants flip true, instead of a single query that returns "pending" now that the socket appears before the grant. Refs #1761 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughDaemon startup is reordered to bind the Unix socket before running the macOS permissions gate. The CLI transitions from a single permissions check to polling the daemon for up to 180 seconds, with updated timeout messaging. The daemon's re-exec threshold increases from 5 to 25 polls to reduce restart frequency during permission transitions. ChangesmacOS Permissions Gate and Startup Flow
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Problem
On macOS first launch with
com.trycua.driverungranted, theServearm ran the blocking permissions gate (run_if_needed) beforerun_serve_cmdbound the Unix socket. The gate sits inwait_for_grants(prompting + re-exec-looping) until the user grants or the 10-min deadline elapses, so the socket never appears. A daemon launched viaopen -n -g -a CuaDriver --args serve(the only launch that gives correct TCC attribution + System Settings registration) is therefore unreachable for minutes —permissions grantand MCP clients can't even get a "pending" answer.Fix
Reorder the macOS serve arm (
main.rs): serve now runs on a background thread first (it binds the socket — a Unix socket + tokio accept loop has no main-thread requirement), and the gate runs on the main thread (kept there because its prompt APIsrequest_accessibility/request_screen_recordingand the NSPanel must stay on main). The socket is binding/bound within ~1s while the gate works toward the grant. Main stays alive viarun_appkit_main_loop()(PiP) orserve_handle.join()(non-PiP).Why the re-exec stays + cadence tradeoff (
gate.rs):AXIsProcessTrusted()is cached per process, so a process that cachedfalsecannot see a later Accessibility grant without re-executing (execvp, fresh process). The re-exec is load-bearing and is NOT removed. But now that serve runs concurrently, eachreexec_self()restarts the whole daemon and flaps the socket. RaisedEXEC_AFTER_POLLS5 → 25 (~25s between re-execs at the 1s poll interval) to trade grant-detection latency (fine on a human-clicking-through-Settings timescale) for socket stability. Added a "restarting daemon" log before each re-exec so the restart isn't silent.Stale-socket unlink: already present — the macOS
#[cfg(unix)]run_servedoesstd::fs::remove_file(socket_path)beforeUnixListener::bind, andis_daemon_listeningis a connect probe that returns false after the old process is gone. No change needed; verified the restart rebinds cleanly without EADDRINUSE.permissions grantpolling (cli.rs): the socket now appears before the grant, so a singlecheck_permissionsquery returns "pending". Changed to pollcheck_permissionsvia the daemon every 2s up to 180s, tolerating transient connection failures during a re-exec restart, until both grants fliptrue(success) or timeout (tells the user to approve the CuaDriver dialog + re-run). The "daemon already running" fast branch is preserved.Happy path unchanged: when
current_status().all_granted()is true,run_if_neededfast-returns atgate.rs:213— no banner, no polling, no flapping. Serve still starts normally.Scope
macOS-only. The non-macOS
Servearm already spawns serve on a thread and has no gate — untouched.Test plan (live, maintainer — needs GUI + grant clicks)
servewith Accessibility + Screen Recording already granted tocom.trycua.driver. Socket binds immediately, gate fast-returns, no flap, no regression vs current behavior.tccutil reset Accessibility com.trycua.driver && tccutil reset ScreenCapture com.trycua.driver, thencua-driver permissions grant. Verify: socket appears fast (within ~1s,permissions statusanswers "pending" immediately); the system prompt reads "Cua Driver"; after granting both, the daemon stabilizes andgrantreports granted (no infinite flap; the ~25s re-exec cadence means at most a brief socket blip per recheck).cua-driver mcpvia Claude Code connects and drives tools normally.Build
cargo build --release -p cua-driver✅cargo test --no-run -p platform-macos✅ (compile clean; the pre-existinglibswift_Concurrencyrpath run failure is unrelated — compile is what matters here)DRAFT — this is load-bearing daemon-startup code that needs live TCC-state verification before merge. Please do not merge until the test plan above passes on a real machine.
Refs #1761
🤖 Generated with Claude Code
Summary by CodeRabbit