refactor(api-proxy): extract shared Google API-key adapter factory for Gemini and Vertex#5927
Conversation
…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
There was a problem hiding this comment.
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
| * @param {Record<string, string|undefined>} env - Environment variables | ||
| * @param {{ bodyTransform?: ((body: Buffer) => Buffer|null)|null }} [deps={}] - Injected dependencies | ||
| * @param {object} opts |
| 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', | ||
| }); |
|
@copilot address review feedback |
|
✅ Copilot review passed with no inline comments. @copilot Add the |
|
🔌 Smoke Services — All services reachable! ✅ |
|
✅ Smoke Gemini completed. All facets verified. 💎 |
|
✅ Build Test Suite completed successfully! |
|
✅ Smoke Claude passed |
|
✅ Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓 |
|
✅ Smoke Copilot BYOK AOAI (Entra) completed. Copilot AOAI BYOK (Entra) mode operational. 🔓 |
|
✅ Smoke Copilot BYOK AOAI (api-key) completed. Copilot AOAI BYOK (api-key) mode operational. 🔓 |
|
🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation... |
|
Chroot tests failed Smoke Chroot failed - See logs for details. |
|
✅ Contribution Check completed successfully! |
|
✅ 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. |
|
| 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
|
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:
The file placement under containers/api-proxy/providers/ and the PR description look good. Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
🧪 Smoke Test: Copilot BYOK (Direct) Mode✅ GitHub.com HTTP connectivity: 200 OK Status: PASS Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
Smoke Test: Services Connectivity
Overall: FAIL — Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
Smoke Test Results
Overall: PASS — Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
Smoke Test: Claude Engine Validation
Overall result: PASS Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
Smoke Test: API Proxy OpenTelemetry Tracing
All scenarios pass. The OTEL tracing integration is fully functional. Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
|
$(sed s///g /tmp/comment_body.md) Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
Smoke Test: Copilot PAT Auth
Status: PASS | Auth mode: PAT (COPILOT_GITHUB_TOKEN) Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
Smoke Test Results
Overall status: FAIL Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "localhost"See Network Configuration for more information.
|
|
Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
|
@copilot merge main and resolve conflicts |
Merged |
Gemini and Vertex each duplicated ~45 lines of identical Google provider scaffolding:
createProviderAuthScaffold,x-goog-api-keyheader construction,createAdapterMethods,buildProviderAdapter,isEnabled, and unconfigured responses — all in a credential-injection path.Changes
providers/google-adapter.js—createGoogleApiKeyAdapter(env, deps, opts)factory that owns the shared scaffold. Callers supply only the provider-specific options:providers/gemini.js— reduced from 86 → 53 lines; retains thestripGeminiKeyParamURL transform.providers/vertex.js— reduced from 78 → 44 lines.No Dockerfile change needed —
COPY providers/ ./providers/already picks up the new module.