feat(report): add package path (#1274)

This commit is contained in:
Teppei Fukuda
2021-10-06 16:28:48 +09:00
committed by GitHub
parent 1c9ccb5e03
commit f12446d3ba
15 changed files with 80 additions and 113 deletions

2
go.mod
View File

@@ -7,7 +7,7 @@ require (
github.com/Masterminds/sprig v2.22.0+incompatible
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
github.com/aquasecurity/fanal v0.0.0-20211004144717-124d5e3ef398
github.com/aquasecurity/fanal v0.0.0-20211005172059-69527b46560c
github.com/aquasecurity/go-dep-parser v0.0.0-20210919151457-76db061b9305
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798

4
go.sum
View File

@@ -202,8 +202,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/fanal v0.0.0-20211004144717-124d5e3ef398 h1:D2/7fMPN4qG54w2Baw6odXfO/Itojjl9ZWjTwegqj3A=
github.com/aquasecurity/fanal v0.0.0-20211004144717-124d5e3ef398/go.mod h1:nXdCM1C89phZEkn/sHQ6S5IjcvxdTnXLSKcftmhFodg=
github.com/aquasecurity/fanal v0.0.0-20211005172059-69527b46560c h1:pBpjKZpfpWdcotMqZ2J6hMI/lDK5pKshdj2o7+xzLkg=
github.com/aquasecurity/fanal v0.0.0-20211005172059-69527b46560c/go.mod h1:nXdCM1C89phZEkn/sHQ6S5IjcvxdTnXLSKcftmhFodg=
github.com/aquasecurity/go-dep-parser v0.0.0-20210919151457-76db061b9305 h1:xsniAD6IrP+stY8tkytxE2tk8czkzSN3XaUvzoi1hCk=
github.com/aquasecurity/go-dep-parser v0.0.0-20210919151457-76db061b9305/go.mod h1:Zc7Eo6tFl9l4XcqsWeabD7jHnXRBK/LdgZuu9GTSVLU=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=

View File

@@ -33,10 +33,7 @@
"Namespace": "user.bar",
"Query": "data.user.bar.deny",
"Severity": "UNKNOWN",
"Status": "FAIL",
"Layer": {
"DiffID": "sha256:8dc85f0b450296556c427e94db1d76a25fdce31334a4fcedac370f1aa59c86dc"
}
"Status": "FAIL"
},
{
"Type": "N/A",
@@ -46,10 +43,7 @@
"Namespace": "user.foo",
"Query": "data.user.foo.deny",
"Severity": "UNKNOWN",
"Status": "FAIL",
"Layer": {
"DiffID": "sha256:8dc85f0b450296556c427e94db1d76a25fdce31334a4fcedac370f1aa59c86dc"
}
"Status": "FAIL"
}
]
}

View File

@@ -40,10 +40,7 @@
"https://docs.docker.com/develop/develop-images/dockerfile_best-practices/",
"https://avd.aquasec.com/appshield/ds002"
],
"Status": "FAIL",
"Layer": {
"DiffID": "sha256:2f8334a38883ba260fc9cab989110b8eea18721ee15c319b83fa3eba8d5981ca"
}
"Status": "FAIL"
}
]
}

View File

@@ -25,9 +25,6 @@
"PkgName": "jquery",
"InstalledVersion": "3.3.9",
"FixedVersion": "3.4.0",
"Layer": {
"DiffID": "sha256:0b7517474d221ce39e6d69d41dabef6ae965464eef0d7037ba80361160c0d63c"
},
"SeveritySource": "nodejs-security-wg",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-11358",
"Title": "js-jquery: prototype pollution in object's prototype leading to denial of service or remote code execution or property injection",
@@ -95,9 +92,6 @@
"PkgName": "lodash",
"InstalledVersion": "4.17.4",
"FixedVersion": "4.17.12",
"Layer": {
"DiffID": "sha256:0b7517474d221ce39e6d69d41dabef6ae965464eef0d7037ba80361160c0d63c"
},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-10744",
"Title": "nodejs-lodash: prototype pollution in defaultsDeep function leading to modifying properties",
@@ -135,9 +129,6 @@
"PkgName": "lodash",
"InstalledVersion": "4.17.4",
"FixedVersion": "4.17.11",
"Layer": {
"DiffID": "sha256:0b7517474d221ce39e6d69d41dabef6ae965464eef0d7037ba80361160c0d63c"
},
"SeveritySource": "nodejs-security-wg",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2018-16487",
"Title": "lodash: Prototype pollution in utilities function",
@@ -173,9 +164,6 @@
"PkgName": "lodash",
"InstalledVersion": "4.17.4",
"FixedVersion": "4.17.11",
"Layer": {
"DiffID": "sha256:0b7517474d221ce39e6d69d41dabef6ae965464eef0d7037ba80361160c0d63c"
},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-1010266",
"Title": "Moderate severity vulnerability that affects lodash",
@@ -208,9 +196,6 @@
"PkgName": "lodash",
"InstalledVersion": "4.17.4",
"FixedVersion": "4.17.5",
"Layer": {
"DiffID": "sha256:0b7517474d221ce39e6d69d41dabef6ae965464eef0d7037ba80361160c0d63c"
},
"SeveritySource": "nodejs-security-wg",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2018-3721",
"Title": "lodash: Prototype pollution in utilities function",

