mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge pull request #9453 from truffle-dev/fix/vscode-forward-http-proxy-to-cli
fix(vscode): forward VS Code http.proxy settings to spawned CLI process
This commit is contained in:
@@ -104,6 +104,12 @@ export class ServerManager {
|
||||
...(extraCaCerts && { NODE_EXTRA_CA_CERTS: extraCaCerts }),
|
||||
...(!proxyStrictSSL && { NODE_TLS_REJECT_UNAUTHORIZED: "0" }),
|
||||
...process.env,
|
||||
// VS Code's http.proxy / http.noProxy settings are not reflected in
|
||||
// process.env, so spawned children bypass the user's configured proxy
|
||||
// and fail behind corporate firewalls. Forward them as the standard
|
||||
// HTTP_PROXY / HTTPS_PROXY / NO_PROXY env vars that Bun's fetch and
|
||||
// most HTTP clients already respect.
|
||||
...buildProxyEnv(),
|
||||
// Force mimalloc (the allocator Bun ships with) to return freed pages
|
||||
// to the OS immediately instead of retaining them in its arenas.
|
||||
// Without this, Bun.spawn's piped stdio accumulates ~2 MB of native
|
||||
@@ -257,6 +263,72 @@ function stripAnsi(str: string): string {
|
||||
return str.replace(/\x1b\[[0-9;]*m/g, "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate VS Code's `http.proxy` / `http.noProxy` / `http.proxySupport`
|
||||
* settings into the standard proxy env vars, so the spawned CLI honors the
|
||||
* user's proxy configuration. Returns an empty object when no override is
|
||||
* needed, so callers can spread unconditionally.
|
||||
*
|
||||
* `http.proxySupport: "off"` is VS Code's opt-in way to disable proxy support
|
||||
* entirely; when set, we explicitly clear the env vars so ambient shell
|
||||
* HTTP_PROXY/http_proxy doesn't leak into the spawned child.
|
||||
*/
|
||||
export function buildProxyEnv(): Record<string, string> {
|
||||
const httpConfig = vscode.workspace.getConfiguration("http")
|
||||
const proxyInfo = httpConfig.inspect<string>("proxy")
|
||||
const noProxyInfo = httpConfig.inspect<string[]>("noProxy")
|
||||
const proxySupport = httpConfig.get<string>("proxySupport")
|
||||
|
||||
if (proxySupport === "off") {
|
||||
return { HTTP_PROXY: "", HTTPS_PROXY: "", NO_PROXY: "", http_proxy: "", https_proxy: "", no_proxy: "" }
|
||||
}
|
||||
|
||||
const proxy = httpConfig.get<string>("proxy")
|
||||
const noProxy = httpConfig.get<string[]>("noProxy")
|
||||
const proxySet =
|
||||
proxyInfo !== undefined &&
|
||||
[
|
||||
proxyInfo.globalValue,
|
||||
proxyInfo.workspaceValue,
|
||||
proxyInfo.workspaceFolderValue,
|
||||
proxyInfo.globalLanguageValue,
|
||||
proxyInfo.workspaceLanguageValue,
|
||||
proxyInfo.workspaceFolderLanguageValue,
|
||||
].some((value) => value !== undefined)
|
||||
const noProxySet =
|
||||
noProxyInfo !== undefined &&
|
||||
[
|
||||
noProxyInfo.globalValue,
|
||||
noProxyInfo.workspaceValue,
|
||||
noProxyInfo.workspaceFolderValue,
|
||||
noProxyInfo.globalLanguageValue,
|
||||
noProxyInfo.workspaceLanguageValue,
|
||||
noProxyInfo.workspaceFolderLanguageValue,
|
||||
].some((value) => value !== undefined)
|
||||
const env: Record<string, string> = {}
|
||||
if (proxy && proxy.trim() !== "") {
|
||||
env.HTTP_PROXY = proxy
|
||||
env.HTTPS_PROXY = proxy
|
||||
env.http_proxy = proxy
|
||||
env.https_proxy = proxy
|
||||
}
|
||||
if (proxySet && proxy !== undefined && proxy.trim() === "") {
|
||||
env.HTTP_PROXY = ""
|
||||
env.HTTPS_PROXY = ""
|
||||
env.http_proxy = ""
|
||||
env.https_proxy = ""
|
||||
}
|
||||
if (Array.isArray(noProxy) && noProxy.length > 0) {
|
||||
env.NO_PROXY = noProxy.join(",")
|
||||
env.no_proxy = noProxy.join(",")
|
||||
}
|
||||
if (noProxySet && Array.isArray(noProxy) && noProxy.length === 0) {
|
||||
env.NO_PROXY = ""
|
||||
env.no_proxy = ""
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
export function toErrorMessage(
|
||||
error: string,
|
||||
stderrLines: string[],
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import { describe, it, expect, afterEach } from "bun:test"
|
||||
import * as vscode from "vscode"
|
||||
import { buildProxyEnv } from "../../src/services/cli-backend/server-manager"
|
||||
|
||||
type Info = { globalValue?: unknown; workspaceValue?: unknown; workspaceFolderValue?: unknown }
|
||||
type WorkspaceStub = {
|
||||
getConfiguration: (section?: string) => { get: (key: string) => unknown; inspect: (key: string) => Info }
|
||||
}
|
||||
|
||||
const workspace = vscode.workspace as unknown as WorkspaceStub
|
||||
const originalGetConfiguration = workspace.getConfiguration
|
||||
|
||||
function stubHttpConfig(values: { proxy?: unknown; noProxy?: unknown; proxySupport?: unknown }): void {
|
||||
workspace.getConfiguration = (section?: string) => {
|
||||
if (section === "http") {
|
||||
return {
|
||||
get: (key: string) => {
|
||||
if (key === "proxy") return values.proxy
|
||||
if (key === "noProxy") return values.noProxy
|
||||
if (key === "proxySupport") return values.proxySupport
|
||||
return undefined
|
||||
},
|
||||
inspect: (key: string) => {
|
||||
if (key === "proxy" && values.proxy !== undefined) return { workspaceValue: values.proxy }
|
||||
if (key === "noProxy" && values.noProxy !== undefined) return { workspaceValue: values.noProxy }
|
||||
if (key === "proxySupport" && values.proxySupport !== undefined)
|
||||
return { workspaceValue: values.proxySupport }
|
||||
return {}
|
||||
},
|
||||
}
|
||||
}
|
||||
return { get: () => undefined, inspect: () => ({}) }
|
||||
}
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
workspace.getConfiguration = originalGetConfiguration
|
||||
})
|
||||
|
||||
describe("buildProxyEnv", () => {
|
||||
it("returns an empty object when neither proxy nor noProxy is configured", () => {
|
||||
stubHttpConfig({ proxy: undefined, noProxy: undefined })
|
||||
|
||||
expect(buildProxyEnv()).toEqual({})
|
||||
})
|
||||
|
||||
it("forwards http.proxy as HTTP_PROXY and HTTPS_PROXY", () => {
|
||||
stubHttpConfig({ proxy: "http://proxy.corp.example:8080" })
|
||||
|
||||
expect(buildProxyEnv()).toEqual({
|
||||
HTTP_PROXY: "http://proxy.corp.example:8080",
|
||||
HTTPS_PROXY: "http://proxy.corp.example:8080",
|
||||
http_proxy: "http://proxy.corp.example:8080",
|
||||
https_proxy: "http://proxy.corp.example:8080",
|
||||
})
|
||||
})
|
||||
|
||||
it("joins http.noProxy into a comma-separated NO_PROXY value", () => {
|
||||
stubHttpConfig({ noProxy: ["localhost", "127.0.0.1", "*.internal"] })
|
||||
|
||||
expect(buildProxyEnv()).toEqual({
|
||||
NO_PROXY: "localhost,127.0.0.1,*.internal",
|
||||
no_proxy: "localhost,127.0.0.1,*.internal",
|
||||
})
|
||||
})
|
||||
|
||||
it("forwards both proxy and noProxy when both are configured", () => {
|
||||
stubHttpConfig({
|
||||
proxy: "http://proxy.corp.example:8080",
|
||||
noProxy: ["localhost", "*.internal"],
|
||||
})
|
||||
|
||||
expect(buildProxyEnv()).toEqual({
|
||||
HTTP_PROXY: "http://proxy.corp.example:8080",
|
||||
HTTPS_PROXY: "http://proxy.corp.example:8080",
|
||||
NO_PROXY: "localhost,*.internal",
|
||||
http_proxy: "http://proxy.corp.example:8080",
|
||||
https_proxy: "http://proxy.corp.example:8080",
|
||||
no_proxy: "localhost,*.internal",
|
||||
})
|
||||
})
|
||||
|
||||
it("clears env vars when http.proxy is only whitespace", () => {
|
||||
stubHttpConfig({ proxy: " " })
|
||||
|
||||
expect(buildProxyEnv()).toEqual({
|
||||
HTTP_PROXY: "",
|
||||
HTTPS_PROXY: "",
|
||||
http_proxy: "",
|
||||
https_proxy: "",
|
||||
})
|
||||
})
|
||||
|
||||
it("clears env var when http.noProxy is an empty array", () => {
|
||||
stubHttpConfig({ noProxy: [] })
|
||||
|
||||
expect(buildProxyEnv()).toEqual({
|
||||
NO_PROXY: "",
|
||||
no_proxy: "",
|
||||
})
|
||||
})
|
||||
|
||||
it("ignores a non-array http.noProxy value", () => {
|
||||
stubHttpConfig({ noProxy: "localhost" })
|
||||
|
||||
expect(buildProxyEnv()).toEqual({})
|
||||
})
|
||||
|
||||
it("explicitly clears env vars when http.proxySupport is off", () => {
|
||||
stubHttpConfig({ proxySupport: "off" })
|
||||
|
||||
expect(buildProxyEnv()).toEqual({
|
||||
HTTP_PROXY: "",
|
||||
HTTPS_PROXY: "",
|
||||
NO_PROXY: "",
|
||||
http_proxy: "",
|
||||
https_proxy: "",
|
||||
no_proxy: "",
|
||||
})
|
||||
})
|
||||
|
||||
it("http.proxySupport=off wins over a configured http.proxy/http.noProxy", () => {
|
||||
stubHttpConfig({
|
||||
proxy: "http://proxy.corp.example:8080",
|
||||
noProxy: ["localhost"],
|
||||
proxySupport: "off",
|
||||
})
|
||||
|
||||
expect(buildProxyEnv()).toEqual({
|
||||
HTTP_PROXY: "",
|
||||
HTTPS_PROXY: "",
|
||||
NO_PROXY: "",
|
||||
http_proxy: "",
|
||||
https_proxy: "",
|
||||
no_proxy: "",
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user