Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PackageDownload vulnerability telemetry #6180

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from

Conversation

Nigusu-Allehu
Copy link
Contributor

@Nigusu-Allehu Nigusu-Allehu commented Dec 4, 2024

Bug

Fixes: https://github.com/NuGet/Client.Engineering/issues/3112

Description

Telemetry design https://github.com/NuGet/Client.Engineering/blob/main/designs/telemetry/telemetry-design-PackageDownload-vulnerabilities.md
This PR introduces telemetry collection for vulnerabilities in <PackageDownload> packages:

Summary of Changes

  • Collects the list of vulnerable package IDs at the end of the restore operation.

Goals

This telemetry will enable us to:

  • Determine how many restore operations generate warnings due to vulnerable <PackageDownload> packages.
  • Use package names to estimate the proportion of warnings attributable to SDK-managed packages.

PR Checklist

  • Meaningful title, helpful description and a linked NuGet/Home issue
  • Added tests
  • Link to an issue or pull request to update docs if this PR changes settings, environment variables, new feature, etc.

@Nigusu-Allehu Nigusu-Allehu self-assigned this Dec 4, 2024
@Nigusu-Allehu Nigusu-Allehu marked this pull request as ready for review December 6, 2024 00:00
@Nigusu-Allehu Nigusu-Allehu requested a review from a team as a code owner December 6, 2024 00:00
@@ -179,6 +179,9 @@ public async Task Check_ProjectReferencingPackageWithVulnerability_WarningLogged

context.PackagesDependencyProvider.Package("pkga", "1.0.0").DependsOn("pkgb", "1.0.0");
context.PackagesDependencyProvider.Package("pkgb", "1.0.0");
context.PackageDownloadPackages.Add(new DownloadDependency("pkgDownload", new VersionRange(new NuGetVersion("1.0.0"), maxVersion: new NuGetVersion("1.0.0"))));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more of a nitpick: these package download package lines look a lot less nice than adding the package reference packages on the two lines above, since they're using a builder pattern, but this package download is not.

I wonder if it's worthwhile creating a DownloadDependencyProvider so tests that use it are easier to read.

Having said that, half the line length could be reduced if the VersionRange was changed to VersionRange.Parse("[1.0.0]). I wouldn't be surprised if I did the new VersionRange thing in the past, since I know it will execute faster than Parse. I keep changing my mind between "OMG, NuGet's tests are so slow, we need to make them faster, if only by a little bit" and also "these tests need to be easier to read" 🤣

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. Personally, I am indifferent on this. But VersionRange.Parse() looks cleaner to me

Copy link
Member

@nkolev92 nkolev92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a telemetry template issue: https://github.com/NuGet/Client.Engineering/issues/new?assignees=&labels=Type%3AEngineering%2CPriority%3A2&projects=&template=telemetry.md.

I think we've forgotten to use it reliable (includes all of us :) )

@jeffkl jeffkl self-requested a review December 10, 2024 23:09
@Nigusu-Allehu Nigusu-Allehu marked this pull request as draft December 17, 2024 22:15
@Nigusu-Allehu Nigusu-Allehu marked this pull request as ready for review December 19, 2024 18:15
@@ -115,6 +115,7 @@ private readonly Dictionary<RestoreTargetGraph, Dictionary<string, LibraryInclud
private const string AuditTransitiveVulnerabilitySev2 = "Audit.Vulnerability.Transitive.Severity2";
private const string AuditTransitiveVulnerabilitySev3 = "Audit.Vulnerability.Transitive.Severity3";
private const string AuditTransitiveVulnerabilitySevInvalid = "Audit.Vulnerability.Transitive.SeverityInvalid";
private const string AuditPackageDownloadVulnerabilitiesPackages = "Audit.Vulnerability.PackageDownload.Packages";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you and @zivkan have an extra conversation that wasn't included here?

Curious why we're not adding the counts for package downloads with vulnerabilities?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I can remember 🤣

I think Audit.Vulnerability.PackageDownload.* properties make sense and will make it easier for us to tell the difference between older versions of NuGet/VS that don't support this telemetry, and restores that have zero PackageDownloads with known vulnerabilities. We could do it by devenv ExeVersion, but I prefer to filter out null values.

public async Task<bool> CheckPackageVulnerabilitiesAsync(CancellationToken cancellationToken)
{
// Performance: Early exit if restore graph does not contain any packages.
if (!HasPackages())
if (!HasPackages() && (_targetFrameworks.Count() == 0))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never use use Linq's .Count() when the type has a .Length or .Count property.

@@ -78,10 +82,27 @@ public AuditUtility(
}
}

private void CheckPackageDownloadVulnerabilities(IReadOnlyList<IReadOnlyDictionary<string, IReadOnlyList<PackageVulnerabilityInfo>>> knownVulnerabilities)
{
foreach (var targetFramework in _targetFrameworks)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since _targetFrameworks is IList, this foreach loop will cause an allocation. And since audit runs in restore, which is our most perf-critical path, we need to do everything we can to minimize perf impacts. So, either change this to a for loop and use the indexer to get the value from the list, or use NoAllocEnumerate (or whatever that extension method/class is called).

@@ -115,6 +115,7 @@ private readonly Dictionary<RestoreTargetGraph, Dictionary<string, LibraryInclud
private const string AuditTransitiveVulnerabilitySev2 = "Audit.Vulnerability.Transitive.Severity2";
private const string AuditTransitiveVulnerabilitySev3 = "Audit.Vulnerability.Transitive.Severity3";
private const string AuditTransitiveVulnerabilitySevInvalid = "Audit.Vulnerability.Transitive.SeverityInvalid";
private const string AuditPackageDownloadVulnerabilitiesPackages = "Audit.Vulnerability.PackageDownload.Packages";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that I can remember 🤣

I think Audit.Vulnerability.PackageDownload.* properties make sense and will make it easier for us to tell the difference between older versions of NuGet/VS that don't support this telemetry, and restores that have zero PackageDownloads with known vulnerabilities. We could do it by devenv ExeVersion, but I prefer to filter out null values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants