Skip to content

refactor(usage): split usage.ts + proxy hardening (Theme X2)#33

Merged
NagyVikt merged 1 commit into
mainfrom
agent/x2-usage-split
May 18, 2026
Merged

refactor(usage): split usage.ts + proxy hardening (Theme X2)#33
NagyVikt merged 1 commit into
mainfrom
agent/x2-usage-split

Conversation

@NagyVikt
Copy link
Copy Markdown
Collaborator

Theme X2 — usage.ts split + proxy hardening

Implements Theme X2 from docs/future/17-ROADMAP.md and the 5-file split sketched in docs/future/01-ARCHITECTURE.md §2.2.

Exit criteria

  • src/lib/accounts/usage/ directory exists with api-client.ts, proxy-client.ts, local-rollout.ts, math.ts, index.ts.
  • usage.ts is removed (no shim — only internal consumers existed; from "../usage" resolves to usage/index.ts).
  • Proxy client refuses to send credentials over non-loopback URLs even when CODEX_LB_DASHBOARD_* env vars are set.
  • src/tests/usage-math.test.ts covers remainingPercent, usageScore, shouldSwitchCurrent exhaustively (41 cases).

New files (LOC)

File LOC Purpose
src/lib/accounts/usage/math.ts 80 Pure math: remainingPercent, resolveRateWindow, usageScore, shouldSwitchCurrent
src/lib/accounts/usage/local-rollout.ts 107 fetchUsageFromLocal(codexDir) — walks ~/.codex/sessions/ jsonl
src/lib/accounts/usage/api-client.ts 47 fetchUsageFromApi(parsed) — single ChatGPT backend-api fetch with 5s timeout
src/lib/accounts/usage/proxy-client.ts 518 fetchUsageFromProxy() — dashboard session, password env, TOTP, non-loopback refusal
src/lib/accounts/usage/index.ts 17 Public barrel
src/lib/accounts/usage/_internal/snapshot-parsers.ts 87 Shared rate-limits parser helpers (api + local)
src/tests/usage-math.test.ts new 41 exhaustive math tests

(N2-introduced usage/adapter.ts is unchanged; its from "../usage" import now resolves to usage/index.ts.)

Proxy hardening details

  • New error class ProxyInsecureUrlError extends AuthmuxError with code = "E_PROXY_INSECURE_URL", slotted into the N3 taxonomy.
  • Loopback gate accepts literal 127.0.0.0/8, ::1, localhost, and IPv4-mapped IPv6 loopback. Deceptive hostnames (127.example.com, 127.0.0.1.evil.com) are refused.
  • Env resolution is lazy per call (N4 lazy paths): CODEX_LB_DASHBOARD_URL takes precedence over CODEX_LB_URL; default falls back to http://127.0.0.1:2455.
  • AUTHMUX_PROXY_INSECURE=1 opts back into pre-X2 permissive behavior with a process.emitWarning on every call. Will be removed in the next minor release.

Verification

$ CODEX_LB_DASHBOARD_URL=https://evil.example.com/dashboard node -e '...'
OK refused: E_PROXY_INSECURE_URL

$ CODEX_LB_DASHBOARD_URL=http://127.0.0.1:2455 node -e '...'
OK loopback path runs, result: index

$ CODEX_LB_DASHBOARD_URL=https://evil.example.com AUTHMUX_PROXY_INSECURE=1 node -e '...'
WARN: Proxy non-loopback URL allowed — credentials sent over non-loopback. Will be hard-blocked next release.
OK runs with warning, result: null

Edge cases additionally verified locally: http://localhost:2455 accepted, http://[::1]:2455 accepted, http://127.0.0.5:2455 accepted, https://127.example.com refused, http://127.0.0.1.evil.example.com refused.

Test plan

  • npm run build — clean
  • npm test — 170/170 pass (was 129/129; +41 usage-math cases)
  • Manual proxy verification: refusal, override warning, loopback acceptance
  • No behavior change in API/local paths (helpers unchanged, same return contracts)

🤖 Generated with Claude Code

…ing (X2)

Theme X2 from the authmux improvement protocol. The 660-line usage.ts
co-resident with three subsystems (public API client, localhost proxy
with auth dance, local rollout walker) plus pure scoring math is split
into focused modules:

  usage/api-client.ts      —  fetchUsageFromApi(parsed)
  usage/proxy-client.ts    —  fetchUsageFromProxy() + dashboard session
  usage/local-rollout.ts   —  fetchUsageFromLocal(codexDir)
  usage/math.ts            —  pure remainingPercent/usageScore/...
  usage/index.ts           —  barrel
  usage/_internal/snapshot-parsers.ts — shared parser helpers

Proxy hardening: by default the proxy client now refuses to send
dashboard credentials to non-loopback URLs (literal 127.0.0.0/8, ::1,
localhost). Behind AUTHMUX_PROXY_INSECURE=1 the legacy permissive
behavior is preserved for one minor release, with a process.emitWarning
on every call. Refusal raises ProxyInsecureUrlError (code
E_PROXY_INSECURE_URL) extending AuthmuxError per the N3 taxonomy. Env
vars CODEX_LB_DASHBOARD_URL / CODEX_LB_URL are resolved lazily per call
per N4 conventions.

Tests: src/tests/usage-math.test.ts adds 41 cases covering
remainingPercent, resolveRateWindow, usageScore, shouldSwitchCurrent
edge cases (0%, 100%, NaN, negative, reset-expiry, fallback windows,
threshold boundaries). All 170 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@NagyVikt NagyVikt merged commit 8413f87 into main May 18, 2026
12 checks passed
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