Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions pkg/nuget/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package nuget

import (
"encoding/json"
"fmt"
"github.com/aquasecurity/go-dep-parser/pkg/types"
"io"
)

// The lockfile that nuget uses (packages.lock.json) works basically like this:
// Each 'build type' (for example .NETCoreApp,Version=v3.1) have a set of dependencies.
// Those dependencies can be 'Direct', 'Transitive' and 'Project'.
// The dependency consists of a string value key (package name) and an object,
// from which we need to fetch a few different values.
// The following values should be parsed right away: resolved (resolved version),
// type (this information might be worth having) and finally, it's dependencies.
// The dependencies in this stage of the file are only a string map where the key is package name
// and value is package version.

type LockFile struct {
Version int
Dependencies map[string]map[string]Dependency
}

Comment thread
Johannestegner marked this conversation as resolved.
type Dependency struct {
Type string
Resolved string
Dependencies map[string]string
ContentHash string
}

func Parse(r io.Reader) ([]types.Library, error) {
var lockFile LockFile
decoder := json.NewDecoder(r)
err := decoder.Decode(&lockFile)
if err != nil {
return nil, err
Comment thread
Johannestegner marked this conversation as resolved.
Outdated
}
Comment thread
Johannestegner marked this conversation as resolved.
Outdated

var libraries []types.Library
unique := map[string]struct{}{}

for _, targetContent := range lockFile.Dependencies {
for topPkgName, topPkgContent := range targetContent {
for pkgName, version := range topPkgContent.Dependencies {
symbol := fmt.Sprintf("%s@%s", pkgName, version)
if _, ok := unique[symbol]; ok {
continue
}
Comment thread
Johannestegner marked this conversation as resolved.
Outdated

libraries = append(libraries, types.Library{
Name: pkgName,
Version: version,
})
unique[symbol] = struct{}{}
}

if topPkgContent.Type == "Project" {
continue
}

symbol := fmt.Sprintf("%s@%s", topPkgName, topPkgContent)
if _, ok := unique[symbol]; ok {
continue
}

libraries = append(libraries, types.Library{
Name: topPkgName,
Version: topPkgContent.Resolved,
})
Comment thread
Johannestegner marked this conversation as resolved.
Outdated
}
}

return libraries, nil
}
79 changes: 79 additions & 0 deletions pkg/nuget/parse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package nuget

import (
"os"
"path"
"sort"
"strings"
"testing"

"github.com/aquasecurity/go-dep-parser/pkg/types"
"github.com/kylelemons/godebug/pretty"
)

func TestParse(t *testing.T) {
vectors := []struct {
file string // Test input file
libraries []types.Library
}{
{
file: "testdata/packages_lock_normal.json",
libraries: NuGetNormal,
},
{
file: "testdata/packages_lock_dup.json",
libraries: NuGetDuplicated,
},
{
file: "testdata/packages_lock_with_trans.json",
libraries: NuGetWithTransitive,
},
{
file: "testdata/packages_lock_many.json",
libraries: NuGetMany,
},
}

for _, v := range vectors {
t.Run(path.Base(v.file), func(t *testing.T) {
f, err := os.Open(v.file)
if err != nil {
t.Fatalf("Open() error: %v", err)
}
libList, err := Parse(f)
if err != nil {
t.Fatalf("Parse() error: %v", err)
}

sort.Slice(libList, func(i, j int) bool {
ret := strings.Compare(libList[i].Name, libList[j].Name)
if ret == 0 {
return libList[i].Version < libList[j].Version
}
return ret < 0
})

sort.Slice(v.libraries, func(i, j int) bool {
ret := strings.Compare(v.libraries[i].Name, v.libraries[j].Name)
if ret == 0 {
return v.libraries[i].Version < v.libraries[j].Version
}
return ret < 0
})

if len(libList) != len(v.libraries) {
t.Fatalf("lib length: %s", pretty.Compare(libList, v.libraries))
}

for i, got := range libList {
want := v.libraries[i]
if want.Name != got.Name {
t.Errorf("%d: Name: got %s, want %s", i, got.Name, want.Name)
}
if want.Version != got.Version {
t.Errorf("%d: Version: got %s, want %s", i, got.Version, want.Version)
}
}
})
}
}
68 changes: 68 additions & 0 deletions pkg/nuget/parse_testcase.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package nuget
Comment thread
Johannestegner marked this conversation as resolved.

