From 38816dfb86097f1a58513df53c8b32e5aba752b9 Mon Sep 17 00:00:00 2001 From: Jasper Date: Mon, 31 Aug 2026 16:53:21 +0000 Subject: [PATCH] fix(desktop): configure proxy for renderer session (#11708) --- ui/desktop/src/main.ts | 21 ++----------- ui/desktop/src/proxy.test.ts | 61 ++++++++++++++++++++++++++++++++++++ ui/desktop/src/proxy.ts | 27 ++++++++++++++++ 3 files changed, 91 insertions(+), 18 deletions(-) create mode 100644 ui/desktop/src/proxy.test.ts create mode 100644 ui/desktop/src/proxy.ts diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts index b2e63c297..9888343dc 100644 --- a/ui/desktop/src/main.ts +++ b/ui/desktop/src/main.ts @@ -28,6 +28,7 @@ import { execFileSync, spawn, execFile } from 'child_process'; import 'dotenv/config'; import { checkBackendStatus } from './backendStatus'; import { installBackendCertificateVerifiers } from './backendCertificateVerifier'; +import { configureProxy } from './proxy'; import { startGooseServe } from './gooseServe'; import { getLoginShellPath } from './loginShellPath'; import { GooseServeLeaseRegistry, type GooseServeLease } from './gooseServeLeaseRegistry'; @@ -293,23 +294,6 @@ function listGitWorktreeDirs(dir: string): Promise { }); } -async function configureProxy() { - const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy; - const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy; - const noProxy = process.env.NO_PROXY || process.env.no_proxy || ''; - - const proxyUrl = httpsProxy || httpProxy; - - if (proxyUrl) { - console.log('[Main] Configuring proxy'); - await session.defaultSession.setProxy({ - proxyRules: proxyUrl, - proxyBypassRules: noProxy, - }); - console.log('[Main] Proxy configured successfully'); - } -} - if (started) app.quit(); // Certificate trust for active backend leases. Renderer requests and @@ -2472,7 +2456,8 @@ async function appMain() { } }); - await configureProxy(); + const rendererSession = session.fromPartition('persist:goose'); + await configureProxy(session.defaultSession, rendererSession); // Ensure Windows shims are available before any MCP processes are spawned await ensureWinShims(); diff --git a/ui/desktop/src/proxy.test.ts b/ui/desktop/src/proxy.test.ts new file mode 100644 index 000000000..30d2b2983 --- /dev/null +++ b/ui/desktop/src/proxy.test.ts @@ -0,0 +1,61 @@ +import type { Session } from 'electron'; +import { describe, expect, it, vi } from 'vitest'; +import { configureProxy } from './proxy'; + +function createMockSession() { + const setProxy = vi.fn().mockResolvedValue(undefined); + return { + session: { setProxy } as Pick, + setProxy, + }; +} + +describe('proxy configuration', () => { + it('applies the same proxy configuration to both Electron sessions', async () => { + const defaultSession = createMockSession(); + const rendererSession = createMockSession(); + + await configureProxy(defaultSession.session, rendererSession.session, { + HTTPS_PROXY: 'https://proxy.example:8443', + NO_PROXY: 'localhost,127.0.0.1', + }); + + expect(defaultSession.setProxy).toHaveBeenCalledOnce(); + expect(rendererSession.setProxy).toHaveBeenCalledOnce(); + expect(defaultSession.setProxy).toHaveBeenCalledWith({ + proxyRules: 'https://proxy.example:8443', + proxyBypassRules: 'localhost,127.0.0.1', + }); + expect(rendererSession.setProxy.mock.calls[0][0]).toBe( + defaultSession.setProxy.mock.calls[0][0] + ); + }); + + it('falls back to HTTP_PROXY without changing the default bypass rules', async () => { + const defaultSession = createMockSession(); + const rendererSession = createMockSession(); + + await configureProxy(defaultSession.session, rendererSession.session, { + HTTP_PROXY: 'http://proxy.example:8080', + }); + + expect(defaultSession.setProxy).toHaveBeenCalledWith({ + proxyRules: 'http://proxy.example:8080', + proxyBypassRules: '', + }); + expect(rendererSession.setProxy).toHaveBeenCalledWith({ + proxyRules: 'http://proxy.example:8080', + proxyBypassRules: '', + }); + }); + + it('leaves both sessions unchanged when no proxy is configured', async () => { + const defaultSession = createMockSession(); + const rendererSession = createMockSession(); + + await configureProxy(defaultSession.session, rendererSession.session, {}); + + expect(defaultSession.setProxy).not.toHaveBeenCalled(); + expect(rendererSession.setProxy).not.toHaveBeenCalled(); + }); +}); diff --git a/ui/desktop/src/proxy.ts b/ui/desktop/src/proxy.ts new file mode 100644 index 000000000..3e368d29e --- /dev/null +++ b/ui/desktop/src/proxy.ts @@ -0,0 +1,27 @@ +import type { Session } from 'electron'; + +type ProxySession = Pick; +type ProxyEnvironment = Record; + +export async function configureProxy( + defaultSession: ProxySession, + rendererSession: ProxySession, + environment: ProxyEnvironment = process.env +): Promise { + const httpsProxy = environment.HTTPS_PROXY || environment.https_proxy; + const httpProxy = environment.HTTP_PROXY || environment.http_proxy; + const proxyUrl = httpsProxy || httpProxy; + + if (!proxyUrl) { + return; + } + + console.log('[Main] Configuring proxy'); + const proxyConfig = { + proxyRules: proxyUrl, + proxyBypassRules: environment.NO_PROXY || environment.no_proxy || '', + }; + + await Promise.all([defaultSession.setProxy(proxyConfig), rendererSession.setProxy(proxyConfig)]); + console.log('[Main] Proxy configured successfully'); +}