Add support for Version 2 of Nuget's packages.lock.json in SCA
Summary
When using the Gemnasium dependency scanner with a NuGet packages.lock.json
in Version 2, the scanner fails with the error
[FATA] [Gemnasium] [2023-03-22T03:06:13Z] ▶ scanning file /builds/.../packages.lock.json: parsing file /builds/.../packages.lock.json: wrong file format version
Currently only packages.lock.json files in Version 1 are supported (see documentation). However, NuGet generates version 2 files if the new central package management is enabled. (NuGet source for reference)
Steps to reproduce
- Have the the .NET7 SDK installed
- In an empty directory, run
dotnet new console -f net7.0
- Create the file
Directory.Packages.props
with the following contents:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<EnablePackageVersionOverride>false</EnablePackageVersionOverride>
</PropertyGroup>
</Project>
- Add any NuGet to the project, eg. EF Core via
dotnet add package Microsoft.EntityFrameworkCore
- Create a
packages.lock.json
viadotnet restore --use-lock-file
The generated packages.lock.json is in version 2 (as seen at the very top in the json) and thus can't be used with the gemnasium dependency scanner, currently.
What is the current bug behavior?
Gemnasium dependency scanner is not able to use the packages.lock.json file in version 2, even though v2 is backwards compatible to v1.
What is the expected correct behavior?
Gemnasium dependency scanner should be able to use the packages.lock.json in the versions 1 and 2.
Workaround
Replace the version 2 with 1 in the packages.lock.json
find . -maxdepth 2 -type f -name packages.lock.json -print0 | xargs -0 sed -i 's/"version": 2,/"version": 1,/'
Output of checks
This bug happens on GitLab.com
Proposal
Make the existing nuget parser capable of parsing nuget v2
lock files. Lock files in v2
are backwards compatible with v1
.
Implementation Plan
Since there is a backwards compatibility the solution is straight forward:
-
Update the nuget parser version check so that it allows v2
patch
diff --git a/scanner/parser/nuget/nuget.go b/scanner/parser/nuget/nuget.go
index 10e5754..7a46e20 100644
--- a/scanner/parser/nuget/nuget.go
+++ b/scanner/parser/nuget/nuget.go
@@ -43,7 +43,17 @@ type DependencyInfo struct {
// ContentHash string `json:"contentHash"`
}
-const supportedFileFormatVersion = 1
+// Returns whether the given lockfiel version can be parsed
+func isSupportedVersion(version int) error {
+ supportedFileFormatVersion := []int{1, 2}
+ for _, supportedVersion := range supportedFileFormatVersion {
+ if version == supportedVersion {
+ return nil
+ }
+ }
+
+ return parser.ErrWrongFileFormatVersion
+}
// Parse scans a NuGet lock file and returns a list of packages
func Parse(r io.Reader, opts parser.Options) ([]parser.Package, []parser.Dependency, error) {
@@ -55,8 +65,8 @@ func Parse(r io.Reader, opts parser.Options) ([]parser.Package, []parser.Depende
}
// check format version
- if document.Version != supportedFileFormatVersion {
- return nil, nil, parser.ErrWrongFileFormatVersion
+ if err := isSupportedVersion(document.Version); err != nil {
+ return nil, nil, err
}
// collect targets like ".NETCoreApp,Version=v5.0"
-
Update the nuget parser unit tests with another case for v2. -
Update the dependency scanning documentation to indicate that nuget v2 lock files are supported.
Documentation
As stated in the implementation plan we need to update the dependency scanning documentation
Availability & Testing
Our plan is to extend the unit tests to test against a v2 nuget lock file. Since the v2 file is exactly the same as the v1 except the version number, is not worth adding a separate rspec test.