Skip to content

Proxy support: --proxy, HTTPS_PROXY / NO_PROXY - #66

Merged
jochen-testingbot merged 2 commits into
mainfrom
feat/proxy
Oct 31, 2026
Merged

jochen-testingbot merged 2 commits into
mainfrom
feat/proxy

Conversation

@jochen-testingbot

Copy link
Copy Markdown
Contributor

Item 3 of the follow-up list. This PR is independent of #63 and #65 and is based on main.

Why

Behind a corporate proxy the CLI failed before uploading anything:

  • The pre-flight connectivity check uses fetch, which ignores HTTPS_PROXY. It reported "No internet connection" and stopped.
  • Even past that point, axios's built-in env-proxy support sends HTTPS requests to the proxy without CONNECT, which most proxies refuse.
  • The live-updates WebSocket, the tunnel jar download and the tunnel itself also ignored the proxy.

What

  • src/utils/proxy.ts:
    • A routing agent (agent-base + https-proxy-agent / http-proxy-agent v7, which are CommonJS; v9 is ESM-only) picks the proxy for each URL.
    • https goes through a CONNECT tunnel; http requests are sent to the proxy in absolute form.
    • Proxy credentials come from the URL.
    • It replaces http.globalAgent and https.globalAgent, and sets axios.defaults.proxy = false.
  • Where the proxy comes from:
    • --proxy <url>, a program-level option accepted before or after the subcommand. It applies to every URL.
    • Otherwise HTTPS_PROXY for https URLs and HTTP_PROXY for http URLs, with ALL_PROXY as a fallback. Lower-case names work too.
    • NO_PROXY supports hosts, .domain and *.domain suffixes, :port and *.
    • Loopback addresses always go direct.
    • host:port is read as http://host:port.
    • socks or other schemes are rejected with a clear error.
  • WebSocket: the live-updates socket gets proxyAgent() explicitly, because ws bypasses the global agent.
  • Tunnel: with --tunnel, the tunnel (a separate Java process) gets --proxy host:port and --proxy-userpwd. The tunnel jar download already follows the global agent.
  • Connectivity check: when a proxy is in use, the third-party check is skipped, and the network-error diagnostics name the proxy instead.
  • Messages: "Using proxy …" is printed with the password masked (not with --quiet or --json). HTTP 407 maps to "Proxy authentication required", with hints.
  • No proxy configured: nothing changes.

Tests

  • tsc, eslint and prettier pass.
  • jest: 878 passed.
  • tests/utils/proxy.test.ts covers the env/NO_PROXY rules and redaction. It also starts a real proxy on 127.0.0.1 that records what reaches it and refuses every CONNECT, so nothing leaves the machine. Through it, the tests confirm:
    • an axios http request arrives in absolute form;
    • axios https sends CONNECT api.testingbot.com:443 with Proxy-Authorization;
    • a refused CONNECT reaches the caller as the proxy's own status code;
    • a bare https.get (the tunnel download) uses the proxy;
    • the socket.io WebSocket sends CONNECT hub.testingbot.com:443.
  • An xcuitest test checks that the tunnel options include the proxy.
  • On the built CLI: --proxy works before and after the subcommand, HTTPS_PROXY=socks5://… is rejected, and the password is masked in "Using proxy".

Not tested: a full run through a real corporate proxy against production. Worth one manual run before release, for example HTTPS_PROXY=… testingbot devices.

…NO_PROXY

A routing agent replaces Node's global HTTP(S) agents and picks the proxy
per URL (CONNECT for https), so axios, uploads and the tunnel download
follow it; the live-updates WebSocket gets it explicitly and --tunnel passes
it to the tunnel as --proxy/--proxy-userpwd. The third-party connectivity
pre-check is skipped behind a proxy, where it failed before any request.
axios's own env proxy handling is turned off: it sends https requests to the
proxy without CONNECT.
@jochen-testingbot
jochen-testingbot merged commit 07aead0 into main Oct 31, 2026
12 checks passed
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.

1 participant