Repository navigation
fix(config): read each saved secret once per command - #117
Merged
Merged
Conversation
The macOS Keychain can ask for approval on every read, and one command read a saved login once for each credential lookup. Settings now keeps a secret in memory after the first read or write. Taking the credential lock forgets it, so a refresh still sees a token another process saved. Refs #116, DEV-2952
tee8z
approved these changes
Oct 26, 2026
tee8z
left a comment
Contributor
There was a problem hiding this comment.
The design holds up. A refresh still reads the store again under the lock. A failed write or a delete clears the cached secret. holds_secret bypasses the cache on purpose, and Settings has no Debug, so the cached secrets cannot be printed.
Non-blocking: lock() clears every cached secret, and create_profile, add_account, and profiles delete take the lock as well as a refresh does. So a command that reads a secret and then saves configuration can still prompt twice on macOS. To keep the refresh guarantee and avoid that, you could clear only the secret that the refresh reads again. Clearing everything is the safer default, and the description already names the limit, so this is fine to merge as it is.
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.
Problem
On macOS, one command could ask for the keychain password several times. Each credential lookup read the saved secret from the store again: a picker, the wallet currency lookup, the wallet shortlist, and then the API call. A user who selects "Allow" instead of "Always Allow" gets one prompt for each read.
Change
Settingsnow keeps each secret in memory after the first read or write. The process reads the store at most once for each secret, so a command shows at most one prompt.The lock rule keeps refreshes correct. A refresh reads the login again under the lock. That read goes to the store, so it sees a token that another process rotated while this one waited. A refresh therefore reads the store one more time, as before.
Limit: if another process logs out, a long-running command such as
payments list --watchsees that only at its next refresh or 401 retry, not at its next read.This change does not fix the prompts after each upgrade. That needs Developer ID signing of the macOS release binaries, which #116 tracks.
Tests
a_secret_is_read_once_until_the_lock_is_taken: a secret changed by anotherSettingsis not seen until the lock is taken.a_deleted_or_failed_write_reads_the_store_again: after a write that fails after its rename, and after a delete, the next read goes to the store.Settings, because a long-lived one keeps what it read before the CLI subprocess ran.Checks
cargo fmt --check,cargo clippy --locked --all-targets -- -D warnings,cargo machete --with-metadata,cargo test --locked,python3 scripts/check-coverage.py: all pass.src/api.rswait_for_payment, which this change does not touch).voltage-pr-review: one cleanup was applied (aSecretstype alias).Refs #116, DEV-2952