dependabot-nuget 0.265.0 → 0.267.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +6 -6
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +173 -0
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalysisResult.cs +1 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +92 -79
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +21 -8
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +36 -9
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Requirement.cs +88 -45
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +33 -16
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -25
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +1 -1
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +9 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/ProjectBuildFile.cs +2 -2
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/MissingFileException.cs +11 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs +8 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +45 -42
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +19 -1
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +2 -1
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationResult.cs +5 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +70 -22
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +29 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +6 -2
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +450 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/CompatibilityCheckerTests.cs +23 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/RequirementTests.cs +1 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +2 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +148 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -1
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +17 -22
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestHttpServer.cs +81 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +27 -7
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +32 -0
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +447 -2
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +88 -0
  35. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -0
  36. data/lib/dependabot/nuget/file_fetcher.rb +30 -11
  37. data/lib/dependabot/nuget/file_updater.rb +2 -0
  38. data/lib/dependabot/nuget/metadata_finder.rb +160 -2
  39. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +3 -0
  40. data/lib/dependabot/nuget/native_helpers.rb +36 -3
  41. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +1 -0
  42. data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +3 -0
  43. metadata +12 -7
@@ -1,3 +1,8 @@
1
+ using System.Collections.Immutable;
2
+ using System.Text.Json;
3
+
4
+ using NuGetUpdater.Core.Updater;
5
+
1
6
  using Xunit;
2
7
 
3
8
  namespace NuGetUpdater.Core.Test.Update;
@@ -1011,6 +1016,307 @@ public partial class UpdateWorkerTests
1011
1016
  );
1012
1017
  }
1013
1018
 
