refactor: throw CodexValidationError from rotation-proxy startup guards - #586
Conversation
First slice of the audit's §4.3 error-contract adoption (M11). The two startup guards in startRuntimeRotationProxy — the loopback-only host refusal and the missing clientApiKey check — now throw CodexValidationError with field/expected metadata (and the offending host in context) instead of bare Error. Messages are byte-identical, so existing message-matching callers and tests are unaffected; callers can now branch on instanceof or the stable CODEX_VALIDATION_ERROR code. Documents the guarantee in docs/reference/error-contracts.md (new Typed Error Classes section) and pins it with a test asserting the class, field, and context from both guards. The remaining bare throws in savePluginConfig are deferred until #585 merges - they sit inside the ESTALE CAS block that PR rewrites. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
Warning Review limit reached
More reviews will be available in 18 minutes and 54 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
startRuntimeRotationProxynow throwCodexValidationErrorwith machine-readable metadata instead of bareError, and the guarantee is documented indocs/reference/error-contracts.md.What Changed
lib/runtime-rotation-proxy.ts— two conversions, messages byte-identical:CodexValidationErrorwithfield: "host",expected: "a loopback host", and the offending host incontext.host.clientApiKeycheck throwsCodexValidationErrorwithfield: "clientApiKey",expected: "a non-empty string".Since messages are unchanged, every existing message-matching caller and test (
rejects.toThrow("clientApiKey"),/non-loopback/i,/loopback-only/i) passes untouched; callers gaininstanceof CodexValidationErrorand the stableCODEX_VALIDATION_ERRORcode.docs/reference/error-contracts.md— new "Typed Error Classes" section: lists thelib/errors.tshierarchy and records the startup-guard guarantee, so the contract doc is backed by machine-readable types as §4.3 intended. It sits next to the existing note that the dual-call helpers deliberately throw nativeTypeError(that convention is unchanged).test/runtime-rotation-proxy.test.ts— one new test capturing both guard rejections and asserting the class,field, andcontextpayloads.Scope Note
The three remaining bare throws in
lib/config.ts(Aborting config save because … is unreadable.) are deliberately deferred: one of them sits inside the ESTALE CAS block that open PR #585 rewrites, and converting them now would make my own two open PRs conflict. They'll be a tiny follow-up once #585 merges. After that, the three files §4.3 names carry no bare throws (fetch-helpers already has none — it returns mapped Responses by design).Validation
npm run typecheck(also in the pre-commit hook)npx eslint lib/runtime-rotation-proxy.ts test/runtime-rotation-proxy.test.ts --max-warnings=0npm test -- test/runtime-rotation-proxy.test.ts— 77 passed; the only 2 failures are the documented IPv6-disabled-container baseline names (EAFNOSUPPORT ::1, both present verbatim indocs/audits/evidence/test-baseline-2026-06-10.txt)npm run builddeferred to CIDocs and Governance Checklist
docs/reference/error-contracts.mdupdated in the same PR as the behavior it documentsCodexValidationError extends CodexError extends Error, so allinstanceof Errorhandling is unaffectedRisk and Rollback
https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Generated by Claude Code
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
tightens the two startup guards in
startRuntimeRotationProxyfrom bareErrortoCodexValidationErrorwith machine-readablefield,expected, andcontextfields, and documents the contract inerror-contracts.md. messages are byte-identical, so all existing message-matching callers and tests are unaffected.lib/runtime-rotation-proxy.ts: host and clientApiKey guards now throwCodexValidationError; callers gaininstanceofbranching and the stableCODEX_VALIDATION_ERRORcode.test/runtime-rotation-proxy.test.ts: new test covers both guards end-to-end, assertingfield,expected, andcontextpayloads.docs/reference/error-contracts.md: new "Typed Error Classes" section records the error hierarchy and the startup-guard guarantee.Confidence Score: 5/5
safe to merge — error class tightened, throw conditions and messages unchanged, backward-compatible via inheritance
both guards are narrow, deterministic throws at startup; the change only adds metadata to the thrown object.
CodexValidationErrorextendsCodexErrorextendsError, so allinstanceof Errorand message-matching paths in existing callers and tests continue to work. the new test fully coversfield,expected, andcontextfor both guards.no files require special attention
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[startRuntimeRotationProxy called] --> B{isLoopbackHost host?} B -- no --> C[throw CodexValidationError\nfield: host\nexpected: a loopback host\ncontext: host] B -- yes --> D{clientApiKey non-empty?} D -- no --> E[throw CodexValidationError\nfield: clientApiKey\nexpected: a non-empty string] D -- yes --> F[continue startup…]Reviews (2): Last reviewed commit: "test: assert the expected field from bot..." | Re-trigger Greptile