Refactor proxy request error path into shared handler#3323
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR refactors proxyRequest() error handling in the API proxy by extracting duplicated client/upstream error response, metrics, and audit logging logic into a shared helper.
Changes:
- Added
handleRequestError()to centralize error-path metrics, audit logging, and JSON response emission. - Replaced three inline error handlers with calls to the shared helper.
- Added proxy request error-path tests for client stream, upstream response stream, and upstream request failures.
Show a summary per file
| File | Description |
|---|---|
containers/api-proxy/proxy-request.js |
Introduces shared request error handling and wires it into existing proxy error paths. |
containers/api-proxy/server.proxy.test.js |
Adds focused tests for the refactored proxy error response paths. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 3
| function makeRes() { | ||
| return { | ||
| headersSent: false, | ||
| setHeader: jest.fn(), | ||
| writeHead: jest.fn(), | ||
| end: jest.fn(), |
| const duration = Date.now() - startTime; | ||
| metrics.gaugeDec('active_requests', { provider }); | ||
| metrics.increment('requests_errors_total', { provider }); | ||
| if (extraMetrics) extraMetrics(duration); | ||
| logRequest('error', 'request_error', { | ||
| request_id: requestId, provider, method: req.method, | ||
| path: sanitizeForLog(req.url), duration_ms: duration, | ||
| error: sanitizeForLog(err.message), upstream_host: targetHost, |
| proxyRes.on('error', (err) => { | ||
| const duration = Date.now() - startTime; | ||
| metrics.gaugeDec('active_requests', { provider }); | ||
| metrics.increment('requests_errors_total', { provider }); | ||
| logRequest('error', 'request_error', { | ||
| request_id: requestId, provider, method: req.method, | ||
| path: sanitizeForLog(req.url), duration_ms: duration, | ||
| error: sanitizeForLog(err.message), upstream_host: targetHost, | ||
| handleRequestError(err, { | ||
| res, | ||
| requestId, | ||
| provider, | ||
| req, | ||
| targetHost, | ||
| startTime, | ||
| statusCode: 502, | ||
| clientMessage: 'Response stream error', | ||
| }); |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@copilot fix this failing ci check https://github.com/github/gh-aw-firewall/actions/runs/26037978488/job/76552345291?pr=3323 |
Fixed in I addressed the Integration Tests failure by making the protocol checks less flaky (switched from Please re-run the failing check on this latest commit. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@copilot address review feedback |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Addressed in This updates upstream response-stream error handling to avoid writing JSON after headers are sent (now destroys the response in that case), fixes the test mock to toggle |
Smoke Test Results✅ GitHub API: 2 PR entries confirmed in recent-prs.json Result: PASS
|
🔥 Smoke Test: Copilot BYOK (Offline) Mode
Running in BYOK offline mode ( Overall: PASS (core BYOK path confirmed ✅) cc
|
🔬 Smoke Test Results
PR: Refactor proxy request error path into shared handler Overall: PASS 🟢
|
Smoke TestPRs: Refactor COPILOT_MODEL resolution to remove duplicated env precedence logic; refactor: extract shared service test imports into service-test-setup.test-utils Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "registry.npmjs.org"See Network Configuration for more information.
|
Smoke Test Results\n- GitHub MCP Testing: ❌\n- GitHub.com Connectivity: ❌\n- File Writing Testing: ✅\n- Bash Tool Testing: ✅\n\nOverall status: FAILWarning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "localhost"See Network Configuration for more information.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Chroot Smoke Test Results
Result: FAIL — Python and Node.js versions differ between host and chroot.
|
Smoke Test Results
Overall: FAIL —
|
proxyRequest()had three near-identical error blocks for client, upstream response stream, and upstream request failures. This duplicated security-relevant logging/metrics behavior and increased drift risk when evolving the request audit schema.What changed
handleRequestError()helper incontainers/api-proxy/proxy-request.jsto centralize:active_requestsdecrement +requests_errors_totalincrementrequest_erroraudit logging payload (request_id/provider/method/path/duration/error/upstream_host)statusCodeclientMessageextraMetrics(duration)callbackPreserved behavior
400/"Client error"502/"Response stream error"502/"Proxy error"requests_total5xx +request_duration_ms) viaextraMetrics.Test coverage update
server.proxy.test.jscases to assert the three error paths still emit the expected HTTP status and JSON payloads after deduplication.