Skip to content

fix: harden request lifecycle after deep review — crash-safe handlers, byte-safe auth compare, mid-body abort settlement - #7

Merged
dengyie merged 1 commit into
mainfrom
fix/deep-review-hardening
Oct 4, 2026
Merged

dengyie merged 1 commit into
mainfrom
fix/deep-review-hardening

Conversation

@dengyie

@dengyie dengyie commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Deep production review of the whole codebase found 5 real issues (all reproduced before fixing):

P1 — route handler promise returned, not awaited

return handleChatCompletions(...) in the createServer callback meant the outer try/catch never caught handler exceptions: any throw inside an async route handler became an unhandledRejection → process exit. Verified live: a single request crashes the proxy. Also made the finally access log fire at handler entry, so ms was always ~0 (fake duration data). Fix: await handleChatCompletions(...).

P1 — auth timingSafeEqual RangeError (single request → crash)

candidate.length === expected.length compares JS string length, but timingSafeEqual compares byte length. An Authorization header with latin1 high bytes of equal string length (e.g. Bearer test-key-1234\xC3) threw ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH → with the P1 above, process exit. Reproduced: proxy exited code 1 on one request. Fix: try/catch around the compare (byte-length mismatch = auth failure → 401 + counted toward the rate-limit window).

P2 — client aborting mid-body hung the handler forever

req.on('error', () => {}) swallowed ECONNRESET while readBody's promise never settled → every aborted upload leaked a pending closure and the access log never fired. claude code cancellations mid-upload are a real scenario. Fix: settle on premature close/error (req.complete guards the normal path), handle CLIENT_ABORTED as a silent null (socket is dead, nothing to write).

P3 — numeric timeout env garbage → NaN → instant stream aborts

Number(process.env.X || d) yields NaN for garbage; setTimeout(fn, NaN) fires at 0ms → every upstream stream aborts immediately. Added fail-fast validation at boot (refuses to start), matching the module's existing philosophy.

P3 — in-messages system with block-array content demoted to user

convertUserBlocks hardcoded role: 'user'; string-content system messages kept their role but array-content ones silently didn't. Fix: pass the caller's role through.

Tests

71/71 green (was 67): mid-body abort settlement (log-based hang detector), auth crash regression (401 + process survives), NaN fail-fast (spawn exits 1), system block-array role. Private repo d2567d5 already pushed to main.

…te-length safe compare; settle mid-body aborts; NaN timeout fail-fast; keep system role for block-array content
Copilot AI lite review requested due to automatic review settings October 4, 2026 22:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@dengyie
dengyie merged commit 3f86b21 into main Oct 4, 2026
2 checks passed
@dengyie
dengyie deleted the fix/deep-review-hardening branch October 4, 2026 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants