-
Notifications
You must be signed in to change notification settings - Fork 702
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 VulnerabilityInfo to NuGet.Protocol public API #5115
Conversation
Public API review suggestionsSince we use Roslyn's Public API Analyzers, we can see all changes to public APIs in In this PR, I added There are some new public APIs due to necessary NuGet.Protocol design, but the most important API in this PR is
|
I am curious to understand why not return |
May be the decision is already made, have we considered an option to download package vulnerabilities just like package versions by appending package name to the registration base URL for example https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/45bacae2-5efb-47c8-91e5-8ec20c22b4f8/nuget/v3/flat2/nuget.common/index.json. I don't have the performance metrics yet, but I think if the vulnerabilities database size increases in NuGet.org then performance may degrade. |
Is this design spec public? Would you mind sharing it? EDIT: Here it is: https://github.com/NuGet/Home/blob/72a2e173e1c7d82880f21b8574a81874eeb15ead/proposed/2022/vulnerabilities-in-restore.md |
This looks great! Thanks for the excellent write up to make this easy to review, it's very appreciated. Did you consider making
|
for (int i = 0; i < tasks.Length; i++) | ||
{ | ||
V3VulnerabilityIndexEntry indexEntry = indexEntries[i]; | ||
tasks[i] = GetVulnerabilityDataAsync(indexEntry, cacheContext, logger, cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would clamp this to an upper bound to avoid flooding the thread pool with tasks if nuget.org ever decides to have thousands of files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think any WhenAll
http communication should have an upper bound. This one is a sneaky/unobvious one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put in a basic limit of 16 for now. A better throttle so that the max limit isn't all done concurrently can be a perf optimization later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comment was about the parallelization degree instead of the total count of pages actually.
src/NuGet.Core/NuGet.Protocol/Resources/VulnerabilityInfoResourceV3.cs
Outdated
Show resolved
Hide resolved
I am not sure if this is possible because as per https://github.com/NuGet/Home/blob/dev/proposed/2022/vulnerabilities-in-restore.md#dedicated-vulnerability-information-resource, it is possible to update the base file also.
|
If performance is a concern here then have you considered other data structure types? Perhaps a |
In my opinion, the Trie data structure may not be appropriate for this scenario as our objective is not to match prefixes, as in the case of a package source mapping feature. |
/// <remarks>Vulnerability data from a package source typically is spread across multiple files. Therefore, it's | ||
/// possible for some data to be retrieved successfully, while other data failed. This type allows partial data | ||
/// to be returned along with error information.</remarks> | ||
public class GetVulnerabilityInfoResult |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From #5115 (comment), since GitHub mysteriously doesn't supported threaded/resolvable conversations unless it's linked to a specific line in a file
I am curious to understand why not return VulnerabilityInfoResult instead of GetVulnerabilityInfoResult
@kartheekp-ms my thought process was that the data type for the payload data (list of dictionary) is very specific to one API and might not be interesting to other APIs. So, rather than using an overly generic name for a specific data type, give a specific name. Although there's a good chance I was over-thinking it.
I also experimented with:
public class ApiResult<T>
{
public T? Result { get; }
public IReadOnlyList<Exception>? Exceptions { get; }
}
However, I had some problem trying to get it to work. I no longer remember exactly what problems, possibly something to do with Newtonsoft.Json deserialization.
src/NuGet.Core/NuGet.Protocol/Model/GetVulnerabilityInfoResult.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.Protocol/Resources/VulnerabilityInfoResourceV3.cs
Outdated
Show resolved
Hide resolved
76b833b
to
8fce802
Compare
src/NuGet.Core/NuGet.Protocol/Model/IgnoreCaseStringKeyDictionary.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.Protocol/Converters/IgnoreCaseStringKeyDictionaryConverter.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.Protocol/Converters/IgnoreCaseStringKeyDictionaryConverter.cs
Outdated
Show resolved
Hide resolved
src/NuGet.Core/NuGet.Protocol/Resources/VulnerabilityInfoResourceV3.cs
Outdated
Show resolved
Hide resolved
try to reduce chance that customers doing unexpected things causes problems that cause crashes
62c4aa7
to
6edca4d
Compare
continue; | ||
} | ||
|
||
bool hasOnlyValidChars = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this could be a local or static function to be a little cleaner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work!
src/NuGet.Core/NuGet.Protocol/Resources/VulnerabilityInfoResourceV3.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Some great tests.
I don't see any handling of individual file updates. Is that intentional?
for (int i = 0; i < tasks.Length; i++) | ||
{ | ||
V3VulnerabilityIndexEntry indexEntry = indexEntries[i]; | ||
tasks[i] = GetVulnerabilityDataAsync(indexEntry, cacheContext, logger, cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think any WhenAll
http communication should have an upper bound. This one is a sneaky/unobvious one.
src/NuGet.Core/NuGet.Protocol/Resources/VulnerabilityInfoResourceV3.cs
Outdated
Show resolved
Hide resolved
|
||
namespace NuGet.Protocol.Tests.Resources | ||
{ | ||
public class VulnerabilityInfoResourceV3Tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could use a few more tests (can be in a future PR).
- GetVulnerabilityDataAsync
- Fetches data from all index entries (testing more than 1).
- Multiple calls use http cache.
- Multiple calls when 1 file gets updated only fetches the updated file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approving with suggestions! 👍
test/NuGet.Core.Tests/NuGet.Protocol.Tests/Converters/VulnerabilityFileDataConverterTests.cs
Show resolved
Hide resolved
src/NuGet.Core/NuGet.Protocol/Resources/VulnerabilityInfoResourceV3.cs
Outdated
Show resolved
Hide resolved
string name = entry.Name; | ||
if (string.IsNullOrWhiteSpace(name)) | ||
{ | ||
string message = string.Format("Vulnerability page index {0} does not contain a name (Source: '{1}')", | ||
i, _sourceRepository.PackageSource.Name); | ||
AddException(new FatalProtocolException(message), ref exceptions); | ||
continue; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method has a series of validations that follow the same pattern:
Test a predicate. If true, build a message, throw an exception, and continue.
We can reduce code duplication and make it easier to read by making a method or object for the repeated validation pattern.
src/NuGet.Core/NuGet.Protocol/Resources/VulnerabilityInfoResourceV3.cs
Outdated
Show resolved
Hide resolved
{ | ||
/// <summary>Represents one page of vulnerability data.</summary> | ||
/// <remarks>More details at <a href="https://learn.microsoft.com/nuget/api/vulnerability-info-resource">https://learn.microsoft.com/nuget/api/vulnerability-info-resource</a></remarks> | ||
public sealed class V3VulnerabilityIndexEntry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: V3 in the name is probably unnecessary.
Or if it is, I think it should be at the end instead of the beginning.
for (int i = 0; i < tasks.Length; i++) | ||
{ | ||
V3VulnerabilityIndexEntry indexEntry = indexEntries[i]; | ||
tasks[i] = GetVulnerabilityDataAsync(indexEntry, cacheContext, logger, cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comment was about the parallelization degree instead of the total count of pages actually.
Bug
Fixes: NuGet/Home#12518
Regression? Last working version:
Description
Implements VulnerabilityInfo resource as per the vulnerabilities in restore spec.
IReadOnlyDictionary
, only to have aJsonConverter
that allows us to create an instance ofDictionary
withStringComparer.InvariantIgnoreCase
.PR Checklist
PR has a meaningful title
PR has a linked issue.
Described changes
Tests
Documentation