feat: add ChromeDriver proxy for WebDriver and BiDi protocol support#164
feat: add ChromeDriver proxy for WebDriver and BiDi protocol support#164tnsardesai wants to merge 4 commits intomainfrom
Conversation
7941a36 to
433f3d1
Compare
| return msg | ||
| } | ||
| return maybeInjectBidiSession(msg, logger) | ||
| } |
There was a problem hiding this comment.
BiDi WebSocket session response webSocketUrl not rewritten
Medium Severity
The WebSocket message transform only processes the -> (client-to-upstream) direction for injecting debuggerAddress into session.new. It does not intercept <- (upstream-to-client) messages, so the webSocketUrl in the BiDi session.new response is not rewritten. This URL continues to point to the internal ChromeDriver address (127.0.0.1:9225) instead of the proxy, which is inconsistent with the HTTP POST /session flow where rewriteWebSocketURL correctly rewrites it.
| Read(ctx context.Context) (websocket.MessageType, []byte, error) | ||
| Write(ctx context.Context, typ websocket.MessageType, p []byte) error | ||
| Close(statusCode websocket.StatusCode, reason string) error | ||
| } |
There was a problem hiding this comment.
Exported Conn interface in wsproxy appears unused externally
Low Severity
The exported Conn interface is defined for "testing and flexibility" but Pump is the only function using it, and the Proxy function passes concrete *websocket.Conn values. No external callers appear to use Conn or Pump directly — all consumers go through Proxy. This is an unused exported abstraction that adds indirection without current value.
Install ChromeDriver matching the Chromium version in both headful and headless images, managed via supervisord on internal port 9225. A new ChromeDriver proxy (exposed on port 9224) intercepts session creation to inject goog:chromeOptions.debuggerAddress so ChromeDriver attaches to the already-running browser, rewrites webSocketUrl in responses to route BiDi traffic back through the proxy, and transparently proxies all other HTTP and WebSocket traffic. Extracts the shared WebSocket bidirectional pump logic from devtoolsproxy into a reusable wsproxy package with a MessageTransform hook, used by both the existing DevTools proxy and the new ChromeDriver proxy. Expands CDP discovery endpoint proxying to include /json/list and makes proxy ports configurable via environment variables. Includes comprehensive unit tests for the ChromeDriver proxy and manual BiDi validation scripts (raw WebSocket, Puppeteer, Selenium). Co-authored-by: Cursor <cursoragent@cursor.com>
Make the chromedriver proxy runtime-configurable and more robust, then add explicit Vibium BiDi e2e coverage using dynamic session endpoints so remote WebDriver workflows are easier and less brittle. Made-with: Cursor
Prevent parallel e2e tests from racing pnpm setup by making playwright dependency installation single-flight, avoiding intermittent ENOENT failures in CI. Made-with: Cursor
6b38b7c to
d428c05
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| require.NoError(t, err, "Failed to install bidi dependencies: %v\nOutput: %s", err, string(output)) | ||
| t.Log("Bidi test dependencies installed successfully") | ||
| } | ||
| } |
There was a problem hiding this comment.
Concurrent npm install race in ensureBidiDeps
Medium Severity
ensureBidiDeps checks for node_modules and runs npm install without any synchronization, unlike the updated ensurePlaywrightDeps in the same PR which correctly uses sync.Once. When multiple parallel BiDi tests call ensureBidiDeps concurrently, multiple npm install processes can race, potentially corrupting node_modules.
| rewriteChromeURLs(item, chromeHost, proxyHost) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Map rewriting doesn't recurse into nested objects
Low Severity
rewriteChromeURLs handles map[string]interface{} by rewriting known URL fields at the current level, but it never recurses into the map's other values. If a Chrome JSON endpoint ever returns nested objects (not just flat maps or arrays of flat maps), URLs at deeper levels won't be rewritten. The []interface{} case recurses, but the map case does not.


Install ChromeDriver matching the Chromium version in both headful and headless images, managed via supervisord on internal port 9225. A new ChromeDriver proxy (exposed on port 9224) intercepts session creation to inject goog:chromeOptions.debuggerAddress so ChromeDriver attaches to the already-running browser (at port 9222), rewrites webSocketUrl in responses to route BiDi traffic back through the proxy, and transparently proxies all other HTTP and WebSocket traffic.
Extracts the shared WebSocket bidirectional pump logic from devtoolsproxy into a reusable wsproxy package with a MessageTransform hook, used by both the existing DevTools proxy and the new ChromeDriver proxy. Expands CDP discovery endpoint proxying to include /json/list and makes proxy ports configurable via environment variables.
Includes comprehensive unit tests for the ChromeDriver proxy and manual BiDi validation scripts (raw WebSocket, Puppeteer, Selenium).
Checklist
Note
Medium Risk
Introduces a new externally exposed proxy endpoint and request/response rewriting in the API process, plus new runtime services/ports in the browser images, which could impact connectivity and automation flows if misconfigured.
Overview
Adds ChromeDriver support to the Chromium images and runtime. Both headful/headless images now download a Chromium-matching
chromedriver, run it undersupervisordon127.0.0.1:9225, and expose a new proxy port9224(updatedrun-*.shand wrappers to start/stop/wait for ChromeDriver).Adds a ChromeDriver proxy server to the Go API process. The API now serves a dedicated ChromeDriver proxy (configurable ports/upstream via new env vars) that intercepts
POST /sessionand BiDisession.newto injectgoog:chromeOptions.debuggerAddress, rewrites returnedcapabilities.webSocketUrlto route via the proxy, and otherwise reverse-proxies HTTP/WebSocket traffic.Refactors and extends proxy/test infrastructure. WebSocket pumping is extracted into reusable
wsproxyand the DevTools proxy is updated to use it; DevTools JSON discovery proxying is generalized to include/json/listwith URL rewriting; e2e infra now maps/waits for the ChromeDriver port and adds comprehensive BiDi e2e tests plus node-based validation scripts.Written by Cursor Bugbot for commit d428c05. This will update automatically on new commits. Configure here.