fix: propagate proxy settings to SSH environment#1012
Conversation
db5ca20 to
da8f590
Compare
| : ""; | ||
|
|
||
| return { | ||
| ...(proxy ? { HTTP_PROXY: proxy, HTTPS_PROXY: proxy } : {}), |
There was a problem hiding this comment.
Is it right to set both http_proxy and https_proxy? If the user set http_proxy I imagine we should not set it on https_proxy, and maybe vice versa. idk why someone would have Coder on an http URL though, other than for maybe testing.
There was a problem hiding this comment.
There's only one source here: VS Code's core http.proxy, which it applies to all traffic regardless of scheme. No separate http/https values to split apart, so we just fan it out to both
There was a problem hiding this comment.
http.proxy is only populated if the user fills it out right? The plugin also supports the environment variables http_proxy and https_proxy (and others) but not sure if VS Code will populate the http.proxy setting if these are set.
Looks like we are only passing http.proxy and coder.proxyBypass || http.noProxy. Instead we should copy everything used in proxy.ts (or break it out to share in some way).
That includes the setting, and the environment variablesnpm_config_http_proxy, npm_config_https_proxy, http_proxy, https_proxy, npm_config_proxy, and all_proxy (both lowercase and uppercase), then for no proxy we have the settings plus npm_config_no_proxy and no_proxy environment variables (both lowercase and uppercase).
There was a problem hiding this comment.
Oh right but for the local server case those would already be inherited anyway 🤔 Would it make sense to add them for the non-local server case? Unless VS Code already preserves them.
There was a problem hiding this comment.
I just tested actually and in both cases all env variables are inherited still, it's just that useLocalServer=false does not inherit from the current process.env. In that case, we do not need to handle env variables, only the setting -> env variable
Set HTTP_PROXY/HTTPS_PROXY/NO_PROXY on the extension host's process.env from VS Code's http.proxy / coder.proxyBypass / http.noProxy so the spawned `coder ssh` ProxyCommand inherits them. Mutating process.env avoids writing a credentialed proxy URL to the SSH config and keeps multiple windows onto the same workspace independent. Watch the proxy settings so the user is prompted to reload when SSH proxy behavior changes.
When a proxy applies to the deployment but remote.SSH.useLocalServer is off, the spawned SSH connection won't inherit the proxy env. Surface a dismissable warning offering to enable the local server, via a reusable showDismissibleNotification helper.
Move showDismissibleNotification from util into a DismissibleNotifier class under core: it holds globalState and constrains keys to a known DismissibleNotificationKey set, wired through ServiceContainer. Rename applySshProxyEnvironment to applySshEnvironment, generalize its doc to "SSH-related environment variables", keep the internal env type unexported, and order the file public-API first. Make the useLocalServer warning a blocking warning modal so the setting is written (via the jsonc settings util, not cfg.update) before ssh spawns, which lets it apply without a window reload.
df5620b to
c025edc
Compare
c025edc to
2da64c3
Compare
Remote-SSH with `useLocalServer=false` spawns ssh in a terminal, which does not inherit the extension host's process.env, so the proxy never reached it. Also apply the proxy via VS Code's EnvironmentVariableCollection, which the terminal-spawned ssh inherits; process.env still covers the local-server (child-process) path. `applySshEnvironment` now applies both. Drop `warnIfProxyEnvNotInherited` and the `DismissibleNotifier` it relied on: the proxy now reaches ssh in both modes, so nagging users to enable the local server is obsolete.
code-asher
left a comment
There was a problem hiding this comment.
Nice find on the terminal env!
Summary
Propagate VS Code's proxy settings to the spawned
coder sshProxyCommand so connections work behind a proxy. ThecoderCLI has no proxy flag; it readsHTTP_PROXY/HTTPS_PROXY/NO_PROXYfrom its environment like any Go HTTP client, so the job is getting those variables into that process.HTTP_PROXY/HTTPS_PROXYfromhttp.proxy(trimmed; blank ignored).NO_PROXYfromcoder.proxyBypass, falling back tohttp.noProxy. Bypass matching is left to the CLI's GoNO_PROXYparser, so it applies per-connection to whatever host the CLI dials.A single
applySshEnvironmentcall applies the env via two mechanisms, covering both Remote-SSH modes:process.env: inherited by ssh spawned as a child process (useLocalServer=true).EnvironmentVariableCollection: inherited by ssh spawned in a terminal (useLocalServer=false), which can't seeprocess.env.Both run unconditionally, since the spawn path isn't reliably predictable from the setting and neither mechanism covers the other's mode. The collection only touches local terminals, so workspace terminals are unaffected. We mutate the environment instead of writing the SSH config, keeping credentialed URLs off disk and windows independent.
Testing
pnpm lintpnpm typecheckpnpm testManual testing matrix
Verified the proxy variables reach the spawned
coder sshProxyCommand by injecting a marker through each mechanism and reading the live ssh process's environment (ansshwrapper viaremote.SSH.pathdumpingenv).useLocalServer=trueprocess.envuseLocalServer=falseEnvironmentVariableCollectionprocess.env(local-server path)Notes:
useLocalServer=falseruns the connection ssh as the shell of a hidden terminal, so it inherits the terminal environment (the collection), not the extension host'sprocess.env. Modifyingprocess.envdoes not reach terminals; the collection is the documented mechanism (microsoft/vscode#88718).ssh -Vcapability probe spawned directly by the extension host, which always showsprocess.envregardless of mode. Check the real connection process (the-D ... bashone), not the probe.Closes #1010