Skip to content

Commit 3ebfdea

Browse files
author
Daniel Jacinto
authored
[Search DV] Display deprecation and vulnerabilities on search page. (#9440)
* deprecation and vulnerabilities display on search page * Properties added to current Deprecations/Vulnerabilities * nit. * tooltip added. * tooltip tests. * fix. * nit. * update deprecated legacy wording. * fix test. * AdvisoryUrl, and AlternatePackage fix. * version range comma index.
1 parent 36cbb88 commit 3ebfdea

18 files changed

Lines changed: 671 additions & 69 deletions

src/Bootstrap/dist/css/bootstrap-theme.css

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Bootstrap/less/theme/common-list-packages.less

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,30 @@
5858
margin-top: 75px;
5959
margin-bottom: 0px;
6060
}
61+
62+
@severe-warning-background-color: rgb(254, 217, 204);
63+
@severe-warning-icon-color: rgb(216, 59, 1);
64+
@warning-background-color: rgb(255, 244, 206);
65+
@package-warning-color: rgb(50, 49, 48);
66+
@badge-border-radius: 2px;
67+
68+
.package-warning {
69+
padding-right: 8px;
70+
padding-left: 8px;
71+
border-radius: @badge-border-radius;
72+
margin-right: 5px;
73+
color: @package-warning-color
74+
}
75+
76+
.package-warning--vulnerable {
77+
.package-warning;
78+
background-color: @severe-warning-background-color;
79+
i {
80+
color: @severe-warning-icon-color;
81+
}
82+
}
83+
84+
.package-warning--deprecated {
85+
.package-warning;
86+
background-color: @warning-background-color;
87+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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.Linq;
7+
using Newtonsoft.Json.Linq;
8+
using NuGet.Services.Entities;
9+
10+
namespace NuGetGallery.Helpers
11+
{
12+
public static class SearchResponseHelper
13+
{
14+
public static ICollection<PackageDeprecation> GetDeprecationsOrNull(JToken docDeprecation)
15+
{
16+
PackageDeprecation deprecation = null;
17+
if (docDeprecation != null)
18+
{
19+
var docReasons = docDeprecation.Value<JArray>("Reasons");
20+
if (docReasons != null && docReasons.HasValues)
21+
{
22+
PackageDeprecationStatus status = PackageDeprecationStatus.NotDeprecated;
23+
foreach (var reason in docReasons)
24+
{
25+
if (Enum.TryParse<PackageDeprecationStatus>(reason.Value<string>(), out var pdStatus))
26+
{
27+
status |= pdStatus;
28+
}
29+
}
30+
31+
var docAlternatePackage = docDeprecation["AlternatePackage"];
32+
Package alternatePackage = null;
33+
if (docAlternatePackage != null)
34+
{
35+
var range = docAlternatePackage.Value<string>("Range");
36+
var id = docAlternatePackage.Value<string>("Id");
37+
if (!string.IsNullOrEmpty(range) && !string.IsNullOrEmpty(id))
38+
{
39+
var version = string.Empty;
40+
var commaIndex = range.IndexOf(",");
41+
if (range.StartsWith("[") && commaIndex > 0)
42+
{
43+
var startIndex = 1;
44+
version = range.Substring(startIndex, commaIndex - startIndex);
45+
}
46+
47+
alternatePackage = new Package()
48+
{
49+
Id = id,
50+
Version = version
51+
};
52+
}
53+
}
54+
55+
deprecation = new PackageDeprecation()
56+
{
57+
CustomMessage = docDeprecation.Value<string>("Message"),
58+
Status = status,
59+
AlternatePackage = alternatePackage
60+
};
61+
}
62+
}
63+
64+
return deprecation == null ? null : new List<PackageDeprecation>() { deprecation };
65+
}
66+
67+
public static ICollection<VulnerablePackageVersionRange> GetVulnerabilities(JArray docVulnerabilities)
68+
{
69+
var vulnerabilities = new List<VulnerablePackageVersionRange>();
70+
if (docVulnerabilities != null)
71+
{
72+
vulnerabilities = docVulnerabilities.Select(v => new VulnerablePackageVersionRange()
73+
{
74+
Vulnerability = new PackageVulnerability()
75+
{
76+
AdvisoryUrl = v.Value<string>("AdvisoryUrl"),
77+
Severity = (PackageVulnerabilitySeverity)v.Value<int>("Severity")
78+
}
79+
})
80+
.ToList();
81+
}
82+
83+
return vulnerabilities;
84+
}
85+
}
86+
}

src/NuGetGallery/Helpers/ViewModelExtensions/DisplayPackageViewModelFactory.cs

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Linq;
77
using NuGet.Services.Entities;
88
using NuGet.Versioning;
9+
using NuGetGallery.Helpers;
910

1011
namespace NuGetGallery
1112
{
@@ -217,60 +218,11 @@ private DisplayPackageViewModel SetupCommon(
217218
viewModel.MaxVulnerabilitySeverity = default;
218219
}
219220

220-
viewModel.PackageWarningIconTitle =
221-
GetWarningIconTitle(viewModel.Version, deprecation, maxVulnerabilitySeverity);
221+
viewModel.PackageWarningIconTitle = WarningTitleHelper.GetWarningIconTitle(viewModel.Version, deprecation, maxVulnerabilitySeverity);
222222

223223
return viewModel;
224224
}
225225

226-
private static string GetWarningIconTitle(
227-
string version,
228-
PackageDeprecation deprecation,
229-
PackageVulnerabilitySeverity? maxVulnerabilitySeverity)
230-
{
231-
// We want a tooltip title for the warning icon, which concatenates deprecation and vulnerability information cleanly
232-
var deprecationTitle = "";
233-
if (deprecation != null)
234-
{
235-
deprecationTitle = version;
236-
var isLegacy = deprecation.Status.HasFlag(PackageDeprecationStatus.Legacy);
237-
var hasCriticalBugs = deprecation.Status.HasFlag(PackageDeprecationStatus.CriticalBugs);
238-
if (hasCriticalBugs)
239-
{
240-
if (isLegacy)
241-
{
242-
deprecationTitle += " is deprecated because it's legacy and has critical bugs";
243-
}
244-
else
245-
{
246-
deprecationTitle += " is deprecated because it has critical bugs";
247-
}
248-
}
249-
else if (isLegacy)
250-
{
251-
deprecationTitle += " is deprecated because it's legacy and no longer maintained";
252-
}
253-
else
254-
{
255-
deprecationTitle += " is deprecated";
256-
}
257-
}
258-
259-
if (maxVulnerabilitySeverity.HasValue)
260-
{
261-
var severity = Enum.GetName(typeof(PackageVulnerabilitySeverity), maxVulnerabilitySeverity)?.ToLowerInvariant() ?? "unknown";
262-
var vulnerabilitiesTitle = $"{version} has at least one vulnerability with {severity} severity.";
263-
264-
return string.IsNullOrEmpty(deprecationTitle)
265-
? vulnerabilitiesTitle
266-
: $"{deprecationTitle}; {vulnerabilitiesTitle}";
267-
}
268-
269-
return string.IsNullOrEmpty(deprecationTitle)
270-
? string.Empty
271-
: $"{deprecationTitle}.";
272-
}
273-
274226
private static string GetPushedBy(Package package, User currentUser, Dictionary<User, string> pushedByCache)
275227
{
276228
var userPushedBy = package.User;

src/NuGetGallery/Helpers/ViewModelExtensions/ListPackageItemViewModelFactory.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Linq;
55
using NuGet.Services.Entities;
6+
using NuGetGallery.Helpers;
67

78
namespace NuGetGallery
89
{
@@ -39,6 +40,19 @@ private ListPackageItemViewModel SetupInternal(ListPackageItemViewModel viewMode
3940
viewModel.MinClientVersion = package.MinClientVersion;
4041
viewModel.Owners = package.PackageRegistration?.Owners?.Select(GetBasicUserViewModel).ToList();
4142
viewModel.IsVerified = package.PackageRegistration?.IsVerified;
43+
viewModel.IsDeprecated = package.Deprecations?.Count > 0;
44+
viewModel.IsVulnerable = package.VulnerablePackageRanges?.Count > 0;
45+
46+
if (viewModel.IsDeprecated)
47+
{
48+
viewModel.DeprecationTitle = WarningTitleHelper.GetDeprecationTitle(package.Version, package.Deprecations.First().Status);
49+
}
50+
51+
if (viewModel.IsVulnerable)
52+
{
53+
var maxVulnerabilitySeverity = package.VulnerablePackageRanges.Max(vpr => vpr.Vulnerability.Severity);
54+
viewModel.VulnerabilityTitle = WarningTitleHelper.GetVulnerabilityTitle(package.Version, maxVulnerabilitySeverity);
55+
}
4256

4357
viewModel.CanDisplayPrivateMetadata = CanPerformAction(currentUser, package, ActionsRequiringPermissions.DisplayPrivatePackageMetadata);
4458
viewModel.CanEdit = CanPerformAction(currentUser, package, ActionsRequiringPermissions.EditPackage);
@@ -68,9 +82,10 @@ private static bool CanPerformAction(User currentUser, Package package, ActionRe
6882

6983
private static BasicUserViewModel GetBasicUserViewModel(User user)
7084
{
71-
return new BasicUserViewModel {
72-
Username = user.Username,
73-
EmailAddress = user.EmailAddress,
85+
return new BasicUserViewModel
86+
{
87+
Username = user.Username,
88+
EmailAddress = user.EmailAddress,
7489
IsOrganization = user is Organization,
7590
IsLocked = user.IsLocked
7691
};
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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 NuGet.Services.Entities;
6+
7+
namespace NuGetGallery.Helpers
8+
{
9+
public static class WarningTitleHelper
10+
{
11+
public static string GetWarningIconTitle(
12+
string version,
13+
PackageDeprecation deprecation,
14+
PackageVulnerabilitySeverity? maxVulnerabilitySeverity)
15+
{
16+
// We want a tooltip title for the warning icon, which concatenates deprecation and vulnerability information cleanly
17+
var deprecationTitle = "";
18+
if (deprecation != null)
19+
{
20+
deprecationTitle = GetDeprecationTitle(version, deprecation.Status);
21+
}
22+
23+
if (maxVulnerabilitySeverity.HasValue)
24+
{
25+
var vulnerabilitiesTitle = GetVulnerabilityTitle(version, maxVulnerabilitySeverity.Value);
26+
return string.IsNullOrEmpty(deprecationTitle)
27+
? vulnerabilitiesTitle
28+
: $"{deprecationTitle.TrimEnd('.')}; {vulnerabilitiesTitle}";
29+
}
30+
31+
return string.IsNullOrEmpty(deprecationTitle) ? string.Empty : deprecationTitle;
32+
}
33+
34+
public static string GetVulnerabilityTitle(string version, PackageVulnerabilitySeverity maxVulnerabilitySeverity)
35+
{
36+
var severity = Enum.GetName(typeof(PackageVulnerabilitySeverity), maxVulnerabilitySeverity)?.ToLowerInvariant() ?? "unknown";
37+
return $"{version} has at least one vulnerability with {severity} severity.";
38+
}
39+
40+
public static string GetDeprecationTitle(string version, PackageDeprecationStatus status)
41+
{
42+
var deprecationTitle = version;
43+
var isLegacy = status.HasFlag(PackageDeprecationStatus.Legacy);
44+
var hasCriticalBugs = status.HasFlag(PackageDeprecationStatus.CriticalBugs);
45+
46+
if (hasCriticalBugs)
47+
{
48+
if (isLegacy)
49+
{
50+
deprecationTitle += " is deprecated because it is no longer maintained and has critical bugs";
51+
}
52+
else
53+
{
54+
deprecationTitle += " is deprecated because it has critical bugs";
55+
}
56+
}
57+
else if (isLegacy)
58+
{
59+
deprecationTitle += " is deprecated because it is no longer maintained";
60+
}
61+
else
62+
{
63+
deprecationTitle += " is deprecated";
64+
}
65+
66+
return $"{deprecationTitle}.";
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)