Skip to content

azureutils: honor VS Code proxy settings in Azure clients#2356

Open
alexweininger wants to merge 1 commit into
mainfrom
alexweininger-shared-proxy-support
Open

azureutils: honor VS Code proxy settings in Azure clients#2356
alexweininger wants to merge 1 commit into
mainfrom
alexweininger-shared-proxy-support

Conversation

@alexweininger

@alexweininger alexweininger commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

The Azure SDK's built-in proxy policy (@azure/core-rest-pipeline via @typespec/ts-http-runtime) only reads the proxy environment variables (HTTPS_PROXY / HTTP_PROXY / NO_PROXY). It never consults VS Code's http.* settings, and its proxy agent additionally discards TLS settings. On corporate networks where the user configures a proxy through VS Code (rather than env vars), ARM management calls (createAzureClient / createAzureSubscriptionClient) and generic requests (createGenericClient) bypass the proxy and can fail.

This PR closes that proxy-settings gap.

What changed

  • New shared ProxyAgentPolicy (azure/src/utils/ProxyAgentPolicy.ts) that resolves proxy/TLS configuration from VS Code's http.proxy, http.proxyStrictSSL, http.noProxy, and http.proxySupport settings, falling back to the standard proxy environment variables. Resolution is protocol-aware (http: prefers HTTP_PROXY, https: prefers HTTPS_PROXY, with ALL_PROXY as a cross-protocol fallback) and only applies to http(s): request URLs.
  • Wired into addAzExtPipeline, so it applies to createGenericClient, createAzureClient, and createAzureSubscriptionClient across every extension that depends on azureutils (fix once, apply everywhere).
  • Exported two reusable helpers for HTTP clients that do not go through the Azure SDK pipeline: getProxyAgent (for clients that accept an http.Agent) and getProxySettings (for pipeline-based data-plane clients that accept proxyOptions: ProxySettings, e.g. Storage BlobServiceClient / ShareServiceClient, and later Cosmos / Event Hubs / Service Bus).

Public API

export declare function getProxyAgent(requestUrl: string): import('http').Agent | undefined;

export type ProxySettings = import('@azure/core-rest-pipeline').ProxySettings;
export declare function getProxySettings(requestUrl: string): ProxySettings | undefined;
  • getProxyAgent returns an http/https Agent configured from VS Code's proxy settings (or the proxy env vars) for the given request URL, or undefined when no proxy or TLS override applies. It carries the proxyStrictSSL: false TLS override.
  • getProxySettings returns a ProxySettings object (host/port/username/password) for pipeline-based Azure SDK data-plane clients that accept proxyOptions. It shares the same resolver as getProxyAgent but, unlike it, does not carry a TLS (proxyStrictSSL: false) override, since proxyOptions cannot express that.

