microsoft / MSBuildSdks

MSBuild project SDKs
MIT License
460 stars 82 forks source link

[BUG] dotnet restore failed when api.nuget.org is blocked in firewall and custom feed is provided #558

Closed JohanSpannare closed 4 months ago

JohanSpannare commented 7 months ago

Background

We are running Azure DevOps Server on-prem. And for security reason we are not allowing internet access from our build agents. Instead all agents are configured to use internal nuget feeds configured in Artifactory mirroring nuget.org.

In below example i have disabled the access to api.nuget.org on my local laptop. This is being able to reproduce the error locally.

Example

nuget sources

Registered Sources:
  1.  nuget.org [Enabled]
      https://artifactory.XXXX.com/artifactory/api/nuget/nuget.remote/

dotnet build

MSBuild version 17.9.4+90725d08d for .NET
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : Could not resolve SDK "Microsoft.VisualStudio.JavaScript.Sdk". Exactly one of the probing messages below indicates why we could not r
esolve the SDK. Investigate and resolve that message to correctly specify the SDK.
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error :   SDK resolver "Microsoft.DotNet.MSBuildWorkloadSdkResolver" returned null.
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error :   Unable to find package Microsoft.VisualStudio.JavaScript.Sdk. No packages exist with this id in source(s): nuget.org
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error :   MSB4276: The default SDK resolver failed to resolve SDK "Microsoft.VisualStudio.JavaScript.Sdk" because directory "C:\Program Files
\dotnet\sdk\8.0.200\Sdks\Microsoft.VisualStudio.JavaScript.Sdk\Sdk" did not exist.
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning : Unable to load the service index for source https://api.nuget.org/v3/index.json.
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning NU1503: Skipping restore for project 'C:\repo\CST.Klas\cst.klas\cst.klas.esproj'. The project file may be invalid or missing targets
required for restore. [C:\repo\CST.Klas\CST.Klas.sln]
  Determining projects to restore...
  All projects are up-to-date for restore.

Build FAILED.

C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning : Unable to load the service index for source https://api.nuget.org/v3/index.json.
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning NU1503: Skipping restore for project 'C:\repo\CST.Klas\cst.klas\cst.klas.esproj'. The project file may be invalid or missing targets
required for restore. [C:\repo\CST.Klas\CST.Klas.sln]
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : Could not resolve SDK "Microsoft.VisualStudio.JavaScript.Sdk". Exactly one of the probing messages below indicates why we could not r
esolve the SDK. Investigate and resolve that message to correctly specify the SDK.
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error :   SDK resolver "Microsoft.DotNet.MSBuildWorkloadSdkResolver" returned null.
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error :   Unable to find package Microsoft.VisualStudio.JavaScript.Sdk. No packages exist with this id in source(s): nuget.org
C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error :   MSB4276: The default SDK resolver failed to resolve SDK "Microsoft.VisualStudio.JavaScript.Sdk" because directory "C:\Program Files
\dotnet\sdk\8.0.200\Sdks\Microsoft.VisualStudio.JavaScript.Sdk\Sdk" did not exist.
    2 Warning(s)
    1 Error(s)

Time Elapsed 00:00:18.24

Expected result

I expect that any nuget feed configured should be used when resolving SDK´s as well for custom nuget packages.

MSBuild version 17.9.4+90725d08d for .NET
  Determining projects to restore...
  All projects are up-to-date for restore.
  CST.API.Motor.Klas -> C:\repo\CST.Klas\CST.API.Motor.Klas\bin\Debug\net8.0\CST.API.Motor.Klas.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:03.10

Work around

To get around this error, i manually have to preload the nuget cache. This so when MSBuildSdks is trying to resolve and dependencies. It do not need to go externally to download the package via api.nuget.org that is blocked.

mkdir ./dummy;
cd ./dummy;
dotnet new classlib;
dotnet add package Microsoft.VisualStudio.JavaScript.Sdk -s https://artifactory.XXXX.com/artifactory/api/nuget/nuget.remote/

