fix(import): skip re-importing a saved account instead of duplicating it (#59) - #65
Merged
Merged
Conversation
… it (#59) import is create-only, so re-importing an already-saved account wrote a second profile for it. Because OpenAI refresh tokens are single-use, the two copies then raced: whichever refreshed first rotated the token and the other died with refresh_token_reused, forcing a full re-login. Worse, the usage-service validation that runs during import rotates the token itself, so the duplicate was created with a fresh token while the source file (and any existing profile sharing that token) was left holding a dead one. Add profile::existing_import_target: a read-only check that returns the saved profile these credentials already belong to — byte-identical to a stored profile, or the same account_id AND email. import now consults it before the token-rotating validation and skips the file (action "unchanged") when a match is found, so no duplicate is written and the single-use token is never spent. The check only declines, never overwrites, so it cannot hand credentials to the wrong profile and keeps the deliberate create-only safety of save_imported_auth_value intact. Docs updated; unit test covers identity match and a distinct-account miss. Co-authored-by: xJoker <xjoker@users.noreply.github.com>
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.
Fixes #59.
Problem
importis deliberately create-only. If the incomingauth.jsonbelongs to an account that already has a profile, it still wrote a second one (create_import_profileonly de-duplicates on alias-name clashes). Because OpenAI refresh tokens are single-use, the two copies then race: whichever refreshes first (vialistor the daemon) rotates the token and the other dies withrefresh_token_reused, forcing a full re-login.It is worse than a duplicate: the usage-service validation that runs during import rotates the token itself, so the new profile is written with a fresh token while the source file — and any existing profile that shared that token — is left holding a dead one.
Fix
Add
profile::existing_import_target(source, val)— a read-only check that returns the saved profile these credentials already belong to:find_matching_profile), oraccount_idand email (find_profile_by_identity_exact).import_one_fileconsults it before the token-rotating validation and, on a match, skips the file with action"unchanged"(single-file: a clear "already saved … runloginto refresh" message; directory: reported asunchanged). No duplicate profile is written and the single-use refresh token is never spent.Requiring email in addition to
account_idmeans a shared Teamaccount_idnever matches a different member, and because the check only ever declines (never overwrites), it cannot hand credentials to the wrong profile — the deliberate create-only safety ofsave_imported_auth_valueis left intact.Tests
profile::existing_import_target_matches_saved_account_and_ignores_others— a rotated-token re-import of a saved account (different bytes) is detected by identity; a genuinely different account returnsNone.CODEX_SWITCH_HOME): re-importing a saved account printsAlready saved as profile 'alice'; skipped … to protect its single-use refresh token, creates no second profile, makes no network call, and exits 0.Docs
Updated the wiki
Feature-Guide.mdandCommand-Reference.mdto describe the skip-on-duplicate behavior.Verification (Linux)
cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings,cargo test --all— all pass, 0 failed.Note: the CI Format and audit job will be red until #63 (webbrowser RUSTSEC-2026-0257 lockfile bump) merges to
dev; that failure is pre-existing and unrelated to this change.