Behavior

  • Secure VS Code proxy, proxyStrictSSL true (default): injects request.proxySettings and lets the built-in policy build/cache the agent, so NODE_EXTRA_CA_CERTS is still honored.
  • proxyStrictSSL: false (only when explicitly set): owns the agent so the TLS override actually applies to the destination handshake inside the CONNECT tunnel (the built-in agent, and https-proxy-agent's constructor, otherwise drop the destination rejectUnauthorized). Never relaxed by default.
  • Host in http.noProxy (merged with NO_PROXY): no proxy applied.
  • Non-http(s): request URLs (e.g. ftp:): left untouched, no proxy applied.
  • Caller already set request.agent (e.g. sendRequestWithTimeout): left untouched.
  • http.proxySupport: off: this policy is a full no-op and both getProxyAgent and getProxySettings return undefined, even if http.proxy is set. Note that standard proxy environment variables still flow through the Azure SDK's own built-in proxy policy in this case; off opts out of VS Code's setting-based proxy handling, matching the VS Code extension-host default, and fully suppressing env-var proxies is deliberately out of scope for this slice. Default (override) preserves current behavior.
  • No proxy configured / unset: requests go direct, both helpers return undefined.

Known limitations

  • http.noProxy only bypasses proxies that this policy applies. When a proxy comes solely from an environment variable (e.g. HTTPS_PROXY) and http.proxy is unset, the SDK's built-in policy still proxies the request because it consults only NO_PROXY, not VS Code's http.noProxy list.

CA trust

CA-certificate trust is intentionally out of scope here and continues to rely on NODE_EXTRA_CA_CERTS (plus http.systemCertificates), which Node honors globally including through proxy agents. That path is documented separately in microsoft/vscode-azureresourcegroups#1537. This change only closes the separate "SDK ignores the configured proxy" gap.

Testing

  • npm run build, npm run lint (0 warnings), and npm test (vscode-test) all pass in azure/ (57 passing).
  • Unit tests covering isHostBypassed, getProxyAgent, getProxySettings, and ProxyAgentPolicy: secure proxy, insecure TLS override, protocol-aware env-var precedence, ALL_PROXY fallback, non-http(s): schemes, noProxy bypass, caller-set agent, and the proxySupport: off no-op.
  • End-to-end TLS integration tests that stand up a self-signed HTTPS server behind a local CONNECT proxy and assert the request succeeds through the proxy when http.proxyStrictSSL: false and fails with a self-signed-certificate error by default, for both the getProxyAgent export and the agent the policy sets on the request.

Related issues

Related to microsoft/vscode-azurefunctions#5123 and microsoft/vscode-azureappservice#2899 (management half). Motivated by microsoft/vscode-azureresourcegroups#1536.

@alexweininger alexweininger requested a review from a team as a code owner July 1, 2026 15:09
Copilot AI review requested due to automatic review settings July 1, 2026 15:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds proxy/TLS handling that honors VS Code’s http.* settings for Azure SDK clients created via azureutils, and exposes a helper to apply the same behavior to non-pipeline HTTP clients.

Changes:

  • Introduces a new ProxyAgentPolicy plus a getProxyAgent(requestUrl) helper that resolves proxy/TLS settings from VS Code configuration (with env-var fallback).
  • Wires the new policy into addAzExtPipeline so it applies to Azure/generic clients consistently.
  • Adds tests and new runtime dependencies for proxy agent implementations, and exports the new public API.
Show a summary per file
File Description
azure/test/proxyAgent.test.ts Adds coverage for isHostBypassed, getProxyAgent, and ProxyAgentPolicy behaviors.
azure/src/utils/ProxyAgentPolicy.ts New proxy/TLS resolution logic + pipeline policy + exported helper.
azure/src/index.ts Exports getProxyAgent from the package entrypoint.
azure/src/createAzureClient.ts Installs ProxyAgentPolicy into the shared Azure pipeline setup.
azure/package.json Adds http-proxy-agent and https-proxy-agent runtime deps.
azure/package-lock.json Locks new proxy agent dependencies.
azure/index.d.ts Declares the new getProxyAgent public API.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Files not reviewed (1)
  • azure/package-lock.json: Generated file
  • Files reviewed: 5/7 changed files
  • Comments generated: 5
  • Review effort level: Low

Comment thread azure/src/utils/ProxyAgentPolicy.ts Outdated
Comment on lines +56 to +64
function resolveProxyUrl(config: HttpProxyConfig): string | undefined {
if (config.proxyUrl) {
return config.proxyUrl;
}
return process.env.HTTPS_PROXY ?? process.env.https_proxy
?? process.env.ALL_PROXY ?? process.env.all_proxy
?? process.env.HTTP_PROXY ?? process.env.http_proxy
?? undefined;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Made resolveProxyUrl protocol-aware in 3ddf477: http: requests now prefer HTTP_PROXY, https: prefer HTTPS_PROXY, with ALL_PROXY as a cross-protocol fallback. VS Code http.proxy still takes precedence over all env vars. Added a regression test asserting HTTP_PROXY wins for http: URLs.

Comment thread azure/src/utils/ProxyAgentPolicy.ts
Comment thread azure/src/utils/ProxyAgentPolicy.ts Outdated
Comment on lines +197 to +219
const config = getHttpProxyConfig();
// `http.proxySupport: off` is an explicit opt-out: inject no proxySettings or agent.
if (!config.proxySupportEnabled) {
return;
}
const isTls = url.protocol === 'https:';
const bypassed = isHostBypassed(url.hostname, config.noProxy);
const insecure = isTls && config.strictSSL === false;

// Secure proxy from VS Code config: hand off to the built-in policy so it builds/caches the
// agent and honors NODE_EXTRA_CA_CERTS. Env-var proxies are already handled by that policy.
if (config.proxyUrl && !bypassed && !insecure) {
request.proxySettings ??= getDefaultProxySettings(config.proxyUrl);
return;
}

// A TLS override is needed (strictSSL: false), so own the agent — with or without a proxy.
if (insecure) {
const proxyUrl = bypassed ? undefined : resolveProxyUrl(config);
request.agent = proxyUrl
? getProxyAgentForUrl(proxyUrl, isTls, /* rejectUnauthorized */ false)
: getInsecureTlsAgent();
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3ddf477. applyProxy now delegates to the same resolveProxyForRequest() helper, which skips non-http(s) URLs (no proxySettings/agent injected) and resolves env-var proxies protocol-aware for the insecure path. Added a policy test asserting an ftp: request URL is left untouched.

Comment thread azure/test/proxyAgent.test.ts
Comment thread azure/src/createAzureClient.ts Outdated
@alexweininger alexweininger force-pushed the alexweininger-shared-proxy-support branch from f2467ba to 9453727 Compare July 1, 2026 15:26
@alexweininger alexweininger force-pushed the alexweininger-shared-proxy-support branch 2 times, most recently from 3ddf477 to cb40d5c Compare July 1, 2026 19:17
nturinski
nturinski previously approved these changes Jul 1, 2026

@nturinski nturinski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I feel like 80% of the comments copilot writes are way too verbose. Maybe run a session to make them more concise or just remove some of the more self explanatory ones all together?

Comment thread azure/src/utils/ProxyAgentPolicy.ts Outdated
/**
* Adds the policy to `pipeline` (before the built-in proxy policy) unless it is already present.
*/
public static addIfNeeded(pipeline: Pipeline): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really care, but we've never done a pattern of addIfNeeded since it's typically all added at one time anyway. My impression was that this was only added if the user actually had proxy settings though so might be redundant.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, done in 538bc9f. Dropped the addIfNeeded static method and its dedup guard (which was redundant since addAzExtPipeline always runs on a fresh pipeline) and just add the policy inline like the sibling policies: pipeline.addPolicy(new ProxyAgentPolicy(), { beforePolicies: [proxyPolicyName] }). To clarify the redundancy you flagged: the policy is always added; it decides per-request whether any proxy/TLS handling applies (unset/off/noProxy all short-circuit to a no-op), so there's no cost when the user has no proxy configured.

The Azure SDK's built-in proxy policy reads only proxy environment
variables (HTTPS_PROXY/HTTP_PROXY/NO_PROXY) and never consults VS Code's
`http.proxy` / `http.proxyStrictSSL` / `http.noProxy` settings. Its proxy
agent also discards TLS settings. On corporate networks that require an
explicit VS Code proxy, ARM and generic requests therefore bypass the
proxy and can fail.

Add a shared ProxyAgentPolicy and two exported helpers that resolve
proxy/TLS configuration from VS Code's http settings, falling back to the
standard proxy env vars:

- getProxyAgent(requestUrl): an http/https Agent for clients that accept
  a raw agent (also carries an http.proxyStrictSSL:false TLS override).
- getProxySettings(requestUrl): a ProxySettings object for pipeline-based
  Azure SDK data-plane clients that accept proxyOptions (e.g. Storage's
  BlobServiceClient/ShareServiceClient); no TLS override since
  proxyOptions cannot express one.

The policy is wired into addAzExtPipeline so it applies to
createGenericClient, createAzureClient, and createAzureSubscriptionClient.
TLS validation is only relaxed when http.proxyStrictSSL is explicitly
false, and http.proxySupport: off makes the policy a no-op. CA trust
continues to rely on NODE_EXTRA_CA_CERTS (documented separately in
vscode-azureresourcegroups#1537), which Node honors globally including
through proxy agents.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@alexweininger

Copy link
Copy Markdown
Member Author

Thanks for the review @nturinski. Addressed both notes in 538bc9f:

  • Trimmed the verbose comments across ProxyAgentPolicy.ts / createAzureClient.ts (net -90 lines): removed the self-explanatory JSDoc and redundant restatements, and kept only the non-obvious ones worth keeping (the https-proxy-agent .options workaround, the proxySupport:off design intent, and the http.noProxy env-var limitation).
  • Removed the addIfNeeded pattern and add the policy inline like the sibling policies (see the thread above).

build/lint/test all green (57 passing).

@alexweininger alexweininger requested a review from nturinski July 2, 2026 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants