Resolve settings path deterministically and stop reads from clobbering settings.json#183
Conversation
There was a problem hiding this comment.
Copilot wasn't able to review any files in this pull request.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: isourabh <2982389+isourabh@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
A relative MSSTORE_SETTINGS_DIRECTORY can reintroduce CWD-dependent behavior, LoadAsync still has write-side effects that can fail in read-only environments, and the updated critical message can be misleading when a config file exists but is incomplete.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 3
- Review effort level: Lite
Co-authored-by: isourabh <2982389+isourabh@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The MSSTORE_SETTINGS_DIRECTORY override currently accepts relative values (reintroducing CWD-dependent resolution) and the updated “SellerId is not set” message can be misleading when a config file exists but lacks SellerId.
Review details
Suppressed comments (2)
MSStore.CLI/Services/ConfigurationManager.cs:41
MSSTORE_SETTINGS_DIRECTORYis documented as requiring an absolute path, but the code currently accepts a relative value and normalizes it withPath.GetFullPath(...), which makes the resolved settings directory depend on the current working directory and can reintroduce the cross-invocation mismatch this PR is fixing. Consider validating that the override is rooted and failing fast (or ignoring it) when it is not.
var settingsDirectoryOverride = Environment.GetEnvironmentVariable(SettingsDirectoryEnvironmentVariable);
if (!string.IsNullOrWhiteSpace(settingsDirectoryOverride))
{
return Path.GetFullPath(settingsDirectoryOverride);
}
MSStore.CLI/MicrosoftStoreCLI.cs:122
- This log message now states "No configuration was found" when
SellerIdis null, butSellerIdcan also be null when a settings file exists but is missing/cleared/partially-populated. To avoid misleading users, consider wording that reflects what you actually know here (you checked the resolved settings path, andSellerIdis not set).
if (config.SellerId == null)
{
logger.LogCritical("SellerId is not set. No configuration was found at '{SettingsPath}'. Please, run the 'reconfigure' command.", configurationManager.ConfigPath);
return false;
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The new MSSTORE_SETTINGS_DIRECTORY override currently allows relative paths, which can reintroduce CWD-dependent (non-deterministic) settings resolution.
Review details
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
MSStore.CLI/MicrosoftStoreCLI.cs:121
- The critical error message contains a grammatical comma (“Please, run ...”). This reads like a typo and will be user-visible in logs; consider changing it to “Please run ...”.
MSStore.CLI/Services/ConfigurationManager.cs:41
MSSTORE_SETTINGS_DIRECTORYis documented as requiring an absolute path, but the implementation accepts relative values and normalizes them withPath.GetFullPath(...), which makes the settings directory depend on the current working directory again (reintroducing the original non-determinism). Consider rejecting non-rooted overrides with a clear exception message (or other explicit handling) so the override cannot silently become CWD-relative.
var settingsDirectoryOverride = Environment.GetEnvironmentVariable(SettingsDirectoryEnvironmentVariable);
if (!string.IsNullOrWhiteSpace(settingsDirectoryOverride))
{
return Path.GetFullPath(settingsDirectoryOverride);
}
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
…only Co-authored-by: isourabh <2982389+isourabh@users.noreply.github.com>
Co-authored-by: isourabh <2982389+isourabh@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
LoadAsync currently opens the config file with read/write access (File.Open(..., FileMode.Open) default), which can break read-only loading scenarios and undermines the PR’s goal of making configuration loads non-writing/non-requiring write permissions.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
MSStore.CLI/Services/ConfigurationManager.cs:133
- LoadAsync opens the settings file with File.Open(path, FileMode.Open), which defaults to read/write access. This can make a read-only config load fail on read-only filesystems or when the settings file is not writable, contradicting the goal that loading should not require write access.
}
using var file = File.Open(_settingsPath, FileMode.Open);
return await JsonSerializer.DeserializeAsync(file, _jsonTypeInfo, ct) ?? new T();
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Lite
| Path.IsPathRooted(configurationManager.ConfigPath).Should().BeTrue(); | ||
| configurationManager.ConfigPath.Should().NotContain("relative"); |
There was a problem hiding this comment.
🔵 Needs a closer look
LoadAsync still opens the settings file with read-write access, which can fail on read-only settings files/mounts and undermines the intended “read-only load” behavior.
Review details
Suppressed comments (3)
Previously missed (2) — in code that hasn't changed since the last review.
MSStore.CLI/MicrosoftStoreCLI.cs:121
- The critical log message has an unnecessary comma after "Please" ("Please, run...") which reads awkwardly in English.
README.md:13 - In README, "MacOS" should be spelled "macOS" (Apple’s official styling) for consistency with common platform naming.
MSStore.CLI/Services/ConfigurationManager.cs:132
- LoadAsync still opens the settings file with File.Open(path, FileMode.Open), which defaults to FileAccess.ReadWrite and FileShare.None. That can fail when the settings file is readable but not writable (or on read-only mounts), contradicting the goal that loading should not require write access.
return new T();
}
using var file = File.Open(_settingsPath, FileMode.Open);
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
On Linux, a successful
reconfigurewrites a validsettings.json, yet every subsequentmsstoreinvocation fails withSellerId is not set.and no exception logged — the CLI is looking at (and silently overwriting) a different location than the one it wrote.Root cause
ConfigurationManager<T>usedEnvironment.GetFolderPath(SpecialFolder.LocalApplicationData)unvalidated:HOMEdiffers between invocations — e.g. the ephemeralHOMEcommonly used to unlock a freshgnome-keyringon headless Linux:reconfigurewrites under the ephemeralHOME, every later call reads the real one.LoadAsynccalledClearAsync, writing an empty settings.json as a side effect of a read, and logged nothing — hence a "successful" load with a nullSellerIdand no exception.InitAsyncbails beforeinfo --verbosegets to printSettings File Path.Changes
ConfigurationManagerGetSettingsDirectory()always returns a rooted path, with a rooted fallback when the OS cannot resolve local application data.MSSTORE_SETTINGS_DIRECTORYenvironment variable to pin the settings folder, for containers/CI where local application data is unresolvable or unstable.LoadAsyncreturns defaults and logs the probed path instead of writing an empty config.SaveAsyncensures the settings directory exists.MicrosoftStoreCLI.InitAsync—SellerId is not set.now reports the resolved settings file path and points atreconfigure.ConfigurationManagerUnitTestscovers the override, rootedness, no-write-on-missing-file, save/load round-trip, and invalid-config handling with and withoutclearInvalidConfig.