fix(runtime): reject array helper-status files; dedupe isRecord - #544
Conversation
…me-current-account, usage and models commands Per-file line coverage (same metric as the full-suite baseline run): - lib/storage/snapshot-inspectors.ts: 34.7% -> 100% (66 uncovered lines -> 0); describeAccountsWalSnapshot was fully untested - lib/runtime/runtime-current-account.ts: 77.6% -> 99.0% (43 -> 2) - lib/codex-manager/commands/usage.ts: 86.1% -> 100% (45 -> 0) - lib/codex-manager/commands/models.ts: 72.2% -> 100% (20 -> 0) Behaviors pinned: - WAL snapshot inspection: missing-file short-circuit, malformed/forged journal entries (checksum mismatch never reaches the normalizer), schema-valid fast path, raw-JSON legacy fallback with schemaErrors surfaced and non-numeric storedVersion dropped, EACCES read failures reported as existing-but-invalid. - Runtime current-account resolution: index fallback (truncation, negative/out-of-range/NaN rejection) and contradiction checks where a signal's id/email disagrees with the indexed account; helper status file parsing (1 MB cap, type normalization, malformed JSON). Pinned quirk: isRecord() accepts JSON arrays, so an "[]" status file yields an all-null status object instead of null (downstream kind check still rejects it) - suspected oversight, behavior pinned, not fixed. - usage --since parsing (relative 30m/24h/7d/2W against the clock via fake timers, epoch passthrough as number, date strings as strings) and the default atomic report writer (nested mkdir, .tmp consumed on success, EBUSY rename retry, non-retryable failure cleans the staged temp file that briefly exists next to the destination). - models command: --help short-circuits before account loading, --model value validation (missing/empty/flag-like), text-mode availability lines incl. disabled-account reasons, quota cache load failures swallowed. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
The local isRecord copy in runtime-current-account.ts had drifted from the canonical lib/utils.ts guard and accepted JSON arrays, so an [] helper-status file produced an all-null status object instead of null (harmless today only because the downstream kind check rejected it). Deletes the drifted duplicate in favor of the canonical import and flips the behavior-pinning test from PR #543 to the corrected contract. 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 10 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ 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 (5)
✨ 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 |
The createDeps helper inlined the exact drifted array-accepting guard this PR removes from runtime-current-account.ts. Import the canonical helper from lib/utils.js instead so the test deps cannot silently diverge from the production contract. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
…g it Use APP_RUNTIME_HELPER_STATUS_FILE from lib/runtime-constants.js so a rename of the status file cannot silently turn the readAppRuntimeHelperStatus tests into file-not-found nulls. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Inline the #544 isRecord and #546 stream-stall references so the 'surfaced real bugs twice' claim is verifiable without scrolling to section 5.1. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Summary
Fixes the bug surfaced by #543's coverage work: the local
isRecordcopy inlib/runtime/runtime-current-account.tshad drifted from the canonicallib/utils.tsguard and accepted JSON arrays, so an[]helper-status file produced an all-null status object instead ofnull. Harmless today only because the downstreamkindcheck happened to reject the all-null object — but it's exactly the class of silent drift the canonical guard exists to prevent.Changes
isRecordduplicate; imports the canonicalisRecordfromlib/utils.js(which already does!Array.isArray(value)). No cycle risk — utils is a leaf.[]helper-status file now reads asnull(malformed content), not an all-null record.Note for a future sweep: four more files carry local
isRecordcopies (commands/rotation.ts,codex-cli/writer.ts,codex-cli/state.ts, plus one in recovery) — each needs its own semantics check before deduping, so they're deliberately out of scope here.Validation
npm run typecheck; eslint--max-warnings=0runtime-current-accountsuite 17/17 with the corrected expectation; proxy safe-equal + issue-474 + app-router canaries passRisk / Rollback
One guard tightened to match the canonical implementation; revert the single commit. Behavior change is strictly: malformed array status files are now rejected at read time instead of one step later.
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
replaces the drifted local
isRecordcopy inruntime-current-account.tswith the canonical import fromlib/utils.ts, which correctly excludes arrays via!Array.isArray(value). this closes the silent gap where a[]status file produced an all-null object instead ofnull.runtime-current-account.ts— the local duplicate is deleted and the canonical guard takes over, so array-shaped status files are now rejected at theisRecordboundary rather than one step later by thekindcheck.test/runtime-current-account.test.tsgets a fullreadAppRuntimeHelperStatussuite including the array-rejection regression case;test/snapshot-inspectors.test.tsis a new file that uses the canonicalisRecordimport increateDeps(addressing the previous review comment), and two other test files gain additional command-level coverage.removeWithRetry, consistent with the project convention.Confidence Score: 5/5
safe to merge — a one-import swap tightening a guard on an untrusted filesystem read, with a direct regression test covering the corrected behavior
the change is minimal and targeted: the local isRecord copy is deleted, the canonical version (which adds !Array.isArray) is imported, and the new test explicitly asserts that an array status file now returns null. no logic paths beyond the guard change are touched, and downstream consumers of readAppRuntimeHelperStatus are unaffected because the stricter guard only rejects already-malformed input.
no files require special attention — all changed files are straightforward
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[readAppRuntimeHelperStatus] --> B{file exists?} B -- no --> Z1[return null] B -- yes --> C{size > 1 MB?} C -- yes --> Z2[return null] C -- no --> D[JSON.parse file] D --> E{isRecord check} E -- before fix: typeof===object && !==null\naccepts arrays --> F_OLD[array → all-null status object] E -- after fix: canonical isRecord\n!Array.isArray added --> F_NEW[array → return null] F_OLD --> G[downstream kind check rejects] F_NEW --> Z3[return null early] E -- plain object --> H[build AppRuntimeHelperAccountStatus] H --> I[return normalized status]Reviews (2): Last reviewed commit: "Merge branch 'claude/audit-25-coverage-g..." | Re-trigger Greptile