Skip to content

feat: add upstream proxy configuration for outbound requests#1458

Open
Andreybest wants to merge 10 commits intofinos:mainfrom
Andreybest:759-upstream-proxy
Open

feat: add upstream proxy configuration for outbound requests#1458
Andreybest wants to merge 10 commits intofinos:mainfrom
Andreybest:759-upstream-proxy

Conversation

@Andreybest
Copy link
Copy Markdown

Resolves #759.

Adds upstream proxy support. Uses values from both configuration file in upstreamProxy fields and environment variables (HTTPS_PROXY/HTTP_PROXY, NO_PROXY)

@Andreybest Andreybest requested a review from a team as a code owner March 16, 2026 03:17
@netlify
Copy link
Copy Markdown

netlify Bot commented Mar 16, 2026

Deploy Preview for endearing-brigadeiros-63f9d0 canceled.

Name Link
🔨 Latest commit 790aa6c
🔍 Latest deploy log https://app.netlify.com/projects/endearing-brigadeiros-63f9d0/deploys/69e80298d27d8a0008495679

@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented Mar 16, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

@Andreybest Andreybest requested a review from kriswest March 16, 2026 03:17
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 16, 2026

Codecov Report

❌ Patch coverage is 81.44330% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.06%. Comparing base (6981427) to head (790aa6c).

Files with missing lines Patch % Lines
src/proxy/routes/index.ts 81.11% 17 Missing ⚠️
src/config/index.ts 85.71% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1458      +/-   ##
==========================================
- Coverage   90.21%   90.06%   -0.16%     
==========================================
  Files          69       69              
  Lines        5511     5607      +96     
  Branches      944      976      +32     
==========================================
+ Hits         4972     5050      +78     
- Misses        521      539      +18     
  Partials       18       18              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@jescalada jescalada left a comment

Choose a reason for hiding this comment

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

@Andreybest Thanks for the contribution! 🚀

I left some comments for code refactoring. It'd be very helpful if you could upload images or a video demonstrating that this feature works as intended.

@coopernetes Wondering if this implements your original requirements (#759) and works on your end 🤔

Comment thread config.schema.json
Comment thread src/proxy/routes/index.ts Outdated
Comment thread src/proxy/routes/index.ts Outdated
Comment thread src/proxy/routes/index.ts Outdated
Comment thread src/proxy/routes/index.ts Outdated
Comment thread src/proxy/routes/index.ts Outdated
Comment thread src/proxy/routes/index.ts Outdated
Comment thread src/proxy/routes/index.ts Outdated
Comment thread src/proxy/routes/index.ts Outdated
Comment thread test/upstreamProxy.test.ts
Copy link
Copy Markdown
Contributor

@dcoric dcoric left a comment

Choose a reason for hiding this comment

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

Thanks for tackling #759. I've left a few comments focused on correctness and robustness, especially around NO_PROXY pattern handling which is important to get right for the target use case. The main items are the missing */leading-dot NO_PROXY support and proxy URL validation.

Comment thread src/proxy/routes/index.ts
Comment thread src/proxy/routes/index.ts Outdated
return undefined;
}

return new HttpsProxyAgent(proxyUrl);
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.

The proxyUrl (from config or env vars) is passed directly to new HttpsProxyAgent(proxyUrl) without validation. If the URL is malformed (typo, missing protocol, empty string after trimming), this throws a cryptic Invalid URL error that surfaces through express-http-proxy's error handler with no indication that the upstream proxy config is the problem.

Consider wrapping this in a try-catch or validating first:

try {
  new URL(proxyUrl); // validate before constructing agent
} catch {
  throw new Error(`Invalid upstream proxy URL: check your upstreamProxy.url config or HTTPS_PROXY env var`);
}
return new HttpsProxyAgent(proxyUrl);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added

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.

This comment might still need fixing! 🙂

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Don't know how I've missed it, added, thanks @jescalada and @dcoric !

Comment thread docs/Architecture.md
Comment thread src/proxy/routes/index.ts
Comment thread src/config/index.ts Fixed
@Andreybest
Copy link
Copy Markdown
Author

Thanks for the reviews @jescalada and @dcoric!
Made changes and left comments for your comments. Please recheck :)

