Skip to content

refactor(api-proxy): extract shared Google API-key adapter factory for Gemini and Vertex#5927

Merged
lpcox merged 4 commits into
mainfrom
copilot/fix-duplicate-code-google-adapters
Jul 5, 2026
Merged

refactor(api-proxy): extract shared Google API-key adapter factory for Gemini and Vertex#5927
lpcox merged 4 commits into
mainfrom
copilot/fix-duplicate-code-google-adapters

Conversation

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Gemini and Vertex each duplicated ~45 lines of identical Google provider scaffolding: createProviderAuthScaffold, x-goog-api-key header construction, createAdapterMethods, buildProviderAdapter, isEnabled, and unconfigured responses — all in a credential-injection path.

Changes

  • New providers/google-adapter.jscreateGoogleApiKeyAdapter(env, deps, opts) factory that owns the shared scaffold. Callers supply only the provider-specific options:
function createGeminiAdapter(env, deps = {}) {
  return createGoogleApiKeyAdapter(env, deps, {
    name: 'gemini',
    port: 10003,
    envConstants: GEMINI_ENV,
    defaultTarget: 'generativelanguage.googleapis.com',
    validationPath: '/v1beta/models',
    modelsPath: '/v1beta/models',
    healthServiceName: 'awf-api-proxy-gemini',
    unconfiguredErrorMessage: 'Gemini proxy not configured ...',
    healthErrorMessage: 'GEMINI_API_KEY not configured in api-proxy sidecar',
    transformRequestUrl(url) { return stripGeminiKeyParam(url); },
  });
}
  • providers/gemini.js — reduced from 86 → 53 lines; retains the stripGeminiKeyParam URL transform.
  • providers/vertex.js — reduced from 78 → 44 lines.

No Dockerfile change needed — COPY providers/ ./providers/ already picks up the new module.

…rtex

Both providers shared ~45 lines of identical Google API-key adapter
scaffolding (createProviderAuthScaffold, x-goog-api-key header builder,
createAdapterMethods, buildProviderAdapter, isEnabled, unconfigured
responses). Extract to a new providers/google-adapter.js factory so
each provider only supplies its name, port, env constants, paths, and
error messages.

Closes #5918
Copilot AI changed the title [WIP] Refactor Gemini and Vertex adapters to reduce duplicate code refactor(api-proxy): extract shared Google API-key adapter factory for Gemini and Vertex Jul 5, 2026
Copilot finished work on behalf of lpcox July 5, 2026 12:55
Copilot AI requested a review from lpcox July 5, 2026 12:55
@lpcox lpcox marked this pull request as ready for review July 5, 2026 13:15
Copilot AI review requested due to automatic review settings July 5, 2026 13:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the api-proxy’s Google API-key providers (Gemini and Vertex) by extracting their shared adapter scaffolding into a reusable factory, reducing duplication in the credential-injection path while keeping provider-specific behavior configurable.

Changes:

  • Added a new shared factory createGoogleApiKeyAdapter() for Google API-key adapters (x-goog-api-key).
  • Updated Gemini and Vertex providers to use the shared factory, retaining Gemini’s URL query-param stripping.
  • Standardized unconfigured/health stub responses through the shared implementation.
Show a summary per file
File Description
containers/api-proxy/providers/google-adapter.js Introduces shared Google API-key adapter factory used by Gemini and Vertex.
containers/api-proxy/providers/gemini.js Refactors Gemini provider to delegate adapter construction to the shared factory while keeping URL transform.
containers/api-proxy/providers/vertex.js Refactors Vertex provider to delegate adapter construction to the shared factory.

Review details

Tip

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

  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Low

