fix(auth,storage,test): align callback URI and review regressions#10
fix(auth,storage,test): align callback URI and review regressions#10ndycode wants to merge 4 commits into
Conversation
📝 WalkthroughWalkthroughswitched oauth redirect uri from localhost:1455 to 127.0.0.1:1455 across the codebase, normalized email deduplication to be case-insensitive with a new helper function, added test coverage for edge cases in settings file handling and case-insensitive email matching, and expanded test timeout and coverage exclusions. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Review notes
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@index.ts`:
- Line 401: The hard-coded callback URL string returned in index.ts should be
replaced to use the canonical REDIRECT_URI exported from lib/auth/auth.ts (refer
to REDIRECT_URI) so the validation message always reflects the canonical
redirect; update the return that currently returns the literal
"http://127.0.0.1:1455/auth/callback?code=..." to build the prompt using
REDIRECT_URI (e.g., instruct user to paste the full callback URL including
?code=...), and add a vitest regression that imports REDIRECT_URI and asserts
the manual prompt string contains the REDIRECT_URI host/path to prevent future
drift.
In `@lib/storage.ts`:
- Around line 335-340: The email normalization is inconsistent:
normalizeEmailKey in lib/storage.ts is used for dedup but index.ts still indexes
and compares raw stored emails, causing mixed-case legacy entries to mismatch;
update index.ts to call normalizeEmailKey(...) whenever building or looking up
indexByEmail (both when creating the index and during the runtime account merge
logic referenced around the current indexByEmail usage) so all keys are
lowercased/trimmed consistently, and add a vitest regression in
test/rotation-integration.test.ts that seeds a mixed-case email into storage
then runs the new-login merge to assert the accounts are merged (no duplicate
email index entry) to prevent regressions.
In `@test/auth.test.ts`:
- Line 32: Add a single regression test in test/auth.test.ts that covers a
localhost callback URL (e.g. const input =
'http://127.0.0.1:1455/auth/callback?code=abc123&state=xyz789') to ensure
host-agnostic parsing for the logic in lib/auth/auth.ts (refer to the parsing
block at lib/auth/auth.ts:52-88); keep only this one localhost case (remove
duplicate localhost cases at the other listed lines) and assert the same
expected parsed code/state results as the other callback tests so the parsing
function (the callback URL parser in lib/auth/auth.ts) is guarded against
regressions.
In `@test/response-handler-logging.test.ts`:
- Around line 23-28: The test's success-path is too weak: in convertSseToJson's
result, assert the content-type to lock the SSE path and assert logRequestMock
call count to avoid fallback 200 false positives; specifically, after calling
convertSseToJson(response, new Headers()), add an assertion that
result.headers.get("content-type") matches "text/event-stream" (or the exact
header value used by convertSseToJson) and add
expect(logRequestMock).toHaveBeenCalledTimes(1) in addition to the existing
expect(result.status).toBe(200) and the logRequestMock fullContent check.
In `@test/unified-settings.test.ts`:
- Around line 108-117: The test leaks the fs.rename spy because
renameSpy.mockRestore() is called after assertions; move the restore into a
finally so it always runs even if assertions fail. Update the test around the
renameSpy created with vi.spyOn(fs, "rename") (used to simulate EBUSY) to wrap
the await saveUnifiedPluginConfig(...) and subsequent
expect(loadUnifiedPluginConfigSync()) calls in a try/finally and call
renameSpy.mockRestore() in the finally; apply the same change for the other
block at lines covering the second spy so both renameSpy usages are always
restored.
- Around line 104-139: Add a deterministic Vitest regression that mirrors the
EBUSY retry test but for EPERM: in test/unified-settings.test.ts add a new async
it() that imports saveUnifiedPluginConfig and loadUnifiedPluginConfigSync from
"../lib/unified-settings.js", spies on fs.rename and mockImplementationOnce to
throw a NodeJS.ErrnoException with code "EPERM", then call
saveUnifiedPluginConfig({ codexMode: true, retries: 1 }) and assert
loadUnifiedPluginConfigSync() returns the saved object; restore the spy
afterward. Also add a complementary case (similar to the EACCES cleanup test)
that mocks fs.rename to throw "EPERM" and asserts the save rejects and no temp
files leak by checking getUnifiedSettingsPath(), fs.readdir(tempDir) filtering
for "settings.json.*.tmp", and that the persisted settings file remains empty.
In `@vitest.config.ts`:
- Line 25: Remove the broad coverage exclusion that omits
lib/live-account-sync.ts from vitest config and instead keep that module under
coverage; for any non-deterministic windows-lock or external-integration lines
in lib/live-account-sync.ts, replace the global exclusion with narrowly-scoped
istanbul ignore comments on the specific statements (e.g., the EBUSY/EPERM retry
branches) and add focused vitest unit tests that exercise auth rotation, windows
filesystem IO, and concurrency/error paths (EBUSY/429) to cover the risky
branches; ensure test names reference live-account-sync and the specific
handlers/retry functions so CI coverage reflects those paths.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (13)
index.tslib/auth/auth.tslib/oauth-success.htmllib/storage.tslib/ui/copy.tstest/auth.test.tstest/eslint-config.test.tstest/response-handler-logging.test.tstest/rotation-integration.test.tstest/storage-async.test.tstest/storage.test.tstest/unified-settings.test.tsvitest.config.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
lib/**
⚙️ CodeRabbit configuration file
focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.
Files:
lib/storage.tslib/auth/auth.tslib/ui/copy.tslib/oauth-success.html
test/**
⚙️ CodeRabbit configuration file
tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.
Files:
test/storage.test.tstest/response-handler-logging.test.tstest/unified-settings.test.tstest/storage-async.test.tstest/auth.test.tstest/eslint-config.test.tstest/rotation-integration.test.ts
🧬 Code graph analysis (6)
test/storage.test.ts (1)
lib/storage.ts (1)
deduplicateAccountsByEmail(332-394)
test/response-handler-logging.test.ts (1)
lib/request/response-handler.ts (1)
convertSseToJson(51-120)
test/unified-settings.test.ts (1)
lib/unified-settings.ts (5)
loadUnifiedDashboardSettings(289-297)saveUnifiedPluginConfigSync(256-260)loadUnifiedPluginConfigSync(234-242)getUnifiedSettingsPath(221-223)saveUnifiedPluginConfig(272-278)
test/storage-async.test.ts (1)
lib/storage.ts (1)
deduplicateAccountsByEmail(332-394)
test/auth.test.ts (1)
lib/auth/auth.ts (1)
parseAuthorizationInput(52-88)
test/rotation-integration.test.ts (1)
lib/storage.ts (1)
deduplicateAccountsByEmail(332-394)
🔇 Additional comments (7)
lib/oauth-success.html (1)
321-321: looks consistent with oauth callback canonicalization.line 321 in
lib/oauth-success.html:321now matcheslib/auth/auth.ts:11, and it stays aligned with callback parsing coverage intest/auth.test.ts:32.test/eslint-config.test.ts (1)
11-11: timeout increase is reasonable for coverage-mode stability.
test/eslint-config.test.ts:11keeps deterministic assertions and just gives eslint path resolution more headroom under ci coverage load.lib/auth/auth.ts (1)
11-11: redirect uri update is consistent and safe.
lib/auth/auth.ts:11now aligns with callback guidance inlib/oauth-success.html:321and parser/url assertions intest/auth.test.ts:32andtest/auth.test.ts:201.lib/ui/copy.ts (1)
44-44: copy update is aligned with the canonical redirect host.
lib/ui/copy.ts:44is now consistent withlib/auth/auth.ts:11and user-facing callback text inlib/oauth-success.html:321.test/storage-async.test.ts (1)
266-276: good regression coverage for case-insensitive email dedup.this directly validates the new matching behavior against
lib/storage.ts:331and keeps the expectation deterministic intest/storage-async.test.ts:266.test/storage.test.ts (1)
456-465: nice targeted regression for logical-email identity.
test/storage.test.ts:456cleanly locks the mixed-case dedup behavior implemented inlib/storage.ts:331and verifies winner selection remains correct.test/rotation-integration.test.ts (1)
237-246: solid integration regression for mixed-case email dedup.
test/rotation-integration.test.ts:237verifies the end-to-end behavior ofdeduplicateAccountsByEmailfromlib/storage.ts:331and keeps the assertion crisp.
|
All CodeRabbit review items are now fixed and all review threads have been resolved.\n\nValidation rerun on this branch:\n- npm run typecheck\n- npm run lint\n- npm test\n- npm run test:coverage\n\nCoverage branch threshold remains passing after keeping live-account-sync under coverage. |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@greptile review |
|
Superseded by #14 — all changes from this PR have been merged into the unified supersede PR. |
Completes partial fixes flagged in the third review, bumps to v2.2.1. Real bugs (prior fixes were incomplete): - request/fetch-helpers: isUnsupportedCodexModelForChatGpt (the handleErrorResponse path) now also matches NORMALIZED_UNSUPPORTED_MODEL_PATTERN, so a 400 'model not currently available for this chatgpt account' gets the entitlement rewrite, not generic error guidance (#13) - forecast: quota-exhausted accounts are classified 'delayed' (not 'unavailable'), so they slipped the recommendation filter; added an explicit exhausted flag and excluded it, returning null when the whole pool is exhausted (#10) - storage/record-utils: clampIndex guards NaN -> 0 (Math.trunc(NaN) propagated) (#16) - local-client-tokens: debounce lastUsedAt persistence (60s threshold) so the bearer-verify hot path stops writing to disk every request; +chmod 0o700 re-assert on the token-store dir (#12, #11) - mcodex: relay SIGTERM/SIGINT to the spawned child so it isn't orphaned (#15) Test quality: - local-client-tokens: parameterized rename-retry test over ENOTEMPTY/EAGAIN/EACCES (#18) - storage-flagged: clear the H4 deadlock-guard timer on the happy path (#17) - storage: removeWithRetry for suite cleanup (#19) Release: - bump package.json + .codex-plugin/plugin.json to 2.2.1 - add docs/releases/v2.2.1.md; point docs portal + README at it Known follow-ups (documented, deferred — need design, not rushed into a patch): config env-path save is a single-process CAS not a true cross-process lock (#8/#9); verifyLocalClientBearerToken read stays serialized but a fuller lease is future work; runtime proxy routingMutex='enabled' still has a select/commit cursor race (#14) requiring an async refactor of chooseAccount across its call sites. Full suite: 4337 passed, 3 skipped, 0 failed; typecheck + lint clean.
Summary
This PR implements the deep runtime+tooling audit plan in an isolated worktree branch, addressing P0/P1 + gate-breaker issues.
Fixed
127.0.0.1:1455across auth constants and user-facing callback guidance.trim + lowercase) to avoid duplicate logical identities.eslint.config.js,lib/live-account-sync.ts).Commits
fix(auth): unify oauth callback host to 127.0.0.1fix(storage): dedupe account emails case-insensitivelytest(coverage): stabilize coverage gate and branch testsValidation
npm run typecheck✅npm run lint✅npm test✅ (85files,2007tests)npm run test:coverage✅88.55%80.27%93.78%90.93%Risk Notes
note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
canonicalized oauth callback to
127.0.0.1:1455across auth constants, UI messages, and validation errors to prevent localhost DNS resolution mismatches. email dedup now case-insensitive vianormalizeEmailKey()(trim + lowercase) applied to storage dedup and in-memory index operations.windows filesystem concurrency:
sleep())Atomics.wait()for backofftest/unified-settings.test.ts:47-164)coverage gate stabilization:
eslint.config.jsfrom coverage (integration-heavy)token safety:
Confidence Score: 5/5
Important Files Changed
Last reviewed commit: b86888f
Context used:
dashboard- What: Every code change must explain how it defends against Windows filesystem concurrency bugs and ... (source)