dependabot-nuget 0.286.0 → 0.287.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01a6eb36ac3591d016d45ddfc4fc9dbb4068bda72e8560b6453461f5019362f7
4
- data.tar.gz: 4db4968d74f3b9bfac17cbf32a8017635b07cf5338ad0f9db53dd9a16b188874
3
+ metadata.gz: 3bb2d903f08322511a7917fba47df7b66208dbbaca42e52d30a1954f9ef3eaa2
4
+ data.tar.gz: f19cfed3ad2939c93812727546b53ecec603c712641a6c1d0581469cce72d584
5
5
  SHA512:
6
- metadata.gz: 1fce16345ed91813776f2b83b802212e466e15cf5784fcd239c8907ec3af683f0727b7a8e00df7fcb6b97035802c68023ddeb2481a28acce479db6fdfdb6674b
7
- data.tar.gz: 59d4ac62296d157fbeb3870bcfc18313df3deac4e3f86c0c040ea0c2d2d3c73c1c8d0e84f05d32d83a9129583e6b6e38a1f5314e2cbd0df833c1657c5eb2d7f9
6
+ metadata.gz: a3fdc15bd985678106cf45f57c6af6dd4be57858f54b50abea6f4521a8aed3ab66b7ca67cb54f9e73dabe536d8c012619bbf049662207211bc92cbb5e938c321
7
+ data.tar.gz: 3542f489f10b67fe78b3bd55703cc420a58279bf5fb131da4a99be0d99a20fcd7430b124c4b49100929b74f39178b3c7e108e7bb0170baef5f5a91a16dfbd63f
@@ -50,7 +50,7 @@ public partial class AnalyzeWorker : IAnalyzeWorker
50
50
  when (ex.StatusCode == HttpStatusCode.Unauthorized || ex.StatusCode == HttpStatusCode.Forbidden)
51
51
  {
52
52
  var localPath = PathHelper.JoinPath(repoRoot, discovery.Path);
53
- var nugetContext = new NuGetContext(localPath);
53
+ using var nugetContext = new NuGetContext(localPath);
54
54
  analysisResult = new AnalysisResult
55
55
  {
56
56
  ErrorType = ErrorType.AuthenticationFailure,
@@ -24,11 +24,16 @@ internal static class CompatibilityChecker
24
24
  ILogger logger,
25
25
  CancellationToken cancellationToken)
26
26
  {
27
- var (isDevDependency, packageFrameworks) = await GetPackageInfoAsync(
27
+ var packageInfo = await GetPackageInfoAsync(
28
28
  package,
29
29
  nugetContext,
30
30
  cancellationToken);
31
+ if (packageInfo is null)
32
+ {
33
+ return false;
34
+ }
31
35
 
36
+ var (isDevDependency, packageFrameworks) = packageInfo.GetValueOrDefault();
32
37
  return PerformCheck(package, projectFrameworks, isDevDependency, packageFrameworks, logger);
33
38
  }
34
39
 
@@ -70,7 +75,7 @@ internal static class CompatibilityChecker
70
75
  return true;
71
76
  }
72
77
 
73
- internal static async Task<PackageInfo> GetPackageInfoAsync(
78
+ internal static async Task<PackageReaders?> GetPackageReadersAsync(
74
79
  PackageIdentity package,
75
80
  NuGetContext nugetContext,
76
81
  CancellationToken cancellationToken)
@@ -79,7 +84,21 @@ internal static class CompatibilityChecker
79
84
  var readers = File.Exists(tempPackagePath)
80
85
  ? ReadPackage(tempPackagePath)
81
86
  : await DownloadPackageAsync(package, nugetContext, cancellationToken);
87
+ return readers;
88
+ }
89
+
90
+ internal static async Task<PackageInfo?> GetPackageInfoAsync(
91
+ PackageIdentity package,
92
+ NuGetContext nugetContext,
93
+ CancellationToken cancellationToken)
94
+ {
95
+ var readersOption = await GetPackageReadersAsync(package, nugetContext, cancellationToken);
96
+ if (readersOption is null)
97
+ {
98
+ return null;
99
+ }
82
100
 
101
+ var readers = readersOption.GetValueOrDefault();
83
102
  var nuspecStream = await readers.CoreReader.GetNuspecAsync(cancellationToken);
84
103
  var reader = new NuspecReader(nuspecStream);
85
104
 
@@ -127,7 +146,7 @@ internal static class CompatibilityChecker
127
146
  return (archiveReader, archiveReader);
128
147
  }
129
148
 
130
- internal static async Task<PackageReaders> DownloadPackageAsync(
149
+ internal static async Task<PackageReaders?> DownloadPackageAsync(
131
150
  PackageIdentity package,
132
151
  NuGetContext context,
133
152
  CancellationToken cancellationToken)
@@ -179,13 +198,13 @@ internal static class CompatibilityChecker
179
198
  var isDownloaded = await downloader.CopyNupkgFileToAsync(tempPackagePath, cancellationToken);
180
199
  if (!isDownloaded)
181
200
  {
182
- throw new Exception($"Failed to download package [{package.Id}/{package.Version}] from [${source.SourceUri}]");
201
+ continue;
183
202
  }
184
203
 
185
204
  return (downloader.CoreReader, downloader.ContentReader);
186
205
  }
187
206
 
188
- throw new Exception($"Package [{package.Id}/{package.Version}] does not exist in any of the configured sources.");
207
+ return null;
189
208
  }
