Description
The parameterless-ISettings overload of NuGetCache.EnsureCachedAsync (the one used
internally by nuget-installer's CLI) calls:
Settings.LoadDefaultSettings(null)
Passing a literal null root means NuGet's settings loader never scans the current working
directory (or any ancestor) for a project-local nuget.config — it only loads the
machine-wide and user-wide ( ~/.nuget/NuGet/NuGet.Config / %APPDATA%\NuGet\NuGet.Config )
settings. Any repository that defines its real package sources in a repo-local nuget.config
(an extremely common setup — e.g. <clear /> followed by explicit <add key=... value=.../>
entries, with only <packageSourceCredentials> living in the user-level config) will have
those sources silently invisible to nuget-installer , which then only ever queries
whatever's left over in the user/machine-wide config (in our case, just nuget.org ).
This was previously misdiagnosed (by us) as the 401/credential-service registration bug fixed
in 1.3.0 (#60) — it is not. #60 fixes a distinct scenario (credential-provider plugins); this
issue reproduces identically on 1.3.0 with that fix in place, because the actual configured
JFrog sources are never loaded in the first place, so no request (successful or 401) is ever
made against them at all.
### Steps to Reproduce
Given a repo with:
• A repo-local nuget.config at the repo root defining the real package sources (e.g. private
JFrog Artifactory feeds via <clear/> + <add key="..." value=".../index.json" /> ).
• A user-level ~/.nuget/NuGet/NuGet.Config containing only nuget.org as a source, plus
<packageSourceCredentials> entries for the JFrog source names (no matching <packageSources>
entries there).
Run (from the repo root, exactly as nuget-installer 's CLI does):
var settings = NuGet.Configuration.Settings.LoadDefaultSettings(null);
foreach (var s in new NuGet.Configuration.PackageSourceProvider(settings).LoadPackageSources())
Console.WriteLine(s.Name);
// Output: only "nuget.org"
versus:
var settings = NuGet.Configuration.Settings.LoadDefaultSettings(Directory.GetCurrentDirectory());
foreach (var s in new NuGet.Configuration.PackageSourceProvider(settings).LoadPackageSources())
Console.WriteLine(s.Name);
// Output: all repo-local sources (launchcode-nuget-remote, skylight-nuget-local-public, ...) plus nuget.org
The dotnet CLI / MSBuild restore pipeline always passes an ambient root (effectively the
current directory), which is why dotnet restore finds these sources correctly while
nuget-installer does not — despite both nominally reading "the default NuGet settings."
### Expected Behavior
NuGetCache.EnsureCachedAsync(packageId, version) should pass an appropriate root (at minimum
Directory.GetCurrentDirectory() , ideally configurable) to Settings.LoadDefaultSettings , so
that a project/repo-local nuget.config is discovered the same way dotnet restore discovers
it. Without this, nuget-installer cannot be used at all against any repo whose real package
sources live outside the user/machine-wide config — which is the normal, recommended way to
scope NuGet sources per-repository.
### Actual Behavior
## Suggested fix
public static async Task<string> EnsureCachedAsync(
string packageId,
string version,
CancellationToken cancellationToken = default)
{
return await EnsureCachedAsync(
packageId, version, Settings.LoadDefaultSettings(Directory.GetCurrentDirectory()), cancellationToken);
}
(or better, thread through the CLI's own working directory / a --root / --config option, in
case the tool is ever invoked from a directory other than the one containing the relevant
nuget.config ).
### Code Sample
```csharp
Tool Version
0.4.0
.NET Version
.NET 10
Operating System
Linux (Ubuntu, WSL2)
Additional Context
No response
Checklist
Description
The parameterless-
ISettingsoverload ofNuGetCache.EnsureCachedAsync(the one usedinternally by
nuget-installer's CLI) calls:Tool Version
0.4.0
.NET Version
.NET 10
Operating System
Linux (Ubuntu, WSL2)
Additional Context
No response
Checklist