Skip to content

Commit b268021

Browse files
fix: add new method to compare proxy environment settings (#3529)
* fix: add new method to compare proxy environment settings * fix: fix sonar issue * fix: remove regex and update test to cover change * Linting auto fix commit * removed enum --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 8495ee5 commit b268021

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed

.changeset/large-bugs-pump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sap-ux/nodejs-utils': patch
3+
---
4+
5+
Compare proxy to environment variables

packages/nodejs-utils/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './commandRunner';
22
export * from './installedCheck';
33
export * from './httpsUtils';
4+
export * from './proxyCheck';
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
export const ProxyValidationStatus = {
2+
NO_PROXY: 'no-proxy',
3+
MATCH: 'match',
4+
MISMATCH: 'mismatch',
5+
ENV_ONLY: 'env-only',
6+
PARAM_ONLY: 'param-only'
7+
} as const;
8+
9+
export type ProxyValidationStatus = (typeof ProxyValidationStatus)[keyof typeof ProxyValidationStatus];
10+
11+
export interface ProxyValidationResult {
12+
isValid: boolean;
13+
status: ProxyValidationStatus;
14+
message: string;
15+
envProxy?: string;
16+
providedProxy?: string;
17+
}
18+
19+
const PROXY_ENV_VARS = ['HTTP_PROXY', 'http_proxy', 'HTTPS_PROXY', 'https_proxy'] as const;
20+
21+
const getEnvProxy = (): string | undefined => {
22+
for (const envVar of PROXY_ENV_VARS) {
23+
const value = process.env[envVar];
24+
if (value && value.trim() !== '') {
25+
return value;
26+
}
27+
}
28+
return undefined;
29+
};
30+
31+
const normalizeProxy = (value?: string): string | undefined => {
32+
let result = value?.trim().toLowerCase();
33+
while (result?.endsWith('/')) {
34+
result = result.slice(0, -1);
35+
}
36+
return result || undefined;
37+
};
38+
39+
/**
40+
* Validates if the proxy settings match against the process.env proxy settings. Typically used to ensure that the proxy settings in VSCode match those in the environment.
41+
*
42+
* @param {string} [proxy] - The proxy setting to validate. If not provided, it will check the environment variables.
43+
* @returns {ProxyValidationResult} - An object containing the validation result, status, and messages.
44+
*/
45+
export function validateProxySettings(proxy?: string): ProxyValidationResult {
46+
const envProxy = getEnvProxy();
47+
const normalizedEnvProxy = normalizeProxy(envProxy);
48+
const normalizedProxy = normalizeProxy(proxy);
49+
50+
// Exit early if no proxy settings are provided
51+
if (!(normalizedEnvProxy || normalizedProxy)) {
52+
return {
53+
isValid: true,
54+
status: ProxyValidationStatus.NO_PROXY,
55+
message: 'No proxy settings configured.',
56+
providedProxy: undefined,
57+
envProxy: envProxy
58+
};
59+
}
60+
61+
// Only environment proxy is set
62+
if (normalizedEnvProxy && !normalizedProxy) {
63+
return {
64+
isValid: false,
65+
status: ProxyValidationStatus.ENV_ONLY,
66+
message: 'Using environment proxy settings.',
67+
envProxy: normalizedEnvProxy,
68+
providedProxy: undefined
69+
};
70+
}
71+
72+
// Only provided proxy is set
73+
if (!normalizedEnvProxy && normalizedProxy) {
74+
return {
75+
isValid: false,
76+
status: ProxyValidationStatus.PARAM_ONLY,
77+
message: `Using provided (${normalizedProxy}) proxy settings.`,
78+
envProxy: undefined,
79+
providedProxy: normalizedProxy
80+
};
81+
}
82+
83+
// Both exist and match
84+
if (normalizedEnvProxy === normalizedProxy) {
85+
return {
86+
isValid: true,
87+
status: ProxyValidationStatus.MATCH,
88+
message: `Proxy settings match.`,
89+
envProxy: normalizedEnvProxy,
90+
providedProxy: normalizedProxy
91+
};
92+
}
93+
94+
// Both exist but don't match
95+
return {
96+
isValid: false,
97+
status: ProxyValidationStatus.MISMATCH,
98+
message: `Proxy settings conflict between environment (${normalizedEnvProxy}) and parameter (${normalizedProxy}).`,
99+
envProxy: normalizedEnvProxy,
100+
providedProxy: normalizedProxy
101+
};
102+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { validateProxySettings } from '../../src/proxyCheck';
2+
3+
describe('Proxy check', () => {
4+
// Store original environment variables
5+
const originalEnv = process.env;
6+
7+
beforeEach(() => {
8+
// Clear all proxy-related environment variables before each test
9+
jest.resetModules();
10+
process.env = { ...originalEnv };
11+
delete process.env.HTTP_PROXY;
12+
delete process.env.http_proxy;
13+
delete process.env.HTTPS_PROXY;
14+
delete process.env.https_proxy;
15+
});
16+
17+
afterAll(() => {
18+
// Restore original environment variables
19+
process.env = originalEnv;
20+
});
21+
22+
it('should return no-proxy status', () => {
23+
const result = validateProxySettings();
24+
expect(result).toEqual({
25+
isValid: true,
26+
status: 'no-proxy',
27+
message: 'No proxy settings configured.'
28+
});
29+
});
30+
31+
it('should return no-proxy status when proxy parameter is empty string', () => {
32+
const result = validateProxySettings('');
33+
expect(result).toEqual({
34+
isValid: true,
35+
status: 'no-proxy',
36+
message: 'No proxy settings configured.'
37+
});
38+
});
39+
40+
it('should return no-proxy status when proxy parameter is only whitespace', () => {
41+
const result = validateProxySettings(' ');
42+
expect(result).toEqual({
43+
isValid: true,
44+
status: 'no-proxy',
45+
message: 'No proxy settings configured.'
46+
});
47+
});
48+
49+
it('should return env-only status with HTTPS_PROXY', () => {
50+
process.env.HTTPS_PROXY = 'https://secure-proxy.company.com:8443/';
51+
const result = validateProxySettings();
52+
expect(result).toEqual({
53+
isValid: false,
54+
status: 'env-only',
55+
message: 'Using environment proxy settings.',
56+
envProxy: 'https://secure-proxy.company.com:8443'
57+
});
58+
});
59+
60+
it('should return param-only status when only proxy parameter is provided', () => {
61+
const result = validateProxySettings('http://param-proxy.com:3128');
62+
expect(result).toEqual({
63+
isValid: false,
64+
status: 'param-only',
65+
message: 'Using provided (http://param-proxy.com:3128) proxy settings.',
66+
providedProxy: 'http://param-proxy.com:3128'
67+
});
68+
});
69+
70+
it('should return mismatch status when proxies differ', () => {
71+
process.env.HTTP_PROXY = 'http://env-proxy.com:8080';
72+
const result = validateProxySettings('http://param-proxy.com:3128');
73+
expect(result).toEqual({
74+
isValid: false,
75+
status: 'mismatch',
76+
message:
77+
'Proxy settings conflict between environment (http://env-proxy.com:8080) and parameter (http://param-proxy.com:3128).',
78+
envProxy: 'http://env-proxy.com:8080',
79+
providedProxy: 'http://param-proxy.com:3128'
80+
});
81+
});
82+
83+
it('should detect mismatch with different protocols', () => {
84+
process.env.HTTP_PROXY = 'http://proxy.company.com:8080';
85+
const result = validateProxySettings('https://proxy.company.com:8080');
86+
expect(result.isValid).toBe(false);
87+
expect(result.status).toBe('mismatch');
88+
});
89+
90+
it('should return match status when environment and parameter proxies are identical', () => {
91+
process.env.HTTP_PROXY = 'http://proxy.company.com:8080';
92+
const result = validateProxySettings('http://proxy.company.com:8080');
93+
expect(result).toEqual({
94+
isValid: true,
95+
status: 'match',
96+
message: 'Proxy settings match.',
97+
envProxy: 'http://proxy.company.com:8080',
98+
providedProxy: 'http://proxy.company.com:8080'
99+
});
100+
});
101+
});

0 commit comments

Comments
 (0)