190
209
 
191
210
  internal static string GetTempPackagePath(PackageIdentity package, NuGetContext context)
@@ -142,11 +142,22 @@ internal record NuGetContext : IDisposable
142
142
  }
143
143
 
144
144
  var metadataResource = await sourceRepository.GetResourceAsync<PackageMetadataResource>(cancellationToken);
145
- var metadata = await metadataResource.GetMetadataAsync(packageIdentity, SourceCacheContext, Logger, cancellationToken);
146
- var url = metadata.ProjectUrl ?? metadata.LicenseUrl;
147
- if (url is not null)
145
+ if (metadataResource is not null)
148
146
  {
149
- return url.ToString();
147
+ try
148
+ {
149
+ var metadata = await metadataResource.GetMetadataAsync(packageIdentity, SourceCacheContext, Logger, cancellationToken);
150
+ var url = metadata.ProjectUrl ?? metadata.LicenseUrl;
151
+ if (url is not null)
152
+ {
153
+ return url.ToString();
154
+ }
155
+ }
156
+ catch (ArgumentException)
157
+ {
158
+ // there was an issue deserializing the package metadata; this doesn't necessarily mean the package
159
+ // is unavailable, just that we can't return a URL
160
+ }
150
161
  }
151
162
  }
152
163
 
@@ -151,46 +151,17 @@ internal static class VersionFinder
151
151
  ILogger logger,
152
152
  CancellationToken cancellationToken)
153
153
  {
154
- var includePrerelease = version.IsPrerelease;
155
-
156
- var sourceMapping = PackageSourceMapping.GetPackageSourceMapping(nugetContext.Settings);
157
- var packageSources = sourceMapping.GetConfiguredPackageSources(packageId).ToHashSet();
158
- var sources = packageSources.Count == 0
159
- ? nugetContext.PackageSources
160
- : nugetContext.PackageSources
161
- .Where(p => packageSources.Contains(p.Name))
162
- .ToImmutableArray();
163
-
164
- foreach (var source in sources)
154
+ // if it can be downloaded, it exists
155
+ var downloader = await CompatibilityChecker.DownloadPackageAsync(new PackageIdentity(packageId, version), nugetContext, cancellationToken);
156
+ var packageAndVersionExists = downloader is not null;
157
+ if (packageAndVersionExists)
165
158
  {
166
- var sourceRepository = Repository.Factory.GetCoreV3(source);
167
- var feed = await sourceRepository.GetResourceAsync<MetadataResource>();
168
- if (feed is null)
169
- {
170
- logger.Log($"Failed to get MetadataResource for [{source.Source}]");
171
- continue;
172
- }
173
-
174
- try
175
- {
176
- // a non-compliant v2 API returning 404 can cause this to throw
177
- var existsInFeed = await feed.Exists(
178
- new PackageIdentity(packageId, version),
179
- includeUnlisted: false,
180
- nugetContext.SourceCacheContext,
181
- NullLogger.Instance,
182
- cancellationToken);
183
- if (existsInFeed)
184
- {
185
- return true;
186
- }
187
- }
188
- catch (FatalProtocolException)
189
- {
190
- // if anything goes wrong here, the package source obviously doesn't contain the requested package
191
- }
159
+ // release the handles
160
+ var readers = downloader.GetValueOrDefault();
161
+ (readers.CoreReader as IDisposable)?.Dispose();
162
+ (readers.ContentReader as IDisposable)?.Dispose();
192
163
  }
193
164
 
194
- return false;
165
+ return packageAndVersionExists;
195
166
  }
196
167
  }
@@ -275,22 +275,24 @@ public partial class DiscoveryWorker : IDiscoveryWorker
275
275
  foreach (var projectPath in projectPaths)
