fix: make credential file writes atomic and fail closed on corruption#244
Open
bukinoshita wants to merge 4 commits intomainfrom
Open
fix: make credential file writes atomic and fail closed on corruption#244bukinoshita wants to merge 4 commits intomainfrom
bukinoshita wants to merge 4 commits intomainfrom
Conversation
…losed on corruption - Add writeFileAtomic: writes to tmp file, fsyncs, renames over original - Add withFileLock: advisory lock with stale detection for read/modify/write - readCredentials now throws CorruptedCredentialsError on malformed JSON instead of silently returning null (which caused storeApiKey to rebuild an empty config and erase all existing profiles) - removeApiKey no longer deletes the file when it can't parse JSON - All mutators (storeApiKey, removeApiKey, setActiveProfile, renameProfile, storeApiKeyAsync) wrapped in file lock to prevent concurrent overwrites - All mutations use immutable spread patterns instead of in-place mutation - logout command gracefully handles corrupted credentials by catching the error and proceeding to the removal path Fixes: BU-652 Co-authored-by: Bu Kinoshita <bukinoshita@users.noreply.github.com>
Member
Author
|
@cubic-dev-ai can you review? |
Contributor
@bukinoshita I have started the AI code review. It will take a few minutes to complete. |
Contributor
There was a problem hiding this comment.
3 issues found across 7 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/lib/file-lock.ts">
<violation number="1" location="src/lib/file-lock.ts:61">
P2: `sleepSync` burns 100% CPU while spinning. Use `Atomics.wait` for a zero-CPU synchronous sleep — it's available in all supported Node versions (≥20).</violation>
</file>
<file name="src/lib/config.ts">
<violation number="1" location="src/lib/config.ts:394">
P1: The auto-migration write inside `resolveApiKeyAsync` still mutates `creds` in-place and calls `writeCredentials` without `withFileLock`, leaving the same lost-update race this PR eliminates everywhere else. Wrap the write in `withFileLock` and use immutable updates to match the other mutators.</violation>
</file>
<file name="src/commands/auth/logout.ts">
<violation number="1" location="src/commands/auth/logout.ts:52">
P2: This change still allows an uncaught credentials-read throw via `resolveProfileName()`, so logout can crash on corrupted credentials instead of reaching the `remove_failed` handling path.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by cubic
Prevents silent loss of saved auth profiles by making credential writes atomic and locked, and by failing closed on corrupted JSON.
credentials.json.readCredentials()throwsCorruptedCredentialsErroron invalid JSON; file is preserved; mutators stop instead of rebuilding empty state.storeApiKey,removeApiKey,setActiveProfile,renameProfile,storeApiKeyAsync) use immutable updates under the lock;removeApiKeyno longer deletes on parse failure.Written for commit 219f90b. Summary will update on new commits.