1019
+ [Fact]
1020
+ public async Task UpdateBindingRedirect_DuplicateRedirectsForTheSameAssemblyAreRemoved()
1021
+ {
1022
+ await TestUpdateForProject("Some.Package", "7.0.1", "13.0.1",
1023
+ packages:
1024
+ [
1025
+ MockNuGetPackage.CreatePackageWithAssembly("Some.Package", "7.0.1", "net45", "7.0.0.0"),
1026
+ MockNuGetPackage.CreatePackageWithAssembly("Some.Package", "13.0.1", "net45", "13.0.0.0"),
1027
+ ],
1028
+ projectContents: """
1029
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1030
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1031
+ <PropertyGroup>
1032
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1033
+ </PropertyGroup>
1034
+ <ItemGroup>
1035
+ <None Include="packages.config" />
1036
+ </ItemGroup>
1037
+ <ItemGroup>
1038
+ <None Include="app.config" />
1039
+ </ItemGroup>
1040
+ <ItemGroup>
1041
+ <Reference Include="Some.Package, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null">
1042
+ <HintPath>packages\Some.Package.7.0.1\lib\net45\Some.Package.dll</HintPath>
1043
+ <Private>True</Private>
1044
+ </Reference>
1045
+ </ItemGroup>
1046
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1047
+ </Project>
1048
+ """,
1049
+ packagesConfigContents: """
1050
+ <packages>
1051
+ <package id="Some.Package" version="7.0.1" targetFramework="net45" />
1052
+ </packages>
1053
+ """,
1054
+ additionalFiles:
1055
+ [
1056
+ ("app.config", """
1057
+ <configuration>
1058
+ <runtime>
1059
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
1060
+ <dependentAssembly>
1061
+ <assemblyIdentity name="Some.Package" publicKeyToken="null" culture="neutral" />
1062
+ <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
1063
+ </dependentAssembly>
1064
+ <dependentAssembly>
1065
+ <assemblyIdentity name="Some.Package" publicKeyToken="null" culture="neutral" />
1066
+ <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
1067
+ </dependentAssembly>
1068
+ </assemblyBinding>
1069
+ </runtime>
1070
+ </configuration>
1071
+ """)
1072
+ ],
1073
+ expectedProjectContents: """
1074
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1075
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1076
+ <PropertyGroup>
1077
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1078
+ </PropertyGroup>
1079
+ <ItemGroup>
1080
+ <None Include="packages.config" />
1081
+ </ItemGroup>
1082
+ <ItemGroup>
1083
+ <None Include="app.config" />
1084
+ </ItemGroup>
1085
+ <ItemGroup>
1086
+ <Reference Include="Some.Package, Version=13.0.0.0, Culture=neutral, PublicKeyToken=null">
1087
+ <HintPath>packages\Some.Package.13.0.1\lib\net45\Some.Package.dll</HintPath>
1088
+ <Private>True</Private>
1089
+ </Reference>
1090
+ </ItemGroup>
1091
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1092
+ </Project>
1093
+ """,
1094
+ expectedPackagesConfigContents: """
1095
+ <?xml version="1.0" encoding="utf-8"?>
1096
+ <packages>
1097
+ <package id="Some.Package" version="13.0.1" targetFramework="net45" />
1098
+ </packages>
1099
+ """,
1100
+ additionalFilesExpected:
1101
+ [
1102
+ ("app.config", """
1103
+ <configuration>
1104
+ <runtime>
1105
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
1106
+ <dependentAssembly>
1107
+ <assemblyIdentity name="Some.Package" publicKeyToken="null" culture="neutral" />
1108
+ <bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
1109
+ </dependentAssembly>
1110
+ </assemblyBinding>
1111
+ </runtime>
1112
+ </configuration>
1113
+ """)
1114
+ ]
1115
+ );
1116
+ }
1117
+
1118
+ [Fact]
1119
+ public async Task UpdateBindingRedirect_ExistingRedirectForAssemblyPublicKeyTokenDiffersByCase()
1120
+ {
1121
+ // Generated using "sn -k keypair.snk && sn -p keypair.snk public.snk" then converting public.snk to base64
1122
+ // https://learn.microsoft.com/en-us/dotnet/standard/assembly/create-public-private-key-pair
1123
+ var assemblyStrongNamePublicKey = Convert.FromBase64String(
1124
+ "ACQAAASAAACUAAAABgIAAAAkAABSU0ExAAQAAAEAAQAJJW4hmKpxa9pU0JPDvJ9KqjvfQuMUovGtFjkZ9b0i1KQ/7kqEOjW3Va0eGpU7Kz0qHp14iYQ3SsMzBZU3mZ2Ezeqg+dCVuDk7o2lp++4m1FstHsebtXBetyOzWkneo+3iKSzOQ7bOXj2s5M9umqRPk+yj0ZBILf+HvfAd07iIuQ=="
1125
+ ).ToImmutableArray();
1126
+
1127
+ await TestUpdateForProject("Some.Package", "7.0.1", "13.0.1",
1128
+ packages:
1129
+ [
1130
+ MockNuGetPackage.CreatePackageWithAssembly("Some.Package", "7.0.1", "net45", "7.0.0.0", assemblyPublicKey: assemblyStrongNamePublicKey),
1131
+ MockNuGetPackage.CreatePackageWithAssembly("Some.Package", "13.0.1", "net45", "13.0.0.0", assemblyPublicKey: assemblyStrongNamePublicKey),
1132
+ ],
1133
+ projectContents: """
1134
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1135
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1136
+ <PropertyGroup>
1137
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1138
+ </PropertyGroup>
1139
+ <ItemGroup>
1140
+ <None Include="packages.config" />
1141
+ </ItemGroup>
1142
+ <ItemGroup>
1143
+ <None Include="app.config" />
1144
+ </ItemGroup>
1145
+ <ItemGroup>
1146
+ <Reference Include="Some.Package, Version=7.0.0.0, Culture=neutral, PublicKeyToken=13523fc3be375af1">
1147
+ <HintPath>packages\Some.Package.7.0.1\lib\net45\Some.Package.dll</HintPath>
1148
+ <Private>True</Private>
1149
+ </Reference>
1150
+ </ItemGroup>
1151
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1152
+ </Project>
1153
+ """,
1154
+ packagesConfigContents: """
1155
+ <packages>
1156
+ <package id="Some.Package" version="7.0.1" targetFramework="net45" />
1157
+ </packages>
1158
+ """,
1159
+ additionalFiles:
1160
+ [
1161
+ ("app.config", """
1162
+ <configuration>
1163
+ <runtime>
1164
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
1165
+ <dependentAssembly>
1166
+ <assemblyIdentity name="Some.Package" publicKeyToken="13523FC3BE375AF1" culture="neutral" />
1167
+ <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
1168
+ </dependentAssembly>
1169
+ </assemblyBinding>
1170
+ </runtime>
1171
+ </configuration>
1172
+ """)
1173
+ ],
1174
+ expectedProjectContents: """
1175
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1176
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1177
+ <PropertyGroup>
1178
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1179
+ </PropertyGroup>
1180
+ <ItemGroup>
1181
+ <None Include="packages.config" />
1182
+ </ItemGroup>
1183
+ <ItemGroup>
1184
+ <None Include="app.config" />
1185
+ </ItemGroup>
1186
+ <ItemGroup>
1187
+ <Reference Include="Some.Package, Version=13.0.0.0, Culture=neutral, PublicKeyToken=13523fc3be375af1">
1188
+ <HintPath>packages\Some.Package.13.0.1\lib\net45\Some.Package.dll</HintPath>
1189
+ <Private>True</Private>
1190
+ </Reference>
1191
+ </ItemGroup>
1192
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1193
+ </Project>
1194
+ """,
1195
+ expectedPackagesConfigContents: """
1196
+ <?xml version="1.0" encoding="utf-8"?>
1197
+ <packages>
1198
+ <package id="Some.Package" version="13.0.1" targetFramework="net45" />
1199
+ </packages>
1200
+ """,
1201
+ additionalFilesExpected:
1202
+ [
1203
+ ("app.config", """
1204
+ <configuration>
1205
+ <runtime>
1206
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
1207
+ <dependentAssembly>
1208
+ <assemblyIdentity name="Some.Package" publicKeyToken="13523FC3BE375AF1" culture="neutral" />
1209
+ <bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
1210
+ </dependentAssembly>
1211
+ </assemblyBinding>
1212
+ </runtime>
1213
+ </configuration>
1214
+ """)
1215
+ ]
1216
+ );
1217
+ }
1218
+
1219
+ [Fact]
1220
+ public async Task UpdateBindingRedirect_ConfigXmlDeclarationNodeIsPreserved()
1221
+ {
1222
+ await TestUpdateForProject("Some.Package", "7.0.1", "13.0.1",
1223
+ packages:
1224
+ [
1225
+ MockNuGetPackage.CreatePackageWithAssembly("Some.Package", "7.0.1", "net45", "7.0.0.0"),
1226
+ MockNuGetPackage.CreatePackageWithAssembly("Some.Package", "13.0.1", "net45", "13.0.0.0"),
1227
+ ],
1228
+ projectContents: """
1229
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1230
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1231
+ <PropertyGroup>
1232
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1233
+ </PropertyGroup>
1234
+ <ItemGroup>
1235
+ <None Include="packages.config" />
1236
+ </ItemGroup>
1237
+ <ItemGroup>
1238
+ <None Include="app.config" />
1239
+ </ItemGroup>
1240
+ <ItemGroup>
1241
+ <Reference Include="Some.Package, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null">
1242
+ <HintPath>packages\Some.Package.7.0.1\lib\net45\Some.Package.dll</HintPath>
1243
+ <Private>True</Private>
1244
+ </Reference>
1245
+ </ItemGroup>
1246
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1247
+ </Project>
1248
+ """,
1249
+ packagesConfigContents: """
1250
+ <packages>
1251
+ <package id="Some.Package" version="7.0.1" targetFramework="net45" />
1252
+ </packages>
1253
+ """,
1254
+ additionalFiles:
1255
+ [
1256
+ ("app.config", """
1257
+ <?xml version="1.0" encoding="utf-8"?>
1258
+ <configuration>
1259
+ <runtime>
1260
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
1261
+ <dependentAssembly>
1262
+ <assemblyIdentity name="Some.Package" publicKeyToken="null" culture="neutral" />
1263
+ <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
1264
+ </dependentAssembly>
1265
+ <dependentAssembly>
1266
+ <assemblyIdentity name="Some.Package" publicKeyToken="null" culture="neutral" />
1267
+ <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
1268
+ </dependentAssembly>
1269
+ </assemblyBinding>
1270
+ </runtime>
1271
+ </configuration>
1272
+ """)
1273
+ ],
1274
+ expectedProjectContents: """
1275
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1276
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1277
+ <PropertyGroup>
1278
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1279
+ </PropertyGroup>
1280
+ <ItemGroup>
1281
+ <None Include="packages.config" />
1282
+ </ItemGroup>
1283
+ <ItemGroup>
1284
+ <None Include="app.config" />
1285
+ </ItemGroup>
1286
+ <ItemGroup>
1287
+ <Reference Include="Some.Package, Version=13.0.0.0, Culture=neutral, PublicKeyToken=null">
1288
+ <HintPath>packages\Some.Package.13.0.1\lib\net45\Some.Package.dll</HintPath>
1289
+ <Private>True</Private>
1290
+ </Reference>
1291
+ </ItemGroup>
1292
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1293
+ </Project>
1294
+ """,
1295
+ expectedPackagesConfigContents: """
1296
+ <?xml version="1.0" encoding="utf-8"?>
1297
+ <packages>
1298
+ <package id="Some.Package" version="13.0.1" targetFramework="net45" />
1299
+ </packages>
1300
+ """,
1301
+ additionalFilesExpected:
1302
+ [
1303
+ ("app.config", """
1304
+ <?xml version="1.0" encoding="utf-8"?>
1305
+ <configuration>
1306
+ <runtime>
1307
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
1308
+ <dependentAssembly>
1309
+ <assemblyIdentity name="Some.Package" publicKeyToken="null" culture="neutral" />
1310
+ <bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
1311
+ </dependentAssembly>
1312
+ </assemblyBinding>
1313
+ </runtime>
1314
+ </configuration>
1315
+ """)
1316
+ ]
1317
+ );
1318
+ }
1319
+
1014
1320
  [Fact]
