dependabot-nuget 0.262.0 → 0.264.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +37 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/DiscoverCommand.cs +3 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Program.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +169 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +79 -67
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.FrameworkCheck.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +10 -11
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalysisResult.cs +11 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +441 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +177 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +47 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyInfo.cs +12 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Extensions.cs +36 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +128 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Requirement.cs +105 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementConverter.cs +17 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/SecurityVulnerability.cs +11 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/SecurityVulnerabilityExtensions.cs +36 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +179 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionResult.cs +54 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Dependency.cs +5 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/CompatabilityChecker.cs +0 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/FrameworkCompatibilityService.cs +0 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/SupportedFrameworks.cs +0 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +0 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectResolver.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +6 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/XmlFilePreAndPostProcessor.cs +0 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/HashSetExtensions.cs +0 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/Logger.cs +0 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +7 -8
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +0 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +90 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +304 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/CompatibilityCheckerTests.cs +145 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/ExpectedAnalysisResult.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/RequirementTests.cs +69 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/SecurityVulnerabilityExtensionsTests.cs +78 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/VersionFinderTests.cs +193 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +1 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Proj.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +102 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +8 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +8 -7
- data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +63 -0
- data/lib/dependabot/nuget/analysis/dependency_analysis.rb +63 -0
- data/lib/dependabot/nuget/file_fetcher.rb +7 -6
- data/lib/dependabot/nuget/file_parser.rb +28 -21
- data/lib/dependabot/nuget/file_updater.rb +22 -25
- data/lib/dependabot/nuget/metadata_finder.rb +2 -160
- data/lib/dependabot/nuget/native_discovery/native_dependency_details.rb +102 -0
- data/lib/dependabot/nuget/native_discovery/native_dependency_file_discovery.rb +129 -0
- data/lib/dependabot/nuget/native_discovery/native_directory_packages_props_discovery.rb +44 -0
- data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +174 -0
- data/lib/dependabot/nuget/native_discovery/native_evaluation_details.rb +63 -0
- data/lib/dependabot/nuget/native_discovery/native_project_discovery.rb +82 -0
- data/lib/dependabot/nuget/native_discovery/native_property_details.rb +43 -0
- data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +68 -0
- data/lib/dependabot/nuget/native_helpers.rb +59 -0
- data/lib/dependabot/nuget/native_update_checker/native_requirements_updater.rb +105 -0
- data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +200 -0
- data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +3 -2
- data/lib/dependabot/nuget/update_checker.rb +48 -1
- metadata +39 -5
@@ -0,0 +1,36 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
using NuGet.Frameworks;
|
4
|
+
using NuGet.Versioning;
|
5
|
+
|
6
|
+
using NuGetUpdater.Core;
|
7
|
+
|
8
|
+
internal static class Extensions
|
9
|
+
{
|
10
|
+
public static ImmutableArray<Dependency> GetDependencies(this ImmutableDictionary<NuGetFramework, ImmutableArray<Dependency>> dependenciesByTfm)
|
11
|
+
{
|
12
|
+
Dictionary<string, Dependency> dependencies = [];
|
13
|
+
foreach (var (_framework, dependenciesForTfm) in dependenciesByTfm)
|
14
|
+
{
|
15
|
+
foreach (var dependency in dependenciesForTfm)
|
16
|
+
{
|
17
|
+
if (dependencies.TryGetValue(dependency.Name, out Dependency? value))
|
18
|
+
{
|
19
|
+
if (NuGetVersion.Parse(value.Version!) < NuGetVersion.Parse(dependency.Version!))
|
20
|
+
{
|
21
|
+
dependencies[dependency.Name] = dependency with
|
22
|
+
{
|
23
|
+
TargetFrameworks = [.. value.TargetFrameworks ?? [], .. dependency.TargetFrameworks ?? []]
|
24
|
+
};
|
25
|
+
}
|
26
|
+
}
|
27
|
+
else
|
28
|
+
{
|
29
|
+
dependencies.Add(dependency.Name, dependency);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
return [.. dependencies.Values];
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,128 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
using System.Text;
|
3
|
+
|
4
|
+
using NuGet.CommandLine;
|
5
|
+
using NuGet.Common;
|
6
|
+
using NuGet.Configuration;
|
7
|
+
using NuGet.Packaging.Core;
|
8
|
+
using NuGet.Protocol;
|
9
|
+
using NuGet.Protocol.Core.Types;
|
10
|
+
using NuGet.Versioning;
|
11
|
+
|
12
|
+
namespace NuGetUpdater.Core.Analyze;
|
13
|
+
|
14
|
+
internal record NuGetContext : IDisposable
|
15
|
+
{
|
16
|
+
public SourceCacheContext SourceCacheContext { get; }
|
17
|
+
public PackageDownloadContext PackageDownloadContext { get; }
|
18
|
+
public string CurrentDirectory { get; }
|
19
|
+
public ISettings Settings { get; }
|
20
|
+
public IMachineWideSettings MachineWideSettings { get; }
|
21
|
+
public ImmutableArray<PackageSource> PackageSources { get; }
|
22
|
+
public ILogger Logger { get; }
|
23
|
+
public string TempPackageDirectory { get; }
|
24
|
+
|
25
|
+
public NuGetContext(string? currentDirectory = null, ILogger? logger = null)
|
26
|
+
{
|
27
|
+
SourceCacheContext = new SourceCacheContext();
|
28
|
+
PackageDownloadContext = new PackageDownloadContext(SourceCacheContext);
|
29
|
+
CurrentDirectory = currentDirectory ?? Environment.CurrentDirectory;
|
30
|
+
MachineWideSettings = new CommandLineMachineWideSettings();
|
31
|
+
Settings = NuGet.Configuration.Settings.LoadDefaultSettings(
|
32
|
+
CurrentDirectory,
|
33
|
+
configFileName: null,
|
34
|
+
MachineWideSettings);
|
35
|
+
var sourceProvider = new PackageSourceProvider(Settings);
|
36
|
+
PackageSources = sourceProvider.LoadPackageSources()
|
37
|
+
.Where(p => p.IsEnabled)
|
38
|
+
.ToImmutableArray();
|
39
|
+
Logger = logger ?? NullLogger.Instance;
|
40
|
+
TempPackageDirectory = Path.Combine(Path.GetTempPath(), ".dependabot", "packages");
|
41
|
+
}
|
42
|
+
|
43
|
+
public void Dispose()
|
44
|
+
{
|
45
|
+
SourceCacheContext.Dispose();
|
46
|
+
}
|
47
|
+
|
48
|
+
private readonly Dictionary<PackageIdentity, string?> _packageInfoUrlCache = new();
|
49
|
+
|
50
|
+
public async Task<string?> GetPackageInfoUrlAsync(string packageId, string packageVersion, CancellationToken cancellationToken)
|
51
|
+
{
|
52
|
+
var packageIdentity = new PackageIdentity(packageId, NuGetVersion.Parse(packageVersion));
|
53
|
+
if (_packageInfoUrlCache.TryGetValue(packageIdentity, out var cachedUrl))
|
54
|
+
{
|
55
|
+
return cachedUrl;
|
56
|
+
}
|
57
|
+
|
58
|
+
var infoUrl = await FindPackageInfoUrlAsync(packageIdentity, cancellationToken);
|
59
|
+
_packageInfoUrlCache[packageIdentity] = infoUrl;
|
60
|
+
|
61
|
+
return infoUrl;
|
62
|
+
}
|
63
|
+
|
64
|
+
private async Task<string?> FindPackageInfoUrlAsync(PackageIdentity packageIdentity, CancellationToken cancellationToken)
|
65
|
+
{
|
66
|
+
var globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder(Settings);
|
67
|
+
var sourceMapping = PackageSourceMapping.GetPackageSourceMapping(Settings);
|
68
|
+
var packageSources = sourceMapping.GetConfiguredPackageSources(packageIdentity.Id).ToHashSet();
|
69
|
+
var sources = packageSources.Count == 0
|
70
|
+
? PackageSources
|
71
|
+
: PackageSources
|
72
|
+
.Where(p => packageSources.Contains(p.Name))
|
73
|
+
.ToImmutableArray();
|
74
|
+
|
75
|
+
var message = new StringBuilder();
|
76
|
+
message.AppendLine($"finding info url for {packageIdentity}, using package sources: {string.Join(", ", sources.Select(s => s.Name))}");
|
77
|
+
|
78
|
+
foreach (var source in sources)
|
79
|
+
{
|
80
|
+
message.AppendLine($" checking {source.Name}");
|
81
|
+
var sourceRepository = Repository.Factory.GetCoreV3(source);
|
82
|
+
var feed = await sourceRepository.GetResourceAsync<MetadataResource>(cancellationToken);
|
83
|
+
if (feed is null)
|
84
|
+
{
|
85
|
+
message.AppendLine($" feed for {source.Name} was null");
|
86
|
+
continue;
|
87
|
+
}
|
88
|
+
|
89
|
+
var existsInFeed = await feed.Exists(
|
90
|
+
packageIdentity,
|
91
|
+
includeUnlisted: false,
|
92
|
+
SourceCacheContext,
|
93
|
+
NullLogger.Instance,
|
94
|
+
cancellationToken);
|
95
|
+
if (!existsInFeed)
|
96
|
+
{
|
97
|
+
message.AppendLine($" package {packageIdentity} does not exist in {source.Name}");
|
98
|
+
continue;
|
99
|
+
}
|
100
|
+
|
101
|
+
var downloadResource = await sourceRepository.GetResourceAsync<DownloadResource>(cancellationToken);
|
102
|
+
using var downloadResult = await downloadResource.GetDownloadResourceResultAsync(packageIdentity, PackageDownloadContext, globalPackagesFolder, Logger, cancellationToken);
|
103
|
+
if (downloadResult.Status == DownloadResourceResultStatus.Available)
|
104
|
+
{
|
105
|
+
var repositoryMetadata = downloadResult.PackageReader.NuspecReader.GetRepositoryMetadata();
|
106
|
+
message.AppendLine($" repometadata: type=[{repositoryMetadata.Type}], url=[{repositoryMetadata.Url}], branch=[{repositoryMetadata.Branch}], commit=[{repositoryMetadata.Commit}]");
|
107
|
+
if (!string.IsNullOrEmpty(repositoryMetadata.Url))
|
108
|
+
{
|
109
|
+
return repositoryMetadata.Url;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
else
|
113
|
+
{
|
114
|
+
message.AppendLine($" download result status: {downloadResult.Status}");
|
115
|
+
}
|
116
|
+
|
117
|
+
var metadataResource = await sourceRepository.GetResourceAsync<PackageMetadataResource>(cancellationToken);
|
118
|
+
var metadata = await metadataResource.GetMetadataAsync(packageIdentity, SourceCacheContext, Logger, cancellationToken);
|
119
|
+
var url = metadata.ProjectUrl ?? metadata.LicenseUrl;
|
120
|
+
if (url is not null)
|
121
|
+
{
|
122
|
+
return url.ToString();
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
return null;
|
127
|
+
}
|
128
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
using NuGet.Versioning;
|
4
|
+
|
5
|
+
namespace NuGetUpdater.Core.Analyze;
|
6
|
+
|
7
|
+
/// <summary>
|
8
|
+
/// A Requirement is a set of one or more version restrictions. It supports a
|
9
|
+
/// few (=, !=, >, <, >=, <=, ~>) different restriction operators.
|
10
|
+
/// </summary>
|
11
|
+
/// <remarks>
|
12
|
+
/// See Gem::Version for a description on how versions and requirements work
|
13
|
+
/// together in RubyGems.
|
14
|
+
/// </remarks>
|
15
|
+
public class Requirement
|
16
|
+
{
|
17
|
+
private static readonly ImmutableDictionary<string, Func<NuGetVersion, NuGetVersion, bool>> Operators = new Dictionary<string, Func<NuGetVersion, NuGetVersion, bool>>()
|
18
|
+
{
|
19
|
+
["="] = (v, r) => v == r,
|
20
|
+
["!="] = (v, r) => v != r,
|
21
|
+
[">"] = (v, r) => v > r,
|
22
|
+
["<"] = (v, r) => v < r,
|
23
|
+
[">="] = (v, r) => v >= r,
|
24
|
+
["<="] = (v, r) => v <= r,
|
25
|
+
["~>"] = (v, r) => v >= r && v.Version < Bump(r),
|
26
|
+
}.ToImmutableDictionary();
|
27
|
+
|
28
|
+
public static Requirement Parse(string requirement)
|
29
|
+
{
|
30
|
+
var splitIndex = requirement.LastIndexOfAny(['=', '>', '<']);
|
31
|
+
|
32
|
+
// Throw if the requirement is all operator and no version.
|
33
|
+
if (splitIndex == requirement.Length - 1)
|
34
|
+
{
|
35
|
+
throw new ArgumentException($"`{requirement}` is a invalid requirement string", nameof(requirement));
|
36
|
+
}
|
37
|
+
|
38
|
+
string[] parts = splitIndex == -1
|
39
|
+
? [requirement.Trim()]
|
40
|
+
: [requirement[..(splitIndex + 1)].Trim(), requirement[(splitIndex + 1)..].Trim()];
|
41
|
+
|
42
|
+
var op = parts.Length == 1 ? "=" : parts[0];
|
43
|
+
var version = NuGetVersion.Parse(parts[^1]);
|
44
|
+
|
45
|
+
return new Requirement(op, version);
|
46
|
+
}
|
47
|
+
|
48
|
+
public string Operator { get; }
|
49
|
+
public NuGetVersion Version { get; }
|
50
|
+
|
51
|
+
public Requirement(string op, NuGetVersion version)
|
52
|
+
{
|
53
|
+
if (!Operators.ContainsKey(op))
|
54
|
+
{
|
55
|
+
throw new ArgumentException("Invalid operator", nameof(op));
|
56
|
+
}
|
57
|
+
|
58
|
+
Operator = op;
|
59
|
+
Version = version;
|
60
|
+
}
|
61
|
+
|
62
|
+
public override string ToString()
|
63
|
+
{
|
64
|
+
return $"{Operator} {Version}";
|
65
|
+
}
|
66
|
+
|
67
|
+
public bool IsSatisfiedBy(NuGetVersion version)
|
68
|
+
{
|
69
|
+
return Operators[Operator](version, Version);
|
70
|
+
}
|
71
|
+
|
72
|
+
private static readonly Dictionary<string, Version> BumpMap = [];
|
73
|
+
/// <summary>
|
74
|
+
/// Return a new version object where the next to the last revision
|
75
|
+
/// number is one greater (e.g., 5.3.1 => 5.4).
|
76
|
+
/// </summary>
|
77
|
+
/// <remarks>
|
78
|
+
/// This logic intended to be similar to RubyGems Gem::Version#bump
|
79
|
+
/// </remarks>
|
80
|
+
public static Version Bump(NuGetVersion version)
|
81
|
+
{
|
82
|
+
if (BumpMap.TryGetValue(version.OriginalVersion!, out var bumpedVersion))
|
83
|
+
{
|
84
|
+
return bumpedVersion;
|
85
|
+
}
|
86
|
+
|
87
|
+
var versionParts = version.OriginalVersion! // Get the original string this version was created from
|
88
|
+
.Split('-')[0] // Get the version part without pre-release
|
89
|
+
.Split('.') // Split into Major.Minor.Patch.Revision if present
|
90
|
+
.Select(int.Parse)
|
91
|
+
.ToArray();
|
92
|
+
|
93
|
+
if (versionParts.Length > 1)
|
94
|
+
{
|
95
|
+
versionParts = versionParts[..^1]; // Remove the last part
|
96
|
+
}
|
97
|
+
|
98
|
+
versionParts[^1]++; // Increment the new last part
|
99
|
+
|
100
|
+
bumpedVersion = NuGetVersion.Parse(string.Join('.', versionParts)).Version;
|
101
|
+
BumpMap[version.OriginalVersion!] = bumpedVersion;
|
102
|
+
|
103
|
+
return bumpedVersion;
|
104
|
+
}
|
105
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
using System.Text.Json;
|
2
|
+
using System.Text.Json.Serialization;
|
3
|
+
|
4
|
+
namespace NuGetUpdater.Core.Analyze;
|
5
|
+
|
6
|
+
public class RequirementConverter : JsonConverter<Requirement>
|
7
|
+
{
|
8
|
+
public override Requirement? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
9
|
+
{
|
10
|
+
return Requirement.Parse(reader.GetString()!);
|
11
|
+
}
|
12
|
+
|
13
|
+
public override void Write(Utf8JsonWriter writer, Requirement value, JsonSerializerOptions options)
|
14
|
+
{
|
15
|
+
writer.WriteStringValue(value.ToString());
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
namespace NuGetUpdater.Core.Analyze;
|
4
|
+
|
5
|
+
public sealed record SecurityVulnerability
|
6
|
+
{
|
7
|
+
public required string DependencyName { get; init; }
|
8
|
+
public required string PackageManager { get; init; }
|
9
|
+
public required ImmutableArray<Requirement> VulnerableVersions { get; init; }
|
10
|
+
public required ImmutableArray<Requirement> SafeVersions { get; init; }
|
11
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
using NuGet.Versioning;
|
2
|
+
|
3
|
+
namespace NuGetUpdater.Core.Analyze;
|
4
|
+
|
5
|
+
public static class SecurityVulnerabilityExtensions
|
6
|
+
{
|
7
|
+
// This logic taken from Dependabot security_advisory.rb
|
8
|
+
public static bool IsVulnerable(this SecurityVulnerability vulnerability, NuGetVersion version)
|
9
|
+
{
|
10
|
+
var inSafeRange = vulnerability.SafeVersions
|
11
|
+
.Any(r => r.IsSatisfiedBy(version));
|
12
|
+
if (inSafeRange)
|
13
|
+
{
|
14
|
+
// If version is known safe for this advisory, it's not vulnerable
|
15
|
+
return false;
|
16
|
+
}
|
17
|
+
|
18
|
+
var inVulnerableRange = vulnerability.VulnerableVersions
|
19
|
+
.Any(r => r.IsSatisfiedBy(version));
|
20
|
+
if (inVulnerableRange)
|
21
|
+
{
|
22
|
+
// If in the vulnerable range and not known safe, it's vulnerable
|
23
|
+
return true;
|
24
|
+
}
|
25
|
+
|
26
|
+
if (vulnerability.VulnerableVersions.Length > 0)
|
27
|
+
{
|
28
|
+
// If a vulnerable range present but not met, it's not vulnerable
|
29
|
+
return false;
|
30
|
+
}
|
31
|
+
|
32
|
+
// Finally, if no vulnerable range provided, but a safe range provided,
|
33
|
+
// and this versions isn't included (checked earlier), it's vulnerable
|
34
|
+
return vulnerability.SafeVersions.Length > 0;
|
35
|
+
}
|
36
|
+
}
|
@@ -0,0 +1,179 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
using NuGet.Common;
|
4
|
+
using NuGet.Configuration;
|
5
|
+
using NuGet.Packaging.Core;
|
6
|
+
using NuGet.Protocol;
|
7
|
+
using NuGet.Protocol.Core.Types;
|
8
|
+
using NuGet.Versioning;
|
9
|
+
|
10
|
+
namespace NuGetUpdater.Core.Analyze;
|
11
|
+
|
12
|
+
internal static class VersionFinder
|
13
|
+
{
|
14
|
+
public static Task<VersionResult> GetVersionsAsync(
|
15
|
+
string packageId,
|
16
|
+
NuGetVersion currentVersion,
|
17
|
+
NuGetContext nugetContext,
|
18
|
+
Logger logger,
|
19
|
+
CancellationToken cancellationToken)
|
20
|
+
{
|
21
|
+
var versionFilter = CreateVersionFilter(currentVersion);
|
22
|
+
|
23
|
+
return GetVersionsAsync(packageId, currentVersion, versionFilter, nugetContext, logger, cancellationToken);
|
24
|
+
}
|
25
|
+
|
26
|
+
public static Task<VersionResult> GetVersionsAsync(
|
27
|
+
DependencyInfo dependencyInfo,
|
28
|
+
NuGetContext nugetContext,
|
29
|
+
Logger logger,
|
30
|
+
CancellationToken cancellationToken)
|
31
|
+
{
|
32
|
+
var packageId = dependencyInfo.Name;
|
33
|
+
var versionRange = VersionRange.Parse(dependencyInfo.Version);
|
34
|
+
var currentVersion = versionRange.MinVersion!;
|
35
|
+
var versionFilter = CreateVersionFilter(dependencyInfo, versionRange);
|
36
|
+
|
37
|
+
return GetVersionsAsync(packageId, currentVersion, versionFilter, nugetContext, logger, cancellationToken);
|
38
|
+
}
|
39
|
+
|
40
|
+
public static async Task<VersionResult> GetVersionsAsync(
|
41
|
+
string packageId,
|
42
|
+
NuGetVersion currentVersion,
|
43
|
+
Func<NuGetVersion, bool> versionFilter,
|
44
|
+
NuGetContext nugetContext,
|
45
|
+
Logger logger,
|
46
|
+
CancellationToken cancellationToken)
|
47
|
+
{
|
48
|
+
var includePrerelease = currentVersion.IsPrerelease;
|
49
|
+
VersionResult result = new(currentVersion);
|
50
|
+
|
51
|
+
var sourceMapping = PackageSourceMapping.GetPackageSourceMapping(nugetContext.Settings);
|
52
|
+
var packageSources = sourceMapping.GetConfiguredPackageSources(packageId).ToHashSet();
|
53
|
+
var sources = packageSources.Count == 0
|
54
|
+
? nugetContext.PackageSources
|
55
|
+
: nugetContext.PackageSources
|
56
|
+
.Where(p => packageSources.Contains(p.Name))
|
57
|
+
.ToImmutableArray();
|
58
|
+
|
59
|
+
foreach (var source in sources)
|
60
|
+
{
|
61
|
+
var sourceRepository = Repository.Factory.GetCoreV3(source);
|
62
|
+
var feed = await sourceRepository.GetResourceAsync<MetadataResource>();
|
63
|
+
if (feed is null)
|
64
|
+
{
|
65
|
+
logger.Log($"Failed to get MetadataResource for [{source.Source}]");
|
66
|
+
continue;
|
67
|
+
}
|
68
|
+
|
69
|
+
var existsInFeed = await feed.Exists(
|
70
|
+
packageId,
|
71
|
+
includePrerelease,
|
72
|
+
includeUnlisted: false,
|
73
|
+
nugetContext.SourceCacheContext,
|
74
|
+
NullLogger.Instance,
|
75
|
+
cancellationToken);
|
76
|
+
if (!existsInFeed)
|
77
|
+
{
|
78
|
+
continue;
|
79
|
+
}
|
80
|
+
|
81
|
+
var feedVersions = (await feed.GetVersions(
|
82
|
+
packageId,
|
83
|
+
includePrerelease,
|
84
|
+
includeUnlisted: false,
|
85
|
+
nugetContext.SourceCacheContext,
|
86
|
+
NullLogger.Instance,
|
87
|
+
CancellationToken.None)).ToHashSet();
|
88
|
+
|
89
|
+
if (feedVersions.Contains(currentVersion))
|
90
|
+
{
|
91
|
+
result.AddCurrentVersionSource(source);
|
92
|
+
}
|
93
|
+
|
94
|
+
result.AddRange(source, feedVersions.Where(versionFilter));
|
95
|
+
}
|
96
|
+
|
97
|
+
return result;
|
98
|
+
}
|
99
|
+
|
100
|
+
internal static Func<NuGetVersion, bool> CreateVersionFilter(DependencyInfo dependencyInfo, VersionRange versionRange)
|
101
|
+
{
|
102
|
+
// If we are floating to the absolute latest version, we should not filter pre-release versions at all.
|
103
|
+
var currentVersion = versionRange.Float?.FloatBehavior != NuGetVersionFloatBehavior.AbsoluteLatest
|
104
|
+
? versionRange.MinVersion
|
105
|
+
: null;
|
106
|
+
|
107
|
+
return version => (currentVersion is null || version > currentVersion)
|
108
|
+
&& versionRange.Satisfies(version)
|
109
|
+
&& (currentVersion is null || !currentVersion.IsPrerelease || !version.IsPrerelease || version.Version == currentVersion.Version)
|
110
|
+
&& !dependencyInfo.IgnoredVersions.Any(r => r.IsSatisfiedBy(version))
|
111
|
+
&& !dependencyInfo.Vulnerabilities.Any(v => v.IsVulnerable(version));
|
112
|
+
}
|
113
|
+
|
114
|
+
internal static Func<NuGetVersion, bool> CreateVersionFilter(NuGetVersion currentVersion)
|
115
|
+
{
|
116
|
+
return version => version > currentVersion
|
117
|
+
&& (currentVersion is null || !currentVersion.IsPrerelease || !version.IsPrerelease || version.Version == currentVersion.Version);
|
118
|
+
}
|
119
|
+
|
120
|
+
public static async Task<bool> DoVersionsExistAsync(
|
121
|
+
IEnumerable<string> packageIds,
|
122
|
+
NuGetVersion version,
|
123
|
+
NuGetContext nugetContext,
|
124
|
+
Logger logger,
|
125
|
+
CancellationToken cancellationToken)
|
126
|
+
{
|
127
|
+
foreach (var packageId in packageIds)
|
128
|
+
{
|
129
|
+
if (!await DoesVersionExistAsync(packageId, version, nugetContext, logger, cancellationToken))
|
130
|
+
{
|
131
|
+
return false;
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
return true;
|
136
|
+
}
|
137
|
+
|
138
|
+
public static async Task<bool> DoesVersionExistAsync(
|
139
|
+
string packageId,
|
140
|
+
NuGetVersion version,
|
141
|
+
NuGetContext nugetContext,
|
142
|
+
Logger logger,
|
143
|
+
CancellationToken cancellationToken)
|
144
|
+
{
|
145
|
+
var includePrerelease = version.IsPrerelease;
|
146
|
+
|
147
|
+
var sourceMapping = PackageSourceMapping.GetPackageSourceMapping(nugetContext.Settings);
|
148
|
+
var packageSources = sourceMapping.GetConfiguredPackageSources(packageId).ToHashSet();
|
149
|
+
var sources = packageSources.Count == 0
|
150
|
+
? nugetContext.PackageSources
|
151
|
+
: nugetContext.PackageSources
|
152
|
+
.Where(p => packageSources.Contains(p.Name))
|
153
|
+
.ToImmutableArray();
|
154
|
+
|
155
|
+
foreach (var source in sources)
|
156
|
+
{
|
157
|
+
var sourceRepository = Repository.Factory.GetCoreV3(source);
|
158
|
+
var feed = await sourceRepository.GetResourceAsync<MetadataResource>();
|
159
|
+
if (feed is null)
|
160
|
+
{
|
161
|
+
logger.Log($"Failed to get MetadataResource for [{source.Source}]");
|
162
|
+
continue;
|
163
|
+
}
|
164
|
+
|
165
|
+
var existsInFeed = await feed.Exists(
|
166
|
+
new PackageIdentity(packageId, version),
|
167
|
+
includeUnlisted: false,
|
168
|
+
nugetContext.SourceCacheContext,
|
169
|
+
NullLogger.Instance,
|
170
|
+
cancellationToken);
|
171
|
+
if (existsInFeed)
|
172
|
+
{
|
173
|
+
return true;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
return false;
|
178
|
+
}
|
179
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
using System.Collections.Immutable;
|
2
|
+
|
3
|
+
using NuGet.Configuration;
|
4
|
+
using NuGet.Versioning;
|
5
|
+
|
6
|
+
namespace NuGetUpdater.Core.Analyze;
|
7
|
+
|
8
|
+
internal class VersionResult
|
9
|
+
{
|
10
|
+
private readonly Dictionary<NuGetVersion, List<PackageSource>> _versions = [];
|
11
|
+
private readonly List<PackageSource> _currentVersionSources = [];
|
12
|
+
|
13
|
+
public NuGetVersion CurrentVersion { get; }
|
14
|
+
|
15
|
+
public VersionResult(NuGetVersion currentVersion)
|
16
|
+
{
|
17
|
+
CurrentVersion = currentVersion;
|
18
|
+
}
|
19
|
+
|
20
|
+
public void AddCurrentVersionSource(PackageSource source)
|
21
|
+
{
|
22
|
+
_currentVersionSources.Add(source);
|
23
|
+
}
|
24
|
+
|
25
|
+
public void AddRange(PackageSource source, IEnumerable<NuGetVersion> versions)
|
26
|
+
{
|
27
|
+
foreach (var version in versions)
|
28
|
+
{
|
29
|
+
if (_versions.ContainsKey(version))
|
30
|
+
{
|
31
|
+
_versions[version].Add(source);
|
32
|
+
}
|
33
|
+
else
|
34
|
+
{
|
35
|
+
_versions.Add(version, [source]);
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
public ImmutableArray<PackageSource> GetPackageSources(NuGetVersion version)
|
41
|
+
{
|
42
|
+
if (version == CurrentVersion)
|
43
|
+
{
|
44
|
+
return [.. _currentVersionSources];
|
45
|
+
}
|
46
|
+
|
47
|
+
return [.. _versions[version]];
|
48
|
+
}
|
49
|
+
|
50
|
+
public ImmutableArray<NuGetVersion> GetVersions()
|
51
|
+
{
|
52
|
+
return [.. _versions.Keys];
|
53
|
+
}
|
54
|
+
}
|
@@ -14,7 +14,8 @@ public sealed record Dependency(
|
|
14
14
|
bool IsDirect = false,
|
15
15
|
bool IsTransitive = false,
|
16
16
|
bool IsOverride = false,
|
17
|
-
bool IsUpdate = false
|
17
|
+
bool IsUpdate = false,
|
18
|
+
string? InfoUrl = null) : IEquatable<Dependency>
|
18
19
|
{
|
19
20
|
public bool Equals(Dependency? other)
|
20
21
|
{
|
@@ -37,7 +38,8 @@ public sealed record Dependency(
|
|
37
38
|
IsDirect == other.IsDirect &&
|
38
39
|
IsTransitive == other.IsTransitive &&
|
39
40
|
IsOverride == other.IsOverride &&
|
40
|
-
IsUpdate == other.IsUpdate
|
41
|
+
IsUpdate == other.IsUpdate &&
|
42
|
+
InfoUrl == other.InfoUrl;
|
41
43
|
}
|
42
44
|
|
43
45
|
public override int GetHashCode()
|
@@ -53,6 +55,7 @@ public sealed record Dependency(
|
|
53
55
|
hash.Add(IsTransitive);
|
54
56
|
hash.Add(IsOverride);
|
55
57
|
hash.Add(IsUpdate);
|
58
|
+
hash.Add(InfoUrl);
|
56
59
|
return hash.ToHashCode();
|
57
60
|
}
|
58
61
|
}
|
@@ -39,6 +39,7 @@ public partial class DiscoveryWorker
|
|
39
39
|
workspacePath = workspacePath[1..];
|
40
40
|
}
|
41
41
|
|
42
|
+
string initialWorkspacePath = workspacePath;
|
42
43
|
workspacePath = Path.Combine(repoRootPath, workspacePath);
|
43
44
|
|
44
45
|
DotNetToolsJsonDiscoveryResult? dotNetToolsJsonDiscovery = null;
|
@@ -75,7 +76,7 @@ public partial class DiscoveryWorker
|
|
75
76
|
|
76
77
|
var result = new WorkspaceDiscoveryResult
|
77
78
|
{
|
78
|
-
|
79
|
+
Path = initialWorkspacePath,
|
79
80
|
DotNetToolsJson = dotNetToolsJsonDiscovery,
|
80
81
|
GlobalJson = globalJsonDiscovery,
|
81
82
|
DirectoryPackagesProps = directoryPackagesPropsDiscovery,
|
@@ -2,9 +2,9 @@ using System.Collections.Immutable;
|
|
2
2
|
|
3
3
|
namespace NuGetUpdater.Core.Discover;
|
4
4
|
|
5
|
-
public sealed record WorkspaceDiscoveryResult
|
5
|
+
public sealed record WorkspaceDiscoveryResult
|
6
6
|
{
|
7
|
-
public required string
|
7
|
+
public required string Path { get; init; }
|
8
8
|
public bool IsSuccess { get; init; } = true;
|
9
9
|
public ImmutableArray<ProjectDiscoveryResult> Projects { get; init; }
|
10
10
|
public DirectoryPackagesPropsDiscoveryResult? DirectoryPackagesProps { get; init; }
|
data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/FrameworkCompatibilityService.cs
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
// Copyright (c) .NET Foundation. All rights reserved.
|
2
2
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
3
3
|
|
4
|
-
using System;
|
5
|
-
using System.Collections.Generic;
|
6
|
-
|
7
4
|
using NuGet.Frameworks;
|
8
5
|
|
9
6
|
using NuGetGallery.Frameworks;
|
@@ -1,9 +1,6 @@
|
|
1
1
|
// Copyright (c) .NET Foundation. All rights reserved.
|
2
2
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
3
3
|
|
4
|
-
using System;
|
5
|
-
using System.Collections.Generic;
|
6
|
-
|
7
4
|
using NuGet.Frameworks;
|
8
5
|
|
9
6
|
using static NuGet.Frameworks.FrameworkConstants;
|