276
276
  {
277
277
  // If there is some MSBuild logic that needs to run to fully resolve the path skip the project
278
- if (!File.Exists(projectPath))
278
+ // Ensure file existence is checked case-insensitively
279
+ var actualProjectPath = PathHelper.ResolveCaseInsensitivePathInsideRepoRoot(projectPath, repoRootPath);
280
+ if (actualProjectPath == null)
279
281
  {
280
282
  continue;
281
283
  }
282
284
 
283
- if (_processedProjectPaths.Contains(projectPath))
285
+ if (_processedProjectPaths.Contains(actualProjectPath))
284
286
  {
285
287
  continue;
286
288
  }
287
- _processedProjectPaths.Add(projectPath);
289
+ _processedProjectPaths.Add(actualProjectPath);
288
290
 
289
- var relativeProjectPath = Path.GetRelativePath(workspacePath, projectPath);
291
+ var relativeProjectPath = Path.GetRelativePath(workspacePath, actualProjectPath);
290
292
  var packagesConfigDependencies = PackagesConfigDiscovery.Discover(workspacePath, projectPath, _logger)
291
293
  ?.Dependencies;
292
294
 
293
- var projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, projectPath, _logger);
295
+ var projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, actualProjectPath, _logger);
294
296
 
295
297
  // Determine if there were unrestored MSBuildSdks
296
298
  var msbuildSdks = projectResults.SelectMany(p => p.Dependencies.Where(d => d.Type == DependencyType.MSBuildSdk)).ToImmutableArray();
@@ -299,7 +301,7 @@ public partial class DiscoveryWorker : IDiscoveryWorker
299
301
  // If new SDKs were restored, then we need to rerun SdkProjectDiscovery.
300
302
  if (await TryRestoreMSBuildSdksAsync(repoRootPath, workspacePath, msbuildSdks, _logger))
301
303
  {
302
- projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, projectPath, _logger);
304
+ projectResults = await SdkProjectDiscovery.DiscoverAsync(repoRootPath, workspacePath, actualProjectPath, _logger);
303
305
  }
304
306
  }
305
307
 
@@ -43,7 +43,7 @@ internal sealed class ProjectBuildFile : XmlBuildFile
43
43
  {
44
44
  var sdkDependencies = GetSdkDependencies();
45
45
  var packageDependencies = PackageItemNodes
46
- .Select(GetPackageDependency)
46
+ .SelectMany(e => GetPackageDependencies(e) ?? Enumerable.Empty<Dependency>())
47
47
  .OfType<Dependency>();
48
48
  return sdkDependencies.Concat(packageDependencies);
49
49
  }
@@ -89,8 +89,9 @@ internal sealed class ProjectBuildFile : XmlBuildFile
89
89
  : new Dependency(name, version, DependencyType.MSBuildSdk);
90
90
  }
91
91
 
92
- private static Dependency? GetPackageDependency(IXmlElementSyntax element)
92
+ private static IEnumerable<Dependency>? GetPackageDependencies(IXmlElementSyntax element)
93
93
  {
94
+ List<Dependency> dependencies = [];
94
95
  var isUpdate = false;
95
96
 
96
97
  var name = element.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase)?.Trim();
@@ -113,12 +114,18 @@ internal sealed class ProjectBuildFile : XmlBuildFile
113
114
  isVersionOverride = version is not null;
114
115
  }
115
116
 
116
- return new Dependency(
117
- Name: name,
118
- Version: version?.Length == 0 ? null : version,
119
- Type: GetDependencyType(element.Name),
120
- IsUpdate: isUpdate,
121
- IsOverride: isVersionOverride);
117
+ dependencies.AddRange(
118
+ name.Split(';', StringSplitOptions.RemoveEmptyEntries)
119
+ .Select(dep => new Dependency(
120
+ Name: dep.Trim(),
121
+ Version: string.IsNullOrEmpty(version) ? null : version,
122
+ Type: GetDependencyType(element.Name),
123
+ IsUpdate: isUpdate,
124
+ IsOverride: isVersionOverride))
125
+ );
126
+
127
+
128
+ return dependencies;
122
129
  }
123
130
 
124
131
  private static DependencyType GetDependencyType(string name)
@@ -674,11 +674,21 @@ internal static class PackageReferenceUpdater
674
674
  ProjectBuildFile buildFile,
675
675
  string packageName)
