feat(auth): add migrateLegacyAuth helper (4/4)#28
Conversation
doistbot
left a comment
There was a problem hiding this comment.
This PR introduces the final piece of the multi-account auth migration by adding a helper to transition legacy single-user states into the new UserRecordStore. The implementation provides a thoughtful, best-effort fallback mechanism that gracefully handles runtime errors while aiming to protect sensitive user data. However, there are a few areas to refine, such as ensuring the migration is strictly idempotent to prevent stale tokens from triggering accidental re-logins if the initial cleanup fails. Additional adjustments are noted around tightening the return type with a discriminated union, running I/O cleanup operations concurrently, refining how unavailable keyrings are handled, and removing unreachable skip reasons or potentially sensitive log fields.
492efcf to
d196148
Compare
469a73a to
856dc50
Compare
d196148 to
4c1b71a
Compare
856dc50 to
dbb9fe7
Compare
4c1b71a to
e808bd1
Compare
dbb9fe7 to
6f11571
Compare
76f4a3e to
5fb4526
Compare
ee4b302 to
0ef044b
Compare
|
@doistbot /review |
doistbot
left a comment
There was a problem hiding this comment.
This PR introduces a well-structured helper for migrating legacy single-user authentication states into the new v2 multi-account architecture. The best-effort design provides a robust upgrade path while successfully avoiding credential leakage in the logs. A few adjustments are needed to preserve existing default accounts during retries, safely catch synchronous errors in cleanup callbacks, and properly export the new skip reason types. Additionally, refining the legacy store instantiation, updating the README examples to include config paths, and adding tests for custom account mappings and legacy precedence will help ensure the migration logic is completely solid.
Generic one-time helper that walks a v1 single-user keyring + plaintext config slot into the v2 multi-account `UserRecordStore` + per-user keyring slots. Builds on the shared `writeRecordWithKeyringFallback` helper so the migration write path is the same as runtime `set()`: keyring → fallbackToken on `SecureStoreUnavailableError`, with rollback on upsert failure. Best-effort throughout: identify-failure, keyring-write-failure, and upsert-failure all return a `skipped` status without touching the v1 state, so the consumer's runtime fallback can keep serving the legacy token until the next attempt. Default promotion + legacy keyring delete + `cleanupLegacyConfig` are all best-effort outside the critical section. stderr output uses a fixed phrase keyed off an internal `SkipReason` enum so consumer-supplied exception text (which may contain emails, paths, or auth diagnostics) can't leak into logs. The raw detail is still attached to `MigrateAuthResult.reason` for in-process callers (doctor commands, tests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0ef044b to
5c5559f
Compare
## [0.16.0](v0.15.0...v0.16.0) (2026-05-16) ### Features * **auth:** add migrateLegacyAuth helper ([#28](#28)) ([cd7baee](cd7baee))
|
🎉 This PR is included in version 0.16.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Stack position: 4 / 4 — base is #27 (
feat/keyring-token-store-multi-account). Replaces the last part of #24.Summary
Generic one-time helper that walks a v1 single-user keyring + plaintext config slot into the v2 multi-account
UserRecordStore+ per-user keyring slots. Builds onwriteRecordWithKeyringFallbackfrom #27 so the migration write path is the same as runtimeset(): keyring →fallbackTokenonSecureStoreUnavailableError, with rollback on upsert failure.Best-effort throughout: identify-failure, keyring-write-failure, and upsert-failure all return a
skippedstatus without touching the v1 state, so the consumer's runtime fallback can keep serving the legacy token until the next attempt. Default promotion, legacy keyring delete, andcleanupLegacyConfigare all best-effort outside the critical section.stderr output uses a fixed phrase keyed off an internal
SkipReasonenum so consumer-supplied exception text (which may contain emails, paths, or auth diagnostics) can't leak into logs. The raw detail is still attached toMigrateAuthResult.reasonfor in-process callers.Usage
Test plan
npm run type-check,npm run check,npm test(336 passing, +8 for migrate covering already-migrated / no-legacy-state / online keyring / plaintext fallback / fully-offline keyring / identify-failure / two privacy assertions)🤖 Generated with Claude Code