fix: Use http proxy for source control git commands (#24104)

This commit is contained in:
Irénée 2026-01-12 13:49:20 +00:00 committed by GitHub
parent dd1daaba9b
commit 116b245230
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 124 additions and 0 deletions

View file

@ -229,6 +229,120 @@ describe('SourceControlGitService', () => {
);
expect(mockGitInstance.env).toHaveBeenCalledWith('GIT_TERMINAL_PROMPT', '0');
});
describe('proxy configuration', () => {
const originalEnv = process.env;
beforeEach(() => {
process.env = { ...originalEnv };
delete process.env.HTTP_PROXY;
delete process.env.HTTPS_PROXY;
delete process.env.http_proxy;
delete process.env.https_proxy;
delete process.env.NO_PROXY;
delete process.env.no_proxy;
delete process.env.ALL_PROXY;
delete process.env.all_proxy;
(simpleGit as jest.Mock).mockClear();
});
afterEach(() => {
process.env = originalEnv;
});
it('should add http.proxy config when HTTPS_PROXY is set for https repository', async () => {
const credentials = { username: 'testuser', password: 'testpass' };
const repositoryUrl = 'https://github.com/user/repo.git';
const proxyUrl = 'http://proxy.company.com:8080';
process.env.HTTPS_PROXY = proxyUrl;
mockSourceControlPreferencesService.getPreferences.mockReturnValue({
connectionType: 'https',
repositoryUrl,
} as never);
mockSourceControlPreferencesService.getDecryptedHttpsCredentials.mockResolvedValue(
credentials,
);
await sourceControlGitService.setGitCommand();
// Git uses http.proxy for both HTTP and HTTPS URLs
const simpleGitCalls = (simpleGit as jest.Mock).mock.calls;
expect(simpleGitCalls.length).toBeGreaterThan(0);
const lastCallConfig = simpleGitCalls[simpleGitCalls.length - 1][0].config;
expect(lastCallConfig).toContain(`http.proxy=${proxyUrl}`);
});
it('should add http.proxy config when HTTP_PROXY is set for http repository', async () => {
const credentials = { username: 'testuser', password: 'testpass' };
const repositoryUrl = 'http://internal-git.company.com/repo.git';
const proxyUrl = 'http://proxy.company.com:8080';
process.env.HTTP_PROXY = proxyUrl;
mockSourceControlPreferencesService.getPreferences.mockReturnValue({
connectionType: 'https',
repositoryUrl,
} as never);
mockSourceControlPreferencesService.getDecryptedHttpsCredentials.mockResolvedValue(
credentials,
);
await sourceControlGitService.setGitCommand();
const simpleGitCalls = (simpleGit as jest.Mock).mock.calls;
expect(simpleGitCalls.length).toBeGreaterThan(0);
const lastCallConfig = simpleGitCalls[simpleGitCalls.length - 1][0].config;
expect(lastCallConfig).toContain(`http.proxy=${proxyUrl}`);
});
it('should not add proxy config when no proxy environment variables are set', async () => {
const credentials = { username: 'testuser', password: 'testpass' };
const repositoryUrl = 'https://github.com/user/repo.git';
mockSourceControlPreferencesService.getPreferences.mockReturnValue({
connectionType: 'https',
repositoryUrl,
} as never);
mockSourceControlPreferencesService.getDecryptedHttpsCredentials.mockResolvedValue(
credentials,
);
await sourceControlGitService.setGitCommand();
const simpleGitCalls = (simpleGit as jest.Mock).mock.calls;
expect(simpleGitCalls.length).toBeGreaterThan(0);
const lastCallConfig = simpleGitCalls[simpleGitCalls.length - 1][0].config as string[];
const hasProxyConfig = lastCallConfig.some((c: string) => c.includes('proxy='));
expect(hasProxyConfig).toBe(false);
});
it('should respect NO_PROXY and not add proxy config when repository matches', async () => {
const credentials = { username: 'testuser', password: 'testpass' };
const repositoryUrl = 'https://github.com/user/repo.git';
const proxyUrl = 'http://proxy.company.com:8080';
process.env.HTTPS_PROXY = proxyUrl;
process.env.NO_PROXY = 'github.com';
mockSourceControlPreferencesService.getPreferences.mockReturnValue({
connectionType: 'https',
repositoryUrl,
} as never);
mockSourceControlPreferencesService.getDecryptedHttpsCredentials.mockResolvedValue(
credentials,
);
await sourceControlGitService.setGitCommand();
const simpleGitCalls = (simpleGit as jest.Mock).mock.calls;
expect(simpleGitCalls.length).toBeGreaterThan(0);
const lastCallConfig = simpleGitCalls[simpleGitCalls.length - 1][0].config as string[];
const hasProxyConfig = lastCallConfig.some((c: string) => c.includes('proxy='));
expect(hasProxyConfig).toBe(false);
});
});
});
describe('getFileContent', () => {

View file

@ -4,6 +4,7 @@ import { Service } from '@n8n/di';
import { execSync } from 'child_process';
import { UnexpectedError } from 'n8n-workflow';
import path from 'path';
import proxyFromEnv from 'proxy-from-env';
import type {
CommitResult,
DiffResult,
@ -134,6 +135,15 @@ export class SourceControlGitService {
],
};
// Add proxy configuration if proxy environment variables are set
const repositoryUrl = preferences.repositoryUrl;
const proxyUrl = proxyFromEnv.getProxyForUrl(repositoryUrl);
if (proxyUrl) {
// Git uses http.proxy for both HTTP and HTTPS URLs
this.logger.debug('Proxy configuration added', { proxyUrl });
httpsGitOptions.config.push(`http.proxy=${proxyUrl}`);
}
this.git = simpleGit(httpsGitOptions).env('GIT_TERMINAL_PROMPT', '0');
} else if (preferences.connectionType === 'ssh') {
const privateKeyPath = await this.sourceControlPreferencesService.getPrivateKeyPath();