From 168734855eb59563af4fa42b60f6f4f9d4b69e61 Mon Sep 17 00:00:00 2001 From: "Brett V. Forsgren" Date: Wed, 15 Jan 2025 15:35:06 -0700 Subject: [PATCH] create dependency info object in end-to-end updater --- .../Run/MiscellaneousTests.cs | 61 +++++++++++++++++++ .../Run/ApiModel/Advisory.cs | 2 + .../NuGetUpdater.Core/Run/RunWorker.cs | 36 ++++++++--- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs index 17db05d563..b21fe1d432 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs @@ -1,3 +1,5 @@ +using System.Text.Json; + using NuGet.Versioning; using NuGetUpdater.Core.Analyze; @@ -29,6 +31,16 @@ public void RequirementsFromIgnoredVersions(string dependencyName, Condition[] i Assert.Equal(expectedRequirementsStrings, actualRequirementsStrings); } + [Theory] + [MemberData(nameof(DependencyInfoFromJobData))] + public void DependencyInfoFromJob(Job job, Dependency dependency, DependencyInfo expectedDependencyInfo) + { + var actualDependencyInfo = RunWorker.GetDependencyInfo(job, dependency); + var expectedString = JsonSerializer.Serialize(expectedDependencyInfo, AnalyzeWorker.SerializerOptions); + var actualString = JsonSerializer.Serialize(actualDependencyInfo, AnalyzeWorker.SerializerOptions); + Assert.Equal(expectedString, actualString); + } + public static IEnumerable RequirementsFromIgnoredVersionsData() { yield return @@ -82,4 +94,53 @@ public void RequirementsFromIgnoredVersions(string dependencyName, Condition[] i } ]; } + + public static IEnumerable DependencyInfoFromJobData() + { + yield return + [ + // job + new Job() + { + Source = new() + { + Provider = "github", + Repo = "some/repo" + }, + SecurityAdvisories = [ + new() + { + DependencyName = "Some.Dependency", + AffectedVersions = [Requirement.Parse(">= 1.0.0, < 1.1.0")], + PatchedVersions = [Requirement.Parse("= 1.1.0")], + UnaffectedVersions = [Requirement.Parse("= 1.2.0")] + }, + new() + { + DependencyName = "Unrelated.Dependency", + AffectedVersions = [Requirement.Parse(">= 1.0.0, < 99.99.99")] + } + ] + }, + // dependency + new Dependency("Some.Dependency", "1.0.0", DependencyType.PackageReference), + // expectedDependencyInfo + new DependencyInfo() + { + Name = "Some.Dependency", + Version = "1.0.0", + IsVulnerable = true, + IgnoredVersions = [], + Vulnerabilities = [ + new() + { + DependencyName = "Some.Dependency", + PackageManager = "nuget", + VulnerableVersions = [Requirement.Parse(">= 1.0.0, < 1.1.0")], + SafeVersions = [Requirement.Parse("= 1.1.0"), Requirement.Parse("= 1.2.0")], + } + ] + } + ]; + } } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs index eb052eca40..1fddd91f71 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs @@ -10,4 +10,6 @@ public record Advisory public ImmutableArray? AffectedVersions { get; init; } = null; public ImmutableArray? PatchedVersions { get; init; } = null; public ImmutableArray? UnaffectedVersions { get; init; } = null; + + public IEnumerable SafeVersions => (PatchedVersions ?? []).Concat(UnaffectedVersions ?? []); } diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs index 7bce84a7e6..6f4f5f95e4 100644 --- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs @@ -4,6 +4,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +using NuGet.Versioning; + using NuGetUpdater.Core.Analyze; using NuGetUpdater.Core.Discover; using NuGetUpdater.Core.Run.ApiModel; @@ -164,15 +166,7 @@ async Task TrackOriginalContentsAsync(string directory, string fileName) continue; } - var ignoredVersions = GetIgnoredRequirementsForDependency(job, dependency.Name); - var dependencyInfo = new DependencyInfo() - { - Name = dependency.Name, - Version = dependency.Version!, - IsVulnerable = false, - IgnoredVersions = ignoredVersions, - Vulnerabilities = [], - }; + var dependencyInfo = GetDependencyInfo(job, dependency); var analysisResult = await _analyzeWorker.RunAsync(repoContentsPath.FullName, discoveryResult, dependencyInfo); // TODO: log analysisResult if (analysisResult.CanUpdate) @@ -314,6 +308,30 @@ internal static ImmutableArray GetIgnoredRequirementsForDependency( return ignoredVersions; } + internal static DependencyInfo GetDependencyInfo(Job job, Dependency dependency) + { + var dependencyVersion = NuGetVersion.Parse(dependency.Version!); + var securityAdvisories = job.SecurityAdvisories.Where(s => s.DependencyName.Equals(dependency.Name, StringComparison.OrdinalIgnoreCase)).ToArray(); + var isVulnerable = securityAdvisories.Any(s => (s.AffectedVersions ?? []).Any(v => v.IsSatisfiedBy(dependencyVersion))); + var ignoredVersions = GetIgnoredRequirementsForDependency(job, dependency.Name); + var vulnerability = new SecurityVulnerability() + { + DependencyName = dependency.Name, + PackageManager = "nuget", + VulnerableVersions = securityAdvisories.SelectMany(s => s.AffectedVersions ?? []).ToImmutableArray(), + SafeVersions = securityAdvisories.SelectMany(s => s.SafeVersions).ToImmutableArray() + }; + var dependencyInfo = new DependencyInfo() + { + Name = dependency.Name, + Version = dependencyVersion.ToString(), + IsVulnerable = isVulnerable, + IgnoredVersions = ignoredVersions, + Vulnerabilities = [vulnerability], + }; + return dependencyInfo; + } + internal static UpdatedDependencyList GetUpdatedDependencyListFromDiscovery(WorkspaceDiscoveryResult discoveryResult, string pathToContents) { string GetFullRepoPath(string path)