Skip to content

fix(storage): make state writes atomic and single-writer - #182

Open
squarepots wants to merge 23 commits into
Lampese:mainfrom
squarepots:fix/durable-state-mutations
Open

squarepots wants to merge 23 commits into
Lampese:mainfrom
squarepots:fix/durable-state-mutations

Conversation

@squarepots

@squarepots squarepots commented Sep 21, 2026 •

Copy link
Copy Markdown

本 PR 同时解决持久状态的两类故障:文件写入中断造成的损坏,以及多个进程并发 read-modify-write 造成的更新丢失。

账号 mutation 统一通过 mutate_accounts,设置 mutation 统一通过 mutate_app_settings,并分别使用跨进程锁串行化。accounts、settings 和 Codex auth.json 都通过同目录临时文件写入、sync_all 和同文件系统原子替换保存;Windows 使用 replace/write-through,Unix secret 临时文件从创建时即为 0600。现有文件路径、JSON schema 和 active-account 行为保持不变。

新增测试覆盖锁竞争、成功替换、替换前失败时保留旧文件,以及 Unix 限制权限。

验证

  • rustfmt --edition 2021 --check src-tauri/src/auth/storage.rs
  • cargo check --manifest-path src-tauri/Cargo.toml --locked
  • cargo test --manifest-path src-tauri/Cargo.toml --locked:53 项通过
  • cargo fmt --manifest-path src-tauri/Cargo.toml --all -- --check 仅报告现有 src-tauri/src/tray.rs 格式漂移;本 PR 变更文件通过 targeted rustfmt

Closes #159


This PR addresses both durable-state failure modes: corruption from interrupted writes and lost updates when several processes perform read-modify-write operations concurrently.

Account mutations now go through mutate_accounts, settings mutations go through mutate_app_settings, and each path is serialized with a cross-process lock. Accounts, settings, and Codex auth.json are written to same-directory temporary files, synchronized with sync_all, and atomically replaced on the same filesystem. Windows uses replace/write-through behavior, while Unix secret temporaries have 0600 permissions from creation. Existing paths, JSON schemas, and active-account behavior remain unchanged.

New tests cover lock contention, successful replacement, preservation of the old file when replacement fails, and restrictive Unix permissions.

Validation

  • rustfmt --edition 2021 --check src-tauri/src/auth/storage.rs
  • cargo check --manifest-path src-tauri/Cargo.toml --locked
  • cargo test --manifest-path src-tauri/Cargo.toml --locked: 53 passed
  • cargo fmt --manifest-path src-tauri/Cargo.toml --all -- --check reports only pre-existing formatting drift in src-tauri/src/tray.rs; the changed file passes targeted rustfmt

Closes #159

Restores #169 after the source fork was accidentally deleted.


Maintenance triage — 2026-09-30

Prevents future interrupted/concurrent writes; does not repair existing corrupted JSON (#100) or add legacy ChatGPT enum aliases (#58). Preserve both separate acceptance cases.

@Lampese Lampese added bug Something isn't working area:storage Account/settings persistence, data recovery, imports and backups. priority:P1 Address first: auth, data integrity, security, startup or release validation. status:needs-review Maintainer review required; this label is not merge approval. status:needs-ci No check rollup is visible for the current PR head; validate before landing. labels Sep 30, 2026
Bl0ck154 added a commit to Bl0ck154/codex-switcher that referenced this pull request Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:storage Account/settings persistence, data recovery, imports and backups. bug Something isn't working priority:P1 Address first: auth, data integrity, security, startup or release validation. status:needs-ci No check rollup is visible for the current PR head; validate before landing. status:needs-review Maintainer review required; this label is not merge approval.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make durable state persistence atomic and single-writer

2 participants