fix: build api-proxy locally while pulling other containers from GHCR#798
Conversation
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
|
@claude[agent] i only want to build api-proxy locally. all other containers should be pulled from ghcr.io |
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Done! Changed the implementation to build only api-proxy locally while pulling squid and agent from GHCR. Modified Commit: 0be402e |
There was a problem hiding this comment.
Pull request overview
Updates Docker Compose generation to avoid pulling the api-proxy image from GHCR (where it isn’t published) by always building api-proxy locally, while continuing to pull other containers from GHCR for speed.
Changes:
- Removed the
useGHCRbranching forapi-proxyand always sets a localbuildconfig. - Added comments/TODO indicating this is temporary until
api-proxyis published to GHCR.
Comments suppressed due to low confidence (2)
src/docker-manager.ts:938
- This change forces api-proxy to always use
build, soservices['api-proxy'].imageis never set. That regresses the previously supported/tested behavior of pulling api-proxy from the configuredimageRegistry/imageTagwhenbuildLocalis false (including custom registries), and will break existing unit tests that assertproxy.imagefor GHCR/custom registry cases. Consider preserving an image-based path when the user has explicitly set a custom registry/tag (or add a dedicated override for the api-proxy image), and update the corresponding tests to match the intended behavior.
// Always build api-proxy locally since it's not published to GHCR yet
// TODO: Once api-proxy image is published to GHCR, change this to use useGHCR like other containers
proxyService.build = {
context: path.join(projectRoot, 'containers/api-proxy'),
dockerfile: 'Dockerfile',
};
src/docker-manager.ts:938
- With api-proxy always built and no explicit
imagename set,docker compose upwill tag the built image using the Compose project name (derived from the per-run tempworkDir). That can create a new, uniquely named api-proxy image on every run and leave lots of dangling images, increasing disk usage over time/CI runs. Consider setting an explicit, stableimagename alongsidebuild(or otherwise ensuring the build output is reused/cleaned up).
proxyService.build = {
context: path.join(projectRoot, 'containers/api-proxy'),
dockerfile: 'Dockerfile',
};
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Always build api-proxy locally since it's not published to GHCR yet | ||
| // TODO: Once api-proxy image is published to GHCR, change this to use useGHCR like other containers | ||
| proxyService.build = { | ||
| context: path.join(projectRoot, 'containers/api-proxy'), | ||
| dockerfile: 'Dockerfile', | ||
| }; |
There was a problem hiding this comment.
Always building api-proxy means --skip-pull can still trigger network pulls indirectly (e.g., pulling the api-proxy Dockerfile base image) even though the CLI validation only prevents --skip-pull with --build-local. If --skip-pull is intended to avoid any registry access, consider extending the validation/docs for this new behavior or adding logic to avoid/handle api-proxy builds when skipPull is set.
This issue also appears in the following locations of the same file:
- line 933
- line 935
See below for a potential fix:
if (config.skipPull) {
// When skipPull/--skip-pull is set, avoid building the api-proxy image since
// a Docker build may still trigger network pulls for base images.
logger.info(
'API proxy sidecar is disabled because --skip-pull was set; api-proxy requires a local build that may pull base images.'
);
} else {
const proxyService: any = {
container_name: 'awf-api-proxy',
networks: {
'awf-net': {
ipv4_address: networkConfig.proxyIp,
},
},
environment: {
// Pass API keys securely to sidecar (not visible to agent)
...(config.openaiApiKey && { OPENAI_API_KEY: config.openaiApiKey }),
...(config.anthropicApiKey && { ANTHROPIC_API_KEY: config.anthropicApiKey }),
// Route through Squid to respect domain whitelisting
HTTP_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
HTTPS_PROXY: `http://${networkConfig.squidIp}:${SQUID_PORT}`,
},
healthcheck: {
test: ['CMD', 'curl', '-f', 'http://localhost:10000/health'],
interval: '5s',
timeout: '3s',
retries: 5,
start_period: '5s',
},
// Security hardening: Drop all capabilities
cap_drop: ['ALL'],
security_opt: [
'no-new-privileges:true',
],
// Resource limits to prevent DoS attacks
mem_limit: '512m',
memswap_limit: '512m',
pids_limit: 100,
cpu_shares: 512,
};
// Always build api-proxy locally since it's not published to GHCR yet
// TODO: Once api-proxy image is published to GHCR, change this to use useGHCR like other containers
proxyService.build = {
context: path.join(projectRoot, 'containers/api-proxy'),
dockerfile: 'Dockerfile',
};
services['api-proxy'] = proxyService;
// Update agent dependencies to wait for api-proxy
agentService.depends_on['api-proxy'] = {
condition: 'service_healthy',
};
// Set environment variables in agent to use the proxy
if (config.openaiApiKey) {
environment.OPENAI_BASE_URL = `http://api-proxy:10000`;
logger.debug('OpenAI API will be proxied through sidecar at http://api-proxy:10000');
}
if (config.anthropicApiKey) {
environment.ANTHROPIC_BASE_URL = `http://api-proxy:10001`;
logger.debug('Anthropic API will be proxied through sidecar at http://api-proxy:10001');
}
logger.info('API proxy sidecar enabled - API keys will be held securely in sidecar container');
logger.info('API proxy will route through Squid to respect domain whitelisting');
}
The test-examples workflow was failing because example scripts attempted to pull
ghcr.io/github/gh-aw-firewall/api-proxy:latestfrom GHCR, but this image hasn't been published yet. Docker returned "error from registry: denied" causing all example tests to fail.Changes
src/docker-manager.tsto always build the api-proxy container locally (lines 933-938)This approach provides the best of both worlds: fast container startup for squid and agent (pulled from registry) while ensuring api-proxy works correctly (built from source since it's not published to GHCR yet).
Container Image Strategy
containers/api-proxy/Dockerfileghcr.io/github/gh-aw-firewall/squid:latestghcr.io/github/gh-aw-firewall/agent:latestUsers don't need to specify
--build-localflag. The api-proxy container will automatically be built locally when needed, while other containers are pulled from GHCR.Future Work
Once the api-proxy image is published to GHCR in a future release, the build logic in
src/docker-manager.tscan be updated to use the registry image like other containers (see TODO comment in the code).