Skip to content

fix(auth): honor quota.skip_exhausted in isAuthenticated#581

Open
icebear0828 wants to merge 1 commit into
devfrom
fix/auth-skip-exhausted-and-cf-streak
Open

fix(auth): honor quota.skip_exhausted in isAuthenticated#581
icebear0828 wants to merge 1 commit into
devfrom
fix/auth-skip-exhausted-and-cf-streak

Conversation

@icebear0828
Copy link
Copy Markdown
Owner

Summary

AccountRegistry.isAuthenticated() ignored quota.skip_exhausted, treating every cached-quota-exhausted account as unusable regardless of config. That diverges from hasAvailableAccounts() and AccountLifecycle.acquire(), which still allow acquiring limit-reached accounts when skip_exhausted=false. Any pool where every account is at the cached limit fails isAuthenticated() while acquire() would succeed, so every router gated on accountPool.isAuthenticated() (/v1/chat/completions, /v1/messages, /v1/responses, model listing, health) returns 401 even though the request could be served.

This was flagged as [P1] by Codex review on the diff that retired status="rate_limited".

Changes

  • src/auth/account-registry.ts:294-313 — gate the cachedQuota check on skipExhausted, mirror the rule used by hasAvailableAccounts(). Use !== false so test mocks with partial config (quota block missing) observe the schema default (true) rather than tripping a TypeError.
  • tests/unit/auth/account-pool-has-available.test.ts:188-251 — new AccountPool.isAuthenticated describe with 5 cases: empty pool → false; active healthy → true; cached-exhausted + skip_exhausted=true (default) → false (regression guard); cached-exhausted + skip_exhausted=false → true (P1 fix); disabled-only → false.
  • CHANGELOG.md### Fixed bullet under [Unreleased].

Default config behaviour unchanged: quota.skip_exhausted defaults to true, so the cached-quota check still applies for all out-of-the-box deployments.

Test Plan

  • npx vitest run tests/unit/auth/account-pool-has-available.test.ts — 19 → 24 tests pass (5 new)
  • npx vitest run — 2259 tests pass, 1 skipped, 0 failures
  • npx tsc --noEmit — clean
  • Pre-push hook validates the branch

Notes

A related [P2] finding from the same review (src/auth/cf-path-block-tracker.ts:34-35 — auto-disable counter doesn't reset on successful upstream use) lives on an unmerged local branch, not on dev. It will be addressed when that branch opens its own PR.

isAuthenticated() previously short-circuited any account whose
cachedQuota was reported exhausted, regardless of the
quota.skip_exhausted config. That diverges from hasAvailableAccounts
and AccountLifecycle.acquire(), which both still allow acquiring
limit-reached accounts when skip_exhausted=false (the documented
opt-in for letting requests retry against still-limit-reached
accounts on the chance the upstream window has actually rolled).

The mismatch causes any pool where every account is at the cached
limit to fail isAuthenticated() while routing would still produce a
viable account, so every router that calls accountPool.isAuthenticated()
(`/v1/chat/completions`, `/v1/messages`, `/v1/responses`, model
listing, health) returns 401 even though acquire() would succeed.

Gate the cachedQuota check on the same skipExhausted flag. Use
!== false so a missing quota config block (tests with minimal
getConfig mocks, hand-rolled configs) treats the default as true,
matching the schema default.

Tests cover empty pool, default-skip non-exhausted, default-skip
exhausted (still 401), explicit skip_exhausted=false exhausted
(now authenticated), and disabled accounts (still 401).
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.

1 participant