From b2601c86137d3c9850643dde2114dfd92fe9e1e9 Mon Sep 17 00:00:00 2001 From: qwen-code-dev-bot Date: Sat, 11 Jul 2026 03:06:55 +0800 Subject: [PATCH] fix(interactive): configure Docker sandbox networking for protocol tag retry test (#6684) (#6689) The protocol-tags-interactive.test.ts started the fake OpenAI server on 127.0.0.1 without Docker-aware host options, making it unreachable from inside the Docker sandbox container. The CLI running in the container tried to connect to 127.0.0.1 which resolved to the container's own loopback, not the host where the test server listens. Bind the fake server to 0.0.0.0 and advertise host.docker.internal as the base URL host when QWEN_SANDBOX is docker or podman, matching the established pattern in tool-control.test.ts. Also set NO_PROXY to include host.docker.internal so the CLI does not route sandbox model requests through an HTTP proxy. Co-authored-by: qwen-autofix[bot] --- .../protocol-tags-interactive.test.ts | 87 +++++++++++++------ 1 file changed, 60 insertions(+), 27 deletions(-) diff --git a/integration-tests/interactive/protocol-tags-interactive.test.ts b/integration-tests/interactive/protocol-tags-interactive.test.ts index 73c2ebc4be..a45a7a238a 100644 --- a/integration-tests/interactive/protocol-tags-interactive.test.ts +++ b/integration-tests/interactive/protocol-tags-interactive.test.ts @@ -12,52 +12,85 @@ import { } from '../fake-openai-server.js'; import { TestRig, type } from '../test-helper.js'; +const SANDBOX_MODE = process.env['QWEN_SANDBOX']?.toLowerCase().trim(); +const IS_CONTAINER_SANDBOX = + SANDBOX_MODE === 'docker' || SANDBOX_MODE === 'podman'; + describe('Interactive protocol tag retry guard', () => { let fakeServer: FakeOpenAIServer | undefined; let rig: TestRig; + let savedNoProxy: string | undefined; + let savedNoProxyLower: string | undefined; beforeEach(() => { rig = new TestRig(); + if (IS_CONTAINER_SANDBOX) { + savedNoProxy = process.env['NO_PROXY']; + savedNoProxyLower = process.env['no_proxy']; + const noProxy = '127.0.0.1,localhost,host.docker.internal'; + process.env['NO_PROXY'] = noProxy; + process.env['no_proxy'] = noProxy; + } }); afterEach(async () => { await fakeServer?.close(); fakeServer = undefined; + if (IS_CONTAINER_SANDBOX) { + if (savedNoProxy !== undefined) { + process.env['NO_PROXY'] = savedNoProxy; + } else { + delete process.env['NO_PROXY']; + } + if (savedNoProxyLower !== undefined) { + process.env['no_proxy'] = savedNoProxyLower; + } else { + delete process.env['no_proxy']; + } + } await rig.cleanup(); }); it.skipIf(process.platform === 'win32')( 'retries protocol leaks across SSE disconnect and completed streams', async () => { - fakeServer = await startFakeOpenAIServer(({ requestIndex }) => { - if (requestIndex === 0) { - return { - contentChunks: [ - 'hidden before disconnect', - 'WRONG_FIRST_ATTEMPT', - ], - disconnectAfterContentChunks: 1, - }; - } + fakeServer = await startFakeOpenAIServer( + ({ requestIndex }) => { + if (requestIndex === 0) { + return { + contentChunks: [ + 'hidden before disconnect', + 'WRONG_FIRST_ATTEMPT', + ], + disconnectAfterContentChunks: 1, + }; + } - if (requestIndex === 1) { - return { - contentChunks: [ - 'hidden completed attempt', - 'WRONG_COMPLETED_SUMMARY', - ], - }; - } + if (requestIndex === 1) { + return { + contentChunks: [ + 'hidden completed attempt', + 'WRONG_COMPLETED_SUMMARY', + ], + }; + } - return { - contentChunks: ['VISIBLE_TMUX_RETRY_RESPONSE_DONE'], - usage: { - prompt_tokens: 20, - completion_tokens: 8, - total_tokens: 28, - }, - }; - }); + return { + contentChunks: ['VISIBLE_TMUX_RETRY_RESPONSE_DONE'], + usage: { + prompt_tokens: 20, + completion_tokens: 8, + total_tokens: 28, + }, + }; + }, + IS_CONTAINER_SANDBOX + ? { + listenHost: '0.0.0.0', + baseUrlHost: 'host.docker.internal', + } + : undefined, + ); await rig.setup('interactive-protocol-tag-filtering-http-retry', { settings: {