View File

@@ -25,9 +25,6 @@
"PkgName": "Werkzeug",
"InstalledVersion": "0.11",
"FixedVersion": "0.15.3",
"Layer": {
"DiffID": "sha256:6393f36bbbee0b53834ba0f9f585194d9e5ab56b555a2910551254fc8a2aec19"
},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-14806",
"Title": "python-werkzeug: insufficient debugger PIN randomness vulnerability",
@@ -65,9 +62,6 @@
"PkgName": "Werkzeug",
"InstalledVersion": "0.11",
"FixedVersion": "0.11.11",
"Layer": {
"DiffID": "sha256:6393f36bbbee0b53834ba0f9f585194d9e5ab56b555a2910551254fc8a2aec19"
},
"SeveritySource": "nvd",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2016-10516",
"Title": "python-werkzeug: Cross-site scripting in render_full function in debug/tbtools.py",
@@ -103,9 +97,6 @@
"PkgName": "Werkzeug",
"InstalledVersion": "0.11",
"FixedVersion": "0.11.6",
"Layer": {
"DiffID": "sha256:6393f36bbbee0b53834ba0f9f585194d9e5ab56b555a2910551254fc8a2aec19"
},
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2020-28724",
"Title": "Werkzeug before 0.11.6 includes an open redirect vulnerability via a double slash in the URL. See CVE-2020-28724.",
"Severity": "UNKNOWN"
@@ -115,9 +106,6 @@
"PkgName": "Werkzeug",
"InstalledVersion": "0.11",
"FixedVersion": "0.12",
"Layer": {
"DiffID": "sha256:6393f36bbbee0b53834ba0f9f585194d9e5ab56b555a2910551254fc8a2aec19"
},
"Title": "The defaults of ``generate_password_hash`` in werkzeug 0.12 have been changed to more secure ones, see pull request ``#753``.",
"Severity": "UNKNOWN"
},
@@ -126,9 +114,6 @@
"PkgName": "Werkzeug",
"InstalledVersion": "0.11",
"FixedVersion": "0.15.0",
"Layer": {
"DiffID": "sha256:6393f36bbbee0b53834ba0f9f585194d9e5ab56b555a2910551254fc8a2aec19"
},
"Title": "Werkzeug 0.15.0 refactors class:`~middleware.proxy_fix.ProxyFix` to support more headers, multiple values, and a more secure configuration.",
"Severity": "UNKNOWN"
}

View File

