Repository navigation
test(runtime): prove the proxied HTTP forward path end-to-end - #6006
Conversation
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
Review of fac28309 (+78/-4, 2 files). The change sets proxyTunnel: true on the HTTP(S) ProxyAgent in buildProxyDispatcher so plain-HTTP targets are sent as CONNECT host:80 through the proxy instead of being forwarded in absolute form.
P2: this breaks an existing test contract, and CI test is red because of it. packages/eval/src/__tests__/maka-initialization.test.ts ("official Maka shim uses one Host for preflight and execution across retries and key rotation") runs a fixture proxy that expects plain-HTTP requests to http://provider.invalid to be forwarded with Proxy-Authorization. Its connect handler records Unexpected CONNECT and answers 403. On this head the run fails with Error: Unexpected CONNECT provider.invalid:80 (run 37790469660). Main's last five CI runs are green, so the PR causes this failure. Undici 8 has been on main since #1247, so forwarding is the current, tested behavior and not a recent regression. Changing it needs either that fixture updated along with a stated reason, or a narrower fix.
P3: CONNECT to port 80 is often refused by real proxies. Squid's stock config has http_access deny CONNECT !SSL_ports, and many corporate proxies do the same. With proxyTunnel: true, a user with an http:// provider base URL (local gateways, LAN Ollama/vLLM behind a proxy) gets a 403 where forwarding works today. If the goal is to keep the onRequestUpgrade socket cancellation, note that forwarded requests already go through factory, which wraps connect with withSocketCancellation/buildAbortableConnector. Abort coverage may already hold without forcing tunnels; a test showing that an abort during a forwarded request leaks would make the case for this change.
The new startTunnelProxy helper and the CONNECT assertion test look correct for what they check. There are no protocol files, so there is no epoch impact. The PR is MERGEABLE.
fac2830 to
433b64d
Compare
Since undici 8 (undici#1247) ProxyAgent forwards plain-HTTP targets to the proxy in absolute form instead of opening a CONNECT tunnel, and that forwarding semantics is the established contract on main: the eval fixture explicitly asserts the absolute-form request line and rejects CONNECT with 403. The reported 8-second hang (apache#5805) does not reproduce on undici 8.11.2 (local scoped-fetch-transport baseline 42/42 green; recent main CI runs green), and cancellation is already covered at the connect level via withSocketCancellation and buildAbortableConnector inside the dispatcher factory. The fake HTTP proxy used by the success-path test answered every request with a fixed 200, so the proxied HTTP path passed without ever exercising a relay. Replace it with a real forwarding proxy that records the absolute-form request line and the proxy-authorization header as the bytes flow through, then relays the raw connection to a live target server over a TCP pipe; the client response can only come from that target. This also pins the credentials-ride-the-forward contract on the HTTP path. Validated the test itself by temporarily self-answering from the proxy (mimicking the old fixture): the relay assertion fails until the pipe is restored. Generated-by: GLM-5.3-Flash (ZCode)
|
@Astro-Han Thank you — both points are accepted, and the PR has been reshaped accordingly (new head This review and the earlier P2 in #5805 pulled in opposite directions, so each claim was traced back to falsifiable evidence before deciding:
The review's one durable finding — the old fake proxy answered a fixed 200 to anything, so the proxied HTTP success path was never actually proven — is exactly what the reshaped PR fixes. The new |
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.
Incremental review: fac28309 -> 433b64db. Both heads sit on the same main base. The PR was reshaped, not rebased: the old commit is replaced by a single test-only commit (+83/-4, packages/runtime/src/network/__tests__/scoped-fetch-transport.test.ts).
Prior findings
- P2 (eval
maka-initializationtest red becauseproxyTunnel: truemade plain-HTTP targets use CONNECT): fixed.proxy-dispatcher.tsis back to main and is no longer in the diff. Plain-HTTP targets keep the undici 8 forward behavior the eval fixture asserts. CItestis green on this head. - P3 (Squid and similar proxies deny
CONNECTto port 80): resolved by the same revert. Forced tunneling is gone.
New test. For the http case, startForwardProxy replaces the self-answering fake proxy. It records each request head and pipes raw bytes to a live target, so a response can only come from the target. It checks three things: the absolute-form request line, proxy-authorization built from the configured credentials, and targetHits === index + 1. If undici ever switched back to CONNECT, the target HTTP server would answer the piped CONNECT line with 400 and the test would fail. So this pins the forward contract from the runtime side as well as the eval side. The abort-listener check now runs against a real relayed connection rather than a fixed 200, which is what the test name claims. I found no defects.
Non-blocking nit: pending is declared per proxy, not per client connection. It works here because the 25 requests are sequential and each connection closes. Moving it inside the net.createServer callback would make the helper safe if it is ever reused with concurrent or keep-alive connections.
No protocol files are touched, so there is no epoch impact. The PR is MERGEABLE, and CI test passes on 433b64db.
No findings. This looks good to land.
Astro-Han
left a comment
There was a problem hiding this comment.
Approved at @Astro-Han's explicit request: a small, focused change with no blocking findings in our automated review of this exact head, and CI is green.
Summary
This PR was reshaped after review. The original version pinned
ProxyAgentback to CONNECT-first tunneling for plain-HTTP targets(
proxyTunnel: true); that direction is withdrawn here and replaced bya test-only hardening of the existing forwarding behavior. No product
code changes remain:
proxy-dispatcher.tsis back to upstream/mainunchanged, and the CONNECT-asserting regression test is gone.
Why the CONNECT pinning was withdrawn
Two reviews pulled in opposite directions, so each claim was traced
back to falsifiable evidence:
scoped-fetch-transportbaseline is 42/42 green and recent main CI runs are green. Cancellation is already covered at the connect level: the forward request still goes through the dispatcherfactory'sconnectwrapper (withSocketCancellation/buildAbortableConnector);onRequestUpgradeonly fires for TLS tunnel upgrades, so the "cancellation contract broken" argument never applied to the forward path.packages/eval/src/__tests__/maka-initialization.test.ts) explicitly asserts the forward contract: it serves absolute-form URLs and answersCONNECTwith 403 ("Unexpected CONNECT"). Forwarding has been the behavior on main since undici 8 (undici#1247), alive for ~3.5 months with green CI.CONNECTto non-SSL ports, so http:// providers behind a LAN proxy (Ollama, vLLM, ...) would go from working to 403 under forced tunneling.The one finding from the reviews that held up: the runtime success-path
test previously used a fake proxy answering a fixed 200 to anything, so
the proxied HTTP path passed without ever proving a relay
("accidentally green"). This PR closes exactly that gap.
What this PR does instead
startForwardProxyreplaces the self-answering fake for the plain-HTTPsuccess case, and it behaves like a real forward proxy:
asserts the absolute-form request line
(
GET http://127.0.0.1:<port>/models HTTP/1.1);and never answers on its own, so the client response can only have
come from the target;
proxy-authorizationrides the forward request whencredentials are configured (matching the eval fixture's expectation).
If maintainers' actual intent is tunnel semantics for plain-HTTP
targets, reverting this test's direction is the correct and cheap move;
this PR deliberately no longer forces that decision in product code.
Refs #6005
Verification
packages/runtime:tsc -p tsconfig.jsonnode --test dist/network/__tests__/scoped-fetch-transport.test.jsnode --test "dist/network/__tests__/*.test.js"(adjacent suite)node --test "dist/bots/__tests__/*.test.js"(adjacent suite)npx biome checkon the changed filenpm run check:asf-headersAI use
Select exactly one:
Tool(s) and scope: GLM-5.3-Flash (ZCode) authored the analysis, the
test changes and this write-up; the human directed the adjudication
between the conflicting reviews. The commit carries the
Generated-bytrailer.
Checklist
Does this PR entail a change in behavior?