Skip to content

fix: build api-proxy locally while pulling other containers from GHCR#798

Merged
lpcox merged 4 commits intoclaude/enable-api-proxy-by-defaultfrom
claude/fix-github-actions-workflow-another-one
Feb 13, 2026
Merged

fix: build api-proxy locally while pulling other containers from GHCR#798
lpcox merged 4 commits intoclaude/enable-api-proxy-by-defaultfrom
claude/fix-github-actions-workflow-another-one

Conversation

@Claude
Copy link
Contributor

@Claude Claude AI commented Feb 13, 2026

The test-examples workflow was failing because example scripts attempted to pull ghcr.io/github/gh-aw-firewall/api-proxy:latest from GHCR, but this image hasn't been published yet. Docker returned "error from registry: denied" causing all example tests to fail.

Changes

  • Modified src/docker-manager.ts to always build the api-proxy container locally (lines 933-938)
  • Squid and agent containers continue to be pulled from GHCR for faster startup

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

  • api-proxy: Always built locally from containers/api-proxy/Dockerfile
  • squid-proxy: Pulled from ghcr.io/github/gh-aw-firewall/squid:latest
  • agent: Pulled from ghcr.io/github/gh-aw-firewall/agent:latest

Users don't need to specify --build-local flag. 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.ts can be updated to use the registry image like other containers (see TODO comment in the code).

Claude AI and others added 2 commits February 13, 2026 04:07
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
@Claude Claude AI changed the title [WIP] Fix failing GitHub Actions workflow for test examples fix: add --build-local flag to example scripts for CI compatibility Feb 13, 2026
@Claude Claude AI requested a review from lpcox February 13, 2026 04:09
@lpcox
Copy link
Collaborator

lpcox commented Feb 13, 2026

@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>
@Claude
Copy link
Contributor Author

Claude AI commented Feb 13, 2026

@claude[agent] i only want to build api-proxy locally. all other containers should be pulled from ghcr.io

Done! Changed the implementation to build only api-proxy locally while pulling squid and agent from GHCR.

Modified src/docker-manager.ts to always build the api-proxy container locally (lines 933-938), and reverted all example scripts to remove the --build-local flag.

Commit: 0be402e

@Claude Claude AI changed the title fix: add --build-local flag to example scripts for CI compatibility fix: build api-proxy locally while pulling other containers from GHCR Feb 13, 2026
@lpcox lpcox marked this pull request as ready for review February 13, 2026 04:12
Copilot AI review requested due to automatic review settings February 13, 2026 04:12
@lpcox lpcox merged commit cf44476 into claude/enable-api-proxy-by-default Feb 13, 2026
2 checks passed
@lpcox lpcox deleted the claude/fix-github-actions-workflow-another-one branch February 13, 2026 04:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 useGHCR branching for api-proxy and always sets a local build config.
  • Added comments/TODO indicating this is temporary until api-proxy is published to GHCR.
Comments suppressed due to low confidence (2)

src/docker-manager.ts:938

  • This change forces api-proxy to always use build, so services['api-proxy'].image is never set. That regresses the previously supported/tested behavior of pulling api-proxy from the configured imageRegistry/imageTag when buildLocal is false (including custom registries), and will break existing unit tests that assert proxy.image for 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 image name set, docker compose up will tag the built image using the Compose project name (derived from the per-run temp workDir). 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, stable image name alongside build (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.

Comment on lines +933 to +938
// 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',
};
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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');
    }

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments