[feat]: expose headers param on `LocalBrowserConnectOptions`

Merged
SE
13h ago
+541-6

why

port the Python support from #3260 to Go so callers can authenticate against CDP gateways without putting credentials in the URL

what

browser, err := stagehand.ConnectLocalBrowser(ctx, stagehand.LocalBrowserConnectOptions{
    CDPURL:  "https://gateway/.../cdp",
    Headers: map[string]string{"X-Api-Key": "..."},
})

Headers are sent with HTTP discovery and the client’s CDP WebSocket handshake. They only reach endpoints on the same host and effective port, without downgrading TLS, and are never passed to the extension. Both HTTP and WebSocket redirects are guarded using a copy of the HTTP client, preserving the caller’s settings.

Header validation rejects unsafe names, non-ASCII values, and leading or trailing whitespace without exposing credentials in errors. Discovery fails immediately on HTTP 401/403, and debug logging explains when headers are withheld. Includes a minor changeset.

test plan

  • Network tests cover discovery and WebSocket header forwarding, allowed and blocked redirects, redirect limits, and connections with nil or empty headers.
  • Regression tests cover validation, error redaction, host/port/TLS boundaries, safe diagnostics, immediate 401/403 failures, and retries for transient HTTP failures.
  • Factory tests verify headers are copied from the caller’s map and kept out of extension initialization metadata. Redirect tests verify the caller’s HTTP client and redirect policy are preserved.
  • Targeted tests pass with the race detector, and go vet . passes. The broader go test ./... command hits duplicate declarations in the standalone examples directory.

Summary by cubic

Adds Headers to LocalBrowserConnectOptions so Go callers can authenticate against CDP gateways without putting credentials in the URL.

  • Ports the Python support from #3260 to Go, sending headers with HTTP discovery and the client's CDP WebSocket handshake.
  • Headers only reach endpoints on the same host and effective port, never downgrading TLS, and are not passed to the extension.
  • Redirects are guarded using a copy of the HTTP client, preserving caller settings, and URLs are re-validated even if the caller's redirect callback rewrites them; duplicate header names ignoring case are rejected.
  • 401/403 discovery failures fail immediately, and validation rejects unsafe names, non-ASCII values, and whitespace trim issues without exposing credentials in errors.