Repository navigation
fix(codex): keep two host-lane records that a failed read used to destroy (STA-4735) - #15289
Conversation
…troy (STA-4735) `snapshotCodexRuntimeHookTrustProvenance` rebuilt `.orca-hook-trust-provenance.json` from the current `config.toml` on every install and refresh, including when the existing record could not be read. That record is the only thing separating a trust entry Orca wrote from one the user approved inside Codex, so rewriting it after a failed read stamps the approval as Orca-written — and `promoteCodexRuntimeHookApprovalsToSystem`, which runs earlier in the same pass and had already bailed on the same unreadable file, then skips it on every later pass too. One denied read, permanent loss. Only the unreadable case is preserved. A malformed or absent record is still rebuilt, because resetting those IS the intent; conflating the two would wedge a user on a corrupt file forever. `fileContentsEqual` returned `false` from a bare `catch`, so "I could not read this" reached `writeRuntimeAuth` as "these differ" and sent it to the unconditional write below — replacing a refresh token Codex may have rotated a moment earlier with Orca's stale copy. It now reports the difference only when the bytes were actually compared, and the caller refuses instead. `fileContentsMatchExpected`'s `!existsSync` has the same collapse but is left alone deliberately: the write it guards is `writeFileAtomicallyIfUnchanged`, whose rename-and-compare re-checks the real file and refuses on its own, so classifying there would add a guard no test can drive. Noted in a comment. The three `writeRuntimeAuthAtPath` call sites have the same overwrite shape but are all on the WSL lane, which STA-4606 restructures; refusing there without its lane bookkeeping would set a baseline for a write that never happened.
📝 WalkthroughWalkthroughThe change adds definitive filesystem-absence detection for 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/codex-accounts/runtime-home-service.ts (1)
2016-2020: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueShorten the changed TypeScript comments.
Keep only the non-obvious safety invariant. Move detailed regression history to the test name or issue reference.
src/main/codex-accounts/runtime-home-service.ts#L2016-L2020: reduce the credential-overwrite rationale to one short comment.src/main/codex-accounts/runtime-home-service.ts#L2071-L2075: reduce the comparison contract comment to one short comment.src/main/codex-accounts/runtime-home-service.ts#L2091-L2095: reduce the conditional-write note to one short comment.src/main/codex-accounts/sta-4735-unreadable-host-lane-writes.test.ts#L16-L17: remove or shorten the file-level regression summary.src/main/codex-accounts/sta-4735-unreadable-host-lane-writes.test.ts#L138-L141: shorten the expected-behavior explanation.src/main/codex-accounts/sta-4735-unreadable-host-lane-writes.test.ts#L153-L154: shorten the readable-file test rationale.src/main/codex/hook-trust-promotion.ts#L47-L50: reduce thenullcontract comment to one short statement.src/main/codex/hook-trust-promotion.ts#L91-L98: reduce the provenance preservation rationale to one short statement.src/main/codex/sta-4735-hook-trust-provenance-overwrite.test.ts#L7-L11: remove or shorten the file-level regression summary.src/main/codex/sta-4735-hook-trust-provenance-overwrite.test.ts#L126-L128: shorten the expected-behavior explanation.src/main/codex/sta-4735-hook-trust-provenance-overwrite.test.ts#L133-L134: shorten the absent-file test rationale.src/main/codex/sta-4735-hook-trust-provenance-overwrite.test.ts#L142-L144: shorten the malformed-file test rationale.As per coding guidelines: “Comments must be concise, non-obvious, and brief—prefer one line.”
Source: Coding guidelines
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a71fb037-ca10-43b1-b24c-cdd9063279cf
📒 Files selected for processing (5)
src/main/codex-accounts/runtime-home-service.tssrc/main/codex-accounts/sta-4735-unreadable-host-lane-writes.test.tssrc/main/codex/hook-trust-promotion.tssrc/main/codex/sta-4735-hook-trust-provenance-overwrite.test.tssrc/shared/definitive-filesystem-absence.ts
Included review availability: Your plan includes up to 10 reviews per rolling hour; 4 remain after this review.
VerdictPASS — I found no release-blocking or correctness issues in the PR after rebasing it onto current FindingsNo new issues found, so there are no additional file:line fixes to request. The reviewed behavior is now:
Sweep results
Mutation checks
|
…troy (STA-4735) (stablyai#15289) `snapshotCodexRuntimeHookTrustProvenance` rebuilt `.orca-hook-trust-provenance.json` from the current `config.toml` on every install and refresh, including when the existing record could not be read. That record is the only thing separating a trust entry Orca wrote from one the user approved inside Codex, so rewriting it after a failed read stamps the approval as Orca-written — and `promoteCodexRuntimeHookApprovalsToSystem`, which runs earlier in the same pass and had already bailed on the same unreadable file, then skips it on every later pass too. One denied read, permanent loss. Only the unreadable case is preserved. A malformed or absent record is still rebuilt, because resetting those IS the intent; conflating the two would wedge a user on a corrupt file forever. `fileContentsEqual` returned `false` from a bare `catch`, so "I could not read this" reached `writeRuntimeAuth` as "these differ" and sent it to the unconditional write below — replacing a refresh token Codex may have rotated a moment earlier with Orca's stale copy. It now reports the difference only when the bytes were actually compared, and the caller refuses instead. `fileContentsMatchExpected`'s `!existsSync` has the same collapse but is left alone deliberately: the write it guards is `writeFileAtomicallyIfUnchanged`, whose rename-and-compare re-checks the real file and refuses on its own, so classifying there would add a guard no test can drive. Noted in a comment. The three `writeRuntimeAuthAtPath` call sites have the same overwrite shape but are all on the WSL lane, which STA-4606 restructures; refusing there without its lane bookkeeping would set a baseline for a write that never happened.
…troy (STA-4735) (stablyai#15289) `snapshotCodexRuntimeHookTrustProvenance` rebuilt `.orca-hook-trust-provenance.json` from the current `config.toml` on every install and refresh, including when the existing record could not be read. That record is the only thing separating a trust entry Orca wrote from one the user approved inside Codex, so rewriting it after a failed read stamps the approval as Orca-written — and `promoteCodexRuntimeHookApprovalsToSystem`, which runs earlier in the same pass and had already bailed on the same unreadable file, then skips it on every later pass too. One denied read, permanent loss. Only the unreadable case is preserved. A malformed or absent record is still rebuilt, because resetting those IS the intent; conflating the two would wedge a user on a corrupt file forever. `fileContentsEqual` returned `false` from a bare `catch`, so "I could not read this" reached `writeRuntimeAuth` as "these differ" and sent it to the unconditional write below — replacing a refresh token Codex may have rotated a moment earlier with Orca's stale copy. It now reports the difference only when the bytes were actually compared, and the caller refuses instead. `fileContentsMatchExpected`'s `!existsSync` has the same collapse but is left alone deliberately: the write it guards is `writeFileAtomicallyIfUnchanged`, whose rename-and-compare re-checks the real file and refuses on its own, so classifying there would add a guard no test can drive. Noted in a comment. The three `writeRuntimeAuthAtPath` call sites have the same overwrite shape but are all on the WSL lane, which STA-4606 restructures; refusing there without its lane bookkeeping would set a baseline for a write that never happened.
…troy (STA-4735) (stablyai#15289) `snapshotCodexRuntimeHookTrustProvenance` rebuilt `.orca-hook-trust-provenance.json` from the current `config.toml` on every install and refresh, including when the existing record could not be read. That record is the only thing separating a trust entry Orca wrote from one the user approved inside Codex, so rewriting it after a failed read stamps the approval as Orca-written — and `promoteCodexRuntimeHookApprovalsToSystem`, which runs earlier in the same pass and had already bailed on the same unreadable file, then skips it on every later pass too. One denied read, permanent loss. Only the unreadable case is preserved. A malformed or absent record is still rebuilt, because resetting those IS the intent; conflating the two would wedge a user on a corrupt file forever. `fileContentsEqual` returned `false` from a bare `catch`, so "I could not read this" reached `writeRuntimeAuth` as "these differ" and sent it to the unconditional write below — replacing a refresh token Codex may have rotated a moment earlier with Orca's stale copy. It now reports the difference only when the bytes were actually compared, and the caller refuses instead. `fileContentsMatchExpected`'s `!existsSync` has the same collapse but is left alone deliberately: the write it guards is `writeFileAtomicallyIfUnchanged`, whose rename-and-compare re-checks the real file and refuses on its own, so classifying there would add a guard no test can drive. Noted in a comment. The three `writeRuntimeAuthAtPath` call sites have the same overwrite shape but are all on the WSL lane, which STA-4606 restructures; refusing there without its lane bookkeeping would set a baseline for a write that never happened.
ELI5
Two files on the host Codex lane were rewritten or replaced because Orca "couldn't find" them — when in fact it just couldn't read them for a moment. One of them is the record of which hook approvals you made versus which Orca made, and losing it means your approval is silently reclassified as Orca's and never promoted again.
What Changed
1. The hook-trust provenance record
.orca-hook-trust-provenance.jsonis the only thing separating aconfig.tomltrust entry Orca wrote from one the user approved inside Codex.snapshotCodexRuntimeHookTrustProvenancerebuilt it from the currentconfig.tomlon every install and refresh — including when the existing record could not be read.The chain is what makes it permanent, and it runs entirely within one install pass:
promoteCodexRuntimeHookApprovalsToSystem(hook-service.ts:1271) reads the provenance, getsnullfrom the unreadable file, and bails — so a genuine user approval is not promoted.snapshotCodexRuntimeHookTrustProvenance(hook-service.ts:1391) then overwrites the record from the current config, which now says Orca wrote that entry.One denied read, and the approval is gone for good.
Only the unreadable case is preserved. An absent or malformed record is still rebuilt, because resetting those is the intent — conflating the two would wedge a user on a corrupt file forever. That distinction has its own test.
2.
fileContentsEqualfalsereacheswriteRuntimeAuthas "these differ", which sends it to the unconditional write below — replacing a refresh token Codex may have rotated moments earlier with Orca's stale copy. Codex uses rotating refresh tokens, so consuming a rotation twice invalidates the credential permanently; this is the same permanent-logout outcome STA-4422 was reported for.It now reports a difference only when the bytes were actually compared, and the caller refuses.
Why
These are the two host-lane instances left over after #15046 and #15093. They were catalogued while planning STA-4606 and moved out of it because that ticket is the WSL lane.
Two things deliberately left alone
fileContentsMatchExpected's!existsSynchas exactly the same collapse. I wrote the fix and a test for it, then found the test passed with the fix reverted: the write it guards iswriteFileAtomicallyIfUnchanged, whose rename-and-compare re-checks the real file and refuses on its own. Rather than ship a guard no test can drive, the fix is reverted and the reasoning is a comment in the code.The three
writeRuntimeAuthAtPathcall sites have the same overwrite shape, but all three are on the WSL lane, which STA-4606 restructures. Making it refuse there without that ticket's lane bookkeeping would leavelastWrittenWslAuthJsonByDistrorecording a baseline for a write that never happened — a new bug traded for an old one.Linked Issue
Fixes STA-4735. Same defect class as #15046, #15093, #15279, #15287.
Visual Proof
N/A — no UI change. The observable difference is that a file survives, which the tests assert byte-for-byte.
Testing
Two files, 5 tests: 2 driving the fix, 3 anchoring it.
The rig models one denial coherently — a denied path throws from
readFileSync/lstatSync/statSyncand reportsfalsefromexistsSync.Mutation-checked:
hook-trust-promotion.tsruntime-home-service.tsThe credential test also asserts the injected fault was actually consumed by the code under test, so it cannot pass by never reaching the read.
Anchors: a genuinely absent provenance file is still seeded, a malformed one is still replaced, and a readable runtime
auth.jsonis still written normally. Each of these would break under a fix that simply stopped writing.1068/1068 across
codex+codex-accounts.check-changed-code-quality.mjs: 0 findings. Fullpnpm typecheckclean.Automated tests added
Manual: not run. The trigger is a file-denial race reproduced deterministically by the rig.
Merge note
Carries a byte-identical copy of
src/shared/definitive-filesystem-absence.ts, also added by #15279 and #15287, so all three merge cleanly in any order. No dependency between them.AI Disclosure
N/A — internal.