Skip to content

fix: add rollback semantics to secure-storage credential operations#241

Draft
bukinoshita wants to merge 2 commits intomainfrom
fix/auth-secure-storage-desync-4109
Draft

fix: add rollback semantics to secure-storage credential operations#241
bukinoshita wants to merge 2 commits intomainfrom
fix/auth-secure-storage-desync-4109

Conversation

@bukinoshita
Copy link
Copy Markdown
Member

@bukinoshita bukinoshita commented Apr 9, 2026

Summary by cubic

Adds transactional rollback to secure-storage credential operations so the OS keychain and credentials.json stay in sync.

  • Bug Fixes
    • storeApiKeyAsync: roll back backend.set() if writing credentials.json fails.
    • removeApiKeyAsync: require backend.delete() to return true; restore the key if file removal fails.
    • removeAllApiKeysAsync: remove the file only if all backend deletes succeed; throw with failed profile names otherwise.
    • renameProfileAsync: verify old-name delete; clean up new-name or restore old-name if file rename fails.

Written for commit 10df862. Summary will update on new commits.

cursoragent and others added 2 commits April 9, 2026 17:43
Resolve data integrity issue (BU-632) where secure-storage login/logout
paths could leave local auth state inconsistent when a backend or
filesystem failure occurs mid-operation.

Changes to src/lib/config.ts:
- storeApiKeyAsync: roll back backend.set() if credentials file write fails
- removeApiKeyAsync: verify backend.delete() returns true before proceeding;
  restore the key in the backend if file removal fails afterward
- removeAllApiKeysAsync: aggregate all delete results and abort with error
  if any backend deletion fails, preserving the credentials file
- renameProfileAsync: verify backend.delete() returns true; roll back
  backend state if either the old-name delete fails or the file rename
  fails

Tests added for each failure mode:
- storeApiKeyAsync: backend rollback on file write failure
- removeApiKeyAsync: throws on false delete return; restores key on
  file failure
- removeAllApiKeysAsync: preserves file when any backend delete fails
- renameProfileAsync: cleans up new-name on old-name delete failure;
  restores old-name on file write failure

Co-authored-by: Bu Kinoshita <bukinoshita@users.noreply.github.com>
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.

2 participants