Skip to content

Commit 91ab6de

Browse files
authored
Add vulnerabilities service (#8357)
1 parent 9ddf91f commit 91ab6de

17 files changed

Lines changed: 271 additions & 13 deletions

File tree

src/NuGet.Services.Entities/Package.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public Package()
2424
SymbolPackages = new HashSet<SymbolPackage>();
2525
Deprecations = new HashSet<PackageDeprecation>();
2626
AlternativeOf = new HashSet<PackageDeprecation>();
27-
Vulnerabilities = new HashSet<VulnerablePackageVersionRange>();
27+
VulnerablePackageRanges = new HashSet<VulnerablePackageVersionRange>();
2828
Listed = true;
2929
}
3030
#pragma warning restore 618
@@ -289,9 +289,9 @@ public bool HasEmbeddedReadme
289289
public virtual ICollection<PackageDeprecation> AlternativeOf { get; set; }
290290

291291
/// <summary>
292-
/// Gets or sets the list of vulnerabilites that this package has.
292+
/// Gets or sets the list of vulnerable package ranges connecting this package to vulnerabilities.
293293
/// </summary>
294-
public ICollection<VulnerablePackageVersionRange> Vulnerabilities { get; set; }
294+
public ICollection<VulnerablePackageVersionRange> VulnerablePackageRanges { get; set; }
295295

296296
/// <summary>
297297
/// A flag that indicates that the package metadata had an embedded icon specified.

src/NuGetGallery.Core/Entities/EntitiesContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ protected override void OnModelCreating(DbModelBuilder modelBuilder)
482482
modelBuilder.Entity<VulnerablePackageVersionRange>()
483483
.HasKey(pv => pv.Key)
484484
.HasMany(pv => pv.Packages)
485-
.WithMany(p => p.Vulnerabilities);
485+
.WithMany(p => p.VulnerablePackageRanges);
486486

487487
modelBuilder.Entity<VulnerablePackageVersionRange>()
488488
.HasIndex(pv => pv.PackageId);

src/NuGetGallery.Services/PackageManagement/PackageVulnerabilitiesManagementService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public void ApplyExistingVulnerabilitiesToPackage(Package package)
4545
var versionRange = VersionRange.Parse(possibleRange.PackageVersionRange);
4646
if (versionRange.Satisfies(version))
4747
{
48-
package.Vulnerabilities.Add(possibleRange);
48+
package.VulnerablePackageRanges.Add(possibleRange);
4949
possibleRange.Packages.Add(package);
5050
}
5151
}
@@ -278,7 +278,7 @@ private void ProcessNewVulnerabilityRange(VulnerablePackageVersionRange range, H
278278
package.NormalizedVersion,
279279
range.PackageVersionRange);
280280

281-
package.Vulnerabilities.Add(range);
281+
package.VulnerablePackageRanges.Add(range);
282282
range.Packages.Add(package);
283283
packagesToUpdate.Add(package);
284284
}

src/NuGetGallery/App_Start/DefaultDependenciesModule.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ protected override void Load(ContainerBuilder builder)
422422
.As<IPackageDeprecationService>()
423423
.InstancePerLifetimeScope();
424424

425+
builder.RegisterType<PackageVulnerabilitiesService>()
426+
.As<IPackageVulnerabilitiesService>()
427+
.InstancePerLifetimeScope();
428+
425429
builder.RegisterType<PackageRenameService>()
426430
.As<IPackageRenameService>()
427431
.InstancePerLifetimeScope();

src/NuGetGallery/Controllers/PackagesController.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ public partial class PackagesController
121121
private readonly ILicenseExpressionSplitter _licenseExpressionSplitter;
122122
private readonly IFeatureFlagService _featureFlagService;
123123
private readonly IPackageDeprecationService _deprecationService;
124+
private readonly IPackageVulnerabilitiesService _vulnerabilitiesService;
124125
private readonly IPackageRenameService _renameService;
125126
private readonly IABTestService _abTestService;
126127
private readonly IMarkdownService _markdownService;
@@ -161,6 +162,7 @@ public PackagesController(
161162
ILicenseExpressionSplitter licenseExpressionSplitter,
162163
IFeatureFlagService featureFlagService,
163164
IPackageDeprecationService deprecationService,
165+
IPackageVulnerabilitiesService vulnerabilitiesService,
164166
IPackageRenameService renameService,
165167
IABTestService abTestService,
166168
IIconUrlProvider iconUrlProvider,
@@ -197,6 +199,7 @@ public PackagesController(
197199
_licenseExpressionSplitter = licenseExpressionSplitter ?? throw new ArgumentNullException(nameof(licenseExpressionSplitter));
198200
_featureFlagService = featureFlagService ?? throw new ArgumentNullException(nameof(featureFlagService));
199201
_deprecationService = deprecationService ?? throw new ArgumentNullException(nameof(deprecationService));
202+
_vulnerabilitiesService = vulnerabilitiesService ?? throw new ArgumentNullException(nameof(vulnerabilitiesService));
200203
_renameService = renameService ?? throw new ArgumentNullException(nameof(renameService));
201204
_abTestService = abTestService ?? throw new ArgumentNullException(nameof(abTestService));
202205
_iconUrlProvider = iconUrlProvider ?? throw new ArgumentNullException(nameof(iconUrlProvider));
@@ -875,6 +878,8 @@ public virtual async Task<ActionResult> DisplayPackage(string id, string version
875878
.GroupBy(d => d.PackageKey)
876879
.ToDictionary(g => g.Key, g => g.First());
877880

881+
var packageKeyToVulnerabilities = _vulnerabilitiesService.GetVulnerabilitiesById(id);
882+
878883
IReadOnlyList<PackageRename> packageRenames = null;
879884
if (_featureFlagService.IsPackageRenamesEnabled(currentUser))
880885
{
@@ -886,6 +891,7 @@ public virtual async Task<ActionResult> DisplayPackage(string id, string version
886891
allVersions,
887892
currentUser,
888893
packageKeyToDeprecation,
894+
packageKeyToVulnerabilities,
889895
packageRenames,
890896
readme);
891897

@@ -895,6 +901,7 @@ public virtual async Task<ActionResult> DisplayPackage(string id, string version
895901
model.IsCertificatesUIEnabled = _contentObjectService.CertificatesConfiguration?.IsUIEnabledForUser(currentUser) ?? false;
896902
model.IsAtomFeedEnabled = _featureFlagService.IsPackagesAtomFeedEnabled();
897903
model.IsPackageDeprecationEnabled = _featureFlagService.IsManageDeprecationEnabled(currentUser, allVersions);
904+
model.IsPackageVulnerabilitiesEnabled = _featureFlagService.IsDisplayVulnerabilitiesEnabled();
898905
model.IsPackageRenamesEnabled = _featureFlagService.IsPackageRenamesEnabled(currentUser);
899906
model.IsPackageDependentsEnabled = _featureFlagService.IsPackageDependentsEnabled(currentUser);
900907

src/NuGetGallery/Helpers/ViewModelExtensions/DeletePackageViewModelFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public DeletePackageViewModel Setup(
3939
allVersions,
4040
currentUser,
4141
packageKeyToDeprecation: null,
42+
packageKeyToVulnerabilities: null,
4243
packageRenames: null,
4344
readmeResult: null);
4445

src/NuGetGallery/Helpers/ViewModelExtensions/DisplayPackageViewModelFactory.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public DisplayPackageViewModel Create(
2323
IReadOnlyCollection<Package> allVersions,
2424
User currentUser,
2525
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation,
26+
IReadOnlyDictionary<int, IReadOnlyList<PackageVulnerability>> packageKeyToVulnerabilities,
2627
IReadOnlyList<PackageRename> packageRenames,
2728
RenderedMarkdownResult readmeResult)
2829
{
@@ -33,6 +34,7 @@ public DisplayPackageViewModel Create(
3334
allVersions,
3435
currentUser,
3536
packageKeyToDeprecation,
37+
packageKeyToVulnerabilities,
3638
packageRenames,
3739
readmeResult);
3840
}
@@ -43,12 +45,15 @@ public DisplayPackageViewModel Setup(
4345
IReadOnlyCollection<Package> allVersions,
4446
User currentUser,
4547
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation,
48+
IReadOnlyDictionary<int, IReadOnlyList<PackageVulnerability>> packageKeyToVulnerabilities,
4649
IReadOnlyList<PackageRename> packageRenames,
4750
RenderedMarkdownResult readmeResult)
4851
{
4952
_listPackageItemViewModelFactory.Setup(viewModel, package, currentUser);
50-
SetupCommon(viewModel, package, pushedBy: null, packageKeyToDeprecation: packageKeyToDeprecation);
51-
return SetupInternal(viewModel, package, allVersions, currentUser, packageKeyToDeprecation, packageRenames, readmeResult);
53+
SetupCommon(viewModel, package, pushedBy: null,
54+
packageKeyToDeprecation: packageKeyToDeprecation, packageKeyToVulnerabilities: packageKeyToVulnerabilities);
55+
return SetupInternal(viewModel, package, allVersions, currentUser,
56+
packageKeyToDeprecation, packageKeyToVulnerabilities, packageRenames, readmeResult);
5257
}
5358

5459
private DisplayPackageViewModel SetupInternal(
@@ -57,6 +62,7 @@ private DisplayPackageViewModel SetupInternal(
5762
IReadOnlyCollection<Package> allVersions,
5863
User currentUser,
5964
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation,
65+
IReadOnlyDictionary<int, IReadOnlyList<PackageVulnerability>> packageKeyToVulnerabilities,
6066
IReadOnlyList<PackageRename> packageRenames,
6167
RenderedMarkdownResult readmeResult)
6268
{
@@ -74,7 +80,7 @@ private DisplayPackageViewModel SetupInternal(
7480
{
7581
var vm = new DisplayPackageViewModel();
7682
_listPackageItemViewModelFactory.Setup(vm, p, currentUser);
77-
return SetupCommon(vm, p, GetPushedBy(p, currentUser, pushedByCache), packageKeyToDeprecation);
83+
return SetupCommon(vm, p, GetPushedBy(p, currentUser, pushedByCache), packageKeyToDeprecation, packageKeyToVulnerabilities);
7884
})
7985
.ToList();
8086

@@ -136,7 +142,8 @@ private DisplayPackageViewModel SetupCommon(
136142
DisplayPackageViewModel viewModel,
137143
Package package,
138144
string pushedBy,
139-
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation)
145+
IReadOnlyDictionary<int, PackageDeprecation> packageKeyToDeprecation,
146+
IReadOnlyDictionary<int, IReadOnlyList<PackageVulnerability>> packageKeyToVulnerabilities)
140147
{
141148
viewModel.NuGetVersion = NuGetVersion.Parse(NuGetVersionFormatter.ToFullString(package.Version));
142149
viewModel.Copyright = package.Copyright;
@@ -179,6 +186,12 @@ private DisplayPackageViewModel SetupCommon(
179186
viewModel.DeprecationStatus = PackageDeprecationStatus.NotDeprecated;
180187
}
181188

189+
if (packageKeyToVulnerabilities != null && packageKeyToVulnerabilities.TryGetValue(package.Key, out var vulnerabilities))
190+
{
191+
viewModel.Vulnerabilities = vulnerabilities;
192+
viewModel.MaxVulnerabilitySeverity = vulnerabilities.Max(v => v.Severity);
193+
}
194+
182195
return viewModel;
183196
}
184197

src/NuGetGallery/NuGetGallery.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,10 @@
305305
<Compile Include="Modules\CookieComplianceHttpModule.cs" />
306306
<Compile Include="RequestModels\DeletePackagesApiRequest.cs" />
307307
<Compile Include="Services\IMarkdownService.cs" />
308+
<Compile Include="Services\IPackageVulnerabilitiesService.cs" />
308309
<Compile Include="Services\IPackageMetadataValidationService.cs" />
309310
<Compile Include="Services\MarkdownService.cs" />
311+
<Compile Include="Services\PackageVulnerabilitiesService.cs" />
310312
<Compile Include="Services\PackageMetadataValidationService.cs" />
311313
<Compile Include="Services\ConfigurationIconFileProvider.cs" />
312314
<Compile Include="Services\IconUrlDeprecationValidationMessage.cs" />
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Threading.Tasks;
6+
using NuGet.Services.Entities;
7+
8+
namespace NuGetGallery
9+
{
10+
public interface IPackageVulnerabilitiesService
11+
{
12+
/// <summary>
13+
/// Returns a dictionary mapping package keys to collections of vulnerabilities for that package/version
14+
/// </summary>
15+
/// <param name="id">id of the package for this query</param>
16+
IReadOnlyDictionary<int, IReadOnlyList<PackageVulnerability>> GetVulnerabilitiesById(string id);
17+
}
18+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Data.Entity;
7+
using System.Linq;
8+
using NuGet.Services.Entities;
9+
10+
namespace NuGetGallery
11+
{
12+
public class PackageVulnerabilitiesService : IPackageVulnerabilitiesService
13+
{
14+
private readonly IEntitiesContext _entitiesContext;
15+
16+
public PackageVulnerabilitiesService(IEntitiesContext entitiesContext)
17+
{
18+
_entitiesContext = entitiesContext ?? throw new ArgumentNullException(nameof(entitiesContext));
19+
}
20+
21+
public IReadOnlyDictionary<int, IReadOnlyList<PackageVulnerability>> GetVulnerabilitiesById(string id)
22+
{
23+
var result = new Dictionary<int, List<PackageVulnerability>>();
24+
var packagesMatchingId = _entitiesContext.Packages
25+
.Where(p => p.PackageRegistration != null && p.PackageRegistration.Id == id)
26+
.Include($"{nameof(Package.VulnerablePackageRanges)}.{nameof(VulnerablePackageVersionRange.Vulnerability)}");
27+
foreach (var package in packagesMatchingId)
28+
{
29+
if (package.VulnerablePackageRanges == null)
30+
{
31+
continue;
32+
}
33+
34+
if (package.VulnerablePackageRanges.Any())
35+
{
36+
result.Add(package.Key,
37+
package.VulnerablePackageRanges.Select(vr => vr.Vulnerability).ToList());
38+
}
39+
}
40+
41+
return !result.Any() ? null :
42+
result.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<PackageVulnerability>);
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)