1015
1321
  public async Task PackagesConfigUpdateCanHappenEvenWithMismatchedVersionNumbers()
1016
1322
  {
@@ -1420,6 +1726,143 @@ public partial class UpdateWorkerTests
1420
1726
  """);
1421
1727
  }
1422
1728
 
1729
+ [Fact]
1730
+ public async Task MissingTargetsAreReported()
1731
+ {
1732
+ using var temporaryDirectory = await TemporaryDirectory.CreateWithContentsAsync(
1733
+ [
1734
+ ("project.csproj", """
1735
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1736
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1737
+ <Import Project="this.file.does.not.exist.targets" />
1738
+ <PropertyGroup>
1739
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1740
+ </PropertyGroup>
1741
+ <ItemGroup>
1742
+ <None Include="packages.config" />
1743
+ </ItemGroup>
1744
+ <ItemGroup>
1745
+ <Reference Include="Some.Package, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
1746
+ <HintPath>packages\Some.Package.1.0.0\lib\net45\Some.Package.dll</HintPath>
1747
+ <Private>True</Private>
1748
+ </Reference>
1749
+ </ItemGroup>
1750
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1751
+ </Project>
1752
+ """),
1753
+ ("packages.config", """
1754
+ <packages>
1755
+ <package id="Some.Package" version="1.0.0" targetFramework="net45" />
1756
+ </packages>
1757
+ """),
1758
+ ("NuGet.Config", """
1759
+ <configuration>
1760
+ <packageSources>
1761
+ <clear />
1762
+ <add key="private_feed" value="packages" />
1763
+ </packageSources>
1764
+ </configuration>
1765
+ """)
1766
+ ]
1767
+ );
1768
+ MockNuGetPackage[] packages =
1769
+ [
1770
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net45"),
1771
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.1.0", "net45"),
1772
+ ];
1773
+ await MockNuGetPackagesInDirectory(packages, Path.Combine(temporaryDirectory.DirectoryPath, "packages"));
1774
+ var resultOutputPath = Path.Combine(temporaryDirectory.DirectoryPath, "result.json");
1775
+
1776
+ var worker = new UpdaterWorker(new Logger(verbose: true));
1777
+ await worker.RunAsync(temporaryDirectory.DirectoryPath, "project.csproj", "Some.Package", "1.0.0", "1.1.0", isTransitive: false, resultOutputPath: resultOutputPath);
1778
+
1779
+ var resultContents = await File.ReadAllTextAsync(resultOutputPath);
1780
+ var result = JsonSerializer.Deserialize<UpdateOperationResult>(resultContents, UpdaterWorker.SerializerOptions)!;
1781
+ Assert.Equal(ErrorType.MissingFile, result.ErrorType);
1782
+ Assert.Equal(Path.Combine(temporaryDirectory.DirectoryPath, "this.file.does.not.exist.targets"), result.ErrorDetails);
1783
+ }
1784
+
1785
+ [Fact]
1786
+ public async Task ReportsPrivateSourceAuthenticationFailure()
1787
+ {
1788
+ static (int, string) TestHttpHandler(string uriString)
1789
+ {
1790
+ var uri = new Uri(uriString, UriKind.Absolute);
1791
+ var baseUrl = $"{uri.Scheme}://{uri.Host}:{uri.Port}";
1792
+ return uri.PathAndQuery switch
1793
+ {
1794
+ _ => (401, "{}"), // everything is unauthorized
1795
+ };
1796
+ }
1797
+ using var http = TestHttpServer.CreateTestStringServer(TestHttpHandler);
1798
+ await TestUpdateForProject("Some.Package", "1.0.0", "1.1.0",
1799
+ // existing
1800
+ projectContents: """
1801
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1802
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1803
+ <PropertyGroup>
1804
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1805
+ </PropertyGroup>
1806
+ <ItemGroup>
1807
+ <None Include="packages.config" />
1808
+ </ItemGroup>
1809
+ <ItemGroup>
1810
+ <Reference Include="Some.Package, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
1811
+ <HintPath>packages\Some.Package.1.0.0\lib\net45\Some.Package.dll</HintPath>
1812
+ <Private>True</Private>
1813
+ </Reference>
1814
+ </ItemGroup>
1815
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1816
+ </Project>
1817
+ """,
1818
+ packagesConfigContents: """
1819
+ <packages>
1820
+ <package id="Some.Package" version="1.0.0" targetFramework="net45" />
1821
+ </packages>
1822
+ """,
1823
+ additionalFiles:
1824
+ [
1825
+ ("NuGet.Config", $"""
1826
+ <configuration>
1827
+ <packageSources>
1828
+ <clear />
1829
+ <add key="private_feed" value="{http.BaseUrl.TrimEnd('/')}/index.json" allowInsecureConnections="true" />
1830
+ </packageSources>
1831
+ </configuration>
1832
+ """)
1833
+ ],
1834
+ // expected
1835
+ expectedProjectContents: """
1836
+ <Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1837
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
1838
+ <PropertyGroup>
1839
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1840
+ </PropertyGroup>
1841
+ <ItemGroup>
1842
+ <None Include="packages.config" />
1843
+ </ItemGroup>
1844
+ <ItemGroup>
1845
+ <Reference Include="Some.Package, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
1846
+ <HintPath>packages\Some.Package.1.0.0\lib\net45\Some.Package.dll</HintPath>
1847
+ <Private>True</Private>
1848
+ </Reference>
1849
+ </ItemGroup>
1850
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
1851
+ </Project>
1852
+ """,
1853
+ expectedPackagesConfigContents: """
1854
+ <packages>
1855
+ <package id="Some.Package" version="1.0.0" targetFramework="net45" />
1856
+ </packages>
1857
+ """,
1858
+ expectedResult: new()
1859
+ {
1860
+ ErrorType = ErrorType.AuthenticationFailure,
1861
+ ErrorDetails = $"({http.BaseUrl.TrimEnd('/')}/index.json)",
1862
+ }
1863
+ );
1864
+ }
1865
+
1423
1866
  protected static Task TestUpdateForProject(
1424
1867
  string dependencyName,
1425
1868
  string oldVersion,
@@ -1430,7 +1873,8 @@ public partial class UpdateWorkerTests
1430
1873
  string expectedPackagesConfigContents,
1431
1874
  (string Path, string Content)[]? additionalFiles = null,
1432
1875
  (string Path, string Content)[]? additionalFilesExpected = null,
1433
- MockNuGetPackage[]? packages = null)
1876
+ MockNuGetPackage[]? packages = null,
1877
+ UpdateOperationResult? expectedResult = null)
1434
1878
  {
1435
1879
  var realizedAdditionalFiles = new List<(string Path, string Content)>
1436
1880
  {
@@ -1458,7 +1902,8 @@ public partial class UpdateWorkerTests
1458
1902
  expectedProjectContents,
1459
1903
  additionalFiles: realizedAdditionalFiles.ToArray(),
1460
1904
  additionalFilesExpected: realizedAdditionalFilesExpected.ToArray(),
1461
- packages: packages);
1905
+ packages: packages,
1906
+ expectedResult: expectedResult);
1462
1907
  }
1463
1908
  }
1464
1909
  }
@@ -1,5 +1,8 @@
1
1
  using System.Linq;
2
2
  using System.Text;
3
+ using System.Text.Json;
4
+
5
+ using NuGetUpdater.Core.Updater;
3
6
 
4
7
  using Xunit;
5
8
 
@@ -2898,5 +2901,90 @@ public partial class UpdateWorkerTests
2898
2901
  """
2899
2902
  );
