feat(windows): TCP loopback IPC for daemon (Windows compat)#205
feat(windows): TCP loopback IPC for daemon (Windows compat)#205andromeda-vinicius wants to merge 1 commit intobrowser-use:mainfrom
Conversation
Python on Windows lacks socket.AF_UNIX, blocking the original Unix-domain-socket based daemon-runner IPC. This patch adds a small _ipc.py abstraction that: - Uses AF_UNIX + /tmp/bu-<NAME>.sock on macOS/Linux (unchanged) - Uses TCP loopback (127.0.0.1:<random_port>) on Windows - Persists chosen port to %TEMP%\bu-<NAME>.sock (re-purposed as port marker) - Cross-platform: connect_daemon, start_daemon_server, runtime_path, cleanup_endpoint Files patched: - _ipc.py (NEW) — platform-aware IPC helpers - daemon.py — uses start_daemon_server + cleanup_endpoint - admin.py — uses connect_daemon + runtime_path; subprocess uses CREATE_NEW_PROCESS_GROUP on Windows - helpers.py — uses connect_daemon - pyproject.toml — registers _ipc as py-module Tested on Windows 11 + Python 3.13 + uv 0.11. browser-harness --doctor + page_info() work end-to-end against local Chrome with remote-debugging. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
2 issues found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="_ipc.py">
<violation number="1" location="_ipc.py:88">
P1: Windows daemon startup uses a racy two-step port allocation and writes the port marker before successful bind, which can cause intermittent bind failures and invalid endpoint discovery.</violation>
<violation number="2" location="_ipc.py:92">
P1: Windows IPC uses unauthenticated loopback TCP, removing Unix socket permission-based access control and allowing unauthorized local processes to issue daemon commands.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| # Persist port to .sock file (acts as port marker on Win) | ||
| with open(sock_path, "w") as f: | ||
| f.write(str(port)) | ||
| server = await asyncio.start_server(handler, "127.0.0.1", port) |
There was a problem hiding this comment.
P1: Windows IPC uses unauthenticated loopback TCP, removing Unix socket permission-based access control and allowing unauthorized local processes to issue daemon commands.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At _ipc.py, line 92:
<comment>Windows IPC uses unauthenticated loopback TCP, removing Unix socket permission-based access control and allowing unauthorized local processes to issue daemon commands.</comment>
<file context>
@@ -0,0 +1,111 @@
+ # Persist port to .sock file (acts as port marker on Win)
+ with open(sock_path, "w") as f:
+ f.write(str(port))
+ server = await asyncio.start_server(handler, "127.0.0.1", port)
+ return server, f"127.0.0.1:{port}"
+ # Unix
</file context>
| """ | ||
| sock_path = runtime_path(name, SOCK_EXT) | ||
| if is_windows(): | ||
| port = _alloc_port() |
There was a problem hiding this comment.
P1: Windows daemon startup uses a racy two-step port allocation and writes the port marker before successful bind, which can cause intermittent bind failures and invalid endpoint discovery.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At _ipc.py, line 88:
<comment>Windows daemon startup uses a racy two-step port allocation and writes the port marker before successful bind, which can cause intermittent bind failures and invalid endpoint discovery.</comment>
<file context>
@@ -0,0 +1,111 @@
+ """
+ sock_path = runtime_path(name, SOCK_EXT)
+ if is_windows():
+ port = _alloc_port()
+ # Persist port to .sock file (acts as port marker on Win)
+ with open(sock_path, "w") as f:
</file context>
|
Hi, _read_port() does not handle PermissionError/OSError when opening the port-marker file, so Windows temp-directory access issues can surface as unexpected exceptions and break connect_daemon() callers. Severity: remediation recommended | Category: reliability How to fix: Handle PermissionError/OSError Agent prompt to fix - you can give this to your LLM of choice:
Found by Qodo code review |
Summary
Adds Windows compatibility for the daemon-runner IPC. Python on Windows lacks
socket.AF_UNIX, so the original Unix-domain-socket-based IPC fails immediately on Windows withAttributeError: module 'socket' has no attribute 'AF_UNIX'.This patch adds a small
_ipc.pyabstraction that:AF_UNIX+/tmp/bu-<NAME>.sockon macOS/Linux (unchanged behaviour)127.0.0.1:<random_port>) on Windows%TEMP%�u-<NAME>.sock(re-purposed as port marker)connect_daemon,start_daemon_server,runtime_path,cleanup_endpointcross-platform helpersChanges
_ipc.py(new)daemon.pystart_daemon_server+cleanup_endpoint; removes inlineAF_UNIXadmin.pyconnect_daemon+runtime_path; subprocess usesCREATE_NEW_PROCESS_GROUPon Windowshelpers.pyconnect_daemonfor IPC_sendpyproject.toml_ipcaspy-moduleTest
Tested on Windows 11 + Python 3.13 + uv 0.11. End-to-end:
Backwards compatibility
Zero behaviour change on macOS/Linux: same paths, same socket type, same chmod 0600. Just the call sites are routed through
_ipc.pyhelpers that branch onplatform.system().Notes
CREATE_NEW_PROCESS_GROUP(vsstart_new_session=Trueon Unix) to detach from parent's console groupos.kill(pid, signal.SIGTERM)works on Windows since Python 3.x (emulates viaTerminateProcess)Summary by cubic
Adds Windows-compatible IPC for the daemon by using TCP loopback on Windows while keeping Unix domain sockets on macOS/Linux. This enables running the daemon and CLI on Windows with no behavior change on Unix.
_ipc.pywith cross‑platform helpers:connect_daemon,start_daemon_server,runtime_path,cleanup_endpoint.127.0.0.1:<random_port>and writes the port to%TEMP%\bu-<NAME>.sock; Unix remains/tmp/bu-<NAME>.sockwith 0600 perms.daemon.py,admin.py, andhelpers.pyto use the abstraction; Windows daemon launch usesCREATE_NEW_PROCESS_GROUP. Registered_ipcinpyproject.toml.Written for commit 52da586. Summary will update on new commits.