mirror of
https://github.com/n8n-io/n8n
synced 2026-04-21 15:47:20 +00:00
fix: Use http proxy for source control git commands (#24104)
This commit is contained in:
parent
dd1daaba9b
commit
116b245230
2 changed files with 124 additions and 0 deletions
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue