Skip to content

fix(api-proxy): set GOOGLE_GEMINI_BASE_URL to route Gemini CLI through sidecar#2348

Merged
lpcox merged 3 commits intomainfrom
copilot/awf-fix-gemini-engine-proxy-bypass
May 1, 2026
Merged

fix(api-proxy): set GOOGLE_GEMINI_BASE_URL to route Gemini CLI through sidecar#2348
lpcox merged 3 commits intomainfrom
copilot/awf-fix-gemini-engine-proxy-bypass

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 1, 2026

The Gemini CLI reads GOOGLE_GEMINI_BASE_URL to redirect its API endpoint — not GEMINI_API_BASE_URL. AWF was only setting the latter, so the CLI bypassed the api-proxy sidecar entirely and hit generativelanguage.googleapis.com directly without key injection, causing 400 API_KEY_INVALID errors.

Changes

  • src/docker-manager.ts: When geminiApiKey is set, now emits both GOOGLE_GEMINI_BASE_URL (primary — read by google-gemini/gemini-cli) and GEMINI_API_BASE_URL (kept for backward compat with older @google/generative-ai SDK usage), both pointing to http://172.30.0.30:10003. Also adds both GOOGLE_GEMINI_BASE_URL and GEMINI_API_BASE_URL to EXCLUDED_ENV_VARS to prevent host env bleed-through via --env-all in non-Gemini runs.

  • src/docker-manager.test.ts: Five new tests asserting GOOGLE_GEMINI_BASE_URL is set to the sidecar URL when a Gemini key is present, matches GEMINI_API_BASE_URL, is absent when no Gemini key is configured, and that neither GOOGLE_GEMINI_BASE_URL nor GEMINI_API_BASE_URL is inherited from the host via --env-all.

  • docs/: Updated authentication-architecture.md and api-proxy-sidecar.md to document both env vars, clarify which one the CLI reads, and correct the troubleshooting section to reflect that the Gemini routing vars are only injected when geminiApiKey is provided (not "always" when --enable-api-proxy is active).

The fix was traced to contentGenerator.ts in the Gemini CLI source:

const envBaseUrl =
  config.authType === AuthType.USE_VERTEX_AI
    ? process.env['GOOGLE_VERTEX_BASE_URL']
    : process.env['GOOGLE_GEMINI_BASE_URL']; // ← only this is checked

Copilot AI changed the title [WIP] Fix Gemini engine bypassing proxy for API key injection fix(api-proxy): set GOOGLE_GEMINI_BASE_URL to route Gemini CLI through sidecar May 1, 2026
Copilot finished work on behalf of lpcox May 1, 2026 14:08
Copilot AI requested a review from lpcox May 1, 2026 14:08
@lpcox lpcox marked this pull request as ready for review May 1, 2026 14:36
@lpcox lpcox requested a review from Mossaka as a code owner May 1, 2026 14:36
Copilot AI review requested due to automatic review settings May 1, 2026 14:36
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Documentation Preview

Documentation build failed for this PR. View logs.

Built from commit ca20ec7

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 85.87% 85.97% 📈 +0.10%
Statements 85.86% 85.95% 📈 +0.09%
Functions 87.96% 87.96% ➡️ +0.00%
Branches 79.96% 80.00% 📈 +0.04%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 87.4% → 87.7% (+0.34%) 87.0% → 87.3% (+0.32%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

Copy link
Copy Markdown
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 AWF’s api-proxy sidecar routing so the Gemini CLI uses the correct environment variable (GOOGLE_GEMINI_BASE_URL) to route Gemini traffic through the sidecar for key injection, preventing direct calls to generativelanguage.googleapis.com that fail with API_KEY_INVALID.

Changes:

  • Set GOOGLE_GEMINI_BASE_URL (Gemini CLI) alongside GEMINI_API_BASE_URL (older SDK compatibility) when geminiApiKey is configured.
  • Exclude GOOGLE_GEMINI_BASE_URL from --env-all passthrough to prevent host env bleed-through.
  • Add/extend tests and docs to cover the new env var behavior and intended routing.
Show a summary per file
File Description
src/docker-manager.ts Sets GOOGLE_GEMINI_BASE_URL to the Gemini api-proxy listener URL (and keeps GEMINI_API_BASE_URL) and excludes the new var from --env-all inheritance.
src/docker-manager.test.ts Adds tests verifying GOOGLE_GEMINI_BASE_URL behavior (set with Gemini key, not set/ not inherited without it).
docs/authentication-architecture.md Documents both Gemini base URL env vars and clarifies which one the Gemini CLI reads.
docs/api-proxy-sidecar.md Updates env var table and notes for Gemini routing; troubleshooting section also updated (but currently conflicts with code behavior).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 4/4 changed files
  • Comments generated: 2

Comment thread src/docker-manager.ts
EXCLUDED_ENV_VARS.add('ANTHROPIC_API_KEY');
EXCLUDED_ENV_VARS.add('CLAUDE_API_KEY');
EXCLUDED_ENV_VARS.add('GEMINI_API_KEY');
EXCLUDED_ENV_VARS.add('GOOGLE_GEMINI_BASE_URL');
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

GOOGLE_GEMINI_BASE_URL is excluded from --env-all passthrough, but GEMINI_API_BASE_URL is not. In non-Gemini runs with --env-all, a host-defined GEMINI_API_BASE_URL will still be inherited because the Gemini routing block doesn’t run, which can accidentally re-enable Gemini SDK traffic (or at least cause confusing/proxy-bypass behavior). Consider adding GEMINI_API_BASE_URL to EXCLUDED_ENV_VARS (and/or explicitly deleting/overriding it when config.geminiApiKey is absent) for consistency with the “Gemini setup is conditional” intent.

Suggested change
EXCLUDED_ENV_VARS.add('GOOGLE_GEMINI_BASE_URL');
EXCLUDED_ENV_VARS.add('GOOGLE_GEMINI_BASE_URL');
EXCLUDED_ENV_VARS.add('GEMINI_API_BASE_URL');

Copilot uses AI. Check for mistakes.
Comment thread docs/api-proxy-sidecar.md
Comment on lines 433 to 436
### Gemini proxy returns 503

When `--enable-api-proxy` is active, `GEMINI_API_BASE_URL` and a placeholder `GEMINI_API_KEY` are always injected into the agent container. If the real `GEMINI_API_KEY` was not set in the AWF runner environment, the api-proxy Gemini listener (port 10003) responds with **503** to all requests.
When `--enable-api-proxy` is active, `GOOGLE_GEMINI_BASE_URL`, `GEMINI_API_BASE_URL`, and a placeholder `GEMINI_API_KEY` are always injected into the agent container. If the real `GEMINI_API_KEY` was not set in the AWF runner environment, the api-proxy Gemini listener (port 10003) responds with **503** to all requests.

Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

This troubleshooting text says the Gemini base URL vars and placeholder GEMINI_API_KEY are “always injected” when --enable-api-proxy is active, but generateDockerCompose only configures the Gemini env vars/placeholder when geminiApiKey is provided. Update this section to reflect the conditional behavior (or, if the doc is correct, the code needs to be updated to match).

Copilot uses AI. Check for mistakes.
@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented May 1, 2026

@copilot address the review feedback

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 1, 2026

@copilot address the review feedback

Done in commit 09cb7e1:

  1. GEMINI_API_BASE_URL added to EXCLUDED_ENV_VARS — now excluded alongside GOOGLE_GEMINI_BASE_URL so neither is inherited from the host via --env-all in non-Gemini runs. Also added a test to cover this.

  2. Docs corrected — the troubleshooting section in api-proxy-sidecar.md now accurately states that the Gemini routing vars are only injected when GEMINI_API_KEY is provided to AWF, not "always" when --enable-api-proxy is active.

Copilot finished work on behalf of lpcox May 1, 2026 14:45
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Smoke Test Results: Gemini Engine

  • MCP Connectivity: ✅
  • GitHub.com Connectivity: ✅
  • File Write/Read Test: ✅

Overall Status: PASS

PR Titles:

  • ci: update smoke test data

cc: @Copilot

💎 Faceted by Smoke Gemini

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Smoke Test: Copilot BYOK — Run #25218663643

Test Result
GitHub MCP (list PRs)
GitHub.com connectivity
File write/read (smoke-test-copilot-byok-25218663643.txt)
BYOK inference (agent → api-proxy → api.githubcopilot.com)

Running in BYOK offline mode (COPILOT_OFFLINE=true) via api-proxy → api.githubcopilot.com.

Overall: PASS — Author: @Copilot · Assignees: @lpcox @Copilot

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Smoke Test Results

✅ GitHub API: #2339, #2337
✅ Playwright: GitHub page title verified
✅ File creation: smoke-test file created and verified
✅ Bash: File read confirmed

Overall: PASS

💥 [THE END] — Illustrated by Smoke Claude

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

🔬 Smoke Test Results

Test Status
GitHub MCP connectivity
GitHub.com HTTP connectivity ❌ (template vars unexpanded)
File write/read ❌ (template vars unexpanded)

PR: fix(api-proxy): set GOOGLE_GEMINI_BASE_URL to route Gemini CLI through sidecar
Author: @Copilot | Assignees: @lpcox, @Copilot

Overall: FAIL — pre-computed test data ($\{\{ steps.smoke-data.outputs.* }}) was not injected; tests 2 & 3 could not be verified.

📰 BREAKING: Report filed by Smoke Copilot

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ NO
Node.js v24.14.1 v20.20.2 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Result: ❌ Not all tests passed — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Smoke Test

  • feat(api-proxy): write models.json snapshot after startup model fetch ✅
  • fix: gate OpenCode listener (port 10004) on explicit AWF_ENABLE_OPENCODE flag ✅
  • safeinputs-gh PR query ❌
  • GitHub title via Playwright ✅
  • Tavily search ❌
  • File write/read ✅
  • Discussion comment ✅
  • npm ci && npm run build
  • Overall: FAIL

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Smoke Test Results

  • Redis PING: ❌ (timeout — host.docker.internal:6379 unreachable)
  • PostgreSQL pg_isready: ❌ (host.docker.internal:5432 — no response)
  • PostgreSQL SELECT 1: ❌ (skipped — host unreachable)

Overall: FAILhost.docker.internal is not reachable from this runner environment. Service containers may not be running or the host alias is not configured.

🔌 Service connectivity validated by Smoke Services

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx passed ✅ PASS
Node.js execa passed ✅ PASS
Node.js p-limit passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Generated by Build Test Suite for issue #2348 · ● 716.3K ·

@lpcox
Copy link
Copy Markdown
Collaborator

lpcox commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 1, 2026

@copilot look into why this ci check is failing https://github.com/github/gh-aw-firewall/actions/runs/25218663391/job/73946029400?pr=2348

This CI failure is unrelated to the code changes in this PR.

Root cause: The Gemini CLI v0.37.2 is calling MCP tools/call before completing the session handshake, causing the mcpg gateway to return "method 'tools/call' is invalid during session initialization" on every tool call attempt. With no MCP tools working, Gemini never calls the safe output tools, and the validation step fails.

This is a pre-existing, intermittent MCP compatibility issue — run #143 on main failed with the same symptom before any of my changes, and runs on other unrelated branches also fail this way (runs #141, #140, #136). My changes (GEMINI_API_BASE_URL added to EXCLUDED_ENV_VARS) only affect env vars injected into the Docker agent container; they have no effect on this smoke test, which runs the Gemini CLI directly on the CI runner without AWF.

Copilot finished work on behalf of lpcox May 1, 2026 15:21
@lpcox lpcox merged commit 4e45e87 into main May 1, 2026
67 of 71 checks passed
@lpcox lpcox deleted the copilot/awf-fix-gemini-engine-proxy-bypass branch May 1, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[awf] api-proxy: Gemini engine bypasses proxy — GEMINI_API_KEY not injected, requests reach Google directly

3 participants