2900
2903
  }
2904
+
2905
+ [Fact]
2906
+ public async Task UpdatePackageWithWhitespaceInTheXMLAttributeValue()
2907
+ {
2908
+ await TestUpdateForProject("Some.Package", "1.0.0", "1.1.0",
2909
+ packages:
2910
+ [
2911
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.0.0", "net8.0"),
2912
+ MockNuGetPackage.CreateSimplePackage("Some.Package", "1.1.0", "net8.0"),
2913
+ ],
2914
+ projectContents: """
2915
+ <Project Sdk="Microsoft.NET.Sdk">
2916
+ <PropertyGroup>
2917
+ <TargetFramework>net8.0</TargetFramework>
2918
+ </PropertyGroup>
2919
+ <ItemGroup>
2920
+ <PackageReference Include=" Some.Package " Version="1.0.0" />
2921
+ </ItemGroup>
2922
+ </Project>
2923
+ """,
2924
+ expectedProjectContents: """
2925
+ <Project Sdk="Microsoft.NET.Sdk">
2926
+ <PropertyGroup>
2927
+ <TargetFramework>net8.0</TargetFramework>
2928
+ </PropertyGroup>
2929
+ <ItemGroup>
2930
+ <PackageReference Include=" Some.Package " Version="1.1.0" />
2931
+ </ItemGroup>
2932
+ </Project>
2933
+ """
2934
+ );
2935
+ }
2936
+
2937
+ [Fact]
2938
+ public async Task ReportsPrivateSourceAuthenticationFailure()
2939
+ {
2940
+ static (int, string) TestHttpHandler(string uriString)
2941
+ {
2942
+ var uri = new Uri(uriString, UriKind.Absolute);
2943
+ var baseUrl = $"{uri.Scheme}://{uri.Host}:{uri.Port}";
2944
+ return uri.PathAndQuery switch
2945
+ {
2946
+ _ => (401, "{}"), // everything is unauthorized
2947
+ };
2948
+ }
2949
+ using var http = TestHttpServer.CreateTestStringServer(TestHttpHandler);
2950
+ await TestUpdateForProject("Some.Package", "1.0.0", "1.1.0",
2951
+ projectContents: """
2952
+ <Project Sdk="Microsoft.NET.Sdk">
2953
+ <PropertyGroup>
2954
+ <TargetFramework>net8.0</TargetFramework>
2955
+ </PropertyGroup>
2956
+ <ItemGroup>
2957
+ <PackageReference Include="Some.Package" Version="1.0.0" />
2958
+ </ItemGroup>
2959
+ </Project>
2960
+ """,
2961
+ additionalFiles:
2962
+ [
2963
+ ("NuGet.Config", $"""
2964
+ <configuration>
2965
+ <packageSources>
2966
+ <clear />
2967
+ <add key="private_feed" value="{http.BaseUrl.TrimEnd('/')}/index.json" allowInsecureConnections="true" />
2968
+ </packageSources>
2969
+ </configuration>
2970
+ """)
2971
+ ],
2972
+ expectedProjectContents: """
2973
+ <Project Sdk="Microsoft.NET.Sdk">
2974
+ <PropertyGroup>
2975
+ <TargetFramework>net8.0</TargetFramework>
2976
+ </PropertyGroup>
2977
+ <ItemGroup>
2978
+ <PackageReference Include="Some.Package" Version="1.0.0" />
2979
+ </ItemGroup>
2980
+ </Project>
2981
+ """,
2982
+ expectedResult: new()
2983
+ {
2984
+ ErrorType = ErrorType.AuthenticationFailure,
2985
+ ErrorDetails = $"({http.BaseUrl.TrimEnd('/')}/index.json)",
2986
+ }
2987
+ );
2988
+ }
2901
2989
  }
2902
2990
  }
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/nuget/version"
5
+ require "dependabot/nuget/native_helpers"
5
6
  require "sorbet-runtime"
6
7
 
7
8
  module Dependabot
@@ -11,6 +12,8 @@ module Dependabot
11
12
 
12
13
  sig { params(json: T::Hash[String, T.untyped]).returns(DependencyAnalysis) }
13
14
  def self.from_json(json)
15
+ Dependabot::Nuget::NativeHelpers.ensure_no_errors(json)
16
+
14
17
  updated_version = T.let(json.fetch("UpdatedVersion"), String)
15
18
  can_update = T.let(json.fetch("CanUpdate"), T::Boolean)
16
19
  version_comes_from_multi_dependency_property = T.let(json.fetch("VersionComesFromMultiDependencyProperty"),
@@ -43,7 +43,7 @@ module Dependabot
43
43
  ).void
44
44
  end
45
45
  def initialize(source:, credentials:, repo_contents_path: nil, options: {})
46
- super(source: source, credentials: credentials, repo_contents_path: repo_contents_path, options: options)
46
+ super
47
47
 
48
48
  @sln_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
49
49
  @sln_project_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
@@ -51,20 +51,22 @@ module Dependabot
51
51
  @fetched_files = T.let({}, T::Hash[String, T::Array[Dependabot::DependencyFile]])
52
52
  @nuget_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
53
53
  @packages_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
54
+ @assembly_binding_redirect_config_files = T.let(nil, T.nilable(T::Array[Dependabot::DependencyFile]))
54
55
  end
55
56
 
56
57
  sig { override.returns(T::Array[DependencyFile]) }
57
58
  def fetch_files
58
- fetched_files = []
59
- fetched_files += project_files
60
- fetched_files += directory_build_files
61
- fetched_files += imported_property_files
62
-
63
- fetched_files += packages_config_files
64
- fetched_files += nuget_config_files
65
- fetched_files << global_json if global_json
66
- fetched_files << dotnet_tools_json if dotnet_tools_json
67
- fetched_files << packages_props if packages_props
59
+ fetched_files = [
60
+ *project_files,
61
+ *directory_build_files,
62
+ *imported_property_files,
63
+ *packages_config_files,
64
+ *assembly_binding_redirect_config_files,
65
+ *nuget_config_files,
66
+ global_json,
67
+ dotnet_tools_json,
68
+ packages_props
69
+ ].compact
68
70
 
69
71
  # dedup files based on their absolute path
70
72
  fetched_files = fetched_files.uniq do |fetched_file|
@@ -128,6 +130,23 @@ module Dependabot
128
130
  end
129
131
  end
130
132
 
133
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
134
+ def assembly_binding_redirect_config_files
135
+ return @assembly_binding_redirect_config_files if @assembly_binding_redirect_config_files
136
+
137
+ candidate_paths =
138
+ [*project_files.map { |f| File.dirname(f.name) }, "."].uniq
139
+
140
+ # Assembly binding redirects can appear in any app/web.config file for a .NET Framework project
141
+ # https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/redirect-assembly-versions#specify-assembly-binding-in-configuration-files
142
+ @assembly_binding_redirect_config_files =
143
+ candidate_paths.filter_map do |dir|
144
+ file = repo_contents(dir: dir)
145
+ .find { |f| f.name.match?(/^(app|web)\.config$/i) }
146
+ fetch_file_from_host(File.join(dir, file.name)) if file
147
+ end
148
+ end
149
+
131
150
  # rubocop:disable Metrics/PerceivedComplexity
132
151
  sig { returns(T.nilable(T::Array[T.untyped])) }
133
152
  def sln_file_names