From 298f192091ed082cd432a99651eb7c8b4a310402 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 27 Jun 2024 17:24:33 +0600 Subject: [PATCH 01/10] feat(parser): check `Targets` to mark libs as dev --- pkg/dependency/id.go | 3 +- .../parser/dotnet/core_deps/parse.go | 68 ++++++++++++++++--- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/pkg/dependency/id.go b/pkg/dependency/id.go index 8f01bf23123a..4bb97bd644b2 100644 --- a/pkg/dependency/id.go +++ b/pkg/dependency/id.go @@ -16,7 +16,8 @@ func ID(ltype types.LangType, name, version string) string { sep := "@" switch ltype { - case types.Conan: + // cf. https://github.com/dotnet/sdk/blob/529132850841a6bcfce96799262ce688e3851875/documentation/specs/runtime-configuration-file.md#targets-section-depsjson + case types.Conan, types.DotNetCore: sep = "/" case types.GoModule, types.GoBinary: // Return a module ID according the Go way. diff --git a/pkg/dependency/parser/dotnet/core_deps/parse.go b/pkg/dependency/parser/dotnet/core_deps/parse.go index 4314e9af9b3d..052cdd69d785 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse.go @@ -2,23 +2,51 @@ package core_deps import ( "io" + "sort" "strings" + "sync" "github.com/liamg/jfather" + "github.com/samber/lo" "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/dependency" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) +type dotNetDependencies struct { + Libraries map[string]dotNetLibrary `json:"libraries"` + RuntimeTarget RuntimeTarget `json:"runtimeTarget"` + Targets map[string]map[string]Target `json:"targets"` +} + +type dotNetLibrary struct { + Type string `json:"type"` + StartLine int + EndLine int +} + +type RuntimeTarget struct { + Name string `json:"name"` +} + +type Target struct { + Runtime any `json:"runtime"` + RuntimeTargets any `json:"runtimeTargets"` + Native any `json:"native"` +} + type Parser struct { logger *log.Logger + once sync.Once } func NewParser() *Parser { return &Parser{ logger: log.WithPrefix("dotnet"), + once: sync.Once{}, } } @@ -29,11 +57,14 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc if err != nil { return nil, nil, xerrors.Errorf("read error: %w", err) } - if err := jfather.Unmarshal(input, &depsFile); err != nil { + if err = jfather.Unmarshal(input, &depsFile); err != nil { return nil, nil, xerrors.Errorf("failed to decode .deps.json file: %w", err) } - var pkgs []ftypes.Package + // Select target for RuntimeTarget + target := depsFile.Targets[depsFile.RuntimeTarget.Name] + + var pkgs ftypes.Packages for nameVer, lib := range depsFile.Libraries { if !strings.EqualFold(lib.Type, "package") { continue @@ -47,6 +78,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc } pkgs = append(pkgs, ftypes.Package{ + ID: dependency.ID(ftypes.DotNetCore, split[0], split[1]), Name: split[0], Version: split[1], Locations: []ftypes.Location{ @@ -55,20 +87,36 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc EndLine: lib.EndLine, }, }, + // We're still not sure that we need to skip libraries built into .NETCore (or that we detect them correctly). + // So we mark these libraries as Dev to skip the scan by default, but keep the options for displaying these libraries. + Dev: p.isLibraryBuiltIntoNetCore(target, depsFile.RuntimeTarget.Name, nameVer), }) } + sort.Sort(pkgs) return pkgs, nil, nil } -type dotNetDependencies struct { - Libraries map[string]dotNetLibrary `json:"libraries"` -} - -type dotNetLibrary struct { - Type string `json:"type"` - StartLine int - EndLine int +// isLibraryBuiltIntoNetCore returns true if library doesn't contain `runtime`, `runtimeTarget` and `native` sections. +// See https://github.com/aquasecurity/trivy/discussions/4282#discussioncomment-8830365 for more details. +func (p *Parser) isLibraryBuiltIntoNetCore(target map[string]Target, runtimeTargetName, library string) bool { + // `Target` for `RuntimeTarget.Name` not found + if target == nil { + p.once.Do(func() { + p.logger.Debug("Unable to find `Target` for Runtime Target Name. All dependencies from `libraries` section will be included in the report", log.String("RuntimeTarget", runtimeTargetName)) + }) + return false + } + lib, ok := target[library] + // Selected target doesn't contain library + if !ok { + p.once.Do(func() { + p.logger.Debug("Unable to determine that the library is built into .NET Core. Library not found in `Target` section.", log.String("RuntimeTarget", runtimeTargetName), log.String("Library", library)) + }) + return false + } + // Check that `runtime`, `runtimeTarget` and `native` sections are empty + return lo.IsEmpty(lib) } // UnmarshalJSONWithMetadata needed to detect start and end lines of deps From c8df60ad77bbae161b22ef589e076f74ae3d0fb8 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 27 Jun 2024 17:25:38 +0600 Subject: [PATCH 02/10] test(parser): add testcase with `dev` field --- .../parser/dotnet/core_deps/parse_test.go | 88 +++++++++++++++-- ...{ExampleApp1.deps.json => happy.deps.json} | 0 ...nvalidJson.deps.json => invalid.deps.json} | 0 ...aries.deps.json => no-libraries.deps.json} | 0 .../testdata/without-runtime.deps.json | 96 +++++++++++++++++++ 5 files changed, 176 insertions(+), 8 deletions(-) rename pkg/dependency/parser/dotnet/core_deps/testdata/{ExampleApp1.deps.json => happy.deps.json} (100%) rename pkg/dependency/parser/dotnet/core_deps/testdata/{InvalidJson.deps.json => invalid.deps.json} (100%) rename pkg/dependency/parser/dotnet/core_deps/testdata/{NoLibraries.deps.json => no-libraries.deps.json} (100%) create mode 100644 pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json diff --git a/pkg/dependency/parser/dotnet/core_deps/parse_test.go b/pkg/dependency/parser/dotnet/core_deps/parse_test.go index a495fe0d61fe..6673dbd69d3d 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse_test.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse_test.go @@ -2,7 +2,6 @@ package core_deps import ( "os" - "path" "sort" "testing" @@ -13,29 +12,102 @@ import ( ) func TestParse(t *testing.T) { - vectors := []struct { + tests := []struct { + name string file string // Test input file want []ftypes.Package wantErr string }{ { - file: "testdata/ExampleApp1.deps.json", + name: "happy path", + file: "testdata/happy.deps.json", want: []ftypes.Package{ - {Name: "Newtonsoft.Json", Version: "13.0.1", Locations: []ftypes.Location{{StartLine: 33, EndLine: 39}}}, + { + ID: "Newtonsoft.Json/13.0.1", + Name: "Newtonsoft.Json", + Version: "13.0.1", + Locations: []ftypes.Location{ + { + StartLine: 33, EndLine: 39, + }, + }, + }, }, }, { - file: "testdata/NoLibraries.deps.json", + name: "happy path with skipped libs", + file: "testdata/without-runtime.deps.json", + want: []ftypes.Package{ + { + ID: "JsonDiffPatch/2.0.61", + Name: "JsonDiffPatch", + Version: "2.0.61", + Locations: []ftypes.Location{ + { + StartLine: 60, EndLine: 66, + }, + }, + }, + { + ID: "Libuv/1.9.1", + Name: "Libuv", + Version: "1.9.1", + Locations: []ftypes.Location{ + { + StartLine: 67, EndLine: 73, + }, + }, + }, + { + ID: "Microsoft.NETCore.App/1.1.2", + Name: "Microsoft.NETCore.App", + Version: "1.1.2", + Locations: []ftypes.Location{ + { + StartLine: 74, EndLine: 80, + }, + }, + Dev: true, + }, + { + ID: "Microsoft.NETCore.Platforms/1.1.0", + Name: "Microsoft.NETCore.Platforms", + Version: "1.1.0", + Locations: []ftypes.Location{ + { + StartLine: 81, EndLine: 87, + }, + }, + Dev: true, + }, + { + ID: "System.Collections.Immutable/1.3.0", + Name: "System.Collections.Immutable", + Version: "1.3.0", + Locations: []ftypes.Location{ + { + StartLine: 88, EndLine: 94, + }, + }, + // Is false because `targets[.NETCoreApp,Version=v6.0]` doesn't contain this library + Dev: false, + }, + }, + }, + { + name: "happy path without libs", + file: "testdata/no-libraries.deps.json", want: nil, }, { - file: "testdata/InvalidJson.deps.json", + name: "sad path", + file: "testdata/invalid.deps.json", wantErr: "failed to decode .deps.json file: EOF", }, } - for _, tt := range vectors { - t.Run(path.Base(tt.file), func(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { f, err := os.Open(tt.file) require.NoError(t, err) diff --git a/pkg/dependency/parser/dotnet/core_deps/testdata/ExampleApp1.deps.json b/pkg/dependency/parser/dotnet/core_deps/testdata/happy.deps.json similarity index 100% rename from pkg/dependency/parser/dotnet/core_deps/testdata/ExampleApp1.deps.json rename to pkg/dependency/parser/dotnet/core_deps/testdata/happy.deps.json diff --git a/pkg/dependency/parser/dotnet/core_deps/testdata/InvalidJson.deps.json b/pkg/dependency/parser/dotnet/core_deps/testdata/invalid.deps.json similarity index 100% rename from pkg/dependency/parser/dotnet/core_deps/testdata/InvalidJson.deps.json rename to pkg/dependency/parser/dotnet/core_deps/testdata/invalid.deps.json diff --git a/pkg/dependency/parser/dotnet/core_deps/testdata/NoLibraries.deps.json b/pkg/dependency/parser/dotnet/core_deps/testdata/no-libraries.deps.json similarity index 100% rename from pkg/dependency/parser/dotnet/core_deps/testdata/NoLibraries.deps.json rename to pkg/dependency/parser/dotnet/core_deps/testdata/no-libraries.deps.json diff --git a/pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json b/pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json new file mode 100644 index 000000000000..fee8164d21d6 --- /dev/null +++ b/pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json @@ -0,0 +1,96 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "hello2/1.0.0": { + "dependencies": { + "JsonDiffPatch": "2.0.61" + }, + "runtime": { + "hello2.dll": {} + } + }, + "JsonDiffPatch/2.0.61": { + "dependencies": { + "Microsoft.NETCore.App": "1.1.2" + }, + "runtime": { + "lib/netcoreapp1.1/JsonDiffPatch.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Libuv/1.9.1": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + }, + "runtimeTargets": { + "runtimes/debian-x64/native/libuv.so": { + "rid": "debian-x64", + "assetType": "native", + "fileVersion": "0.0.0.0" + }, + "runtimes/fedora-x64/native/libuv.so": { + "rid": "fedora-x64", + "assetType": "native", + "fileVersion": "0.0.0.0" + } + } + }, + "Microsoft.NETCore.App/1.1.2": { + "dependencies": { + "Libuv": "1.9.1", + "System.Collections.Immutable": "1.3.0" + } + }, + "Microsoft.NETCore.Platforms/1.1.0": {} + } + }, + "libraries": { + "hello2/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "JsonDiffPatch/2.0.61": { + "type": "package", + "serviceable": true, + "sha512": "sha512-nZ4QtcU3jR+CBT69qcJBvCcWi5uKgPRrrvSMm4V8Z76ljJ/MFo1P55qXk/nQY0q0WC4v94m5qH4SDhovFfci+Q==", + "path": "jsondiffpatch/2.0.61", + "hashPath": "jsondiffpatch.2.0.61.nupkg.sha512" + }, + "Libuv/1.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-uqX2Frwf9PW8MaY7PRNY6HM5BpW1D8oj1EdqzrmbEFD5nH63Yat3aEjN/tws6Tw6Fk7LwmLBvtUh32tTeTaHiA==", + "path": "libuv/1.9.1", + "hashPath": "libuv.1.9.1.nupkg.sha512" + }, + "Microsoft.NETCore.App/1.1.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-fcN0Ob6rjY7Zu0770cA5l9wRJvj7+ltJPPdryUidejkkhao+y2AYrtezBTlP9nCSFXLmYR9BtaknORT17x8reA==", + "path": "microsoft.netcore.app/1.1.2", + "hashPath": "microsoft.netcore.app.1.1.2.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "System.Collections.Immutable/1.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-zukBRPUuNxwy9m4TGWLxKAnoiMc9+B+8VXeXVyPiBPvOd7yLgAlZ1DlsRWJjMx4VsvhhF2+6q6kO2GRbPja6hA==", + "path": "system.collections.immutable/1.3.0", + "hashPath": "system.collections.immutable.1.3.0.nupkg.sha512" + } + } +} \ No newline at end of file From 7066c9aab459c9289193854c8f0a8963020ca2a3 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 27 Jun 2024 17:25:50 +0600 Subject: [PATCH 03/10] test(fanal): add `id` field --- pkg/fanal/analyzer/language/dotnet/deps/deps_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go b/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go index c91d4467320e..d6a86c78084e 100644 --- a/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go +++ b/pkg/fanal/analyzer/language/dotnet/deps/deps_test.go @@ -29,6 +29,7 @@ func Test_depsLibraryAnalyzer_Analyze(t *testing.T) { FilePath: "testdata/datacollector.deps.json", Packages: types.Packages{ { + ID: "Newtonsoft.Json/9.0.1", Name: "Newtonsoft.Json", Version: "9.0.1", Locations: []types.Location{ From e5831085ff42323be0e320c4bdf3eb4ca548416c Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 27 Jun 2024 17:27:02 +0600 Subject: [PATCH 04/10] test(integration): update golden file --- integration/testdata/dotnet.json.golden | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/integration/testdata/dotnet.json.golden b/integration/testdata/dotnet.json.golden index 778b1270fcf2..4c76a08fc300 100644 --- a/integration/testdata/dotnet.json.golden +++ b/integration/testdata/dotnet.json.golden @@ -22,10 +22,11 @@ "Type": "dotnet-core", "Packages": [ { + "ID": "Newtonsoft.Json/9.0.1", "Name": "Newtonsoft.Json", "Identifier": { "PURL": "pkg:nuget/Newtonsoft.Json@9.0.1", - "UID": "19955f480b8a6340" + "UID": "e678401f5d07418a" }, "Version": "9.0.1", "Layer": {}, @@ -40,10 +41,11 @@ "Vulnerabilities": [ { "VulnerabilityID": "GHSA-5crp-9r3c-p9vr", + "PkgID": "Newtonsoft.Json/9.0.1", "PkgName": "Newtonsoft.Json", "PkgIdentifier": { "PURL": "pkg:nuget/Newtonsoft.Json@9.0.1", - "UID": "19955f480b8a6340" + "UID": "e678401f5d07418a" }, "InstalledVersion": "9.0.1", "FixedVersion": "13.0.1", From d8dcd128fe9050d2b73ae42d983dda364b89524f Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 27 Jun 2024 17:42:38 +0600 Subject: [PATCH 05/10] docs: add info about `--include-dev-deps` flag into .NET page --- docs/docs/coverage/language/dotnet.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/docs/coverage/language/dotnet.md b/docs/docs/coverage/language/dotnet.md index 0a05454365e9..7c0700f92bd3 100644 --- a/docs/docs/coverage/language/dotnet.md +++ b/docs/docs/coverage/language/dotnet.md @@ -24,6 +24,12 @@ Trivy parses `*.deps.json` files. Trivy currently excludes dev dependencies from ## packages.config Trivy only finds dependency names and versions from `packages.config` files. To build dependency graph, it is better to use `packages.lock.json` files. +### libraries built into .NET Core +[libraries section][net-core-libraries] of `*deps.json` file may contain dependencies that included to `.NET Core` (dependencies with empty `runtime`, `runtimeTarget` and `native` fields in [target][net-core-target] section). +These dependencies are not needed by the runtime, and the `dotnet build` command doesn't create `*.dll` files for them. + +Trivy marks these dependencies as the development dependencies and skip them by default. If you need to show them, use the `--include-dev-deps` flag. + ## *Packages.props Trivy parses `*Packages.props` files. Both legacy `Packages.props` and modern `Directory.Packages.props` are supported. @@ -49,3 +55,5 @@ Same as [packages.config](#license-detection) [global-packages]: https://learn.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders [license]: https://learn.microsoft.com/en-us/nuget/reference/nuspec#license [license-url]: https://learn.microsoft.com/en-us/nuget/reference/nuspec#licenseurl +[net-core-libraries]: https://github.com/dotnet/sdk/blob/529132850841a6bcfce96799262ce688e3851875/documentation/specs/runtime-configuration-file.md#libraries-section-depsjson +[net-core-target]: https://github.com/dotnet/sdk/blob/529132850841a6bcfce96799262ce688e3851875/documentation/specs/runtime-configuration-file.md#targets-section-depsjson From 2725e2cdbc2de029c31dc537bb701b88e4bbd70f Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Mon, 15 Jul 2024 08:19:20 +0600 Subject: [PATCH 06/10] refactor: remove non-runtime libs --- .../parser/dotnet/core_deps/parse.go | 46 +++++++++---------- .../parser/dotnet/core_deps/parse_test.go | 36 ++++----------- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/pkg/dependency/parser/dotnet/core_deps/parse.go b/pkg/dependency/parser/dotnet/core_deps/parse.go index 052cdd69d785..3ab171e25b14 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse.go @@ -17,9 +17,9 @@ import ( ) type dotNetDependencies struct { - Libraries map[string]dotNetLibrary `json:"libraries"` - RuntimeTarget RuntimeTarget `json:"runtimeTarget"` - Targets map[string]map[string]Target `json:"targets"` + Libraries map[string]dotNetLibrary `json:"libraries"` + RuntimeTarget RuntimeTarget `json:"runtimeTarget"` + Targets map[string]map[string]TargetLib `json:"targets"` } type dotNetLibrary struct { @@ -32,7 +32,7 @@ type RuntimeTarget struct { Name string `json:"name"` } -type Target struct { +type TargetLib struct { Runtime any `json:"runtime"` RuntimeTargets any `json:"runtimeTargets"` Native any `json:"native"` @@ -61,9 +61,6 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc return nil, nil, xerrors.Errorf("failed to decode .deps.json file: %w", err) } - // Select target for RuntimeTarget - target := depsFile.Targets[depsFile.RuntimeTarget.Name] - var pkgs ftypes.Packages for nameVer, lib := range depsFile.Libraries { if !strings.EqualFold(lib.Type, "package") { @@ -77,6 +74,18 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc continue } + // Take target libraries for RuntimeTarget + if targetLibs, ok := depsFile.Targets[depsFile.RuntimeTarget.Name]; !ok { + // If the target is not found, take all dependencies + p.once.Do(func() { + p.logger.Debug("Unable to find `Target` for Runtime Target Name. All dependencies from `libraries` section will be included in the report", log.String("Runtime Target Name", depsFile.RuntimeTarget.Name)) + }) + } else if !p.isRuntimeLibrary(targetLibs, nameVer) { + // Skip non-runtime libraries + // cf. https://github.com/aquasecurity/trivy/pull/7039#discussion_r1674566823 + continue + } + pkgs = append(pkgs, ftypes.Package{ ID: dependency.ID(ftypes.DotNetCore, split[0], split[1]), Name: split[0], @@ -87,9 +96,6 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc EndLine: lib.EndLine, }, }, - // We're still not sure that we need to skip libraries built into .NETCore (or that we detect them correctly). - // So we mark these libraries as Dev to skip the scan by default, but keep the options for displaying these libraries. - Dev: p.isLibraryBuiltIntoNetCore(target, depsFile.RuntimeTarget.Name, nameVer), }) } @@ -97,26 +103,20 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc return pkgs, nil, nil } -// isLibraryBuiltIntoNetCore returns true if library doesn't contain `runtime`, `runtimeTarget` and `native` sections. +// isRuntimeLibrary returns true if library doesn't contain `runtime`, `runtimeTarget` and `native` sections. // See https://github.com/aquasecurity/trivy/discussions/4282#discussioncomment-8830365 for more details. -func (p *Parser) isLibraryBuiltIntoNetCore(target map[string]Target, runtimeTargetName, library string) bool { - // `Target` for `RuntimeTarget.Name` not found - if target == nil { - p.once.Do(func() { - p.logger.Debug("Unable to find `Target` for Runtime Target Name. All dependencies from `libraries` section will be included in the report", log.String("RuntimeTarget", runtimeTargetName)) - }) - return false - } - lib, ok := target[library] +func (p *Parser) isRuntimeLibrary(targetLibs map[string]TargetLib, library string) bool { + lib, ok := targetLibs[library] // Selected target doesn't contain library + // Mark these libraries as runtime to avoid mistaken omission if !ok { p.once.Do(func() { - p.logger.Debug("Unable to determine that the library is built into .NET Core. Library not found in `Target` section.", log.String("RuntimeTarget", runtimeTargetName), log.String("Library", library)) + p.logger.Debug("Unable to determine that this is runtime library. Library not found in `Target` section.", log.String("Library", library)) }) - return false + return true } // Check that `runtime`, `runtimeTarget` and `native` sections are empty - return lo.IsEmpty(lib) + return !lo.IsEmpty(lib) } // UnmarshalJSONWithMetadata needed to detect start and end lines of deps diff --git a/pkg/dependency/parser/dotnet/core_deps/parse_test.go b/pkg/dependency/parser/dotnet/core_deps/parse_test.go index 6673dbd69d3d..8e5c486467a5 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse_test.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse_test.go @@ -28,7 +28,8 @@ func TestParse(t *testing.T) { Version: "13.0.1", Locations: []ftypes.Location{ { - StartLine: 33, EndLine: 39, + StartLine: 33, + EndLine: 39, }, }, }, @@ -44,7 +45,8 @@ func TestParse(t *testing.T) { Version: "2.0.61", Locations: []ftypes.Location{ { - StartLine: 60, EndLine: 66, + StartLine: 60, + EndLine: 66, }, }, }, @@ -54,43 +56,21 @@ func TestParse(t *testing.T) { Version: "1.9.1", Locations: []ftypes.Location{ { - StartLine: 67, EndLine: 73, + StartLine: 67, + EndLine: 73, }, }, }, - { - ID: "Microsoft.NETCore.App/1.1.2", - Name: "Microsoft.NETCore.App", - Version: "1.1.2", - Locations: []ftypes.Location{ - { - StartLine: 74, EndLine: 80, - }, - }, - Dev: true, - }, - { - ID: "Microsoft.NETCore.Platforms/1.1.0", - Name: "Microsoft.NETCore.Platforms", - Version: "1.1.0", - Locations: []ftypes.Location{ - { - StartLine: 81, EndLine: 87, - }, - }, - Dev: true, - }, { ID: "System.Collections.Immutable/1.3.0", Name: "System.Collections.Immutable", Version: "1.3.0", Locations: []ftypes.Location{ { - StartLine: 88, EndLine: 94, + StartLine: 88, + EndLine: 94, }, }, - // Is false because `targets[.NETCoreApp,Version=v6.0]` doesn't contain this library - Dev: false, }, }, }, From 21c6cd3e023903e09ec9bac35846bc9033daf266 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Mon, 15 Jul 2024 08:26:22 +0600 Subject: [PATCH 07/10] docs: update coverage page --- docs/docs/coverage/language/dotnet.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/docs/coverage/language/dotnet.md b/docs/docs/coverage/language/dotnet.md index 7c0700f92bd3..76ca23235d63 100644 --- a/docs/docs/coverage/language/dotnet.md +++ b/docs/docs/coverage/language/dotnet.md @@ -21,15 +21,12 @@ The following table provides an outline of the features Trivy offers. ## *.deps.json Trivy parses `*.deps.json` files. Trivy currently excludes dev dependencies from the report. +!!! note + Trivy only includes runtime dependencies in the report. + ## packages.config Trivy only finds dependency names and versions from `packages.config` files. To build dependency graph, it is better to use `packages.lock.json` files. -### libraries built into .NET Core -[libraries section][net-core-libraries] of `*deps.json` file may contain dependencies that included to `.NET Core` (dependencies with empty `runtime`, `runtimeTarget` and `native` fields in [target][net-core-target] section). -These dependencies are not needed by the runtime, and the `dotnet build` command doesn't create `*.dll` files for them. - -Trivy marks these dependencies as the development dependencies and skip them by default. If you need to show them, use the `--include-dev-deps` flag. - ## *Packages.props Trivy parses `*Packages.props` files. Both legacy `Packages.props` and modern `Directory.Packages.props` are supported. From 5799449c167bf96a5078f1a020c9ecec1ec9ba82 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Mon, 15 Jul 2024 08:36:30 +0600 Subject: [PATCH 08/10] docs: remove unused links --- docs/docs/coverage/language/dotnet.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/docs/coverage/language/dotnet.md b/docs/docs/coverage/language/dotnet.md index 76ca23235d63..311e5c010b2d 100644 --- a/docs/docs/coverage/language/dotnet.md +++ b/docs/docs/coverage/language/dotnet.md @@ -52,5 +52,3 @@ Same as [packages.config](#license-detection) [global-packages]: https://learn.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders [license]: https://learn.microsoft.com/en-us/nuget/reference/nuspec#license [license-url]: https://learn.microsoft.com/en-us/nuget/reference/nuspec#licenseurl -[net-core-libraries]: https://github.com/dotnet/sdk/blob/529132850841a6bcfce96799262ce688e3851875/documentation/specs/runtime-configuration-file.md#libraries-section-depsjson -[net-core-target]: https://github.com/dotnet/sdk/blob/529132850841a6bcfce96799262ce688e3851875/documentation/specs/runtime-configuration-file.md#targets-section-depsjson From afe12b40e146d9b92c663eeeac14e46168a2286c Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 17 Jul 2024 13:33:20 +0600 Subject: [PATCH 09/10] fix: update incorrect comments --- pkg/dependency/parser/dotnet/core_deps/parse.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/dependency/parser/dotnet/core_deps/parse.go b/pkg/dependency/parser/dotnet/core_deps/parse.go index 3ab171e25b14..7fc8d3df5d5e 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse.go @@ -103,7 +103,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc return pkgs, nil, nil } -// isRuntimeLibrary returns true if library doesn't contain `runtime`, `runtimeTarget` and `native` sections. +// isRuntimeLibrary returns true if library contains `runtime`, `runtimeTarget` or `native` sections, or if the library is missing from `targetLibs`. // See https://github.com/aquasecurity/trivy/discussions/4282#discussioncomment-8830365 for more details. func (p *Parser) isRuntimeLibrary(targetLibs map[string]TargetLib, library string) bool { lib, ok := targetLibs[library] @@ -115,7 +115,7 @@ func (p *Parser) isRuntimeLibrary(targetLibs map[string]TargetLib, library strin }) return true } - // Check that `runtime`, `runtimeTarget` and `native` sections are empty + // Check that `runtime`, `runtimeTarget` and `native` sections are not empty return !lo.IsEmpty(lib) } From ca87c122ef3df052866a9e05c62d53251ee651b7 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 17 Jul 2024 13:33:52 +0600 Subject: [PATCH 10/10] test: add `System.Net.Http` and `NETStandard.Library` to test file --- .../parser/dotnet/core_deps/parse_test.go | 12 +++++----- .../testdata/without-runtime.deps.json | 22 ++++++++++++++++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pkg/dependency/parser/dotnet/core_deps/parse_test.go b/pkg/dependency/parser/dotnet/core_deps/parse_test.go index 8e5c486467a5..82bf0e0a1d47 100644 --- a/pkg/dependency/parser/dotnet/core_deps/parse_test.go +++ b/pkg/dependency/parser/dotnet/core_deps/parse_test.go @@ -45,8 +45,8 @@ func TestParse(t *testing.T) { Version: "2.0.61", Locations: []ftypes.Location{ { - StartLine: 60, - EndLine: 66, + StartLine: 66, + EndLine: 72, }, }, }, @@ -56,8 +56,8 @@ func TestParse(t *testing.T) { Version: "1.9.1", Locations: []ftypes.Location{ { - StartLine: 67, - EndLine: 73, + StartLine: 73, + EndLine: 79, }, }, }, @@ -67,8 +67,8 @@ func TestParse(t *testing.T) { Version: "1.3.0", Locations: []ftypes.Location{ { - StartLine: 88, - EndLine: 94, + StartLine: 101, + EndLine: 107, }, }, }, diff --git a/pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json b/pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json index fee8164d21d6..ba882c61cb5f 100644 --- a/pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json +++ b/pkg/dependency/parser/dotnet/core_deps/testdata/without-runtime.deps.json @@ -48,7 +48,13 @@ "System.Collections.Immutable": "1.3.0" } }, - "Microsoft.NETCore.Platforms/1.1.0": {} + "Microsoft.NETCore.Platforms/1.1.0": {}, + "NETStandard.Library/1.6.0": { + "dependencies": { + "System.Net.Http": "4.1.0" + } + }, + "System.Net.Http/4.1.0": {} } }, "libraries": { @@ -85,12 +91,26 @@ "path": "microsoft.netcore.platforms/1.1.0", "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" }, + "NETStandard.Library/1.6.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ypsCvIdCZ4IoYASJHt6tF2fMo7N30NLgV1EbmC+snO490OMl9FvVxmumw14rhReWU3j3g7BYudG6YCrchwHJlA==", + "path": "netstandard.library/1.6.0", + "hashPath": "netstandard.library.1.6.0.nupkg.sha512" + }, "System.Collections.Immutable/1.3.0": { "type": "package", "serviceable": true, "sha512": "sha512-zukBRPUuNxwy9m4TGWLxKAnoiMc9+B+8VXeXVyPiBPvOd7yLgAlZ1DlsRWJjMx4VsvhhF2+6q6kO2GRbPja6hA==", "path": "system.collections.immutable/1.3.0", "hashPath": "system.collections.immutable.1.3.0.nupkg.sha512" + }, + "System.Net.Http/4.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ULq9g3SOPVuupt+Y3U+A37coXzdNisB1neFCSKzBwo182u0RDddKJF8I5+HfyXqK6OhJPgeoAwWXrbiUXuRDsg==", + "path": "system.net.http/4.1.0", + "hashPath": "system.net.http.4.1.0.nupkg.sha512" } } } \ No newline at end of file