-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
fix(dotnet): don't include non-runtime libraries into report for *.deps.json
files
#7039
Changes from 8 commits
298f192
c8df60a
7066c9a
e583108
d8dcd12
2725e2c
21c6cd3
5799449
afe12b4
ca87c12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,10 +22,11 @@ | |
"Type": "dotnet-core", | ||
"Packages": [ | ||
{ | ||
"ID": "Newtonsoft.Json/9.0.1", | ||
"Name": "Newtonsoft.Json", | ||
"Identifier": { | ||
"PURL": "pkg:nuget/[email protected]", | ||
"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/[email protected]", | ||
"UID": "19955f480b8a6340" | ||
"UID": "e678401f5d07418a" | ||
}, | ||
"InstalledVersion": "9.0.1", | ||
"FixedVersion": "13.0.1", | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -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]TargetLib `json:"targets"` | ||||||
} | ||||||
|
||||||
type dotNetLibrary struct { | ||||||
Type string `json:"type"` | ||||||
StartLine int | ||||||
EndLine int | ||||||
} | ||||||
|
||||||
type RuntimeTarget struct { | ||||||
Name string `json:"name"` | ||||||
} | ||||||
|
||||||
type TargetLib 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,11 @@ 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 | ||||||
var pkgs ftypes.Packages | ||||||
for nameVer, lib := range depsFile.Libraries { | ||||||
if !strings.EqualFold(lib.Type, "package") { | ||||||
continue | ||||||
|
@@ -46,7 +74,20 @@ 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], | ||||||
Version: split[1], | ||||||
Locations: []ftypes.Location{ | ||||||
|
@@ -58,17 +99,24 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc | |||||
}) | ||||||
} | ||||||
|
||||||
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 | ||||||
// 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) 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 this is runtime library. Library not found in `Target` section.", log.String("Library", library)) | ||||||
}) | ||||||
return true | ||||||
} | ||||||
// Check that `runtime`, `runtimeTarget` and `native` sections are empty | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks to me like it checks if they are not empty.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed in afe12b4 |
||||||
return !lo.IsEmpty(lib) | ||||||
} | ||||||
|
||||||
// UnmarshalJSONWithMetadata needed to detect start and end lines of deps | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to add another testcase that references some of the commonly reported false positives and proves that those aren't flagged? For example - a deps file listing a vulnerable version of This was created with
This shows that all the old packages (some vulnerable) making up the NETStandard surface area are all excluded when targeting the latest frameworks which provide inbox support for all those package. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your test file is too large. |
||
"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" | ||
} | ||
} | ||
} |
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 this function returns true if the library contains one of these sections, or if the library is completely missing from the section. The behavior looks correct, just the comment seems inverted.
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 updated this function, but forgot to update comment.
Thanks!
Fixed in afe12b4