Comment on lines +20 to +22
* @param {Record<string, string|undefined>} env - Environment variables
* @param {{ bodyTransform?: ((body: Buffer) => Buffer|null)|null }} [deps={}] - Injected dependencies
* @param {object} opts
Comment on lines 28 to 39
function createVertexAdapter(env, deps = {}) {
const { apiKey, rawTarget, basePath, bodyTransform } = createProviderAuthScaffold(env, deps, {
keyEnvVar: VERTEX_ENV.KEY,
targetEnvVar: VERTEX_ENV.TARGET,
basePathEnvVar: VERTEX_ENV.BASE_PATH,
defaultTarget: 'aiplatform.googleapis.com',
});
const buildAuthHeaders = () => providerKeyHeaders('x-goog-api-key', apiKey);

const adapterMethods = createAdapterMethods({
apiKey,
rawTarget,
basePath,
provider: 'vertex',
return createGoogleApiKeyAdapter(env, deps, {
name: 'vertex',
port: 10004,
envConstants: VERTEX_ENV,
defaultTarget: 'aiplatform.googleapis.com',
validationPath: '/v1/projects',
validationHeaders: buildAuthHeaders,
modelsPath: null,
modelsFetchHeaders: null,
});

return buildProviderAdapter({
name: 'vertex',
port: 10004,
isManagementPort: false,
alwaysBind: true,
adapterMethods,
getAuthHeaders() {
return buildAuthHeaders();
},
bodyTransform,
isEnabled() { return !!apiKey; },
/** Response returned for all requests when no GOOGLE_API_KEY is configured. */
getUnconfiguredResponse() {
return {
statusCode: 503,
body: { error: 'Vertex AI proxy not configured (no GOOGLE_API_KEY). Set GOOGLE_API_KEY in the AWF runner environment to enable credential isolation.' },
};
},
/** /health response when not configured. */
getUnconfiguredHealthResponse() {
return makeUnconfiguredHealthResponse('awf-api-proxy-vertex', 'GOOGLE_API_KEY not configured in api-proxy sidecar');
},
healthServiceName: 'awf-api-proxy-vertex',
unconfiguredErrorMessage: 'Vertex AI proxy not configured (no GOOGLE_API_KEY). Set GOOGLE_API_KEY in the AWF runner environment to enable credential isolation.',
healthErrorMessage: 'GOOGLE_API_KEY not configured in api-proxy sidecar',
});
@lpcox

lpcox commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed in c752a80: widened the Google adapter JSDoc deps.bodyTransform type to include async transforms, and added Vertex auth-matrix coverage for x-goog-api-key header, default target, and isEnabled gating.

Copilot finished work on behalf of lpcox July 5, 2026 13:25
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

✅ Copilot review passed with no inline comments.

@copilot Add the ready-for-aw label to this PR to trigger agentic CI smoke tests.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🔌 Smoke Services — All services reachable! ✅

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Gemini completed. All facets verified. 💎

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Build Test Suite completed successfully!

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Claude passed

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK AOAI (Entra) completed. Copilot AOAI BYOK (Entra) mode operational. 🔓

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK AOAI (api-key) completed. Copilot AOAI BYOK (api-key) mode operational. 🔓

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation...

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Chroot tests failed Smoke Chroot failed - See logs for details.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Contribution Check completed successfully!

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Security Guard completed successfully!

PR #5927 security review: API proxy refactoring only. No changes to firewall rules, iptables, Squid config, Docker capabilities, DNS, credential handling, or authentication mechanisms. Pure code consolidation of duplicate Google adapter scaffolding. No security concerns.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

Metric Base PR Delta
Lines 98.81% 98.81% ➡️ +0.00%
Statements 98.73% 98.73% ➡️ +0.00%
Functions 99.58% 99.58% ➡️ +0.00%
Branches 95.14% 95.10% 📉 -0.04%

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

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Thanks for the clear refactor and for adding Vertex auth-matrix coverage. One important item to address before this fully meets the CONTRIBUTING.md guidance:

  • Testing / behavior preservation: CONTRIBUTING.md asks contributors to include tests for new functionality and ensure tests pass. This refactor removes the previous alwaysBind: true setting from the Vertex adapter path, but the added tests only cover API-key headers, default target, and isEnabled gating. Please either preserve that Vertex behavior in the shared factory options or add/update a test that confirms the intended binding behavior is unchanged.

The file placement under containers/api-proxy/providers/ and the PR description look good.

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

Generated by Contribution Check for #5927 · 56.1 AIC · ⊞ 20.9K ·
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🧪 Smoke Test: Copilot BYOK (Direct) Mode

GitHub.com HTTP connectivity: 200 OK
File I/O operations: Working
BYOK inference path: Operational (api-proxy → api.githubcopilot.com)
All tests passed

Status: PASS
Mode: Direct BYOK via COPILOT_PROVIDER_API_KEY + api-proxy sidecar

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🔑 BYOK report filed by Smoke Copilot BYOK
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Test: Services Connectivity

  • Redis PING: ❌ Network is unreachable
  • PostgreSQL pg_isready: ❌ No response
  • PostgreSQL SELECT 1: ❌ Network is unreachable

Overall: FAILhost.docker.internal (172.17.0.1) is not reachable from this runner environment.

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🔌 Service connectivity validated by Smoke Services
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Test Results

Test Status
GitHub MCP connectivity
GitHub.com HTTP
File write/read ✅ (verified)

Overall: PASS@lpcox

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

📰 BREAKING: Report filed by Smoke Copilot
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Test: Claude Engine Validation

Check Result
API status ✅ PASS
GH check ✅ PASS
File status ✅ PASS

Overall result: PASS

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

Generated by Smoke Claude for #5927 · 35.5 AIC · ⊞ 3.3K ·
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Test: API Proxy OpenTelemetry Tracing

Scenario Result Details
1. Module Loading ✅ Pass otel.js loads successfully; exports: startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown, isEnabled
2. Test Suite ✅ Pass 59 tests passed, 0 failed across otel.test.js + otel-fanout.test.js — span creation, token usage attrs, parent context propagation, exporters all covered
3. Env Var Forwarding ✅ Pass src/services/api-proxy-env-config.ts forwards GH_AW_OTLP_ENDPOINTS, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, GITHUB_AW_OTEL_TRACE_ID, GITHUB_AW_OTEL_PARENT_SPAN_ID, OTEL_SERVICE_NAME to api-proxy container
4. Token Tracker Integration ✅ Pass onUsage callback confirmed in token-tracker-http.js (lines 283/324) as the OTEL hook for gen_ai.usage.* span attributes
5. OTEL Diagnostics i️ N/A No live containers in this validation run; graceful degradation confirmed — isEnabled() returns true with valid config, falls back to FileSpanExporter when no OTLP endpoint set

All scenarios pass. The OTEL tracing integration is fully functional.

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

📡 OTel tracing validated by Smoke OTel Tracing
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

$(sed s///g /tmp/comment_body.md)

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🪪 BYOK (AOAI Entra) report filed by Smoke Copilot BYOK AOAI (Entra)
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot PAT Auth

Test Result
MCP connectivity
GitHub.com HTTP ✅ 200
File write/read

Status: PASS | Auth mode: PAT (COPILOT_GITHUB_TOKEN)

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🔑 PAT report filed by Smoke Copilot PAT
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Smoke Test Results

  1. GitHub MCP Testing: ❌ (API unreachable, tools missing)
  2. GitHub.com Connectivity: ❌ (Status 000)
  3. File Writing Testing: ✅
  4. Bash Tool Testing: ✅

Overall status: FAIL

Warning

Firewall blocked 1 domain

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

  • localhost

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

network:
  allowed:
    - defaults
    - "localhost"

See Network Configuration for more information.

💎 Faceted by Smoke Gemini
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🔑 BYOK (AOAI api-key) report filed by Smoke Copilot BYOK AOAI (api-key)
Add label ready-for-aw to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🏗️ 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 all passed ✅ PASS
Node.js execa all passed ✅ PASS
Node.js p-limit all passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

Generated by Build Test Suite for #5927 · 171.9 AIC · ⊞ 6.9K ·
Add label ready-for-aw to run again

@lpcox

lpcox commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

@copilot merge main and resolve conflicts

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

@copilot merge main and resolve conflicts

Merged main and resolved conflicts in containers/api-proxy/providers/gemini.js and containers/api-proxy/providers/vertex.js in commit dcd9528.

Copilot finished work on behalf of lpcox July 5, 2026 15:12
@lpcox lpcox merged commit 74af558 into main Jul 5, 2026
22 of 23 checks passed
@lpcox lpcox deleted the copilot/fix-duplicate-code-google-adapters branch July 5, 2026 15:30
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.

[Duplicate Code] Gemini and Vertex adapters repeat Google provider scaffolding

3 participants