@Andreybest
Copy link
Copy Markdown
Author

@jescalada
Here is the video on how the proxy works:

Screen.Recording.2026-03-25.at.21.35.35_no_audio.mov

Comment thread proxy.config.json Outdated
Co-authored-by: Thomas Cooper <[email protected]>
Signed-off-by: Andrew <[email protected]>
Copy link
Copy Markdown
Contributor

@jescalada jescalada left a comment

Choose a reason for hiding this comment

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

LGTM after fixing Denis' comment about validating/error handling the HttpsProxyAgent creation.

@coopernetes Does everything work as you expected? 🤔

Comment thread src/proxy/routes/index.ts

const getOrCreateProxyAgent = (proxyUrl: string): HttpsProxyAgent<string> => {
if (!_cachedProxyAgent || _cachedProxyAgent.proxyUrl !== proxyUrl) {
_cachedProxyAgent = { proxyUrl, agent: new HttpsProxyAgent(proxyUrl) };
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.

Just repeating Denis earlier comment - this should be properly validated and/or throw a descriptive error

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added, thanks for remind :)

Comment thread src/proxy/routes/index.ts Outdated
return undefined;
}

return new HttpsProxyAgent(proxyUrl);
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.

This comment might still need fixing! 🙂

Comment thread src/proxy/routes/index.ts
Comment thread src/proxy/routes/index.ts Outdated

const proxyUrl = url || getEnvProxyUrl();

if (enabled === false || !proxyUrl) {
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.

I think the env-var-only path is still broken. proxy.config.json is imported as the default config, and it now contains upstreamProxy.enabled: false. When a user omits upstreamProxy from their config and relies only on HTTPS_PROXY/HTTP_PROXY, the merged config still has enabled === false, so buildUpstreamProxyAgent() returns before using the env var. This contradicts the docs saying env vars enable proxying when upstreamProxy is not configured. The current test mocks getUpstreamProxyConfig() as {}, so it does not cover the real default-config path. Can we either remove upstreamProxy from the shipped default config, distinguish “unset” from explicitly disabled, or change the documented behavior and add a test for the default merge?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I don't know how I've missed it, but now it's fixed. Unset enable now is treated as false. Thanks!

Comment thread src/proxy/routes/index.ts Outdated
const getOrCreateProxyAgent = (proxyUrl: string): HttpsProxyAgent<string> => {
if (!_cachedProxyAgent || _cachedProxyAgent.proxyUrl !== proxyUrl) {
try {
new URL(proxyUrl);
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.

This validation still accepts values that are syntactically parseable URLs but not valid HTTP(S) proxy URLs. For example, new URL("socks5://proxy.example.com:1080"), new URL("ftp://proxy.example.com:21"), and even new URL("localhost:8081") all succeed. HttpsProxyAgent also constructs for those values, then treats non-https: schemes as plain TCP proxy connections, so the user gets a later connectivity failure instead of a descriptive config error. Can we parse once, require protocol to be http: or https:, require a non-empty hostname, and add tests for unsupported schemes and missing protocol?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added checks to accept only https and http, and for hostname to exist.

Copy link
Copy Markdown
Contributor

@coopernetes coopernetes left a comment

Choose a reason for hiding this comment

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

LGTM. The only rub is the lack of direct authentication support in the proxy agent. Many client and server libraries do not implement auth directly so it's fine to leave it out for now. Worth making a follow up issue to add HTTP Basic and NTLM (Windows) auth support which are the two most common methods (at least that I'm aware of).

@kriswest
Copy link
Copy Markdown
Contributor

Worth making a follow up issue to add HTTP Basic and NTLM (Windows) auth support which are the two most common methods (at least that I'm aware of).

I'd suggest making that HTTP Basic, NTLM and Negotiate (the negotiate protocol is used to detect support for NTLM or Kerberos auth and then kick off which ever is supported).

@Andreybest
Copy link
Copy Markdown
Author

@dcoric Thank you again for the review! Can you please check again? :)

@Andreybest Andreybest requested a review from dcoric April 21, 2026 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose proxy support within GitProxy itself for air gapped environments

6 participants