676
676
  => buildFile.PackageItemNodes.Where(e =>
677
- string.Equals(
678
- (e.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase) ?? e.GetAttributeOrSubElementValue("Update", StringComparison.OrdinalIgnoreCase))?.Trim(),
679
- packageName,
680
- StringComparison.OrdinalIgnoreCase) &&
681
- (e.GetAttributeOrSubElementValue("Version", StringComparison.OrdinalIgnoreCase) ?? e.GetAttributeOrSubElementValue("VersionOverride", StringComparison.OrdinalIgnoreCase)) is not null);
677
+ {
678
+ // Attempt to get "Include" or "Update" attribute values
679
+ var includeOrUpdateValue = e.GetAttributeOrSubElementValue("Include", StringComparison.OrdinalIgnoreCase)
680
+ ?? e.GetAttributeOrSubElementValue("Update", StringComparison.OrdinalIgnoreCase);
681
+ // Trim and split if there's a valid value
682
+ var packageNames = includeOrUpdateValue?
683
+ .Trim()
684
+ .Split(';', StringSplitOptions.RemoveEmptyEntries)
685
+ .Select(t => t.Trim())
686
+ .Where(t => t.Equals(packageName.Trim(), StringComparison.OrdinalIgnoreCase));
687
+ // Check if there's a matching package name and a non-null version attribute
688
+ return packageNames?.Any() == true &&
689
+ (e.GetAttributeOrSubElementValue("Version", StringComparison.OrdinalIgnoreCase)
690
+ ?? e.GetAttributeOrSubElementValue("VersionOverride", StringComparison.OrdinalIgnoreCase)) is not null;
691
+ });
682
692
 
683
693
  private static async Task<bool> AreDependenciesCoherentAsync(string repoRootPath, string projectPath, string dependencyName, ILogger logger, ImmutableArray<ProjectBuildFile> buildFiles, string[] tfms)
684
694
  {
@@ -261,7 +261,11 @@ internal static partial class MSBuildHelper
261
261
  ? evaluationResult.EvaluatedValue.TrimStart('[', '(').TrimEnd(']', ')')
262
262
  : evaluationResult.EvaluatedValue;
263
263
 
264
- yield return new Dependency(name, packageVersion, dependencyType, EvaluationResult: evaluationResult, IsUpdate: isUpdate);
264
+ // If at this point we have a semicolon in the name then split it and yield multiple dependencies.
265
+ foreach (var splitName in name.Split(';', StringSplitOptions.RemoveEmptyEntries))
266
+ {
267
+ yield return new Dependency(splitName.Trim(), packageVersion, dependencyType, EvaluationResult: evaluationResult, IsUpdate: isUpdate);
268
+ }
265
269
  }
266
270
  }
267
271
 
@@ -87,6 +87,55 @@ internal static class PathHelper
87
87
  return candidatePaths.ToArray();
88
88
  }
89
89
 
90
+ /// <summary>
91
+ /// Resolves the case of the file path in a case-insensitive manner. Returns null if the file path is not found. file path must be a full path inside the repoRootPath.
92
+ /// </summary>
93
+ /// <param name="filePath">The file path to resolve.</param>
94
+ /// <param name="repoRootPath">The root path of the repository.</param>
95
+ public static string? ResolveCaseInsensitivePathInsideRepoRoot(string filePath, string repoRootPath)
96
+ {
97
+ if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(repoRootPath))
98
+ {
99
+ return null; // Invalid input
100
+ }
101
+
102
+ // Normalize paths
103
+ var normalizedFilePath = filePath.FullyNormalizedRootedPath();
104
+ var normalizedRepoRoot = repoRootPath.FullyNormalizedRootedPath();
105
+
106
+ // Ensure the file path starts with the repo root path
107
+ if (!normalizedFilePath.StartsWith(normalizedRepoRoot + "/", StringComparison.OrdinalIgnoreCase))
108
+ {
109
+ return null; // filePath is outside of repoRootPath
110
+ }
111
+
112
+ // Start resolving from the root path
113
+ var currentPath = normalizedRepoRoot;
114
+ var relativePath = normalizedFilePath.Substring(normalizedRepoRoot.Length).TrimStart('/');
115
+
116
+ foreach (var part in relativePath.Split('/'))
117
+ {
118
+ if (string.IsNullOrEmpty(part))
119
+ {
120
+ continue;
121
+ }
122
+
123
+ // Enumerate the current directory to find a case-insensitive match
124
+ var nextPath = Directory
125
+ .EnumerateFileSystemEntries(currentPath)
126
+ .FirstOrDefault(entry => string.Equals(Path.GetFileName(entry), part, StringComparison.OrdinalIgnoreCase));
127
+
128
+ if (nextPath == null)
129
+ {
130
+ return null; // Part of the path does not exist
131
+ }
132
+
133
+ currentPath = nextPath;
134
+ }
135
+
136
+ return currentPath; // Fully resolved path with correct casing
137
+ }
138
+
90
139
  /// <summary>
91
140
  /// Check in every directory from <paramref name="initialPath"/> up to <paramref name="rootPath"/> for the file specified in <paramref name="fileName"/>.
92
141
  /// </summary>