fix(configure): preserve existing config instead of overwriting it - #72
Merged
Merged
Conversation
runConfigure never read the existing config: it built a fresh Config with a hardcoded default_provider and an empty Favorites map and saved that, so every re-run of `grant configure` silently destroyed the user's favorites, default_provider and cache_ttl. It now loads the existing config and merges onto a successful load, overwriting only the fields it owns. The rebuild-from-defaults path is kept for the case config.Load fails, which is what keeps configure reachable when the on-disk config is unloadable (no-lockout), and it now warns on stderr instead of discarding the file silently.
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.
The bug
runConfigure(cmd/configure.go) never read the existing config file. It constructed a fresh&config.Config{}with a hardcodeddefault_provider: azureand an emptyFavoritesmap andSaved that over the top.User impact
Every re-run of
grant configure— including the auto-configure branch ingrant login— silently destroyed:grant favorites addwork, gone with no prompt and no message)default_providercache_ttlThe fix
runConfigurenow resolves the config path first, callsconfig.Load, and merges onto a successful load, overwriting only the field it owns (profile). Everything else in the file is carried through untouched.config.LoadreturnsDefaultConfig(), nilforos.ErrNotExist, so a first run merges onto defaults rather than taking the fallback — asserted by a test rather than assumed.Loadnever returns a partial config (every failure path returnsnil, err), so there is no half-loaded state to reason about.The no-lockout property, and how it is preserved
The clobber was also what kept
grant configureusable when the on-disk config could not be loaded (e.g.cache_ttl: garbage) — the only command that can repair such a file must not itself fail on it. That is preserved exactly: whenconfig.Loadreturns an error, configure falls back toconfig.DefaultConfig()and writes it, as before. Making configure fail on an unloadable config would lock the user out; it does not.Two changes on that path:
CLAUDE.mdkeeps that guidance, and thecache_ttlerror messages continue not to point atconfigure.Existing test renamed — deliberately, not silently
TestConfigure_OverwritesInvalidCacheTTLAndClobbersFavorites→TestConfigure_UnloadableConfigIsRebuiltFromDefaults.Its fixture is an unloadable config, so every one of its assertions still holds: configure succeeds,
cache_ttlis rewritten away, favorites anddefault_providerare lost. Its intent — pin no-lockout, and keep the collateral loss visible so nobody mistakes configure for a safe repair tool — is unchanged and now also asserts the stderr warning. Only the name changed, because "ClobbersFavorites" is no longer true in general: a loadable config is preserved. The doc comment now cross-references the preservation test.No other test depended on the clobber (
rgover the repo: only this one).Tests added
TestConfigure_PreservesExistingConfigOnRerun— loadable config: favorites,default_provider: awsandcache_ttl: 30mall survive.TestConfigure_FirstRunMergesOntoDefaults— no config file: succeeds onto defaults, empty favorites, no rebuild warning.TestConfigure_UnloadableConfigIsRebuiltFromDefaults— renamed above, plus the stderr-warning assertions.Written first; all three failed against the old implementation on the assertions that matter.
Verification
gofmt -s -l .go build ./...go test -race -count=1 ./...go test -tags=integration -count=1 ./cmdgo test -shuffle=on -count=1 ./cmdgolangci-lint runDocs
CHANGELOG.md: one### Fixedline under[Unreleased].CLAUDE.md: the Config section's "known sharp edge / deliberately not fixed" passage is rewritten — the clobber half is fixed; the no-lockout property and the "never advertise configure as the remedy" guidance are retained and re-justified for the fallback path.docs/mutation-ledger.md: CFG-02's parenthetical about configure never callingLoadis marked superseded.