$latestVersion= (Get-ChildItem ~\.nuget\packages\microsoft.visualstudio.javascript.sdk\ -Directory | Sort-Object -Descending)[0].FullName
$latestSDKVersion = (Get-ChildItem 'C:\Program Files\dotnet\sdk\' -Directory |Where-Object -Property name -Match "8."|  Sort-Object -Descending)[0].FullName

cp $latestVersion $latestSDKVersion\sdks\microsoft.visualstudio.javascript.sdk\ -Recurse -Force -ErrorAction Ignore
JohanSpannare commented 7 months ago

@jeffkl

uberDoward commented 5 months ago

This is, indeed, a problem. Trying to use Microsoft.Build.Sql (sqlproj) from a build server with custom nuget feeds enabled, and having the same issue.

jeffkl commented 4 months ago

This looks like an authentication problem, when the NuGet-based MSBuild project SDK resolver contacts the feed it doesn't have any access.

Its a little confusing, do you have a source named "nuget.org" that's really an artifactory URL?

This error says

warning : Unable to load the service index for source https://api.nuget.org/v3/index.json.

But you don't have nuget.org configured?

Keep in mind that the NuGet-based MSBuild project SDK resolver can only be configured via NuGet.config and setting MSBuild properties to configured feeds is not supported. So whatever feed is in the NuGet.config is what will be used. It finds the NuGet.config nearest the project or solution file.

JohanSpannare commented 4 months ago

Hi @jeffkl, in this example the feed is named nuget.org and pointing towards an Artifactory instance. But it cant be an authentication problem because the feed works for other packages referenced by the project it self.

Same problem also happen when using Azure DevOps as feed source.

I have an open support case with Microsoft, i added you to the mail conversation a while ago. You should be able to read the mail thread and also see the 3 demos i had with Microsoft Support.

You mentioned above that NuGet.config is the file that will be used as source in SDK resolver. I will state that that is incorrect, whatever you set in NuGet.config is not respected by the resolver. That is the problem!.

Below you can see the result of cat NuGet.Config, nuget locals all -clear; dotnet build and ping api.nuget.org

PS C:\repo\CST.Klas> cat .\NuGet.config <?xml version="1.0" encoding="utf-8"?>

PS C:\repo\CST.Klas> nuget locals all -clear; dotnet build Clearing NuGet HTTP cache: C:\Users\UserName\AppData\Local\NuGet\v3-cache Clearing NuGet global packages folder: C:\Users\UserName.nuget\packages\ Clearing NuGet Temp cache: C:\Users\UserName\AppData\Local\Temp\NuGetScratch Clearing NuGet plugins cache: C:\Users\UserName\AppData\Local\NuGet\plugins-cache Local resources cleared. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning : Unable to load the service index for source https://api.nuget.org/v3/index.json. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning NU1503: Skipping restore for project 'C:\repo\CST.Klas\cst.klas\cst.klas.esproj'. The project file may be invalid or missing targets required for restore. [C:\repo\CST.Klas\CST.Klas.sln] Determining projects to restore... C:\Program Files\dotnet\sdk\8.0.301\NuGet.targets(169,5): warning : Unable to find a project to restore! [C:\repo\CST.Klas\CST.Klas.sln] C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : Could not resolve SDK "Microsoft.VisualStudio.JavaScript.Sdk". Exactly one of the probing messages below indicate s why we could not resolve the SDK. Investigate and resolve that message to correctly specify the SDK. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : SDK resolver "Microsoft.DotNet.MSBuildWorkloadSdkResolver" returned null. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : Unable to find package Microsoft.VisualStudio.JavaScript.Sdk. No packages exist with this id in source(s): nuge t.org C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning : Unable to load the service index for source https://api.nuget.org/v3/index.json. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error MSB4236: The SDK 'Microsoft.VisualStudio.JavaScript.Sdk/1.0.862903' specified could not be found.

Build FAILED.

C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning : Unable to load the service index for source https://api.nuget.org/v3/index.json. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning NU1503: Skipping restore for project 'C:\repo\CST.Klas\cst.klas\cst.klas.esproj'. The project file may be invalid or missing targets required for restore. [C:\repo\CST.Klas\CST.Klas.sln] C:\Program Files\dotnet\sdk\8.0.301\NuGet.targets(169,5): warning : Unable to find a project to restore! [C:\repo\CST.Klas\CST.Klas.sln] C:\repo\CST.Klas\cst.klas\cst.klas.esproj : warning : Unable to load the service index for source https://api.nuget.org/v3/index.json. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : Could not resolve SDK "Microsoft.VisualStudio.JavaScript.Sdk". Exactly one of the probing messages below indicate s why we could not resolve the SDK. Investigate and resolve that message to correctly specify the SDK. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : SDK resolver "Microsoft.DotNet.MSBuildWorkloadSdkResolver" returned null. C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error : Unable to find package Microsoft.VisualStudio.JavaScript.Sdk. No packages exist with this id in source(s): nuge t.org C:\repo\CST.Klas\cst.klas\cst.klas.esproj : error MSB4236: The SDK 'Microsoft.VisualStudio.JavaScript.Sdk/1.0.862903' specified could not be found. 4 Warning(s) 2 Error(s)

Time Elapsed 00:00:12.53 PS C:\repo\CST.Klas> ping api.nuget.org

Pinging api.nuget.org [127.0.0.1] with 32 bytes of data: Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

To reproduce this error set a hosts record for api.nuget.org like below

Add this two lines to C:\Windows\System32\drivers\etc\hosts

127.0.0.1 api.nuget.org 127.0.0.1 nuget.org

Make sure your global NuGet.config at C:\Users\UserName\AppData\Roaming\NuGet\NuGet.Config do not have any proxy configuration set.

>   <config>
>     <!-- <add key="http_proxy" value="http://proxyServer:8080" /> -->
>     <!-- <add key="http_proxy.user" value="proxyUser" /> -->
>     <!-- <add key="no_proxy" value="*.myDomain" /> -->
>   </config>
jeffkl commented 4 months ago

Okay can you help me understand better?

You do not have access to nuget.org from the agent but you have a proxy server and your NuGet.config contains that proxy server? In your cat NuGet.config above, I don't see what feeds you have configured. If the NuGet APIs can't contact api.nuget.org, I'd expect the above error. I'll try to set up a proxy to test locally.

Do you have only one feed configured and your NuGet.Config looks like:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="http_proxy" value="http://proxyServer:8080" />
    <add key="http_proxy.user" value="proxyUser" />
    <add key="no_proxy" value="*.myDomain" />
  </config>
  <packageSources>
    <clear />
    <add key="artifactory" value="https://artifactory.XXXX.com/artifactory/api/nuget/nuget.remote/" />
  </packageSources>
</configuration>

If you the <clear /> first in the <packageSources /> element and only one feed configured, NuGet should not be trying to contact api.nuget.org at all.

jeffkl commented 4 months ago

I'm wondering where NuGet is being told to contact api.nuget.org at all. If your NuGet.config looks like this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="http_proxy" value="http://127.0.0.1:8080" />
    <add key="http_proxy.user" value="proxyUser" />
    <add key="no_proxy" value="*.myDomain" />
  </config>
  <packageSources>
    <clear />
    <add key="artifactory" value="https://artifactory.com/artifactory/api/nuget/nuget.remote/" />
  </packageSources>
</configuration>

That <clear /> in the <packageSources /> should remove any other configured sources leaving only a single feed to contact and I would not expect NuGet to be contacting api.nuget.org at all? What exactly does your NuGet.config have?

JohanSpannare commented 4 months ago

I have to confess that this is not an BUG, its a user side error.

While trying to understand where the api.nuget.org was coming from. I ran process monitor on dotnet process.

While reading the output i saw this line... image

The developer had by mistake added an nuget.config file to the project directory. So whatever nuget setting that was configured to the root directory nuget file, was overwritten by the project level nuget config.

After deleting this file i can confirm that the resolve of SDK dependencies is now working as expected!

Thank you @jeffkl for being inquisitive and therefor rubber-ducking me!

jeffkl commented 4 months ago

Sorry for the bad experience. At the end of a normal NuGet restore, all of the NuGet.config files that were used are printed to the console. But when the SDK resolver runs, it doesn't print that sort of info. That might be a good feature so I filed an issue at https://github.com/NuGet/Home/issues/13602 that maybe I can include in a future update to the SDK resolver.