Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/services/agent-environment/proxy-environment.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { WrapperConfig } from '../../types';
import { NetworkConfig } from '../squid-service';
import { buildNoProxyValue } from '../no-proxy-utils';

interface ProxyEnvironmentParams {
config: WrapperConfig;
Expand All @@ -10,21 +11,21 @@ interface ProxyEnvironmentParams {
export function buildProxyEnvironment(params: ProxyEnvironmentParams): void {
const { config, networkConfig, environment } = params;

environment.NO_PROXY = `localhost,127.0.0.1,::1,0.0.0.0,${networkConfig.squidIp},${networkConfig.agentIp}`;
environment.no_proxy = environment.NO_PROXY;
const noProxyHosts: string[] = ['0.0.0.0', networkConfig.squidIp, networkConfig.agentIp];

if (config.enableHostAccess) {
const subnetBase = networkConfig.subnet.split('/')[0];
const parts = subnetBase.split('.');
const networkGatewayIp = `${parts[0]}.${parts[1]}.${parts[2]}.1`;
environment.NO_PROXY += `,host.docker.internal,${networkGatewayIp}`;
environment.no_proxy = environment.NO_PROXY;
noProxyHosts.push('host.docker.internal', networkGatewayIp);
}

if (config.enableApiProxy && networkConfig.proxyIp) {
// Include both IP and Docker service hostname — Node.js undici matches
// NO_PROXY against the request hostname string, not the resolved IP.
environment.NO_PROXY += `,${networkConfig.proxyIp},api-proxy`;
environment.no_proxy = environment.NO_PROXY;
noProxyHosts.push(networkConfig.proxyIp, 'api-proxy');
}

environment.NO_PROXY = buildNoProxyValue(noProxyHosts);
environment.no_proxy = environment.NO_PROXY;
}
4 changes: 2 additions & 2 deletions src/services/api-proxy-env-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { WrapperConfig } from '../types';
import { getConfigEnvValue, getLowerCaseProcessEnvValue, pickEnvVars } from '../env-utils';
import { OPENAI_ENV, ANTHROPIC_ENV, GEMINI_ENV, COPILOT_ENV, VERTEX_ENV, OIDC_AUTH_ENV_VARS, OIDC_AUTH_ENV_MAPPING } from '../api-proxy-env-constants';
import { NetworkConfig } from './squid-service';
import { buildNoProxyEnv } from './no-proxy-utils';

const DEFAULT_API_PROXY_SHUTDOWN_TIMEOUT_MS = 8000;

Expand Down Expand Up @@ -141,8 +142,7 @@ function buildProxyRoutingEnv(networkConfig: NetworkConfig): Record<string, stri
HTTPS_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
https_proxy: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
// Prevent curl health check from routing localhost through Squid
NO_PROXY: 'localhost,127.0.0.1,::1',
no_proxy: 'localhost,127.0.0.1,::1',
...buildNoProxyEnv(),
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/cli-proxy-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { WrapperConfig, CLI_PROXY_PORT } from '../types';
import { NetworkConfig, ImageBuildConfig } from './squid-service';
import { applyHostPathPrefixToVolumes } from './host-path-prefix';
import { buildContainerSecurityHardening } from './service-security';
import { buildNoProxyEnv } from './no-proxy-utils';

interface CliProxyBuildResult {
/** The cli-proxy service definition to add to Docker Compose services. */
Expand Down Expand Up @@ -76,8 +77,7 @@ export function buildCliProxyService(params: CliProxyServiceParams): CliProxyBui
...(process.env.GH_TOKEN && { GH_TOKEN: process.env.GH_TOKEN }),
...(process.env.GITHUB_TOKEN && !process.env.GH_TOKEN && { GH_TOKEN: process.env.GITHUB_TOKEN }),
// Prevent curl/node from routing localhost or host.docker.internal through Squid
NO_PROXY: `localhost,127.0.0.1,::1,host.docker.internal`,
no_proxy: `localhost,127.0.0.1,::1,host.docker.internal`,
...buildNoProxyEnv(['host.docker.internal']),
},
healthcheck: {
test: ['CMD', 'curl', '-f', `http://127.0.0.1:${CLI_PROXY_PORT}/health`],
Expand Down
29 changes: 29 additions & 0 deletions src/services/no-proxy-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Loopback addresses that are always excluded from proxy routing.
* All three proxy environments (agent, api-proxy, cli-proxy) share this baseline.
*/
const LOOPBACK_NO_PROXY_HOSTS = ['localhost', '127.0.0.1', '::1'];

/**
* Builds the NO_PROXY / no_proxy value from loopback defaults and any
* service-specific additional host bypasses.
*
* @param additionalHosts - Extra hosts/IPs to exclude from proxy routing.
*/
export function buildNoProxyValue(additionalHosts: string[] = []): string {
return [...LOOPBACK_NO_PROXY_HOSTS, ...additionalHosts.filter(Boolean)].join(',');
}

/**
* Returns `{ NO_PROXY, no_proxy }` set to the same value, composed from the
* loopback defaults and any service-specific additional host bypasses.
*
* Using this helper keeps `NO_PROXY`/`no_proxy` behaviour consistent across the
* agent, api-proxy, and cli-proxy environment builders and avoids bypass regressions.
*
* @param additionalHosts - Extra hosts/IPs to exclude from proxy routing.
*/
export function buildNoProxyEnv(additionalHosts: string[] = []): { NO_PROXY: string; no_proxy: string } {
const value = buildNoProxyValue(additionalHosts);
return { NO_PROXY: value, no_proxy: value };
}
Loading