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

Enable vulnerability checking for packages.config projects during commandline restore #5639

Merged
merged 22 commits into from
Feb 26, 2024

Conversation

nkolev92
Copy link
Member

@nkolev92 nkolev92 commented Feb 21, 2024

Bug

Fixes: NuGet/Home#13253
Fixes: https://github.com/NuGet/Client.Engineering/issues/2698

Regression? Last working version:

Description

See NuGet/Home#13154 for the main design.

  • The Visual Studio side requires a lot of changes, and as such to make the review easier, I've split up the enablement of audit checking for VS scenarios. Despite that, there are changes/ideas here that are driven by that. Note that even the public APIs here aren't fully committed, but simply a good enough version as of right now.
  • PackageRestoreManager is where the main work for packages.config restore happens.
  • It's a short lived service based on https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Core/NuGet.PackageManagement/IDE/IPackageRestoreManager.cs.
    Counterintuitively the service part is used more frequently in non-VS scenarios, which is why I have this length explanation.
  • There are 4 methods in this class, 2 for solution based, 2 for package driven restoring, I have deprecated the 2 unused methods as they just add complexity to adding any changes like vulnerability checking, since I now need to check many inputs.
  • Given that in the design we decided to use properties to enable/disable audit, I have reused the RestoreAuditProperties class.
  • Extract 2 methods for parsing the restore audit properties, in particular the 2 that we need for packages.config restore.
  • Create a public API for vulnerability running.
  • The check returns a type that can be "stored" and used for no-op in Visual Studio scenarios. In particular, in a future version, if the restore in VS has no-op, we'll just "replay" the warnings raised by the previous restore if any.
  • The type knows how to make additions to a telemetry event. Note that this isn't final, as I don't have the complete Visual Studio implementation yet.
  • CLI scenarios, such as restore, install from nuget.exe and msbuild /t:restore will run audit by default, even if packages are downloaded.

PR Checklist

@nkolev92 nkolev92 force-pushed the dev-nkolev92-PCVulnerabilityInRestore branch from 7dba399 to 35a7083 Compare February 22, 2024 00:21
@nkolev92 nkolev92 marked this pull request as ready for review February 22, 2024 21:24
@nkolev92 nkolev92 requested a review from a team as a code owner February 22, 2024 21:24
Copy link
Member

@zivkan zivkan left a comment

Choose a reason for hiding this comment

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

I only looked at the product code so far, not tests, but generally looks good. I have a meeting now, so don't have time to finish reviewing today.

Comment on lines +16 to +26
internal bool IsAuditEnabled { get; set; } = true;

internal int Severity0VulnerabilitiesFound { get; set; }
internal int Severity1VulnerabilitiesFound { get; set; }
internal int Severity2VulnerabilitiesFound { get; set; }
internal int Severity3VulnerabilitiesFound { get; set; }
internal int InvalidSeverityVulnerabilitiesFound { get; set; }
internal List<PackageIdentity>? Packages { get; set; }
internal double? DownloadDurationInSeconds { get; set; }
internal double? CheckPackagesDurationInSeconds { get; set; }
internal int? SourcesWithVulnerabilities { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

Considering this type is a record, and therefore a struct, I think it's important to make all these properties get; init;, rather than get; set;.

The problem with get; set; in a struct, is if one is passed in as a method parameter (but not as a ref, changing the value of properties will cause the values to be lost when the method returns. So, it's significant risk of bugs if people use it wrong.

Making it only possible to set at initialization time reduces the risk that it gets set wrong.

Copy link
Member Author

Choose a reason for hiding this comment

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

These are not always known/available in every audit situation.

I have tests ensuring things get set in the expected scenarios. Obviously that doesn't guard against future additions.

I can have a bunch of internal constructors I guess if you'd prefer that.

Copy link
Member

@zivkan zivkan Feb 26, 2024

Choose a reason for hiding this comment

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

init does not mean required, it just means that the type is read only, and needs to have a new "instance" created to change a value. Using the with expression makes this very easy. Therefore multiple constructors are not needed, unless you want to validate that when "property 1" is set "property 2" must be as well.

And when I reviewed this PR last week, I didn't see any examples of the type having any values changed after initialization. At least in the product code, I only saw properties being set on init.

Obviously that doesn't guard against future additions.

This is the point of my suggestion. It does prevent future incorrect usage that might otherwise go unnoticed.

@nkolev92 nkolev92 requested a review from zivkan February 23, 2024 18:12
@nkolev92
Copy link
Member Author

@zivkan Thanks for taking a look!
I've addressed or responded too all of your feedback and it's ready for another look.

@nkolev92 nkolev92 requested a review from jeffkl February 23, 2024 19:03
jeffkl
jeffkl previously approved these changes Feb 23, 2024
Copy link
Member

@zivkan zivkan left a comment

Choose a reason for hiding this comment

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

Two opportunities to follow best perf practises, but otherwise LGTM.

CreateWarnings(packagesWithKnownVulnerabilities, auditSettings, ref Sev0Matches, ref Sev1Matches, ref Sev2Matches, ref Sev3Matches, ref InvalidSevMatches, ref packagesWithReportedAdvisories) :
Array.Empty<ILogMessage>();

foreach (var warning in warnings)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
foreach (var warning in warnings)
foreach (var warning in warnings.NoAllocEnumerate())

warnings is IReadOnlyList<T>, hence foreach will do a heap alloc by default.

@nkolev92
Copy link
Member Author

thanks @zivkan

I'll address these in the next PR. Merging the PR allows me to unblock my VS work.

@nkolev92 nkolev92 merged commit 5ecd0be into dev Feb 26, 2024
16 checks passed
@nkolev92 nkolev92 deleted the dev-nkolev92-PCVulnerabilityInRestore branch February 26, 2024 17:49
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.

Warn when vulnerabilities are detected during packages.config restore in CLI scenarios.
3 participants