-
Notifications
You must be signed in to change notification settings - Fork 304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable extension-specific proxy settings #5650
Conversation
3e39ab6
to
48ca172
Compare
vscode/src/configuration.ts
Outdated
function expandTilde(path?: string): string | undefined { | ||
if (path?.startsWith('~/')) { | ||
const homeDir = process.env.HOME || process.env.USERPROFILE | ||
if (homeDir) { | ||
return `${homeDir}/${path.slice(2)}` | ||
} | ||
} | ||
return path | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this just be a path.resolve?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
path.resolve
doesn't understand ~/
, but I could probably use os.homedir()
instead of relying on the environment variables, and maybe also handle %USERPROFILE%\
as well for Windows.
vscode/src/configuration.ts
Outdated
if (!fs.statSync(path).isSocket()) { | ||
throw new Error('Not a socket') | ||
} | ||
fs.accessSync(path, fs.constants.R_OK | fs.constants.W_OK) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be very careful with this and double check it platform specific docs. For instance on windows there's all sorts of EACCESS edge cases if the file or folder is busy.
From memory we are already importing extra-fs which handles this or I think the fs/promises avoids some of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Switched to using fs-extra
, and looked into issues with Windows and file locks. Looks like stat
and access
aren't affected by busy files.
vscode/src/configuration.ts
Outdated
} | ||
|
||
function readProxyCACert(): string | undefined { | ||
const path = expandTilde(config.get<string>(CONFIG_KEY.proxyCacert)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be moving to the new observable config so it automatically re-calculates on change without reload.
Could be some some initialization timing problems that might come up with reading config as fixed value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sqs already did that. I double-checked locally, and the custom agent is re-created when settings.json
changes.
vscode/src/configuration.ts
Outdated
} | ||
try { | ||
return fs.readFileSync(path, { encoding: 'utf-8' }) | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make sure to add a logerror too? Notifications don't show in logs if someone asks for support
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! Added them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... and took them away again. Adding logError
caused the code to be called repeatedly. Did I do something wrong? Posted in Slack.
vscode/src/configuration.ts
Outdated
const vsCodeConfig = vscode.workspace.getConfiguration() | ||
|
||
return { | ||
proxy: vsCodeConfig.get<string>('http.proxy'), | ||
proxyHost: config.get<string>(CONFIG_KEY.proxyHost), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we validate what it says in description that values need to be set together?
Alternatively, the config is full json schema compatible and it still gets flattened down. so you can instead of separate strings ask for a union of different config objects so that they are always set together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. I re-worked the schema to enforce setting them together. Doesn't really enforce anything, but it does show the user when a value is missing. I added an error message display when the config is read to help out.
vscode/src/fetch.node.ts
Outdated
...(proxyPort ? { port: proxyPort } : null), | ||
...(proxyPath ? { socketPath: proxyPath } : null), | ||
keepAlive: true, | ||
keepAliveMsecs: 60000, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙈 ... oh keepAlive; the "golden bullet" that keeps claiming friendly fire. But that's for a later day 😅
Just for now, I don't think Keep Alive works this way with socks proxy agent. So there might be significant latency overhead.
Also I think EventSource has problems with this and reconnection / server closed connections. Which given how socks proxy agent operates might give issues. Not quite sure But just so you're aware.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok; I was just making sure to copy the settings that are being used in the proxy agents if the global proxy url is set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we not include keepAlive settings in this proxy agent? They're included in the existing http(s) proxy agents, so I thought they should be included in this one.
@peterguy @RXminuS This is an interesting new addition to the proxy space but I wanted to add that its entirely possible certain edge cases be not covered by this. We would also test all the cases with this google sheet just to extra sure that this actually works. I think using Fiddler Mitm etc is fine but we have sourcegraph based proxies too so using those could also be helpful just to be extra certain. Aside from what rik already pointed out about the keep alive stuff. We also had a long long history of changes around this as mentioned in this PR . We did use proxy agent before but then caused more issues so we reverted it although perhaps it might be okay to use it just for your case coz You can read the whole history here and if the PR still concedes I am happy to do a deep dive by manually running all the cases etc. There's other issues also with the proxy stuff like the ability to load local windows certs and self signed certs loading being specifically an issue(You are very likely fully aware of all of these). I am sure you have probably covered many to almost all of these but maybe not ALL of these and that's my concern(Unless you do in-fact cover all of the cases atleast for now). So a question for you both(Rik and Peter):
|
a4331f3
to
9758ccf
Compare
@arafatkatze this affects VSCode. Do you have a setup where you can test on Windows? I'm working on getting a dev environment set up in Windows, but if you have a setup already, it'll be faster to test. |
@peterguy When I tested proxy stuff on Windows I would just make the VSIX File(in my macbook environment) by
This would make a
IS that something that would work for you? Or are you perhaps looking at a more complex setup with some sort of packet capture etc? |
const proxyConfig = config.get<{ | ||
server?: string | ||
path?: string | ||
cacert?: string | ||
} | null>(CONFIG_KEY.proxy, null) | ||
|
||
function resolveHomedir(filePath: string | null | undefined): string | undefined { | ||
for (const homeDir of ['~/', '%USERPROFILE%\\']) { | ||
if (filePath?.startsWith(homeDir)) { | ||
return `${os.homedir()}${path.sep}${filePath.slice(homeDir.length)}` | ||
} | ||
} | ||
return filePath ? filePath : undefined | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left this in here because it seems to comply with "some sanitization". Can move to validateProxySettings
if there's too much clutter in here.
return subscriptionDisposable( | ||
resolvedConfig.subscribe(config => setCustomAgent(config.configuration)) | ||
) | ||
return subscriptionDisposable(proxySettings.subscribe(setCustomAgent)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to use the validated proxy settings here, so need to use proxySettings
.
vscode/src/fetch.node.ts
Outdated
const customAgent = setCustomAgent(getConfiguration()) | ||
const customAgent = setCustomAgent( | ||
validateProxySettings({ | ||
configuration: getConfiguration(), | ||
auth: {} as AuthCredentials, | ||
clientState: {} as ClientState, | ||
}) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to manually validate the proxy settings, because I don't know how to get around using getConfiguration()
here. initializeNetworkAgent
is called when the extension is starting up, from vscode/src/extension.node.ts => activate()
. Would like to use a subscription, but not sure how to do that, or if it can be done.
vscode/src/main.ts
Outdated
|
||
proxySettings.subscribe(setCustomAgent) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this how we envision using the config subscription? I'm not sure that getCustomAgent
really conforms to the subscription approach, but I'm not familiar enough with either to make major changes.
proxySettings
is exported from the new configuration-proxy.ts
file because it's used in multiple places.
- add CA cert proxy setting to support self-signed certificates in the proxy - include keepalive and other settings in the new proxy agent
…uration reading tools already in place. - Rename the settings to match the Cody pattern and to conform to the camel case requirements.
…'s home directory.
… self-validating (to some extent) - memoize the verifying of the proxy path file and the reading of the proxy cacert file - memoize the check of the proxy host and port to cut down on repeated error messages to the user - remove logError on config errors because including it caused the code to be called many times over - combine the global agent CA list with the CA from the settings to ensure that the http(s) client doesn't lack required CA certs.
- move the proxy validation code into its own file - use a config subscriber to validate and disseminate the proxy settings - manually validate the proxy settings in initializeNetworkAgent because it's called when the extension starts up and uses getConfiguration() - run pnpm update-agent-recordings
c3432cf
to
3214257
Compare
…es when building for the browser.
Moved to #5883 |
Support extension-specific proxy settings (don't rely on
http(s)_proxy
).Support using a unix domain socket as a proxy.
Add a CA cert setting to enable using proxies with self-signed or not-public certificates.
Closes CODY-3092
Test plan
To test locally:
socat
andmitmproxy
(brew install socat mitmproxy
)git switch peterguy/vscode-add-proxy-settings
socat
to listen on a UDS and send TCP connections tomitm
mitmproxy
. I like to usemitmweb
because it opens a web view of the traffic that is friendly.settings.json
(It's at~/Library/Application Support/Code/User/settings.json
for me; you can also get to it by opening the Command Palette (Cmd-Shift-P), typing "settings" to filter, then selecting "Open User Settings (JSON)".In addition to specifying proxy settings for the Cody extension, it also toggles VSCode's proxy support from
override
toon
. If it's in the defaultoverride
mode, it won't use the proxy agents we set up. I'd like to avoid this requirement, but until we figure out how to do that (probably with more "monkey patching", to quote @RXminuS 😄 ), we have to toggle the proxy support to eitheron
orfallback
.5. Launch the Cody extension via the Run And Debug pane (Cmd-Shift-D), by clicking the green "play" icon at the top of the pane, when "Launch VSCode Extension (Desktop, recommended)" is selected (it's the default).
6. Note the outputs of
socat
andmitmproxy
in the two terminals, and if you launchedmitmweb
, see the requests in the browser. If you are usingmitmweb
you can use the web interface to see the types of requests being made.7. Execute a completion. I used Document Code as a simple triggerable one. If you launched
mitmweb
and are using a non-local LLM model (not Ollama), you should see calls to the completions endpoint in the mitm web page.8. Optional: change the proxy settings to use
mitmproxy
directly. Remove theproxyPath
setting and addproxyHost
andproxyPort
:Then verify again that the extension is still operative. You should still see activity in the terminal that's running
mitmproxy
(ormitmweb
), and themitmweb
web page should show more traffic, but there should be no activity in thesocat
terminal.