import "github.com/aquasecurity/go-dep-parser/pkg/types"

var (
NuGetNormal = []types.Library{
{"Microsoft.NET.Test.Sdk", "16.6.1"},
{"Microsoft.CodeCoverage", "16.6.1"},
{"Microsoft.TestPlatform.TestHost", "16.6.1"},
{"Newtonsoft.Json", "12.0.3"},
{"System.Runtime", "4.3.1"},
}

NuGetDuplicated = []types.Library{
{"Microsoft.NET.Test.Sdk", "16.6.1"},
{"Microsoft.CodeCoverage", "16.6.1"},
{"Microsoft.TestPlatform.TestHost", "16.6.1"},
{"Newtonsoft.Json", "12.0.3"},
{"System.Runtime", "4.3.2"},
{"System.Runtime", "4.3.1"},
}

NuGetWithTransitive = []types.Library{
{"Microsoft.NET.Test.Sdk", "16.6.1"},
{"Microsoft.CodeCoverage", "16.6.1"},
{"Microsoft.TestPlatform.TestHost", "16.6.1"},
{"Newtonsoft.Json", "12.0.3"},
{"System.Runtime", "4.3.1"},
{"NETStandard.Library", "1.6.1"},
{"Microsoft.NETCore.Platforms", "1.1.0"},
{"Microsoft.Win32.Primitives", "4.3.0"},
{"System.AppContext", "4.3.0"},
{"System.Collections", "4.3.0"},
{"System.Collections.Concurrent", "4.3.0"},
{"System.Console", "4.3.0"},
{"System.Diagnostics.Debug", "4.3.0"},
{"System.Diagnostics.Tools", "4.3.0"},
{"NuGet.Frameworks", "5.0.0"},
}

NuGetMany = []types.Library{
{"Microsoft.NET.Test.Sdk", "16.6.1"},
{"Microsoft.CodeCoverage", "16.6.1"},
{"Microsoft.TestPlatform.TestHost", "16.6.1"},
{"Newtonsoft.Json", "12.0.3"},
{"xunit.runner.utility", "2.4.1"},
{"NETStandard.Library", "1.6.0"},
{"System.Runtime.Loader", "4.0.0"},
{"xunit.abstractions", "2.0.3"},
{"System.Runtime", "4.3.1"},
{"NETStandard.Library", "1.6.1"},
{"xunit.runner.visualstudio", "2.4.2"},
{"Microsoft.NETCore.Platforms", "1.1.0"},
{"Microsoft.Win32.Primitives", "4.3.0"},
{"System.AppContext", "4.3.0"},
{"System.Collections", "4.3.0"},
{"System.Collections.Concurrent", "4.3.0"},
{"System.Console", "4.3.0"},
{"System.Diagnostics.Debug", "4.3.0"},
{"System.Diagnostics.Tools", "4.3.0"},
{"NuGet.Frameworks", "5.0.0"},
{"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl", "4.3.0"},
{"System.Linq", "4.3.0"},
{"System.Resources.ResourceManager", "4.3.0"},
{"System.Runtime", "4.3.0"},
{"System.Runtime.Extensions", "4.3.0"},
}
)
30 changes: 30 additions & 0 deletions pkg/nuget/testdata/packages_lock_dup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"version": 1,
"dependencies": {
".NETCoreApp,Version=v3.1": {
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
"requested": "[16.6.1, )",
"resolved": "16.6.1",
"contentHash": "zYAjfWzpxKb64P9ntReT1Xr8HdONZnpLVs12HIjXWo+UOCDpevP1UWRoaAgNysaD1/l3teBKvgbSeG9bRssfOQ==",
"dependencies": {
"Microsoft.CodeCoverage": "16.6.1",
"Microsoft.TestPlatform.TestHost": "16.6.1",
"System.Runtime": "4.3.2"
}
},
"Newtonsoft.Json": {
"type": "Direct",
"requested": "[12.0.3, )",
"resolved": "12.0.3",
"contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg=="
},
"my.project": {
"type": "Project",
"dependencies": {
"System.Runtime": "4.3.1"
}
}
}
}
}
83 changes: 83 additions & 0 deletions pkg/nuget/testdata/packages_lock_many.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"version": 1,
"dependencies": {
".NETCoreApp,Version=v3.1": {
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
"requested": "[16.6.1, )",
"resolved": "16.6.1",
"contentHash": "zYAjfWzpxKb64P9ntReT1Xr8HdONZnpLVs12HIjXWo+UOCDpevP1UWRoaAgNysaD1/l3teBKvgbSeG9bRssfOQ==",
"dependencies": {
"Microsoft.CodeCoverage": "16.6.1",
"Microsoft.TestPlatform.TestHost": "16.6.1"
}
},
"Newtonsoft.Json": {
"type": "Direct",
"requested": "[12.0.3, )",
"resolved": "12.0.3",
"contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg=="
},
"xunit.runner.utility": {
"type": "Direct",
"requested": "[2.4.1, )",
"resolved": "2.4.1",
"contentHash": "OR1KQpDegHK9mxARihYEWSiG82ce/WbWvv7/unSyAuEsGVPpLCzYt1ExsyUE136i28qSqPmoS1Fh1hs9NmKCTQ==",
"dependencies": {
"NETStandard.Library": "1.6.0",
"System.Runtime.Loader": "4.0.0",
"xunit.abstractions": "2.0.3"
}
},
"xunit.runner.visualstudio": {
"type": "Direct",
"requested": "[2.4.2, )",
"resolved": "2.4.2",
"contentHash": "Trt9multph2KE3U0p9oBt0k4Fq6lUv4btUcONaQEeuFnMCak2k/b7PAArbLtMFW7HO1jxlBHUgIPKEqci3Y1dg=="
},
"NETStandard.Library": {
"type": "Transitive",
"resolved": "1.6.1",
"contentHash": "WcSp3+vP+yHNgS8EV5J7pZ9IRpeDuARBPN28by8zqff1wJQXm26PVU8L3/fYLBJVU7BtDyqNVWq2KlCVvSSR4A==",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.Win32.Primitives": "4.3.0",
"System.AppContext": "4.3.0",
"System.Collections": "4.3.0",
"System.Collections.Concurrent": "4.3.0",
"System.Console": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Diagnostics.Tools": "4.3.0"
}
},
"NuGet.Frameworks": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA=="
},
"runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
"type": "Transitive",
"resolved": "4.3.0",
"contentHash": "VB5cn/7OzUfzdnC8tqAIMQciVLiq2epm2NrAm1E9OjNRyG4lVhfR61SMcLizejzQP8R8Uf/0l5qOIbUEi+RdEg=="
},
"System.Linq": {
"type": "Transitive",
"resolved": "4.3.0",
"contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==",
"dependencies": {
"System.Collections": "4.3.0",
"System.Diagnostics.Debug": "4.3.0",
"System.Resources.ResourceManager": "4.3.0",
"System.Runtime": "4.3.0",
"System.Runtime.Extensions": "4.3.0"
}
},
"my.project": {
"type": "Project",
"dependencies": {
"System.Runtime": "4.3.1"
}
}
}
}
}
29 changes: 29 additions & 0 deletions pkg/nuget/testdata/packages_lock_normal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"version": 1,
"dependencies": {
".NETCoreApp,Version=v3.1": {
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
"requested": "[16.6.1, )",
"resolved": "16.6.1",
"contentHash": "zYAjfWzpxKb64P9ntReT1Xr8HdONZnpLVs12HIjXWo+UOCDpevP1UWRoaAgNysaD1/l3teBKvgbSeG9bRssfOQ==",
"dependencies": {
"Microsoft.CodeCoverage": "16.6.1",
"Microsoft.TestPlatform.TestHost": "16.6.1"
}
},
"Newtonsoft.Json": {
"type": "Direct",
"requested": "[12.0.3, )",
"resolved": "12.0.3",
"contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg=="
},
"my.project": {
"type": "Project",
"dependencies": {
"System.Runtime": "4.3.1"
}
}
}
}
}
Loading