Repository navigation
[AI Improvement] [Task] Fix no-misused-promises violations (Express 4 async handlers, listeners, streams) and remove its warn override - #11347
Conversation
…ync handlers, listeners, streams) and remove its warn override (b/576834648)
There was a problem hiding this comment.
Code Review
This pull request systematically addresses unhandled promise rejections and uncaught asynchronous errors across various Firebase emulators, CLI commands, and services. It introduces an asyncHandler utility for Express 4 routes and wraps numerous event listeners, watchers, and callbacks in error-catching wrappers. The code review identified two critical security vulnerabilities in src/emulator/hub.ts where missing return statements after 403 responses allow unauthorized actions (exporting data and clearing SQL Connect data) to proceed anyway; these should be resolved using the provided code suggestions.
| if (req.headers.origin) { | ||
| res.status(403).json({ | ||
| message: `Export cannot be triggered by external callers.`, | ||
| }); | ||
| } |
There was a problem hiding this comment.
The handler is missing a return statement after sending the 403 Forbidden response. Without it, the function will continue to execute, performing the export and attempting to send another response, which will cause a 'Cannot set headers after they are sent to the client' error and bypass the security check.
| if (req.headers.origin) { | |
| res.status(403).json({ | |
| message: `Export cannot be triggered by external callers.`, | |
| }); | |
| } | |
| if (req.headers.origin) { | |
| res.status(403).json({ | |
| message: "Export cannot be triggered by external callers.", | |
| }); | |
| return; | |
| } |
| if (req.headers.origin) { | ||
| res.status(403).json({ | ||
| message: `Clear SQL Connect cannot be triggered by external callers.`, | ||
| }); | ||
| } |
There was a problem hiding this comment.
The handler is missing a return statement after sending the 403 Forbidden response. Without it, the function will continue to execute, clearing the Data Connect emulator data and attempting to send another response, which will cause a 'Cannot set headers after they are sent to the client' error and bypass the security check.
| if (req.headers.origin) { | |
| res.status(403).json({ | |
| message: `Clear SQL Connect cannot be triggered by external callers.`, | |
| }); | |
| } | |
| if (req.headers.origin) { | |
| res.status(403).json({ | |
| message: "Clear SQL Connect cannot be triggered by external callers.", | |
| }); | |
| return; | |
| } |
|
/joe-review |
|
Addressed review feedback in commit 700ba91:
|
🤖 Adversarial AI review (review skill)Requested by joehan. This PR's worker agent should address every finding below: fix it, or reply with the reason it doesn't apply. (This is posted as a regular comment because a pending review on this PR blocks creating a new inline review.) One blocking issue, in the follow-up commit; the lint work itself is correct. The new What I verified at 700ba91.
Other checks:
Findings
|
|
Addressed all feedback from the adversarial review in commit 837a6d1:
Verified cleanly with |
| * A rejection is passed to `next(err)` (Express's error handling) instead of becoming an | ||
| * unhandled promise rejection, which by default terminates the Node.js process. | ||
| */ | ||
| export function asyncHandler( |
There was a problem hiding this comment.
This being required (and its uses) kinda throws me through a loop. I get it's working around an Express thing, but it still feels odd.
|
@bkendall Regarding Totally agree that having to wrap route handlers with In Express 4 (which this repo currently uses), route handlers are invoked synchronously ( Until then, Thanks for the review and approval! |
…mulator Adds jsonErrorHandler to src/emulator/shared/express.ts and registers it after all routes in the Emulator Hub and the Storage emulator. Errors that reach Express's error handling, such as rejections that asyncHandler forwards and malformed JSON bodies, now return a JSON body instead of Express's default HTML error page. 5xx responses use a generic message, and the error with its stack is logged through EmulatorLogger. 4xx errors keep their status and message. Adds src/emulator/shared/express.spec.ts.
|
@bkendall I pushed one more commit after your approval: b2206b1. It adds Errors that reach Express's error handling, such as rejections Could you take a quick look? Auto-merge is on, so I'm asking you directly rather than relying on the earlier approval. |
Description
Resolves Buganizer b/576834648
This PR addresses all 53 violations of
@typescript-eslint/no-misused-promisesacross 22 files and removes the"warn"override in.eslintrc.jsfor*.tsfiles so the recommended preset default ("error") applies with standardchecksVoidReturn: true.Key Fixes & Failure-Path Behavior Changes:
src/emulator/shared/express.ts):Introduced
asyncHandlerhelper routing rejected async route handler promises tonext(err)rather than becoming unhandled promise rejections that terminate the Node.js emulator process. Applied acrosssrc/emulator/hub.ts,src/emulator/storage/apis/firebase.ts,src/emulator/storage/apis/gcloud.ts, andsrc/emulator/storage/server.ts. Note: whitespace indentation changes in these routes are extensive; please review with "Hide whitespace".database:importStream Error Handling Fix (src/database/import.ts:189):writeBatch._transformpreviously did not calldone()ifdoWriteBatchrejected, failing with an unhandled promise rejection. Now invokesdone(err)on rejection, propagating the write error to the pipeline error handler.firebase login --localhostError Propagation Fix (src/auth.ts:608):Wrapped the server callback in a handler that catches rejections from template loading, properly rejecting the outer login promise and closing the HTTP server rather than failing with an unhandled promise rejection.
src/emulator/hub.ts):Added
return;after sending 403 responses so requests rejected by the Origin check now stop.src/emulator/firestoreEmulator.ts,src/emulator/databaseEmulator.ts):Rules watcher callbacks now catch read and update failures and log warnings rather than crashing the emulator process.
src/deploy/functions/services/index.ts):Added
syncNoopfor void-returningvalidateTriggerservice hooks across 10 service definitions.src/hosting/proxy.ts,src/mcp/index.ts,src/mcp/apps/init/mcp-app.ts):Safely adapted asynchronous handlers to void callbacks with
.catch(next)or explicitvoidcalls with comments documenting error confinement.src/emulator/shared/express.ts,src/emulator/hub.ts,src/emulator/storage/server.ts):Added
jsonErrorHandler, registered after all routes. Errors that reach Express's error handling, such as rejections thatasyncHandlernow forwards and malformed JSON bodies, return a JSON body ({ "error": { "code", "message" } }) instead of Express's default HTML error page. 5xx responses use a generic message, and the error with its stack is logged throughEmulatorLogger. 4xx errors keep their status and message.Scenarios Tested
npm run build: Passed cleanly.npm run test:compile: Passed cleanly.npm run lint:quiet: Full repository lint passed with 0 errors.@typescript-eslint/no-misused-promisesviolations found across the entire repository.npx mocha src/emulator/shared/express.spec.ts: new tests forjsonErrorHandler(generic 5xx body, logging, 4xx passthrough, malformed JSON, response already sent).npx mocha: Over 550 tests passed across targeted suites (database/import.spec.ts,frameworks/utils.spec.ts,utils.spec.ts,hosting/cloudRunProxy.spec.ts,hosting/functionsProxy.spec.ts,emulator/storage/**/*.spec.ts,mcp/**/*.spec.ts,deploy/functions/services/*.spec.ts,emulator/commandUtils.spec.ts,emulator/databaseEmulator.spec.ts,emulator/downloadableEmulators.spec.ts,deploy/functions/runtimes/discovery/**/*.spec.ts,emulator/hub.spec.ts).Sample Commands
N/A (Linter configuration and internal async handling fix).