Skip to content

Commit 6d82b95

Browse files
abhisekclaude
andauthored
fix: use bare ::1 in NO_PROXY to avoid crashing Python httpx (#340)
* fix: use bare ::1 in NO_PROXY to avoid crashing Python httpx Bracketed [::1] is URL authority syntax, not valid NO_PROXY syntax. Python's urllib/httpx parses bracketed entries as a URL and crashes with 'Invalid port: :1]'. Use the bare IPv6 loopback ::1 instead, which both Node and Python accept. Fixes #339 https://claude.ai/code/session_01NnkUKCn82Dc83VandSsgim * chore: condense NO_PROXY comment https://claude.ai/code/session_01NnkUKCn82Dc83VandSsgim * docs: note Node IPv6 literal NO_PROXY trade-off https://claude.ai/code/session_01NnkUKCn82Dc83VandSsgim --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9a02e8d commit 6d82b95

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

internal/flows/proxy_flow.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,12 @@ func ciEnvOverride() []string {
425425
func (f *proxyFlow) setupEnvForProxy(proxyAddr, caCertPath string) []string {
426426
proxyURL := fmt.Sprintf("http://%s", proxyAddr)
427427

428-
noProxyList := "localhost,127.0.0.1,[::1]"
428+
// IPv6 loopback uses the bare ::1: the bracketed [::1] is URL syntax that
429+
// crashes Python's urllib/httpx (#339). Trade-off: Node's NODE_USE_ENV_PROXY
430+
// (undici) only bypasses the bracketed form, so a literal http://[::1] from
431+
// Node still gets proxied. localhost/127.0.0.1 cover the common cases; the
432+
// IPv6 literal is a rare edge we accept since NO_PROXY can't be set per-client.
433+
noProxyList := "localhost,127.0.0.1,::1"
429434

430435
return []string{
431436
"NODE_USE_ENV_PROXY=1",

internal/flows/proxy_flow_env_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ func TestSetupEnvForProxyConfiguresYarn(t *testing.T) {
4141
"yarn ignores NODE_EXTRA_CA_CERTS; YARN_HTTPS_CA_FILE_PATH is required to trust the MITM CA")
4242
}
4343

44+
// TestSetupEnvForProxyNoProxyIPv6 proves the fix for #339: the IPv6 loopback in
45+
// NO_PROXY must be bare (::1), not bracketed ([::1]). Brackets are URL syntax,
46+
// not NO_PROXY syntax, and Python's urllib/httpx crashes parsing them with
47+
// "Invalid port: ':1]'".
48+
func TestSetupEnvForProxyNoProxyIPv6(t *testing.T) {
49+
f := &proxyFlow{}
50+
env := envToMap(f.setupEnvForProxy("127.0.0.1:54321", "/tmp/pmg-ca-cert.pem"))
51+
52+
for _, key := range []string{"NO_PROXY", "no_proxy"} {
53+
assert.Equal(t, "localhost,127.0.0.1,::1", env[key],
54+
"%s must use bare ::1; bracketed [::1] is invalid NO_PROXY syntax and crashes httpx", key)
55+
assert.NotContains(t, env[key], "[::1]",
56+
"%s must not contain bracketed IPv6 loopback", key)
57+
}
58+
}
59+
4460
// TestCIEnvOverride proves the fix for #335: pmg forces CI=true for
4561
// non-interactive runs but must not clobber a CI value the user set
4662
// explicitly (e.g. CI=false on a build server).

0 commit comments

Comments
 (0)