@@ -8,7 +8,7 @@ import (
)
// Detect scans and returns vulnerabilities of library
func Detect(libType string, pkgs []ftypes.LibraryInfo) ([]types.DetectedVulnerability, error) {
func Detect(libType string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
driver, err := NewDriver(libType)
if err != nil {
return nil, xerrors.Errorf("failed to new driver: %w", err)
@@ -22,10 +22,10 @@ func Detect(libType string, pkgs []ftypes.LibraryInfo) ([]types.DetectedVulnerab
return vulns, nil
}
func detect(driver Driver, libs []ftypes.LibraryInfo) ([]types.DetectedVulnerability, error) {
func detect(driver Driver, libs []ftypes.Package) ([]types.DetectedVulnerability, error) {
var vulnerabilities []types.DetectedVulnerability
for _, lib := range libs {
vulns, err := driver.Detect(lib.Library.Name, lib.Library.Version)
vulns, err := driver.Detect(lib.Name, lib.Version)
if err != nil {
return nil, xerrors.Errorf("failed to detect %s vulnerabilities: %w", driver.Type(), err)
}

View File

@@ -19,7 +19,7 @@ type OperationDetectArgs struct {
FilePathAnything bool
Created time.Time
CreatedAnything bool
Pkgs []types.LibraryInfo
Pkgs []types.Package
PkgsAnything bool
}
@@ -65,11 +65,11 @@ func (_m *MockOperation) ApplyDetectExpectations(expectations []OperationDetectE
}
// Detect provides a mock function with given fields: imageName, filePath, created, pkgs
func (_m *MockOperation) Detect(imageName string, filePath string, created time.Time, pkgs []types.LibraryInfo) ([]pkgtypes.DetectedVulnerability, error) {
func (_m *MockOperation) Detect(imageName string, filePath string, created time.Time, pkgs []types.Package) ([]pkgtypes.DetectedVulnerability, error) {
ret := _m.Called(imageName, filePath, created, pkgs)
var r0 []pkgtypes.DetectedVulnerability
if rf, ok := ret.Get(0).(func(string, string, time.Time, []types.LibraryInfo) []pkgtypes.DetectedVulnerability); ok {
if rf, ok := ret.Get(0).(func(string, string, time.Time, []types.Package) []pkgtypes.DetectedVulnerability); ok {
r0 = rf(imageName, filePath, created, pkgs)
} else {
if ret.Get(0) != nil {
@@ -78,7 +78,7 @@ func (_m *MockOperation) Detect(imageName string, filePath string, created time.
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, time.Time, []types.LibraryInfo) error); ok {
if rf, ok := ret.Get(1).(func(string, string, time.Time, []types.Package) error); ok {
r1 = rf(imageName, filePath, created, pkgs)
} else {
r1 = ret.Error(1)

View File

@@ -60,18 +60,16 @@ func ConvertFromRPCPkgs(rpcPkgs []*common.Package) []ftypes.Package {
}
// ConvertFromRPCLibraries returns list of Fanal library
func ConvertFromRPCLibraries(rpcLibs []*common.Library) []ftypes.LibraryInfo {
var libs []ftypes.LibraryInfo
func ConvertFromRPCLibraries(rpcLibs []*common.Library) []ftypes.Package {
var pkgs []ftypes.Package
for _, l := range rpcLibs {
libs = append(libs, ftypes.LibraryInfo{
Library: deptypes.Library{
pkgs = append(pkgs, ftypes.Package{
Name: l.Name,
Version: l.Version,
License: l.License,
},
})
}
return libs
return pkgs
}
// ConvertToRPCLibraries returns list of libraries
@@ -411,9 +409,9 @@ func ConvertToRPCBlobInfo(diffID string, blobInfo ftypes.BlobInfo) *cache.PutBlo
var libs []*common.Library
for _, lib := range app.Libraries {
libs = append(libs, &common.Library{
Name: lib.Library.Name,
Version: lib.Library.Version,
License: lib.Library.License,
Name: lib.Name,
Version: lib.Version,
License: lib.License,
})
}
applications = append(applications, &common.Application{

View File

@@ -141,7 +141,7 @@ func TestConvertFromRpcLibraries(t *testing.T) {
tests := []struct {
name string
args args
want []ftypes.LibraryInfo
want []ftypes.Package
}{
{
name: "happy path",
@@ -151,9 +151,9 @@ func TestConvertFromRpcLibraries(t *testing.T) {
{Name: "bar", Version: "4.5.6"},
},
},
want: []ftypes.LibraryInfo{
{Library: ptypes.Library{Name: "foo", Version: "1.2.3"}},
{Library: ptypes.Library{Name: "bar", Version: "4.5.6"}},
want: []ftypes.Package{
{Name: "foo", Version: "1.2.3"},
{Name: "bar", Version: "4.5.6"},
},
},
}

View File

@@ -15,7 +15,6 @@ import (
"github.com/aquasecurity/fanal/cache"
ftypes "github.com/aquasecurity/fanal/types"
deptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/db"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/utils"
@@ -406,22 +405,18 @@ func TestCacheServer_PutBlob(t *testing.T) {
{
Type: "composer",
FilePath: "php-app/composer.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: deptypes.Library{
Name: "guzzlehttp/guzzle",
Version: "6.2.0",
},
},
{
Library: deptypes.Library{
Name: "guzzlehttp/promises",
Version: "v1.3.1",
},
},
},
},
},
OpaqueDirs: []string{"etc/"},
WhiteoutFiles: []string{"etc/hostname"},
},

View File

@@ -216,7 +216,7 @@ func (s Scanner) scanLibrary(apps []ftypes.Application, options types.ScanOption
Type: app.Type,
}
if options.ListAllPackages {
libReport.Packages = s.listAllPkgs(app)
libReport.Packages = app.Libraries
}
results = append(results, libReport)
}
@@ -226,23 +226,6 @@ func (s Scanner) scanLibrary(apps []ftypes.Application, options types.ScanOption
return results, nil
}
func (s Scanner) listAllPkgs(app ftypes.Application) []ftypes.Package {
var pkgs []ftypes.Package
for _, lib := range app.Libraries {
pkgs = append(pkgs, ftypes.Package{
Name: lib.Library.Name,
Version: lib.Library.Version,
License: lib.Library.License,
Layer: lib.Layer,
})
}
sort.Slice(pkgs, func(i, j int) bool {
return strings.Compare(pkgs[i].Name, pkgs[j].Name) <= 0
})
return pkgs
}
func (s Scanner) misconfsToResults(misconfs []ftypes.Misconfiguration, options types.ScanOptions) report.Results {
log.Logger.Infof("Detected config files: %d", len(misconfs))
var results report.Results

View File

@@ -9,7 +9,6 @@ import (
"github.com/aquasecurity/fanal/analyzer"
ftypes "github.com/aquasecurity/fanal/types"
dtypes "github.com/aquasecurity/go-dep-parser/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/dbtest"
@@ -68,9 +67,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: ftypes.Bundler,
FilePath: "/app/Gemfile.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "rails", Version: "4.0.2"},
Name: "rails",
Version: "4.0.2",
Layer: ftypes.Layer{
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
},
@@ -194,9 +194,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: "bundler",
FilePath: "/app/Gemfile.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "rails", Version: "4.0.2"},
Name: "rails",
Version: "4.0.2",
Layer: ftypes.Layer{
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
},
@@ -331,9 +332,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: "bundler",
FilePath: "/app/Gemfile.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "rails", Version: "4.0.2"},
Name: "rails",
Version: "4.0.2",
Layer: ftypes.Layer{
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
},
@@ -389,9 +391,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: "bundler",
FilePath: "/app/Gemfile.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "rails", Version: "4.0.2"},
Name: "rails",
Version: "4.0.2",
Layer: ftypes.Layer{
DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33",
},
@@ -467,9 +470,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: "bundler",
FilePath: "/app/Gemfile.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "rails", Version: "4.0.2"},
Name: "rails",
Version: "4.0.2",
Layer: ftypes.Layer{
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
},
@@ -567,9 +571,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: "bundler",
FilePath: "/app/Gemfile.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "rails", Version: "4.0.2"},
Name: "rails",
Version: "4.0.2",
Layer: ftypes.Layer{
DiffID: "sha256:5cb2a5009179b1e78ecfef81a19756328bb266456cf9a9dbbcf9af8b83b735f0",
},
@@ -579,9 +584,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: "composer",
FilePath: "/app/composer-lock.json",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "laravel/framework", Version: "6.0.0"},
Name: "laravel/framework",
Version: "6.0.0",
Layer: ftypes.Layer{
DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303",
},
@@ -890,9 +896,10 @@ func TestScanner_Scan(t *testing.T) {
{
Type: "bundler",
FilePath: "/app/Gemfile.lock",
Libraries: []ftypes.LibraryInfo{
Libraries: []ftypes.Package{
{
Library: dtypes.Library{Name: "rails", Version: "6.0"},
Name: "rails",
Version: "6.0",
Layer: ftypes.Layer{
DiffID: "sha256:9bdb2c849099a99c8ab35f6fd7469c623635e8f4479a0a5a3df61e22bae509f6",
},

View File

@@ -108,6 +108,11 @@ func (s Scanner) ScanArtifact(ctx context.Context, options types.ScanOptions) (r
log.Logger.Warnf("The vulnerability detection may be insufficient because security updates are not provided")
}
// Layer makes sense only when scanning container images
if artifactInfo.Type != ftypes.ArtifactContainerImage {
removeLayer(results)
}
return report.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: artifactInfo.Name,
@@ -123,3 +128,19 @@ func (s Scanner) ScanArtifact(ctx context.Context, options types.ScanOptions) (r
Results: results,
}, nil
}
func removeLayer(results report.Results) {
for i := range results {
result := results[i]
for j := range result.Packages {
result.Packages[j].Layer = ftypes.Layer{}
}
for j := range result.Vulnerabilities {
result.Vulnerabilities[j].Layer = ftypes.Layer{}
}
for j := range result.Misconfigurations {
result.Misconfigurations[j].Layer = ftypes.Layer{}
}
}
}

View File

@@ -38,6 +38,7 @@ func TestScanner_ScanArtifact(t *testing.T) {
Returns: artifact.ArtifactInspectReturns{
Reference: ftypes.ArtifactReference{
Name: "alpine:3.11",
Type: ftypes.ArtifactContainerImage,
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
ImageMetadata: ftypes.ImageMetadata{
@@ -96,6 +97,7 @@ func TestScanner_ScanArtifact(t *testing.T) {
want: report.Report{
SchemaVersion: 2,
ArtifactName: "alpine:3.11",
ArtifactType: ftypes.ArtifactContainerImage,
Metadata: report.Metadata{
OS: &ftypes.OS{
Family: "alpine",