Skip to content

fix(coding-agent): write settings and credentials atomically and migrate auth safely - #989

Closed
Adolanium wants to merge 1 commit into
PrimeIntellect-ai:mainfrom
Adolanium:fix/983-credential-file-durability
Closed

fix(coding-agent): write settings and credentials atomically and migrate auth safely#989
Adolanium wants to merge 1 commit into
PrimeIntellect-ai:mainfrom
Adolanium:fix/983-credential-file-durability

Conversation

@Adolanium

@Adolanium Adolanium commented Aug 8, 2026

Copy link
Copy Markdown

Fixes #983.

What was broken

Three ways to silently lose settings or credentials:

  1. FileSettingsStorage.withLock computed the next state before taking the lock when the file did not exist yet, so two concurrent first-time creators both merged from empty state and the later write won. It also wrote directly to the target, so a crash mid-write left a truncated settings.json that the loader silently replaced with defaults.
  2. FileAuthStorageBackend wrote auth.json in place on both the sync and async paths. A crash mid-write corrupted every stored OAuth refresh token and API key at once.
  3. migrateAuthToAuthJson renamed oauth.json to .migrated and deleted apiKeys from settings.json before auth.json was written. A crash in that window left nothing to migrate on the next run.

The fix

  • Settings writes now re-read under the lock before a first-time write and go through temp file + rename.
  • Both auth write paths go through temp file (0o600 at creation) + chmod + rename, mirroring the existing writePrimeCliConfigData pattern.
  • The migration writes auth.json first and only then rewrites settings.json and renames oauth.json.

Locking structure, the sync retry API, and the OAuth refresh flow are unchanged.

Testing

  • New regression file test/suite/regressions/983-credential-file-durability.test.ts (5 tests): migration ordering asserted via recorded fs events, re-read under lock on first creation, temp+rename with no leftovers on the settings and auth paths.
  • npx tsx ../../node_modules/vitest/dist/cli.js --run on the new file plus the existing auth-storage, settings-manager, and migrations suites: all green. (Three failures in auth-storage.test.ts / auth-flows.test.ts / 4620-fast-mode-settings reproduce on pristine main and are unrelated, verified in a clean worktree.)
  • npm run check clean.

Note

Write auth.json and settings.json atomically and harden credential migration

  • Auth writes in FileAuthStorageBackend now go through a new writeAtomically helper: content is written to a uniquely-named 0600 temp file in the same directory, then renamed over the target, avoiding truncation on crash.
  • Settings writes in FileSettingsStorage use a new writeSettingsFileAtomically helper with the same temp-file-and-rename approach; first-time creation re-reads under the lock to avoid losing concurrent writes.
  • migrateAuthToAuthJson now writes auth.json durably (via atomic helper, 0600) before removing apiKeys from settings.json or renaming oauth.json, reducing credential loss risk on crash mid-migration.
  • A new regression test suite in 983-credential-file-durability.test.ts verifies atomic rename behavior, lock re-read semantics, and restrictive file permissions.

Macroscope summarized 99a136c.

…ate auth safely

- FileSettingsStorage.withLock re-reads the settings file under the lock before a first-time write, so concurrent creators no longer lose each other's updates, and writes go through a temp file and rename instead of truncating settings.json in place.
- FileAuthStorageBackend writes auth.json via a 0600 temp file and atomic rename on both the sync and async lock paths, so a crash mid-write can no longer corrupt all stored credentials.
- migrateAuthToAuthJson writes auth.json first and only then rewrites settings.json and renames oauth.json to .migrated, so a crash during migration cannot destroy credentials.

fixes PrimeIntellect-ai#983
@sethkarten

Copy link
Copy Markdown
Contributor

Thank you for the report and proposed work. This root cause is now covered by maintainer-owned stacked PR #1160, authored independently from upstream/main.

We did not inspect or reuse this PR's diff, branch, commits, implementation code, or tests; its public description/comments were used only as a bug report. To keep one review surface, this PR is superseded by #1160 and is being closed.

The complete review stack is #1158#1165. It is being left unmerged for human review after CI and review-bot findings are cleared.

@sethkarten sethkarten closed this Aug 10, 2026
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.

Settings and credential files can be silently lost: non-atomic writes and unsafe auth migration order

2 participants