From 7b60b964f36570e261bca311d9c72ef3bcf921b3 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:41:02 +0400 Subject: [PATCH 01/24] refactor: rename consts for misconfiguration statuses Signed-off-by: knqyf263 --- pkg/cloud/report/convert.go | 6 ++-- pkg/compliance/report/json_test.go | 15 ++++++++-- pkg/compliance/report/report_test.go | 6 ++-- pkg/compliance/report/summary_test.go | 20 ++++++++++--- pkg/compliance/report/table_test.go | 4 +-- pkg/compliance/spec/mapper.go | 6 ++-- pkg/compliance/spec/mapper_test.go | 10 +++---- pkg/k8s/report/report_test.go | 41 +++++++++++++-------------- pkg/k8s/writer_test.go | 27 +++++++++--------- pkg/report/sarif_test.go | 4 +-- pkg/report/table/misconfig.go | 10 +++---- pkg/report/writer_test.go | 4 +-- pkg/result/filter.go | 6 ++-- pkg/scanner/local/scan.go | 8 +++--- pkg/scanner/local/scan_test.go | 12 ++++---- pkg/types/misconfiguration.go | 12 ++++---- pkg/types/report.go | 2 +- 17 files changed, 106 insertions(+), 87 deletions(-) diff --git a/pkg/cloud/report/convert.go b/pkg/cloud/report/convert.go index d1e41bcb2fe9..7babc9157701 100644 --- a/pkg/cloud/report/convert.go +++ b/pkg/cloud/report/convert.go @@ -61,12 +61,12 @@ func ConvertResults(results scan.Results, provider string, scoped []string) map[ primaryURL = fmt.Sprintf("https://avd.aquasec.com/misconfig/%s", strings.ToLower(result.Rule().AVDID)) } - status := types.StatusFailure + status := types.MisconfStatusFailure switch result.Status() { case scan.StatusPassed: - status = types.StatusPassed + status = types.MisconfStatusPassed case scan.StatusIgnored: - status = types.StatusException + status = types.MisconfStatusException } flat := result.Flatten() diff --git a/pkg/compliance/report/json_test.go b/pkg/compliance/report/json_test.go index a21ad5744d2c..31680b4ff513 100644 --- a/pkg/compliance/report/json_test.go +++ b/pkg/compliance/report/json_test.go @@ -26,7 +26,10 @@ func TestJSONWriter_Write(t *testing.T) { Results: types.Results{ { Misconfigurations: []types.DetectedMisconfiguration{ - {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + { + AVDID: "AVD-KSV012", + Status: types.MisconfStatusFailure, + }, }, }, }, @@ -38,7 +41,10 @@ func TestJSONWriter_Write(t *testing.T) { Results: types.Results{ { Misconfigurations: []types.DetectedMisconfiguration{ - {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + { + AVDID: "AVD-KSV013", + Status: types.MisconfStatusFailure, + }, }, }, }, @@ -69,7 +75,10 @@ func TestJSONWriter_Write(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { buf := new(bytes.Buffer) - tr := report.JSONWriter{Report: tt.reportType, Output: buf} + tr := report.JSONWriter{ + Report: tt.reportType, + Output: buf, + } err := tr.Write(tt.input) require.NoError(t, err) diff --git a/pkg/compliance/report/report_test.go b/pkg/compliance/report/report_test.go index b6a1dcc6bcc5..9254b4922207 100644 --- a/pkg/compliance/report/report_test.go +++ b/pkg/compliance/report/report_test.go @@ -57,13 +57,13 @@ func TestBuildComplianceReport(t *testing.T) { "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", "https://avd.aquasec.com/misconfig/ksv001", }, - Status: types.StatusPassed, + Status: types.MisconfStatusPassed, }, { Type: "Kubernetes Security Check", ID: "KSV002", AVDID: "AVD-KSV-9999", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, }, }, @@ -179,7 +179,7 @@ func TestBuildComplianceReport(t *testing.T) { "https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted", "https://avd.aquasec.com/misconfig/ksv001", }, - Status: types.StatusPassed, + Status: types.MisconfStatusPassed, }, }, }, diff --git a/pkg/compliance/report/summary_test.go b/pkg/compliance/report/summary_test.go index c8b9178ba336..1dbf862d59ba 100644 --- a/pkg/compliance/report/summary_test.go +++ b/pkg/compliance/report/summary_test.go @@ -32,7 +32,10 @@ func TestBuildSummary(t *testing.T) { Results: types.Results{ { Misconfigurations: []types.DetectedMisconfiguration{ - {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + { + AVDID: "AVD-KSV012", + Status: types.MisconfStatusFailure, + }, }, }, }, @@ -44,7 +47,10 @@ func TestBuildSummary(t *testing.T) { Results: types.Results{ { Misconfigurations: []types.DetectedMisconfiguration{ - {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + { + AVDID: "AVD-KSV013", + Status: types.MisconfStatusFailure, + }, }, }, }, @@ -86,7 +92,10 @@ func TestBuildSummary(t *testing.T) { Results: types.Results{ { Misconfigurations: []types.DetectedMisconfiguration{ - {AVDID: "AVD-KSV012", Status: types.StatusFailure}, + { + AVDID: "AVD-KSV012", + Status: types.MisconfStatusFailure, + }, }, }, }, @@ -98,7 +107,10 @@ func TestBuildSummary(t *testing.T) { Results: types.Results{ { Misconfigurations: []types.DetectedMisconfiguration{ - {AVDID: "AVD-KSV013", Status: types.StatusFailure}, + { + AVDID: "AVD-KSV013", + Status: types.MisconfStatusFailure, + }, }, }, }, diff --git a/pkg/compliance/report/table_test.go b/pkg/compliance/report/table_test.go index ec880adb518d..839909a94359 100644 --- a/pkg/compliance/report/table_test.go +++ b/pkg/compliance/report/table_test.go @@ -39,7 +39,7 @@ func TestTableWriter_Write(t *testing.T) { Misconfigurations: []types.DetectedMisconfiguration{ { AVDID: "AVD-KSV012", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, }, }, @@ -54,7 +54,7 @@ func TestTableWriter_Write(t *testing.T) { Misconfigurations: []types.DetectedMisconfiguration{ { AVDID: "AVD-KSV013", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, }, }, diff --git a/pkg/compliance/spec/mapper.go b/pkg/compliance/spec/mapper.go index 7a3203868ba2..abcba2a7dbac 100644 --- a/pkg/compliance/spec/mapper.go +++ b/pkg/compliance/spec/mapper.go @@ -45,11 +45,11 @@ func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Sca func misconfigSummary(misconfig types.DetectedMisconfiguration) *types.MisconfSummary { rms := types.MisconfSummary{} switch misconfig.Status { - case types.StatusPassed: + case types.MisconfStatusPassed: rms.Successes = 1 - case types.StatusFailure: + case types.MisconfStatusFailure: rms.Failures = 1 - case types.StatusException: + case types.MisconfStatusException: rms.Exceptions = 1 } return &rms diff --git a/pkg/compliance/spec/mapper_test.go b/pkg/compliance/spec/mapper_test.go index 47d606c6acc8..63d828b9d2c0 100644 --- a/pkg/compliance/spec/mapper_test.go +++ b/pkg/compliance/spec/mapper_test.go @@ -42,15 +42,15 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) { Misconfigurations: []types.DetectedMisconfiguration{ { AVDID: "AVD-KSV012", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, { AVDID: "AVD-KSV013", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, { AVDID: "AVD-1.2.31", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, }, }, @@ -68,7 +68,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) { Misconfigurations: []types.DetectedMisconfiguration{ { AVDID: "AVD-KSV012", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, }, }, @@ -86,7 +86,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) { Misconfigurations: []types.DetectedMisconfiguration{ { AVDID: "AVD-1.2.31", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, }, }, diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index b2b99804c62a..f6813f124933 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/assert" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" - ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/types" ) @@ -28,37 +27,37 @@ var ( Misconfigurations: []types.DetectedMisconfiguration{ { ID: "ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "ID101", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, { ID: "ID102", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, { ID: "ID103", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "CRITICAL", }, { ID: "ID104", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "UNKNOWN", }, { ID: "ID105", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "ID106", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, }, @@ -131,37 +130,37 @@ var ( Misconfigurations: []types.DetectedMisconfiguration{ { ID: "ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "ID101", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, { ID: "ID102", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, { ID: "ID103", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "CRITICAL", }, { ID: "ID104", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "UNKNOWN", }, { ID: "ID105", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "ID106", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, }, @@ -244,7 +243,7 @@ var ( Misconfigurations: []types.DetectedMisconfiguration{ { ID: "ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, }, @@ -281,28 +280,28 @@ var ( Misconfigurations: []types.DetectedMisconfiguration{ { ID: "KSV-ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "KSV-ID101", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, { ID: "KSV-ID102", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, { ID: "KCV-ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "KCV-ID101", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, }, diff --git a/pkg/k8s/writer_test.go b/pkg/k8s/writer_test.go index f8ab555b26c6..46f1167f513f 100644 --- a/pkg/k8s/writer_test.go +++ b/pkg/k8s/writer_test.go @@ -11,7 +11,6 @@ import ( "github.com/stretchr/testify/assert" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" - ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/k8s/report" "github.com/aquasecurity/trivy/pkg/types" ) @@ -38,7 +37,7 @@ var ( Misconfigurations: []types.DetectedMisconfiguration{ { ID: "ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, }, @@ -54,28 +53,28 @@ var ( Misconfigurations: []types.DetectedMisconfiguration{ { ID: "KSV-ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "KSV-ID101", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, { ID: "KSV-ID102", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, { ID: "KCV-ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "KCV-ID101", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, }, @@ -110,37 +109,37 @@ var ( Misconfigurations: []types.DetectedMisconfiguration{ { ID: "ID100", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "ID101", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "MEDIUM", }, { ID: "ID102", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, { ID: "ID103", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "CRITICAL", }, { ID: "ID104", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "UNKNOWN", }, { ID: "ID105", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "LOW", }, { ID: "ID106", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Severity: "HIGH", }, }, diff --git a/pkg/report/sarif_test.go b/pkg/report/sarif_test.go index d5f88d443373..a5c285b34fb8 100644 --- a/pkg/report/sarif_test.go +++ b/pkg/report/sarif_test.go @@ -197,7 +197,7 @@ func TestReportWriter_Sarif(t *testing.T) { Message: "Message", Severity: "HIGH", PrimaryURL: "https://avd.aquasec.com/appshield/ksv001", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, { Type: "Kubernetes Security Check", @@ -206,7 +206,7 @@ func TestReportWriter_Sarif(t *testing.T) { Message: "Message", Severity: "CRITICAL", PrimaryURL: "https://avd.aquasec.com/appshield/ksv002", - Status: types.StatusPassed, + Status: types.MisconfStatusPassed, }, }, }, diff --git a/pkg/report/table/misconfig.go b/pkg/report/table/misconfig.go index e4cef3a441ef..3f9d345c93ea 100644 --- a/pkg/report/table/misconfig.go +++ b/pkg/report/table/misconfig.go @@ -74,7 +74,7 @@ func (r *misconfigRenderer) Render() string { func (r *misconfigRenderer) countSeverities() map[string]int { severityCount := make(map[string]int) for _, misconf := range r.result.Misconfigurations { - if misconf.Status == types.StatusFailure { + if misconf.Status == types.MisconfStatusFailure { severityCount[misconf.Severity]++ } } @@ -110,11 +110,11 @@ func (r *misconfigRenderer) renderSummary(misconf types.DetectedMisconfiguration // show pass/fail/exception unless we are only showing failures if r.includeNonFailures { switch misconf.Status { - case types.StatusPassed: + case types.MisconfStatusPassed: r.printf("%s: ", misconf.Status) - case types.StatusFailure: + case types.MisconfStatusFailure: r.printf("%s: ", misconf.Status) - case types.StatusException: + case types.MisconfStatusException: r.printf("%s: ", misconf.Status) } } @@ -217,7 +217,7 @@ func (r *misconfigRenderer) outputTrace() { } c := green - if misconf.Status == types.StatusFailure { + if misconf.Status == types.MisconfStatusFailure { c = red } diff --git a/pkg/report/writer_test.go b/pkg/report/writer_test.go index 0a9d64b9f1ea..e0e4274cb221 100644 --- a/pkg/report/writer_test.go +++ b/pkg/report/writer_test.go @@ -50,7 +50,7 @@ func TestResults_Failed(t *testing.T) { { Type: "Docker Security Check", ID: "ID-001", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, }, }, }, @@ -67,7 +67,7 @@ func TestResults_Failed(t *testing.T) { { Type: "Docker Security Check", ID: "ID-001", - Status: types.StatusPassed, + Status: types.MisconfStatusPassed, }, }, }, diff --git a/pkg/result/filter.go b/pkg/result/filter.go index 524738043bb2..ed1225506642 100644 --- a/pkg/result/filter.go +++ b/pkg/result/filter.go @@ -212,11 +212,11 @@ func filterLicenses(licenses []types.DetectedLicense, severities, ignoreLicenseN func summarize(status types.MisconfStatus, summary *types.MisconfSummary) { switch status { - case types.StatusFailure: + case types.MisconfStatusFailure: summary.Failures++ - case types.StatusPassed: + case types.MisconfStatusPassed: summary.Successes++ - case types.StatusException: + case types.MisconfStatusException: summary.Exceptions++ } } diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index f76c5c7ab0ea..92db52fe826a 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -229,16 +229,16 @@ func (s Scanner) MisconfsToResults(misconfs []ftypes.Misconfiguration) types.Res var detected []types.DetectedMisconfiguration for _, f := range misconf.Failures { - detected = append(detected, toDetectedMisconfiguration(f, dbTypes.SeverityCritical, types.StatusFailure, misconf.Layer)) + detected = append(detected, toDetectedMisconfiguration(f, dbTypes.SeverityCritical, types.MisconfStatusFailure, misconf.Layer)) } for _, w := range misconf.Warnings { - detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityMedium, types.StatusFailure, misconf.Layer)) + detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityMedium, types.MisconfStatusFailure, misconf.Layer)) } for _, w := range misconf.Successes { - detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.StatusPassed, misconf.Layer)) + detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.MisconfStatusPassed, misconf.Layer)) } for _, w := range misconf.Exceptions { - detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.StatusException, misconf.Layer)) + detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.MisconfStatusException, misconf.Layer)) } results = append(results, types.Result{ diff --git a/pkg/scanner/local/scan_test.go b/pkg/scanner/local/scan_test.go index 2cee7311f73f..6677910ed856 100644 --- a/pkg/scanner/local/scan_test.go +++ b/pkg/scanner/local/scan_test.go @@ -981,7 +981,7 @@ func TestScanner_Scan(t *testing.T) { Message: "something bad", Namespace: "main.kubernetes.id100", Severity: "HIGH", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Layer: ftypes.Layer{ DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", }, @@ -997,7 +997,7 @@ func TestScanner_Scan(t *testing.T) { References: []string{ "https://avd.aquasec.com/misconfig/id200", }, - Status: types.StatusPassed, + Status: types.MisconfStatusPassed, Layer: ftypes.Layer{ DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", }, @@ -1016,7 +1016,7 @@ func TestScanner_Scan(t *testing.T) { Message: "No issues found", Namespace: "main.kubernetes.id300", Severity: "MEDIUM", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, Layer: ftypes.Layer{ DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", }, @@ -1028,7 +1028,7 @@ func TestScanner_Scan(t *testing.T) { Message: "No issues found", Namespace: "main.kubernetes.id100", Severity: "HIGH", - Status: types.StatusException, + Status: types.MisconfStatusException, Layer: ftypes.Layer{ DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", }, @@ -1199,7 +1199,7 @@ func TestScanner_Scan(t *testing.T) { Description: "Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.", Severity: "HIGH", Resolution: "Add 'USER ' line to the Dockerfile", - Status: types.StatusFailure, + Status: types.MisconfStatusFailure, PrimaryURL: "https://avd.aquasec.com/misconfig/ds002", References: []string{"https://avd.aquasec.com/misconfig/ds002"}, CauseMetadata: ftypes.CauseMetadata{ @@ -1219,7 +1219,7 @@ func TestScanner_Scan(t *testing.T) { Description: "When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated.", Severity: "MEDIUM", Resolution: "Add a tag to the image in the 'FROM' statement", - Status: types.StatusPassed, + Status: types.MisconfStatusPassed, CauseMetadata: ftypes.CauseMetadata{ Provider: "Dockerfile", Service: "general", diff --git a/pkg/types/misconfiguration.go b/pkg/types/misconfiguration.go index 29e5828e269d..b857e383efee 100644 --- a/pkg/types/misconfiguration.go +++ b/pkg/types/misconfiguration.go @@ -28,14 +28,14 @@ type DetectedMisconfiguration struct { type MisconfStatus string const ( - // StatusPassed represents successful status - StatusPassed MisconfStatus = "PASS" + // MisconfStatusPassed represents successful status + MisconfStatusPassed MisconfStatus = "PASS" - // StatusFailure represents failure status - StatusFailure MisconfStatus = "FAIL" + // MisconfStatusFailure represents failure status + MisconfStatusFailure MisconfStatus = "FAIL" - // StatusException Passed represents the status of exception - StatusException MisconfStatus = "EXCEPTION" + // MisconfStatusException Passed represents the status of exception + MisconfStatusException MisconfStatus = "EXCEPTION" ) // GetID retrun misconfig ID diff --git a/pkg/types/report.go b/pkg/types/report.go index 9d01a704a081..09b3e3bb1008 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -135,7 +135,7 @@ func (results Results) Failed() bool { return true } for _, m := range r.Misconfigurations { - if m.Status == StatusFailure { + if m.Status == MisconfStatusFailure { return true } } From 96111dae59bcc2da326a30b723e2ddeda2d13210 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:46:03 +0400 Subject: [PATCH 02/24] refactor: add DetectedSecret Signed-off-by: knqyf263 --- pkg/compliance/spec/custom.go | 5 ++--- pkg/compliance/spec/mapper_test.go | 4 ++-- pkg/k8s/report/report_test.go | 2 +- pkg/k8s/writer_test.go | 2 +- pkg/report/sarif_test.go | 2 +- pkg/report/table/secret.go | 12 ++++++------ pkg/report/table/secret_test.go | 12 ++++++++---- pkg/rpc/convert.go | 20 ++++++++++++++++---- pkg/sbom/spdx/marshal_test.go | 2 +- pkg/scanner/local/scan.go | 8 +++++--- pkg/types/report.go | 2 +- pkg/types/secret.go | 9 +++++++++ 12 files changed, 53 insertions(+), 27 deletions(-) create mode 100644 pkg/types/secret.go diff --git a/pkg/compliance/spec/custom.go b/pkg/compliance/spec/custom.go index 700a608d59c2..8e7ed6679340 100644 --- a/pkg/compliance/spec/custom.go +++ b/pkg/compliance/spec/custom.go @@ -4,7 +4,6 @@ import ( "github.com/samber/lo" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" - ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/types" ) @@ -63,8 +62,8 @@ func filterHighSecrets(result types.Result) types.Result { } func filterSecrets(result types.Result, severity dbTypes.Severity) types.Result { - filtered := lo.Filter(result.Secrets, func(vuln ftypes.SecretFinding, _ int) bool { - return vuln.Severity == severity.String() + filtered := lo.Filter(result.Secrets, func(secret types.DetectedSecret, _ int) bool { + return secret.Severity == severity.String() }) return types.Result{ Target: result.Target, diff --git a/pkg/compliance/spec/mapper_test.go b/pkg/compliance/spec/mapper_test.go index 63d828b9d2c0..62050d27ec47 100644 --- a/pkg/compliance/spec/mapper_test.go +++ b/pkg/compliance/spec/mapper_test.go @@ -99,7 +99,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) { result: types.Result{ Target: "target", Class: types.ClassSecret, - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "aws-access-key-id", Category: secret.CategoryAWS, @@ -135,7 +135,7 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) { { Target: "target", Class: types.ClassSecret, - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "aws-access-key-id", Category: secret.CategoryAWS, diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index f6813f124933..311fc650832d 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -257,7 +257,7 @@ var ( Name: "lua", Results: types.Results{ { - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "secret1", Severity: "CRITICAL", diff --git a/pkg/k8s/writer_test.go b/pkg/k8s/writer_test.go index 46f1167f513f..11abcdb35a21 100644 --- a/pkg/k8s/writer_test.go +++ b/pkg/k8s/writer_test.go @@ -87,7 +87,7 @@ var ( Name: "lua", Results: types.Results{ { - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "secret1", Severity: "CRITICAL", diff --git a/pkg/report/sarif_test.go b/pkg/report/sarif_test.go index a5c285b34fb8..9968fafbef34 100644 --- a/pkg/report/sarif_test.go +++ b/pkg/report/sarif_test.go @@ -338,7 +338,7 @@ func TestReportWriter_Sarif(t *testing.T) { { Target: "library/test", Class: types.ClassSecret, - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "aws-secret-access-key", Category: "AWS", diff --git a/pkg/report/table/secret.go b/pkg/report/table/secret.go index 30833dc8336d..1a647a4f55fb 100644 --- a/pkg/report/table/secret.go +++ b/pkg/report/table/secret.go @@ -9,19 +9,19 @@ import ( "github.com/aquasecurity/tml" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" - "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/types" ) type secretRenderer struct { w *bytes.Buffer target string - secrets []types.SecretFinding + secrets []types.DetectedSecret severities []dbTypes.Severity width int ansi bool } -func NewSecretRenderer(target string, secrets []types.SecretFinding, ansi bool, severities []dbTypes.Severity) *secretRenderer { +func NewSecretRenderer(target string, secrets []types.DetectedSecret, ansi bool, severities []dbTypes.Severity) *secretRenderer { width, _, err := term.GetSize(0) if err != nil || width == 0 { width = 40 @@ -76,13 +76,13 @@ func (r *secretRenderer) printSingleDivider() { r.printf("%s\r\n", strings.Repeat("─", r.width)) } -func (r *secretRenderer) renderSingle(secret types.SecretFinding) { +func (r *secretRenderer) renderSingle(secret types.DetectedSecret) { r.renderSummary(secret) r.renderCode(secret) r.printf("\r\n\r\n") } -func (r *secretRenderer) renderSummary(secret types.SecretFinding) { +func (r *secretRenderer) renderSummary(secret types.DetectedSecret) { // severity switch secret.Severity { @@ -108,7 +108,7 @@ func (r *secretRenderer) renderSummary(secret types.SecretFinding) { r.printSingleDivider() } -func (r *secretRenderer) renderCode(secret types.SecretFinding) { +func (r *secretRenderer) renderCode(secret types.DetectedSecret) { // highlight code if we can... if lines := secret.Code.Lines; len(lines) > 0 { diff --git a/pkg/report/table/secret_test.go b/pkg/report/table/secret_test.go index 3af1b71dde43..92011f8d17ff 100644 --- a/pkg/report/table/secret_test.go +++ b/pkg/report/table/secret_test.go @@ -1,6 +1,7 @@ package table_test import ( + "github.com/aquasecurity/trivy/pkg/types" "strings" "testing" @@ -15,12 +16,12 @@ func TestSecretRenderer(t *testing.T) { tests := []struct { name string - input []ftypes.SecretFinding + input []types.DetectedSecret want string }{ { name: "single line", - input: []ftypes.SecretFinding{ + input: []types.DetectedSecret{ { RuleID: "rule-id", Category: ftypes.SecretRuleCategory("category"), @@ -62,7 +63,7 @@ this is a title }, { name: "multiple line", - input: []ftypes.SecretFinding{ + input: []types.DetectedSecret{ { RuleID: "rule-id", Category: ftypes.SecretRuleCategory("category"), @@ -135,7 +136,10 @@ this is a title for _, test := range tests { t.Run(test.name, func(t *testing.T) { - renderer := table.NewSecretRenderer("my-file", test.input, false, []dbTypes.Severity{dbTypes.SeverityHigh, dbTypes.SeverityMedium}) + renderer := table.NewSecretRenderer("my-file", test.input, false, []dbTypes.Severity{ + dbTypes.SeverityHigh, + dbTypes.SeverityMedium, + }) assert.Equal(t, test.want, strings.ReplaceAll(renderer.Render(), "\r\n", "\n")) }) } diff --git a/pkg/rpc/convert.go b/pkg/rpc/convert.go index 7e2a09f2c7da..2bf7ba3e5d96 100644 --- a/pkg/rpc/convert.go +++ b/pkg/rpc/convert.go @@ -393,7 +393,7 @@ func ConvertFromRPCResults(rpcResults []*scanner.Result) []types.Result { Type: ftypes.TargetType(result.Type), Packages: ConvertFromRPCPkgs(result.Packages), CustomResources: ConvertFromRPCCustomResources(result.CustomResources), - Secrets: ConvertFromRPCSecretFindings(result.Secrets), + Secrets: ConvertFromRPCDetectedSecrets(result.Secrets), Licenses: ConvertFromRPCDetectedLicenses(result.Licenses), }) } @@ -461,6 +461,15 @@ func ConvertFromRPCCode(rpcCode *common.Code) ftypes.Code { } } +func ConvertFromRPCDetectedSecrets(rpcFindings []*common.SecretFinding) []types.DetectedSecret { + if len(rpcFindings) == 0 { + return nil + } + return lo.Map(ConvertFromRPCSecretFindings(rpcFindings), func(s ftypes.SecretFinding, _ int) types.DetectedSecret { + return types.DetectedSecret(s) + }) +} + func ConvertFromRPCSecretFindings(rpcFindings []*common.SecretFinding) []ftypes.SecretFinding { var findings []ftypes.SecretFinding for _, finding := range rpcFindings { @@ -913,16 +922,19 @@ func ConvertToMissingBlobsRequest(imageID string, layerIDs []string) *cache.Miss func ConvertToRPCScanResponse(results types.Results, fos ftypes.OS) *scanner.ScanResponse { var rpcResults []*scanner.Result for _, result := range results { + secretFindings := lo.Map(result.Secrets, func(s types.DetectedSecret, _ int) ftypes.SecretFinding { + return ftypes.SecretFinding(s) + }) rpcResults = append(rpcResults, &scanner.Result{ Target: result.Target, Class: string(result.Class), Type: string(result.Type), + Packages: ConvertToRPCPkgs(result.Packages), Vulnerabilities: ConvertToRPCVulns(result.Vulnerabilities), Misconfigurations: ConvertToRPCMisconfs(result.Misconfigurations), - Packages: ConvertToRPCPkgs(result.Packages), - CustomResources: ConvertToRPCCustomResources(result.CustomResources), - Secrets: ConvertToRPCSecretFindings(result.Secrets), + Secrets: ConvertToRPCSecretFindings(secretFindings), Licenses: ConvertToRPCLicenses(result.Licenses), + CustomResources: ConvertToRPCCustomResources(result.CustomResources), }) } diff --git a/pkg/sbom/spdx/marshal_test.go b/pkg/sbom/spdx/marshal_test.go index 616108886264..a66a1d5ee46c 100644 --- a/pkg/sbom/spdx/marshal_test.go +++ b/pkg/sbom/spdx/marshal_test.go @@ -885,7 +885,7 @@ func TestMarshaler_Marshal(t *testing.T) { { Target: "key.pem", Class: types.ClassSecret, - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "private-key", Category: "AsymmetricPrivateKey", diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index 92db52fe826a..e4025f17945c 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -266,9 +266,11 @@ func (s Scanner) secretsToResults(secrets []ftypes.Secret, options types.ScanOpt log.Logger.Debugf("Secret file: %s", secret.FilePath) results = append(results, types.Result{ - Target: secret.FilePath, - Class: types.ClassSecret, - Secrets: secret.Findings, + Target: secret.FilePath, + Class: types.ClassSecret, + Secrets: lo.Map(secret.Findings, func(secret ftypes.SecretFinding, index int) types.DetectedSecret { + return types.DetectedSecret(secret) + }), }) } return results diff --git a/pkg/types/report.go b/pkg/types/report.go index 09b3e3bb1008..94f2a4b7ad6e 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -108,7 +108,7 @@ type Result struct { Vulnerabilities []DetectedVulnerability `json:"Vulnerabilities,omitempty"` MisconfSummary *MisconfSummary `json:"MisconfSummary,omitempty"` Misconfigurations []DetectedMisconfiguration `json:"Misconfigurations,omitempty"` - Secrets []ftypes.SecretFinding `json:"Secrets,omitempty"` + Secrets []DetectedSecret `json:"Secrets,omitempty"` Licenses []DetectedLicense `json:"Licenses,omitempty"` CustomResources []ftypes.CustomResource `json:"CustomResources,omitempty"` } diff --git a/pkg/types/secret.go b/pkg/types/secret.go new file mode 100644 index 000000000000..4e86059575e1 --- /dev/null +++ b/pkg/types/secret.go @@ -0,0 +1,9 @@ +package types + +import ( + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" +) + +type DetectedSecret ftypes.SecretFinding + +func (DetectedSecret) findingType() FindingType { return FindingTypeSecret } From e25f76cf354bfee14192e4a8584602cc2cc3a5aa Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:47:22 +0400 Subject: [PATCH 03/24] feat: add a struct for modified findings Signed-off-by: knqyf263 --- pkg/types/finding.go | 47 +++++++++++++++++++++++++++++++++++ pkg/types/license.go | 2 ++ pkg/types/misconfiguration.go | 5 +--- pkg/types/report.go | 5 ++++ pkg/types/vulnerability.go | 5 +--- 5 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 pkg/types/finding.go diff --git a/pkg/types/finding.go b/pkg/types/finding.go new file mode 100644 index 000000000000..9e194b8e6b74 --- /dev/null +++ b/pkg/types/finding.go @@ -0,0 +1,47 @@ +package types + +type FindingType string +type FindingStatus string + +const ( + FindingTypeVulnerability FindingType = "vulnerability" + FindingTypeMisconfiguration FindingType = "misconfiguration" + FindingTypeSecret FindingType = "secret" + FindingTypeLicense FindingType = "license" + + FindingStatusIgnored FindingStatus = "ignored" // Trivy + FindingStatusUnknown FindingStatus = "unknown" // Trivy + FindingStatusNotAffected FindingStatus = "not_affected" // VEX + FindingStatusAffected FindingStatus = "affected" // VEX + FindingStatusFixed FindingStatus = "fixed" // VEX + FindingStatusUnderInvestigation FindingStatus = "under_investigation" // VEX +) + +// Finding represents one of the findings that Trivy can detect, +// such as vulnerabilities, misconfigurations, secrets, and licenses. +type finding interface { + findingType() FindingType +} + +// ModifiedFinding represents a security finding that has been modified by an external source, +// such as .trivyignore and VEX. Currently, it is primarily used to account for vulnerabilities +// that are ignored via .trivyignore or identified as not impactful through VEX. +// However, it is planned to also store vulnerabilities whose severity has been adjusted by VEX, +// or that have been detected through Wasm modules in the future. +type ModifiedFinding struct { + Type FindingType + Status FindingStatus + Statement string + Source string + Finding finding // one of findings +} + +func NewModifiedFinding(f finding, status FindingStatus, statement, source string) ModifiedFinding { + return ModifiedFinding{ + Type: f.findingType(), + Status: status, + Statement: statement, + Source: source, + Finding: f, + } +} diff --git a/pkg/types/license.go b/pkg/types/license.go index 5cf94a9e2ac2..baca0328a457 100644 --- a/pkg/types/license.go +++ b/pkg/types/license.go @@ -29,3 +29,5 @@ type DetectedLicense struct { // Link is a SPDX link of the license Link string } + +func (DetectedLicense) findingType() FindingType { return FindingTypeLicense } diff --git a/pkg/types/misconfiguration.go b/pkg/types/misconfiguration.go index b857e383efee..ebd21a23d36b 100644 --- a/pkg/types/misconfiguration.go +++ b/pkg/types/misconfiguration.go @@ -38,7 +38,4 @@ const ( MisconfStatusException MisconfStatus = "EXCEPTION" ) -// GetID retrun misconfig ID -func (mc *DetectedMisconfiguration) GetID() string { - return mc.AVDID -} +func (DetectedMisconfiguration) findingType() FindingType { return FindingTypeMisconfiguration } diff --git a/pkg/types/report.go b/pkg/types/report.go index 94f2a4b7ad6e..4db84b6a6084 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -111,6 +111,11 @@ type Result struct { Secrets []DetectedSecret `json:"Secrets,omitempty"` Licenses []DetectedLicense `json:"Licenses,omitempty"` CustomResources []ftypes.CustomResource `json:"CustomResources,omitempty"` + + // ModifiedFindings holds a list of findings that have been modified from their original state. + // This can include vulnerabilities that have been marked as ignored, not affected, or have had + // their severity adjusted. It is currently available only in the table format. + ModifiedFindings []ModifiedFinding `json:"-"` } func (r *Result) IsEmpty() bool { diff --git a/pkg/types/vulnerability.go b/pkg/types/vulnerability.go index 7e0d942cfd92..693b212d077d 100644 --- a/pkg/types/vulnerability.go +++ b/pkg/types/vulnerability.go @@ -30,10 +30,7 @@ type DetectedVulnerability struct { types.Vulnerability } -// GetID retrun Vulnerability ID -func (vuln *DetectedVulnerability) GetID() string { - return vuln.VulnerabilityID -} +func (DetectedVulnerability) findingType() FindingType { return FindingTypeVulnerability } // BySeverity implements sort.Interface based on the Severity field. type BySeverity []DetectedVulnerability From 4ecc6f3a9c7be537120641650b49c69e7d202ad7 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:48:56 +0400 Subject: [PATCH 04/24] feat: include modified findings in results Signed-off-by: knqyf263 --- pkg/result/filter.go | 149 +++++++++++++++++++++++++------------------ pkg/result/ignore.go | 44 +++++++++++-- pkg/vex/csaf.go | 40 +++++++----- pkg/vex/cyclonedx.go | 38 ++++++----- pkg/vex/openvex.go | 37 +++++++---- pkg/vex/status.go | 11 ---- pkg/vex/vex.go | 2 +- pkg/vex/vex_test.go | 7 +- 8 files changed, 203 insertions(+), 125 deletions(-) delete mode 100644 pkg/vex/status.go diff --git a/pkg/result/filter.go b/pkg/result/filter.go index ed1225506642..5454ebe69228 100644 --- a/pkg/result/filter.go +++ b/pkg/result/filter.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os" + "path/filepath" "sort" "github.com/open-policy-agent/opa/rego" @@ -13,7 +14,6 @@ import ( "golang.org/x/xerrors" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" - ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/vex" ) @@ -40,7 +40,7 @@ func Filter(ctx context.Context, report types.Report, opt FilterOption) error { return xerrors.Errorf("VEX error: %w", err) } - ignoreConf, err := getIgnoredFindings(ctx, opt.IgnoreFile) + ignoreConf, err := parseIgnoreFile(ctx, opt.IgnoreFile) if err != nil { return xerrors.Errorf("%s error: %w", opt.IgnoreFile, err) } @@ -60,29 +60,17 @@ func FilterResult(ctx context.Context, result *types.Result, ignoreConf IgnoreCo return s.String() }) - filteredVulns := filterVulnerabilities(result, severities, opt.IgnoreStatuses, ignoreConf.Vulnerabilities) - misconfSummary, filteredMisconfs := filterMisconfigurations(result, severities, opt.IncludeNonFailures, ignoreConf.Misconfigurations) - result.Secrets = filterSecrets(result, severities, ignoreConf.Secrets) - result.Licenses = filterLicenses(result.Licenses, severities, opt.IgnoreLicenses, ignoreConf.Licenses) + filterVulnerabilities(result, severities, opt.IgnoreStatuses, ignoreConf) + filterMisconfigurations(result, severities, opt.IncludeNonFailures, ignoreConf) + filterSecrets(result, severities, ignoreConf) + filterLicenses(result, severities, opt.IgnoreLicenses, ignoreConf) - var ignoredMisconfs int if opt.PolicyFile != "" { - var err error - var ignored int - filteredVulns, filteredMisconfs, ignored, err = applyPolicy(ctx, filteredVulns, filteredMisconfs, opt.PolicyFile) - if err != nil { + if err := applyPolicy(ctx, result, opt.PolicyFile); err != nil { return xerrors.Errorf("failed to apply the policy: %w", err) } - ignoredMisconfs += ignored - } - sort.Sort(types.BySeverity(filteredVulns)) - - result.Vulnerabilities = filteredVulns - result.MisconfSummary = misconfSummary - if result.MisconfSummary != nil { - result.MisconfSummary.Exceptions += ignoredMisconfs } - result.Misconfigurations = filteredMisconfs + sort.Sort(types.BySeverity(result.Vulnerabilities)) return nil } @@ -102,15 +90,13 @@ func filterByVEX(report types.Report, opt FilterOption) error { if len(result.Vulnerabilities) == 0 { continue } - report.Results[i].Vulnerabilities = vexDoc.Filter(result.Vulnerabilities) + vexDoc.Filter(&report.Results[i]) } return nil } -func filterVulnerabilities(result *types.Result, severities []string, ignoreStatuses []dbTypes.Status, - ignoreFindings IgnoreFindings) []types.DetectedVulnerability { +func filterVulnerabilities(result *types.Result, severities []string, ignoreStatuses []dbTypes.Status, ignoreConfig IgnoreConfig) { uniqVulns := make(map[string]types.DetectedVulnerability) - for _, vuln := range result.Vulnerabilities { if vuln.Severity == "" { vuln.Severity = dbTypes.SeverityUnknown.String() @@ -123,9 +109,12 @@ func filterVulnerabilities(result *types.Result, severities []string, ignoreStat // Filter by status case slices.Contains(ignoreStatuses, vuln.Status): continue + } + // Filter by ignore file - case ignoreFindings.Match(result.Target, vuln.VulnerabilityID) || - ignoreFindings.Match(vuln.PkgPath, vuln.VulnerabilityID): + if f := ignoreConfig.MatchVulnerability(vuln.VulnerabilityID, result.Target, vuln.PkgPath); f != nil { + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(vuln, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath)) continue } @@ -136,78 +125,99 @@ func filterVulnerabilities(result *types.Result, severities []string, ignoreStat } uniqVulns[key] = vuln } - if len(uniqVulns) == 0 { - return nil + + // Override the detected vulnerabilities + result.Vulnerabilities = maps.Values(uniqVulns) + if len(result.Vulnerabilities) == 0 { + result.Vulnerabilities = nil } - return maps.Values(uniqVulns) } func filterMisconfigurations(result *types.Result, severities []string, includeNonFailures bool, - ignoreMisconfs IgnoreFindings) (*types.MisconfSummary, []types.DetectedMisconfiguration) { + ignoreConfig IgnoreConfig) { var filtered []types.DetectedMisconfiguration - summary := new(types.MisconfSummary) + result.MisconfSummary = new(types.MisconfSummary) for _, misconf := range result.Misconfigurations { + // Filter by severity if !slices.Contains(severities, misconf.Severity) { - // Filter by severity continue - } else if ignoreMisconfs.Match(result.Target, misconf.ID) || ignoreMisconfs.Match(result.Target, misconf.AVDID) { - // Filter misconfigurations by ignore file - summary.Exceptions++ + } + + // Filter by ignore file + if f := ignoreConfig.MatchMisconfiguration(misconf.ID, misconf.AVDID, result.Target); f != nil { + result.MisconfSummary.Exceptions++ + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(misconf, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath)) continue } // Count successes, failures, and exceptions - summarize(misconf.Status, summary) + summarize(misconf.Status, result.MisconfSummary) - if misconf.Status != types.StatusFailure && !includeNonFailures { + if misconf.Status != types.MisconfStatusFailure && !includeNonFailures { continue } filtered = append(filtered, misconf) } - if summary.Empty() { - return nil, nil + result.Misconfigurations = filtered + if result.MisconfSummary.Empty() { + result.Misconfigurations = nil + result.MisconfSummary = nil } - - return summary, filtered } -func filterSecrets(result *types.Result, severities []string, ignoreFindings IgnoreFindings) []ftypes.SecretFinding { - var filtered []ftypes.SecretFinding +func filterSecrets(result *types.Result, severities []string, ignoreConfig IgnoreConfig) { + var filtered []types.DetectedSecret for _, secret := range result.Secrets { if !slices.Contains(severities, secret.Severity) { // Filter by severity continue - } else if ignoreFindings.Match(result.Target, secret.RuleID) { + } else if f := ignoreConfig.MatchSecret(secret.RuleID, result.Target); f != nil { // Filter by ignore file + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(secret, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath)) continue } filtered = append(filtered, secret) } - return filtered + result.Secrets = filtered } -func filterLicenses(licenses []types.DetectedLicense, severities, ignoreLicenseNames []string, ignoreFindings IgnoreFindings) []types.DetectedLicense { +func filterLicenses(result *types.Result, severities, ignoreLicenseNames []string, ignoreConfig IgnoreConfig) { // Merge ignore license names into ignored findings + var ignoreLicenses IgnoreFindings for _, licenseName := range ignoreLicenseNames { - ignoreFindings = append(ignoreFindings, IgnoreFinding{ + ignoreLicenses = append(ignoreLicenses, IgnoreFinding{ ID: licenseName, }) } var filtered []types.DetectedLicense - for _, l := range licenses { + for _, l := range result.Licenses { + // Filter by severity if !slices.Contains(severities, l.Severity) { - // Filter by severity continue - } else if ignoreFindings.Match(l.FilePath, l.Name) { - // Filter by ignore file or ignore license names + } + + // Filter by `--ignored-licenses` + if f := ignoreLicenses.Match(l.Name, l.FilePath); f != nil { + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(l, types.FindingStatusIgnored, "", "--ignored-licenses")) + continue + } + + // Filter by ignore file + if f := ignoreConfig.MatchLicense(l.Name, l.FilePath); f != nil { + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(l, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath)) continue } + filtered = append(filtered, l) } - return filtered + result.Licenses = filtered } func summarize(status types.MisconfStatus, summary *types.MisconfSummary) { @@ -221,11 +231,11 @@ func summarize(status types.MisconfStatus, summary *types.MisconfSummary) { } } -func applyPolicy(ctx context.Context, vulns []types.DetectedVulnerability, misconfs []types.DetectedMisconfiguration, - policyFile string) ([]types.DetectedVulnerability, []types.DetectedMisconfiguration, int, error) { +func applyPolicy(ctx context.Context, result *types.Result, policyFile string) error { + policyFile = filepath.Clean(policyFile) policy, err := os.ReadFile(policyFile) if err != nil { - return nil, nil, 0, xerrors.Errorf("unable to read the policy file: %w", err) + return xerrors.Errorf("unable to read the policy file: %w", err) } query, err := rego.New( @@ -234,38 +244,51 @@ func applyPolicy(ctx context.Context, vulns []types.DetectedVulnerability, misco rego.Module("trivy.rego", string(policy)), ).PrepareForEval(ctx) if err != nil { - return nil, nil, 0, xerrors.Errorf("unable to prepare for eval: %w", err) + return xerrors.Errorf("unable to prepare for eval: %w", err) } // Vulnerabilities var filteredVulns []types.DetectedVulnerability - for _, vuln := range vulns { + for _, vuln := range result.Vulnerabilities { ignored, err := evaluate(ctx, query, vuln) if err != nil { - return nil, nil, 0, err + return err } if ignored { + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(vuln, types.FindingStatusIgnored, "Filtered by Rego", policyFile)) continue } filteredVulns = append(filteredVulns, vuln) } + result.Vulnerabilities = filteredVulns // Misconfigurations - var ignoredMisconfs int var filteredMisconfs []types.DetectedMisconfiguration - for _, misconf := range misconfs { + for _, misconf := range result.Misconfigurations { ignored, err := evaluate(ctx, query, misconf) if err != nil { - return nil, nil, 0, err + return err } if ignored { - ignoredMisconfs++ + result.MisconfSummary.Exceptions++ + switch misconf.Status { + case types.MisconfStatusFailure: + result.MisconfSummary.Failures-- + case types.MisconfStatusPassed: + result.MisconfSummary.Successes-- + } + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(misconf, types.FindingStatusIgnored, "Filtered by Rego", policyFile)) continue } filteredMisconfs = append(filteredMisconfs, misconf) } - return filteredVulns, filteredMisconfs, ignoredMisconfs, nil + result.Misconfigurations = filteredMisconfs + + return nil } + func evaluate(ctx context.Context, query rego.PreparedEvalQuery, input interface{}) (bool, error) { results, err := query.Eval(ctx, rego.EvalInput(input)) if err != nil { diff --git a/pkg/result/ignore.go b/pkg/result/ignore.go index ee7fef0d6ce7..f627eed95957 100644 --- a/pkg/result/ignore.go +++ b/pkg/result/ignore.go @@ -43,7 +43,7 @@ type IgnoreFinding struct { type IgnoreFindings []IgnoreFinding -func (f *IgnoreFindings) Match(path, id string) bool { +func (f *IgnoreFindings) Match(id, path string) *IgnoreFinding { for _, finding := range *f { if id != finding.ID { continue @@ -53,10 +53,10 @@ func (f *IgnoreFindings) Match(path, id string) bool { continue } log.Logger.Debugw("Ignored", log.String("id", id), log.String("path", path)) - return true + return &finding } - return false + return nil } func pathMatch(path string, patterns []string) bool { @@ -96,13 +96,48 @@ func (f *IgnoreFindings) Filter(ctx context.Context) { // IgnoreConfig represents the structure of .trivyignore.yaml. type IgnoreConfig struct { + FilePath string Vulnerabilities IgnoreFindings `yaml:"vulnerabilities"` Misconfigurations IgnoreFindings `yaml:"misconfigurations"` Secrets IgnoreFindings `yaml:"secrets"` Licenses IgnoreFindings `yaml:"licenses"` } -func getIgnoredFindings(ctx context.Context, ignoreFile string) (IgnoreConfig, error) { +func (c *IgnoreConfig) MatchVulnerability(vulnID, filePath, pkgPath string) *IgnoreFinding { + paths := []string{ + filePath, + pkgPath, + } + for _, p := range paths { + if f := c.Vulnerabilities.Match(vulnID, p); f != nil { + return f + } + } + return nil +} + +func (c *IgnoreConfig) MatchMisconfiguration(misconfID, avdID, filePath string) *IgnoreFinding { + ids := []string{ + misconfID, + avdID, + } + for _, id := range ids { + if f := c.Misconfigurations.Match(id, filePath); f != nil { + return f + } + } + return nil +} + +func (c *IgnoreConfig) MatchSecret(secretID, filePath string) *IgnoreFinding { + return c.Secrets.Match(secretID, filePath) +} + +func (c *IgnoreConfig) MatchLicense(licenseID, filePath string) *IgnoreFinding { + return c.Licenses.Match(licenseID, filePath) +} + +func parseIgnoreFile(ctx context.Context, ignoreFile string) (IgnoreConfig, error) { var conf IgnoreConfig if _, err := os.Stat(ignoreFile); errors.Is(err, fs.ErrNotExist) { // .trivyignore doesn't necessarily exist @@ -132,6 +167,7 @@ func getIgnoredFindings(ctx context.Context, ignoreFile string) (IgnoreConfig, e conf.Misconfigurations.Filter(ctx) conf.Secrets.Filter(ctx) conf.Licenses.Filter(ctx) + conf.FilePath = filepath.Clean(ignoreFile) return conf, nil } diff --git a/pkg/vex/csaf.go b/pkg/vex/csaf.go index 87684064b9d4..f70f626b6702 100644 --- a/pkg/vex/csaf.go +++ b/pkg/vex/csaf.go @@ -23,8 +23,8 @@ func newCSAF(advisory csaf.Advisory) VEX { } } -func (v *CSAF) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulnerability { - return lo.Filter(vulns, func(vuln types.DetectedVulnerability, _ int) bool { +func (v *CSAF) Filter(result *types.Result) { + result.Vulnerabilities = lo.Filter(result.Vulnerabilities, func(vuln types.DetectedVulnerability, _ int) bool { found, ok := lo.Find(v.advisory.Vulnerabilities, func(item *csaf.Vulnerability) bool { return string(*item.CVE) == vuln.VulnerabilityID }) @@ -32,31 +32,29 @@ func (v *CSAF) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulne return true } - return v.affected(found, vuln.PkgIdentifier.PURL) + if status := v.match(found, vuln.PkgIdentifier.PURL); status != "" { + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(vuln, status, statement(found), "CSAF VEX")) + return false + } + return true }) } -func (v *CSAF) affected(vuln *csaf.Vulnerability, pkgURL *packageurl.PackageURL) bool { +func (v *CSAF) match(vuln *csaf.Vulnerability, pkgURL *packageurl.PackageURL) types.FindingStatus { if pkgURL == nil || vuln.ProductStatus == nil { - return true + return "" } - var status Status + var status types.FindingStatus switch { case v.matchPURL(vuln.ProductStatus.KnownNotAffected, pkgURL): - status = StatusNotAffected + status = types.FindingStatusNotAffected case v.matchPURL(vuln.ProductStatus.Fixed, pkgURL): - status = StatusFixed - } - - if status != "" { - v.logger.Infow("Filtered out the detected vulnerability", - zap.String("vulnerability-id", string(*vuln.CVE)), - zap.String("status", string(status))) - return false + status = types.FindingStatusFixed } - return true + return status } // matchPURL returns true if the given PackageURL is found in the ProductTree. @@ -83,3 +81,13 @@ func (v *CSAF) matchPURL(products *csaf.Products, pkgURL *packageurl.PackageURL) return false } + +func statement(vuln *csaf.Vulnerability) string { + threat, ok := lo.Find(vuln.Threats, func(threat *csaf.Threat) bool { + return lo.FromPtr(threat.Category) == csaf.CSAFThreatCategoryImpact + }) + if !ok { + return "" + } + return lo.FromPtr(threat.Details) +} diff --git a/pkg/vex/cyclonedx.go b/pkg/vex/cyclonedx.go index dbe65b5820a8..5b9db00d13c7 100644 --- a/pkg/vex/cyclonedx.go +++ b/pkg/vex/cyclonedx.go @@ -19,8 +19,8 @@ type CycloneDX struct { type Statement struct { VulnerabilityID string Affects []string - Status Status - Justification string // TODO: define a type + Status types.FindingStatus + Justification string } func newCycloneDX(cdxSBOM *ftypes.CycloneDX, vex *cdx.BOM) *CycloneDX { @@ -45,15 +45,20 @@ func newCycloneDX(cdxSBOM *ftypes.CycloneDX, vex *cdx.BOM) *CycloneDX { } } -func (v *CycloneDX) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulnerability { - return lo.Filter(vulns, func(vuln types.DetectedVulnerability, _ int) bool { +func (v *CycloneDX) Filter(result *types.Result) { + result.Vulnerabilities = lo.Filter(result.Vulnerabilities, func(vuln types.DetectedVulnerability, _ int) bool { stmt, ok := lo.Find(v.statements, func(item Statement) bool { return item.VulnerabilityID == vuln.VulnerabilityID }) if !ok { return true } - return v.affected(vuln, stmt) + if !v.affected(vuln, stmt) { + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(vuln, stmt.Status, stmt.Justification, "CycloneDX VEX")) + return false + } + return true }) } @@ -66,29 +71,32 @@ func (v *CycloneDX) affected(vuln types.DetectedVulnerability, stmt Statement) b continue } if v.sbom.SerialNumber != link.SerialNumber() || v.sbom.Version != link.Version() { - v.logger.Warnw("URN doesn't match with SBOM", zap.String("serial number", link.SerialNumber()), + v.logger.Warnw("URN doesn't match with SBOM", + zap.String("serial number", link.SerialNumber()), zap.Int("version", link.Version())) continue } - if vuln.PkgIdentifier.Match(link.Reference()) && (stmt.Status == StatusNotAffected || stmt.Status == StatusFixed) { - v.logger.Infow("Filtered out the detected vulnerability", zap.String("vulnerability-id", vuln.VulnerabilityID), - zap.String("status", string(stmt.Status)), zap.String("justification", stmt.Justification)) + if vuln.PkgIdentifier.Match(link.Reference()) && (stmt.Status == types.FindingStatusNotAffected || stmt.Status == types.FindingStatusFixed) { + v.logger.Infow("Filtered out the detected vulnerability", + zap.String("vulnerability-id", vuln.VulnerabilityID), + zap.String("status", string(stmt.Status)), + zap.String("justification", stmt.Justification)) return false } } return true } -func cdxStatus(s cdx.ImpactAnalysisState) Status { +func cdxStatus(s cdx.ImpactAnalysisState) types.FindingStatus { switch s { case cdx.IASResolved, cdx.IASResolvedWithPedigree: - return StatusFixed + return types.FindingStatusFixed case cdx.IASExploitable: - return StatusAffected + return types.FindingStatusAffected case cdx.IASInTriage: - return StatusUnderInvestigation + return types.FindingStatusUnderInvestigation case cdx.IASFalsePositive, cdx.IASNotAffected: - return StatusNotAffected + return types.FindingStatusNotAffected } - return StatusUnknown + return types.FindingStatusUnknown } diff --git a/pkg/vex/openvex.go b/pkg/vex/openvex.go index 796439291b95..24e2bb6cca9c 100644 --- a/pkg/vex/openvex.go +++ b/pkg/vex/openvex.go @@ -3,31 +3,27 @@ package vex import ( openvex "github.com/openvex/go-vex/pkg/vex" "github.com/samber/lo" - "go.uber.org/zap" - "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" ) type OpenVEX struct { - vex openvex.VEX - logger *zap.SugaredLogger + vex openvex.VEX } func newOpenVEX(vex openvex.VEX) VEX { return &OpenVEX{ - vex: vex, - logger: log.Logger.With(zap.String("VEX format", "OpenVEX")), + vex: vex, } } -func (v *OpenVEX) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulnerability { - return lo.Filter(vulns, func(vuln types.DetectedVulnerability, _ int) bool { - var stmts []openvex.Statement - if vuln.PkgIdentifier.PURL != nil { - matchedStmts := v.vex.Matches(vuln.VulnerabilityID, vuln.PkgIdentifier.PURL.String(), nil) - stmts = append(stmts, matchedStmts...) +func (v *OpenVEX) Filter(result *types.Result) { + result.Vulnerabilities = lo.Filter(result.Vulnerabilities, func(vuln types.DetectedVulnerability, _ int) bool { + if vuln.PkgIdentifier.PURL == nil { + return true } + + stmts := v.vex.Matches(vuln.VulnerabilityID, vuln.PkgIdentifier.PURL.String(), nil) if len(stmts) == 0 { return true } @@ -37,10 +33,23 @@ func (v *OpenVEX) Filter(vulns []types.DetectedVulnerability) []types.DetectedVu // cf. https://github.com/openvex/spec/blob/fa5ba0c0afedb008dc5ebad418548cacf16a3ca7/OPENVEX-SPEC.md#the-vex-statement stmt := stmts[len(stmts)-1] if stmt.Status == openvex.StatusNotAffected || stmt.Status == openvex.StatusFixed { - v.logger.Infow("Filtered out the detected vulnerability", zap.String("vulnerability-id", vuln.VulnerabilityID), - zap.String("status", string(stmt.Status)), zap.String("justification", string(stmt.Justification))) + result.ModifiedFindings = append(result.ModifiedFindings, + types.NewModifiedFinding(vuln, findingStatus(stmt.Status), string(stmt.Justification), "OpenVEX")) return false } return true }) } + +func findingStatus(status openvex.Status) types.FindingStatus { + switch status { + case openvex.StatusNotAffected: + return types.FindingStatusNotAffected + case openvex.StatusFixed: + return types.FindingStatusFixed + case openvex.StatusUnderInvestigation: + return types.FindingStatusUnderInvestigation + default: + return types.FindingStatusUnknown + } +} diff --git a/pkg/vex/status.go b/pkg/vex/status.go deleted file mode 100644 index dee810fd99f0..000000000000 --- a/pkg/vex/status.go +++ /dev/null @@ -1,11 +0,0 @@ -package vex - -type Status string - -const ( - StatusNotAffected Status = "not_affected" - StatusAffected Status = "affected" - StatusFixed Status = "fixed" - StatusUnderInvestigation Status = "under_investigation" - StatusUnknown Status = "unknown" -) diff --git a/pkg/vex/vex.go b/pkg/vex/vex.go index 644b00d62b3a..61a41a960246 100644 --- a/pkg/vex/vex.go +++ b/pkg/vex/vex.go @@ -20,7 +20,7 @@ import ( // Note: This is in the experimental stage and does not yet support many specifications. // The implementation may change significantly. type VEX interface { - Filter([]types.DetectedVulnerability) []types.DetectedVulnerability + Filter(*types.Result) } func New(filePath string, report types.Report) (VEX, error) { diff --git a/pkg/vex/vex_test.go b/pkg/vex/vex_test.go index 004a0d14d842..80bca72f3fbd 100644 --- a/pkg/vex/vex_test.go +++ b/pkg/vex/vex_test.go @@ -291,7 +291,12 @@ func TestVEX_Filter(t *testing.T) { return } require.NoError(t, err) - assert.Equal(t, tt.want, v.Filter(tt.args.vulns)) + + got := &types.Result{ + Vulnerabilities: tt.args.vulns, + } + v.Filter(got) + assert.Equal(t, tt.want, got.Vulnerabilities) }) } } From ba8d2129b1d1a0fc7494a760668aa7f0020a1a20 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:49:46 +0400 Subject: [PATCH 05/24] refactor: remove unneeded methods Signed-off-by: knqyf263 --- pkg/compliance/spec/mapper.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/compliance/spec/mapper.go b/pkg/compliance/spec/mapper.go index abcba2a7dbac..2efa488bff54 100644 --- a/pkg/compliance/spec/mapper.go +++ b/pkg/compliance/spec/mapper.go @@ -11,10 +11,10 @@ func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Sca mapCheckByID := make(map[string]types.Results) for _, vuln := range result.Vulnerabilities { // Skip irrelevant check IDs - if !slices.Contains(checkIDs[types.VulnerabilityScanner], vuln.GetID()) { + if !slices.Contains(checkIDs[types.VulnerabilityScanner], vuln.VulnerabilityID) { continue } - mapCheckByID[vuln.GetID()] = append(mapCheckByID[vuln.GetID()], types.Result{ + mapCheckByID[vuln.VulnerabilityID] = append(mapCheckByID[vuln.VulnerabilityID], types.Result{ Target: result.Target, Class: result.Class, Type: result.Type, @@ -23,11 +23,11 @@ func MapSpecCheckIDToFilteredResults(result types.Result, checkIDs map[types.Sca } for _, m := range result.Misconfigurations { // Skip irrelevant check IDs - if !slices.Contains(checkIDs[types.MisconfigScanner], m.GetID()) { + if !slices.Contains(checkIDs[types.MisconfigScanner], m.AVDID) { continue } - mapCheckByID[m.GetID()] = append(mapCheckByID[m.GetID()], types.Result{ + mapCheckByID[m.AVDID] = append(mapCheckByID[m.AVDID], types.Result{ Target: result.Target, Class: result.Class, Type: result.Type, From d9d7cc8b13097556e8577d230ea385751d05f7d3 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:50:16 +0400 Subject: [PATCH 06/24] test: support modified findings Signed-off-by: knqyf263 --- pkg/result/filter_test.go | 764 +++++++----------- pkg/result/testdata/.trivyignore | 8 +- ...olicy-misconf.rego => ignore-misconf.rego} | 2 +- .../testdata/{test.rego => ignore-vuln.rego} | 0 4 files changed, 308 insertions(+), 466 deletions(-) rename pkg/result/testdata/{test-ignore-policy-misconf.rego => ignore-misconf.rego} (68%) rename pkg/result/testdata/{test.rego => ignore-vuln.rego} (100%) diff --git a/pkg/result/filter_test.go b/pkg/result/filter_test.go index 4edd86348c9b..0da3833491e3 100644 --- a/pkg/result/filter_test.go +++ b/pkg/result/filter_test.go @@ -17,6 +17,143 @@ import ( ) func TestFilter(t *testing.T) { + var ( + vuln1 = types.DetectedVulnerability{ + VulnerabilityID: "CVE-2019-0001", + PkgName: "foo", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "foo", + Version: "1.2.3", + }, + }, + InstalledVersion: "1.2.3", + FixedVersion: "1.2.4", + Vulnerability: dbTypes.Vulnerability{ + Severity: dbTypes.SeverityLow.String(), + }, + } + vuln2 = types.DetectedVulnerability{ + VulnerabilityID: "CVE-2019-0002", + PkgName: "foo", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "foo", + Version: "4.5.6", + }, + }, + InstalledVersion: "1.2.3", + FixedVersion: "1.2.4", + Vulnerability: dbTypes.Vulnerability{ + Severity: dbTypes.SeverityCritical.String(), + }, + } + vuln3 = types.DetectedVulnerability{ + VulnerabilityID: "CVE-2019-0003", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "1.2.4", + Vulnerability: dbTypes.Vulnerability{ + Severity: dbTypes.SeverityLow.String(), + }, + } + vuln4 = types.DetectedVulnerability{ + VulnerabilityID: "CVE-2019-0004", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "1.2.4", + Vulnerability: dbTypes.Vulnerability{ + Severity: dbTypes.SeverityLow.String(), + }, + } + vuln5 = types.DetectedVulnerability{ + VulnerabilityID: "CVE-2019-0005", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "1.2.4", + Vulnerability: dbTypes.Vulnerability{ + Severity: dbTypes.SeverityLow.String(), + }, + } + vuln6 = types.DetectedVulnerability{ + VulnerabilityID: "CVE-2019-0006", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "1.2.4", + Vulnerability: dbTypes.Vulnerability{ + Severity: dbTypes.SeverityLow.String(), + }, + } + misconf1 = types.DetectedMisconfiguration{ + Type: "Kubernetes Security Check", + ID: "ID100", + AVDID: "AVD-ID100", + Title: "Bad Deployment", + Message: "something bad", + Severity: dbTypes.SeverityHigh.String(), + Status: types.MisconfStatusFailure, + } + misconf2 = types.DetectedMisconfiguration{ + Type: "Kubernetes Security Check", + ID: "ID200", + AVDID: "AVD-ID200", + Title: "Bad Pod", + Message: "something bad", + Severity: dbTypes.SeverityLow.String(), + Status: types.MisconfStatusPassed, + } + misconf3 = types.DetectedMisconfiguration{ + Type: "Kubernetes Security Check", + ID: "ID300", + AVDID: "AVD-ID300", + Title: "Bad Job", + Message: "something bad", + Severity: dbTypes.SeverityLow.String(), + Status: types.MisconfStatusFailure, + } + secret1 = types.DetectedSecret{ + RuleID: "generic-wanted-rule", + Severity: dbTypes.SeverityLow.String(), + Title: "Secret that should pass filter on rule id", + StartLine: 1, + EndLine: 2, + Match: "*****", + } + secret2 = types.DetectedSecret{ + RuleID: "generic-unwanted-rule", + Severity: dbTypes.SeverityLow.String(), + Title: "Secret that should not pass filter on rule id", + StartLine: 3, + EndLine: 4, + Match: "*****", + } + secret3 = types.DetectedSecret{ + RuleID: "generic-unwanted-rule2", + Severity: dbTypes.SeverityLow.String(), + Title: "Secret that should not pass filter on rule id", + StartLine: 5, + EndLine: 6, + Match: "*****", + } + license1 = types.DetectedLicense{ + Name: "GPL-3.0", + Severity: dbTypes.SeverityLow.String(), + FilePath: "usr/share/gcc/python/libstdcxx/v6/__init__.py", + Category: "restricted", + Confidence: 1, + } + license2 = types.DetectedLicense{ + Name: "GPL-3.0", + Severity: dbTypes.SeverityLow.String(), + FilePath: "usr/share/gcc/python/libstdcxx/v6/printers.py", + Category: "restricted", + Confidence: 1, + } + ) type args struct { report types.Report severities []dbTypes.Severity @@ -37,44 +174,14 @@ func TestFilter(t *testing.T) { Results: []types.Result{ { Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - VulnerabilityID: "CVE-2019-0002", - PkgName: "bar", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityCritical.String(), - }, - }, + vuln1, + vuln2, }, Misconfigurations: []types.DetectedMisconfiguration{ - { - Type: "Kubernetes Security Check", - ID: "ID100", - Title: "Bad Deployment", - Message: "something bad", - Severity: dbTypes.SeverityHigh.String(), - Status: types.StatusFailure, - }, - { - Type: "Kubernetes Security Check", - ID: "ID200", - Title: "Bad Pod", - Message: "something bad", - Severity: dbTypes.SeverityMedium.String(), - Status: types.StatusPassed, - }, + misconf1, + misconf2, }, - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "generic-critical-rule", Severity: dbTypes.SeverityCritical.String(), @@ -104,15 +211,7 @@ func TestFilter(t *testing.T) { Results: []types.Result{ { Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2019-0002", - PkgName: "bar", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityCritical.String(), - }, - }, + vuln2, }, MisconfSummary: &types.MisconfSummary{ Successes: 0, @@ -120,16 +219,9 @@ func TestFilter(t *testing.T) { Exceptions: 0, }, Misconfigurations: []types.DetectedMisconfiguration{ - { - Type: "Kubernetes Security Check", - ID: "ID100", - Title: "Bad Deployment", - Message: "something bad", - Severity: dbTypes.SeverityHigh.String(), - Status: types.StatusFailure, - }, + misconf1, }, - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ { RuleID: "generic-critical-rule", Severity: dbTypes.SeverityCritical.String(), @@ -150,40 +242,8 @@ func TestFilter(t *testing.T) { Results: types.Results{ types.Result{ Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - PkgIdentifier: ftypes.PkgIdentifier{ - PURL: &packageurl.PackageURL{ - Type: packageurl.TypeGolang, - Namespace: "github.com/aquasecurity", - Name: "foo", - Version: "1.2.3", - }, - }, - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - VulnerabilityID: "CVE-2019-0001", - PkgName: "bar", - PkgIdentifier: ftypes.PkgIdentifier{ - PURL: &packageurl.PackageURL{ - Type: packageurl.TypeGolang, - Namespace: "github.com/aquasecurity", - Name: "bar", - Version: "4.5.6", - }, - }, - InstalledVersion: "4.5.6", - FixedVersion: "4.5.7", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityCritical.String(), - }, - }, + vuln1, + vuln2, }, }, }, @@ -201,22 +261,15 @@ func TestFilter(t *testing.T) { Results: types.Results{ types.Result{ Vulnerabilities: []types.DetectedVulnerability{ + vuln2, + }, + ModifiedFindings: []types.ModifiedFinding{ { - VulnerabilityID: "CVE-2019-0001", - PkgName: "bar", - PkgIdentifier: ftypes.PkgIdentifier{ - PURL: &packageurl.PackageURL{ - Type: packageurl.TypeGolang, - Namespace: "github.com/aquasecurity", - Name: "bar", - Version: "4.5.6", - }, - }, - InstalledVersion: "4.5.6", - FixedVersion: "4.5.7", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityCritical.String(), - }, + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusNotAffected, + Statement: "vulnerable_code_not_in_execute_path", + Source: "OpenVEX", + Finding: vuln1, }, }, }, @@ -231,25 +284,8 @@ func TestFilter(t *testing.T) { types.Result{ Target: "debian:11 (debian 11)", Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - VulnerabilityID: "CVE-2018-0002", - PkgName: "bar", - InstalledVersion: "1.2.3", - FixedVersion: "", - Status: dbTypes.StatusWillNotFix, - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityHigh.String(), - }, - }, + vuln1, + vuln2, }, }, }, @@ -277,98 +313,28 @@ func TestFilter(t *testing.T) { Target: "package-lock.json", Class: types.ClassLangPkg, Vulnerabilities: []types.DetectedVulnerability{ - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0002", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - VulnerabilityID: "CVE-2019-0003", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - VulnerabilityID: "CVE-2022-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2022-0002", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2022-0003", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, + vuln1, // ignored + vuln2, // filtered by severity + vuln3, + vuln4, + vuln5, // ignored + vuln6, // ignored }, }, { - Target: "Dockerfile", + Target: "deployment.yaml", Class: types.ClassConfig, Misconfigurations: []types.DetectedMisconfiguration{ - { - Type: "Kubernetes Security Check", - ID: "ID100", - Title: "Bad Deployment", - Message: "something bad", - Severity: dbTypes.SeverityLow.String(), - Status: types.StatusFailure, - }, + misconf1, + misconf2, + misconf3, }, }, { - Secrets: []ftypes.SecretFinding{ - { - RuleID: "generic-wanted-rule", - Severity: dbTypes.SeverityLow.String(), - Title: "Secret that should pass filter on rule id", - StartLine: 1, - EndLine: 2, - Match: "*****", - }, - { - RuleID: "generic-unwanted-rule", - Severity: dbTypes.SeverityLow.String(), - Title: "Secret that should not pass filter on rule id", - StartLine: 3, - EndLine: 4, - Match: "*****", - }, + Target: "config.yaml", + Secrets: []types.DetectedSecret{ + secret1, + secret2, }, }, }, @@ -382,44 +348,58 @@ func TestFilter(t *testing.T) { Target: "package-lock.json", Class: types.ClassLangPkg, Vulnerabilities: []types.DetectedVulnerability{ + vuln3, + vuln4, + }, + ModifiedFindings: []types.ModifiedFinding{ { - VulnerabilityID: "CVE-2019-0003", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore", + Finding: vuln1, }, { - VulnerabilityID: "CVE-2022-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore", + Finding: vuln5, + }, + { + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore", + Finding: vuln6, }, }, }, { - Target: "Dockerfile", + Target: "deployment.yaml", Class: types.ClassConfig, MisconfSummary: &types.MisconfSummary{ - Successes: 0, + Successes: 1, Failures: 0, Exceptions: 1, }, + ModifiedFindings: []types.ModifiedFinding{ + { + Type: types.FindingTypeMisconfiguration, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore", + Finding: misconf3, + }, + }, }, { - Secrets: []ftypes.SecretFinding{ + Target: "config.yaml", + Secrets: []types.DetectedSecret{ + secret1, + }, + ModifiedFindings: []types.ModifiedFinding{ { - RuleID: "generic-wanted-rule", - Severity: dbTypes.SeverityLow.String(), - Title: "Secret that should pass filter on rule id", - StartLine: 1, - EndLine: 2, - Match: "*****", + Type: types.FindingTypeSecret, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore", + Finding: secret2, }, }, }, @@ -434,146 +414,35 @@ func TestFilter(t *testing.T) { { Target: "foo/package-lock.json", Vulnerabilities: []types.DetectedVulnerability{ - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0002", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - PkgPath: "bar/package.json", - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0003", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - VulnerabilityID: "CVE-2019-0004", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0005", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - VulnerabilityID: "CVE-2019-0006", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, + vuln1, // ignored + vuln2, // filtered by severity + vuln3, // ignored + vuln4, + vuln5, // ignored + vuln6, }, }, { Target: "app/Dockerfile", Misconfigurations: []types.DetectedMisconfiguration{ - { - // this misconfiguration is ignored - Type: "Kubernetes Security Check", - ID: "ID100", - Title: "Bad Deployment", - Message: "something bad", - Severity: dbTypes.SeverityLow.String(), - Status: types.StatusFailure, - }, - { - // this misconfiguration is ignored - Type: "Kubernetes Security Check", - ID: "ID200", - Title: "Bad Deployment", - Message: "something bad", - Severity: dbTypes.SeverityLow.String(), - Status: types.StatusFailure, - }, - { - Type: "Kubernetes Security Check", - ID: "ID300", - Title: "Bad Deployment", - Message: "something bad", - Severity: dbTypes.SeverityLow.String(), - Status: types.StatusFailure, - }, + misconf1, // filtered by severity + misconf2, // ignored + misconf3, }, }, { Target: "config.yaml", - Secrets: []ftypes.SecretFinding{ - { - RuleID: "generic-wanted-rule", - Severity: dbTypes.SeverityLow.String(), - Title: "Secret that should pass filter on rule id", - StartLine: 1, - EndLine: 2, - Match: "*****", - }, - { - // this secret is ignored - RuleID: "generic-unwanted-rule", - Severity: dbTypes.SeverityLow.String(), - Title: "Secret that should not pass filter on rule id", - StartLine: 3, - EndLine: 4, - Match: "*****", - }, - { - // this secret is ignored - RuleID: "generic-unwanted-rule2", - Severity: dbTypes.SeverityLow.String(), - Title: "Secret that should not pass filter on rule id", - StartLine: 5, - EndLine: 6, - Match: "*****", - }, + Secrets: []types.DetectedSecret{ + secret1, + secret2, // ignored + secret3, // ignored }, }, { + Target: "LICENSE.txt", Licenses: []types.DetectedLicense{ - { - // this license is ignored - Name: "GPL-3.0", - Severity: dbTypes.SeverityLow.String(), - FilePath: "usr/share/gcc/python/libstdcxx/v6/__init__.py", - Category: "restricted", - Confidence: 1, - }, - { - Name: "GPL-3.0", - Severity: dbTypes.SeverityLow.String(), - FilePath: "usr/share/gcc/python/libstdcxx/v6/printers.py", - Category: "restricted", - Confidence: 1, - }, + license1, // ignored + license2, }, }, }, @@ -586,23 +455,27 @@ func TestFilter(t *testing.T) { { Target: "foo/package-lock.json", Vulnerabilities: []types.DetectedVulnerability{ + vuln4, + vuln6, + }, + ModifiedFindings: []types.ModifiedFinding{ { - VulnerabilityID: "CVE-2019-0004", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore.yaml", + Finding: vuln1, }, { - VulnerabilityID: "CVE-2019-0006", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore.yaml", + Finding: vuln3, + }, + { + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore.yaml", + Finding: vuln5, }, }, }, @@ -611,40 +484,51 @@ func TestFilter(t *testing.T) { MisconfSummary: &types.MisconfSummary{ Successes: 0, Failures: 1, - Exceptions: 2, + Exceptions: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ + misconf3, + }, + ModifiedFindings: []types.ModifiedFinding{ { - Type: "Kubernetes Security Check", - ID: "ID300", - Title: "Bad Deployment", - Message: "something bad", - Severity: dbTypes.SeverityLow.String(), - Status: types.StatusFailure, + Type: types.FindingTypeMisconfiguration, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore.yaml", + Finding: misconf2, }, }, }, { Target: "config.yaml", - Secrets: []ftypes.SecretFinding{ + Secrets: []types.DetectedSecret{ + secret1, + }, + ModifiedFindings: []types.ModifiedFinding{ { - RuleID: "generic-wanted-rule", - Severity: dbTypes.SeverityLow.String(), - Title: "Secret that should pass filter on rule id", - StartLine: 1, - EndLine: 2, - Match: "*****", + Type: types.FindingTypeSecret, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore.yaml", + Finding: secret2, + }, + { + Type: types.FindingTypeSecret, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore.yaml", + Finding: secret3, }, }, }, { + Target: "LICENSE.txt", Licenses: []types.DetectedLicense{ + license2, + }, + ModifiedFindings: []types.ModifiedFinding{ { - Name: "GPL-3.0", - Severity: dbTypes.SeverityLow.String(), - FilePath: "usr/share/gcc/python/libstdcxx/v6/printers.py", - Category: "restricted", - Confidence: 1, + Type: types.FindingTypeLicense, + Status: types.FindingStatusIgnored, + Source: "testdata/.trivyignore.yaml", + Finding: license1, }, }, }, @@ -652,60 +536,35 @@ func TestFilter(t *testing.T) { }, }, { - name: "policy file", + name: "policy file for vulnerabilities", args: args{ report: types.Report{ Results: types.Results{ { Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0002", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, - { - // this vulnerability is ignored - VulnerabilityID: "CVE-2019-0003", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, - }, + vuln1, + vuln2, // ignored by policy + vuln3, // ignored by policy }, }, }, }, severities: []dbTypes.Severity{dbTypes.SeverityLow}, - policyFile: "./testdata/test.rego", + policyFile: "./testdata/ignore-vuln.rego", }, want: types.Report{ Results: types.Results{ { Vulnerabilities: []types.DetectedVulnerability{ + vuln1, + }, + ModifiedFindings: []types.ModifiedFinding{ { - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", - Vulnerability: dbTypes.Vulnerability{ - Severity: dbTypes.SeverityLow.String(), - }, + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Statement: "Filtered by Rego", + Source: "testdata/ignore-vuln.rego", + Finding: vuln3, }, }, }, @@ -713,60 +572,43 @@ func TestFilter(t *testing.T) { }, }, { - name: "ignore file for misconf", + name: "policy file for misconfigurations", args: args{ report: types.Report{ Results: types.Results{ { Misconfigurations: []types.DetectedMisconfiguration{ - { - ID: "AVD-TEST-0001", - AVDID: "AVD-TEST-0001", - Title: "test-0001", - Description: "foo", - Severity: dbTypes.SeverityHigh.String(), - Status: types.StatusFailure, - }, - { - ID: "AVD-TEST-0002", - AVDID: "AVD-TEST-0002", - Title: "test-0002", - Description: "bar", - Severity: dbTypes.SeverityHigh.String(), - Status: types.StatusPassed, - }, - { - // this misconf is ignored - ID: "AVD-TEST-0003", - AVDID: "AVD-TEST-0003", - Title: "test-0003", - Description: "baz", - Severity: dbTypes.SeverityHigh.String(), - Status: types.StatusFailure, - }, + misconf1, + misconf2, + misconf3, // ignored by policy }, }, }, }, - severities: []dbTypes.Severity{dbTypes.SeverityHigh}, - policyFile: "./testdata/test-ignore-policy-misconf.rego", + severities: []dbTypes.Severity{ + dbTypes.SeverityLow, + dbTypes.SeverityHigh, + }, + policyFile: "./testdata/ignore-misconf.rego", }, want: types.Report{ Results: types.Results{ { MisconfSummary: &types.MisconfSummary{ Successes: 1, - Failures: 2, + Failures: 1, Exceptions: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ + misconf1, + }, + ModifiedFindings: []types.ModifiedFinding{ { - ID: "AVD-TEST-0001", - AVDID: "AVD-TEST-0001", - Title: "test-0001", - Description: "foo", - Severity: dbTypes.SeverityHigh.String(), - Status: types.StatusFailure, + Type: types.FindingTypeMisconfiguration, + Status: types.FindingStatusIgnored, + Statement: "Filtered by Rego", + Source: "testdata/ignore-misconf.rego", + Finding: misconf3, }, }, }, diff --git a/pkg/result/testdata/.trivyignore b/pkg/result/testdata/.trivyignore index 3ac56952e983..fb2e885ab842 100644 --- a/pkg/result/testdata/.trivyignore +++ b/pkg/result/testdata/.trivyignore @@ -1,12 +1,12 @@ # vulnerabilities CVE-2019-0001 CVE-2019-0002 -CVE-2022-0001 exp:2020-01-01 -CVE-2022-0002 exp:9999-01-01 -CVE-2022-0003 exp:9999-01-01 key2:value2 +CVE-2019-0004 exp:2020-01-01 +CVE-2019-0005 exp:9999-01-01 +CVE-2019-0006 exp:9999-01-01 key2:value2 # misconfigurations -ID100 +ID300 # secrets generic-unwanted-rule \ No newline at end of file diff --git a/pkg/result/testdata/test-ignore-policy-misconf.rego b/pkg/result/testdata/ignore-misconf.rego similarity index 68% rename from pkg/result/testdata/test-ignore-policy-misconf.rego rename to pkg/result/testdata/ignore-misconf.rego index 39838ef27210..1aa5062ddf24 100644 --- a/pkg/result/testdata/test-ignore-policy-misconf.rego +++ b/pkg/result/testdata/ignore-misconf.rego @@ -5,5 +5,5 @@ import data.lib.trivy default ignore=false ignore { - input.AVDID != "AVD-TEST-0001" + input.AVDID != "AVD-ID100" } diff --git a/pkg/result/testdata/test.rego b/pkg/result/testdata/ignore-vuln.rego similarity index 100% rename from pkg/result/testdata/test.rego rename to pkg/result/testdata/ignore-vuln.rego From 009fc610d6ce14126fc3b94f6e08308b63bd1de8 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:52:16 +0400 Subject: [PATCH 07/24] feat(cli): add --show-suppressed Signed-off-by: knqyf263 --- pkg/flag/report_flags.go | 10 ++++++++++ pkg/report/table/table.go | 5 ++++- pkg/report/table/vulnerability.go | 15 +++++---------- pkg/report/writer.go | 1 + 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 5ab4788e71cc..988383eb9ed5 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -101,6 +101,11 @@ var ( ConfigName: "scan.compliance", Usage: "compliance report to generate", } + ShowSuppressedFlag = Flag[bool]{ + Name: "show-suppressed", + ConfigName: "scan.show-suppressed", + Usage: "show suppressed security findings", + } ) // ReportFlagGroup composes common printer flag structs @@ -119,6 +124,7 @@ type ReportFlagGroup struct { OutputPluginArg *Flag[string] Severity *Flag[[]string] Compliance *Flag[string] + ShowSuppressed *Flag[bool] } type ReportOptions struct { @@ -135,6 +141,7 @@ type ReportOptions struct { OutputPluginArgs []string Severities []dbTypes.Severity Compliance spec.ComplianceSpec + ShowSuppressed bool } func NewReportFlagGroup() *ReportFlagGroup { @@ -152,6 +159,7 @@ func NewReportFlagGroup() *ReportFlagGroup { OutputPluginArg: OutputPluginArgFlag.Clone(), Severity: SeverityFlag.Clone(), Compliance: ComplianceFlag.Clone(), + ShowSuppressed: ShowSuppressedFlag.Clone(), } } @@ -174,6 +182,7 @@ func (f *ReportFlagGroup) Flags() []Flagger { f.OutputPluginArg, f.Severity, f.Compliance, + f.ShowSuppressed, } } @@ -247,6 +256,7 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { OutputPluginArgs: outputPluginArgs, Severities: toSeverity(f.Severity.Value()), Compliance: cs, + ShowSuppressed: f.ShowSuppressed.Value(), }, nil } diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 652fda43a327..ec13e1f76218 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -36,6 +36,9 @@ type Writer struct { // Show dependency origin tree Tree bool + // Show suppressed findings + ShowSuppressed bool + // We have to show a message once about using the '-format json' subcommand to get the full pkgPath ShowMessageOnce *sync.Once @@ -73,7 +76,7 @@ func (tw Writer) write(result types.Result) { switch { // vulnerability case result.Class == types.ClassOSPkg || result.Class == types.ClassLangPkg: - renderer = NewVulnerabilityRenderer(result, tw.isOutputToTerminal(), tw.Tree, tw.Severities) + renderer = NewVulnerabilityRenderer(result, tw.isOutputToTerminal(), tw.Tree, tw.ShowSuppressed, tw.Severities) // misconfiguration case result.Class == types.ClassConfig: renderer = NewMisconfigRenderer(result, tw.Severities, tw.Trace, tw.IncludeNonFailures, tw.isOutputToTerminal()) diff --git a/pkg/report/table/vulnerability.go b/pkg/report/table/vulnerability.go index 62dec9ada824..fdd59f60a662 100644 --- a/pkg/report/table/vulnerability.go +++ b/pkg/report/table/vulnerability.go @@ -61,15 +61,10 @@ func (r *vulnerabilityRenderer) Render() string { RenderTarget(r.w, target, r.isTerminal) r.printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", ")) - r.tableWriter.Render() - if r.tree { - r.renderDependencyTree() - } - - return r.w.String() + tw.Render() } -func (r *vulnerabilityRenderer) setHeaders() { +func (r *vulnerabilityRenderer) setHeaders(tw *table.Table) { if len(r.result.Vulnerabilities) == 0 { return } @@ -82,10 +77,10 @@ func (r *vulnerabilityRenderer) setHeaders() { "Fixed Version", "Title", } - r.tableWriter.SetHeaders(header...) + tw.SetHeaders(header...) } -func (r *vulnerabilityRenderer) setVulnerabilityRows(vulns []types.DetectedVulnerability) { +func (r *vulnerabilityRenderer) setVulnerabilityRows(tw *table.Table, vulns []types.DetectedVulnerability) { for _, v := range vulns { lib := v.PkgName if v.PkgPath != "" { @@ -139,7 +134,7 @@ func (r *vulnerabilityRenderer) setVulnerabilityRows(vulns []types.DetectedVulne } } - r.tableWriter.AddRow(row...) + tw.AddRow(row...) } } diff --git a/pkg/report/writer.go b/pkg/report/writer.go index 3a095bbbfc8e..3b25e2d165b9 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -49,6 +49,7 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e Output: output, Severities: option.Severities, Tree: option.DependencyTree, + ShowSuppressed: option.ShowSuppressed, ShowMessageOnce: &sync.Once{}, IncludeNonFailures: option.IncludeNonFailures, Trace: option.Trace, From 4d5304b54614fe58d432222b955806b4b59a50a3 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:52:46 +0400 Subject: [PATCH 08/24] feat(table): print suppressed vulns Signed-off-by: knqyf263 --- pkg/report/table/vulnerability.go | 89 +++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 17 deletions(-) diff --git a/pkg/report/table/vulnerability.go b/pkg/report/table/vulnerability.go index fdd59f60a662..c35b56a568ae 100644 --- a/pkg/report/table/vulnerability.go +++ b/pkg/report/table/vulnerability.go @@ -22,34 +22,49 @@ import ( ) type vulnerabilityRenderer struct { - w *bytes.Buffer - tableWriter *table.Table - result types.Result - isTerminal bool - tree bool - severities []dbTypes.Severity - once *sync.Once + w *bytes.Buffer + result types.Result + isTerminal bool + tree bool // Show dependency tree + showSuppressed bool // Show suppressed vulnerabilities + severities []dbTypes.Severity + once *sync.Once } -func NewVulnerabilityRenderer(result types.Result, isTerminal, tree bool, severities []dbTypes.Severity) *vulnerabilityRenderer { +func NewVulnerabilityRenderer(result types.Result, isTerminal, tree, suppressed bool, severities []dbTypes.Severity) *vulnerabilityRenderer { buf := bytes.NewBuffer([]byte{}) if !isTerminal { tml.DisableFormatting() } return &vulnerabilityRenderer{ - w: buf, - tableWriter: newTableWriter(buf, isTerminal), - result: result, - isTerminal: isTerminal, - tree: tree, - severities: severities, - once: new(sync.Once), + w: buf, + result: result, + isTerminal: isTerminal, + tree: tree, + showSuppressed: suppressed, + severities: severities, + once: new(sync.Once), } } func (r *vulnerabilityRenderer) Render() string { - r.setHeaders() - r.setVulnerabilityRows(r.result.Vulnerabilities) + r.renderDetectedVulnerabilities() + + if r.tree { + r.renderDependencyTree() + } + + if r.showSuppressed { + r.renderModifiedVulnerabilities() + } + + return r.w.String() +} + +func (r *vulnerabilityRenderer) renderDetectedVulnerabilities() { + tw := newTableWriter(r.w, r.isTerminal) + r.setHeaders(tw) + r.setVulnerabilityRows(tw, r.result.Vulnerabilities) severityCount := r.countSeverities(r.result.Vulnerabilities) total, summaries := summarize(r.severities, severityCount) @@ -146,6 +161,46 @@ func (r *vulnerabilityRenderer) countSeverities(vulns []types.DetectedVulnerabil return severityCount } +func (r *vulnerabilityRenderer) renderModifiedVulnerabilities() { + tw := newTableWriter(r.w, r.isTerminal) + header := []string{ + "Library", + "Vulnerability", + "Severity", + "Status", + "Statement", + "Source", + } + tw.SetHeaders(header...) + + var total int + for _, m := range r.result.ModifiedFindings { + vuln, ok := m.Finding.(types.DetectedVulnerability) + if !ok { + continue + } + total++ + + stmt := lo.Ternary(m.Statement != "", m.Statement, "N/A") + tw.AddRow(vuln.PkgName, vuln.VulnerabilityID, vuln.Severity, string(m.Status), stmt, m.Source) + } + + if total == 0 { + return + } + + title := fmt.Sprintf("Suppressed Vulnerabilities (Total: %d)", total) + if r.isTerminal { + // nolint + _ = tml.Fprintf(r.w, "\n%s\n\n", title) + } else { + _, _ = fmt.Fprintf(r.w, "\n%s\n", title) + _, _ = fmt.Fprintf(r.w, "%s\n", strings.Repeat("=", len(title))) + } + + tw.Render() +} + func (r *vulnerabilityRenderer) renderDependencyTree() { // Get parents of each dependency parents := ftypes.Packages(r.result.Packages).ParentDeps() From 0ea599ee927367ab337e771aab3912e347b58821 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:52:57 +0400 Subject: [PATCH 09/24] chore: generate easyjson structs Signed-off-by: knqyf263 --- pkg/module/serialize/types_easyjson.go | 110 ++++++++++++------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/pkg/module/serialize/types_easyjson.go b/pkg/module/serialize/types_easyjson.go index cd2826c716ea..988347841c28 100644 --- a/pkg/module/serialize/types_easyjson.go +++ b/pkg/module/serialize/types_easyjson.go @@ -266,16 +266,16 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(in *jle in.Delim('[') if out.Secrets == nil { if !in.IsDelim(']') { - out.Secrets = make([]types1.SecretFinding, 0, 0) + out.Secrets = make([]types.DetectedSecret, 0, 0) } else { - out.Secrets = []types1.SecretFinding{} + out.Secrets = []types.DetectedSecret{} } } else { out.Secrets = (out.Secrets)[:0] } for !in.IsDelim(']') { - var v10 types1.SecretFinding - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in, &v10) + var v10 types.DetectedSecret + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in, &v10) out.Secrets = append(out.Secrets, v10) in.WantComma() } @@ -298,7 +298,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(in *jle } for !in.IsDelim(']') { var v11 types.DetectedLicense - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in, &v11) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes4(in, &v11) out.Licenses = append(out.Licenses, v11) in.WantComma() } @@ -321,7 +321,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(in *jle } for !in.IsDelim(']') { var v12 types1.CustomResource - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &v12) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in, &v12) out.CustomResources = append(out.CustomResources, v12) in.WantComma() } @@ -412,7 +412,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize2(out *jw if v19 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out, v20) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out, v20) } out.RawByte(']') } @@ -426,7 +426,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize2(out *jw if v21 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out, v22) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes4(out, v22) } out.RawByte(']') } @@ -440,7 +440,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize2(out *jw if v23 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, v24) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out, v24) } out.RawByte(']') } @@ -471,7 +471,7 @@ func (v *Result) UnmarshalJSON(data []byte) error { func (v *Result) UnmarshalEasyJSON(l *jlexer.Lexer) { easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize2(l, v) } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.Lexer, out *types1.CustomResource) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.Lexer, out *types1.CustomResource) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -495,7 +495,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.L case "FilePath": out.FilePath = string(in.String()) case "Layer": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer) case "Data": if m, ok := out.Data.(easyjson.Unmarshaler); ok { m.UnmarshalEasyJSON(in) @@ -514,7 +514,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter.Writer, in types1.CustomResource) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter.Writer, in types1.CustomResource) { out.RawByte('{') first := true _ = first @@ -531,7 +531,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter { const prefix string = ",\"Layer\":" out.RawString(prefix) - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer) } { const prefix string = ",\"Data\":" @@ -546,7 +546,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in *jlexer.Lexer, out *types1.Layer) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in *jlexer.Lexer, out *types1.Layer) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -581,7 +581,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out *jwriter.Writer, in types1.Layer) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out *jwriter.Writer, in types1.Layer) { out.RawByte('{') first := true _ = first @@ -613,7 +613,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out *jwriter } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in *jlexer.Lexer, out *types.DetectedLicense) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes4(in *jlexer.Lexer, out *types.DetectedLicense) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -656,7 +656,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in *jlexer.Lexer, in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out *jwriter.Writer, in types.DetectedLicense) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes4(out *jwriter.Writer, in types.DetectedLicense) { out.RawByte('{') first := true _ = first @@ -697,7 +697,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out *jwriter.Writ } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.Lexer, out *types1.SecretFinding) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes3(in *jlexer.Lexer, out *types.DetectedSecret) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -729,11 +729,11 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.L case "EndLine": out.EndLine = int(in.Int()) case "Code": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in, &out.Code) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Code) case "Match": out.Match = string(in.String()) case "Layer": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer) default: in.SkipRecursive() } @@ -744,7 +744,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes1(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter.Writer, in types1.SecretFinding) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes3(out *jwriter.Writer, in types.DetectedSecret) { out.RawByte('{') first := true _ = first @@ -781,7 +781,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter { const prefix string = ",\"Code\":" out.RawString(prefix) - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out, in.Code) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Code) } { const prefix string = ",\"Match\":" @@ -791,11 +791,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes1(out *jwriter if true { const prefix string = ",\"Layer\":" out.RawString(prefix) - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer) } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.Lexer, out *types1.Code) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in *jlexer.Lexer, out *types1.Code) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -831,7 +831,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.L } for !in.IsDelim(']') { var v25 types1.Line - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in, &v25) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in, &v25) out.Lines = append(out.Lines, v25) in.WantComma() } @@ -847,7 +847,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out *jwriter.Writer, in types1.Code) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out *jwriter.Writer, in types1.Code) { out.RawByte('{') first := true _ = first @@ -862,14 +862,14 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out *jwriter if v26 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out, v27) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out, v27) } out.RawByte(']') } } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in *jlexer.Lexer, out *types1.Line) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in *jlexer.Lexer, out *types1.Line) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -914,7 +914,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out *jwriter.Writer, in types1.Line) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out *jwriter.Writer, in types1.Line) { out.RawByte('{') first := true _ = first @@ -1027,9 +1027,9 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes2(in *jlexer.Lexer, case "Status": out.Status = types.MisconfStatus(in.String()) case "Layer": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer) case "CauseMetadata": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in, &out.CauseMetadata) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in, &out.CauseMetadata) case "Traces": if in.IsNull() { in.Skip() @@ -1210,7 +1210,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes2(out *jwriter.Writ } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer) } if true { const prefix string = ",\"CauseMetadata\":" @@ -1220,7 +1220,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes2(out *jwriter.Writ } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out, in.CauseMetadata) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out, in.CauseMetadata) } if len(in.Traces) != 0 { const prefix string = ",\"Traces\":" @@ -1243,7 +1243,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes2(out *jwriter.Writ } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.Lexer, out *types1.CauseMetadata) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes5(in *jlexer.Lexer, out *types1.CauseMetadata) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -1273,7 +1273,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.L case "EndLine": out.EndLine = int(in.Int()) case "Code": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes4(in, &out.Code) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Code) case "Occurrences": if in.IsNull() { in.Skip() @@ -1291,7 +1291,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.L } for !in.IsDelim(']') { var v34 types1.Occurrence - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in, &v34) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in, &v34) out.Occurrences = append(out.Occurrences, v34) in.WantComma() } @@ -1307,7 +1307,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter.Writer, in types1.CauseMetadata) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes5(out *jwriter.Writer, in types1.CauseMetadata) { out.RawByte('{') first := true _ = first @@ -1365,7 +1365,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes4(out, in.Code) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Code) } if len(in.Occurrences) != 0 { const prefix string = ",\"Occurrences\":" @@ -1381,14 +1381,14 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter if v35 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out, v36) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out, v36) } out.RawByte(']') } } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.Lexer, out *types1.Occurrence) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes6(in *jlexer.Lexer, out *types1.Occurrence) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -1412,7 +1412,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.L case "Filename": out.Filename = string(in.String()) case "Location": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in, &out.Location) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in, &out.Location) default: in.SkipRecursive() } @@ -1423,7 +1423,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out *jwriter.Writer, in types1.Occurrence) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes6(out *jwriter.Writer, in types1.Occurrence) { out.RawByte('{') first := true _ = first @@ -1451,11 +1451,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out *jwriter } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, in.Location) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out, in.Location) } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in *jlexer.Lexer, out *types1.Location) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in *jlexer.Lexer, out *types1.Location) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -1488,7 +1488,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out *jwriter.Writer, in types1.Location) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out *jwriter.Writer, in types1.Location) { out.RawByte('{') first := true _ = first @@ -1629,7 +1629,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes(in *jlexer.Lexer, in.AddError((out.Status).UnmarshalJSON(data)) } case "Layer": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer) case "SeveritySource": out.SeveritySource = types2.SourceID(in.String()) case "PrimaryURL": @@ -1885,7 +1885,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes(out *jwriter.Write } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer) } if in.SeveritySource != "" { const prefix string = ",\"SeveritySource\":" @@ -2297,7 +2297,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le if out.BuildInfo == nil { out.BuildInfo = new(types1.BuildInfo) } - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, out.BuildInfo) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in, out.BuildInfo) } case "Indirect": out.Indirect = bool(in.Bool()) @@ -2325,7 +2325,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le in.Delim(']') } case "Layer": - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes3(in, &out.Layer) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes2(in, &out.Layer) case "FilePath": out.FilePath = string(in.String()) case "Digest": @@ -2347,7 +2347,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le } for !in.IsDelim(']') { var v52 types1.Location - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in, &v52) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes7(in, &v52) out.Locations = append(out.Locations, v52) in.WantComma() } @@ -2553,7 +2553,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, *in.BuildInfo) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, *in.BuildInfo) } if in.Indirect { const prefix string = ",\"Indirect\":" @@ -2592,7 +2592,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes3(out, in.Layer) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes2(out, in.Layer) } if in.FilePath != "" { const prefix string = ",\"FilePath\":" @@ -2628,7 +2628,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. if v58 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, v59) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes7(out, v59) } out.RawByte(']') } @@ -2654,7 +2654,7 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.Lexer, out *types1.BuildInfo) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes8(in *jlexer.Lexer, out *types1.BuildInfo) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -2710,7 +2710,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out *jwriter.Writer, in types1.BuildInfo) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out *jwriter.Writer, in types1.BuildInfo) { out.RawByte('{') first := true _ = first From 60b8ced1f5ece618f465ee2c1461c7b561ca269c Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 11:54:23 +0400 Subject: [PATCH 10/24] docs: restructure filtering Signed-off-by: knqyf263 --- docs/docs/configuration/filtering.md | 177 ++++++++------------ docs/docs/scanner/misconfiguration/index.md | 38 ++++- docs/docs/scanner/vulnerability.md | 70 ++++++++ mkdocs.yml | 6 +- 4 files changed, 183 insertions(+), 108 deletions(-) diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index 1f40d160c9cb..24af7b53596d 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -1,8 +1,34 @@ # Filtering Trivy provides various methods for filtering the results. +```mermaid +flowchart LR + Issues("Detected\nIssues") --> Severity + + subgraph Filtering + subgraph Prioritization + direction TB + Severity("By Severity") --> Status("By Status") + end + subgraph Suppression + Status --> Ignore("By Finding IDs") + Ignore --> Rego("By Rego") + Rego --> VEX("By VEX") + end + end + VEX --> Results +``` + +Similar to the functionality of filtering results, you can also limit the sub-targets for each scanner. +For information on these settings, please refer to the scanner-specific documentation ([vulnerability](../scanner/vulnerability.md) , [misconfiguration](../scanner/misconfiguration/index.md), etc.). + +## Prioritization +You can filter the results by + +- Severity +- Status -## By Status +### By Status | Scanner | Supported | |:----------------:|:---------:| @@ -75,7 +101,7 @@ Total: 527 (UNKNOWN: 0, LOW: 276, MEDIUM: 83, HIGH: 158, CRITICAL: 10) $ trivy image --ignore-unfixed ruby:2.4.0 ``` -## By Severity +### By Severity | Scanner | Supported | |:----------------:|:---------:| @@ -202,11 +228,49 @@ See https://avd.aquasec.com/misconfig/avd-aws-0081 ``` -## By Finding IDs +## Suppression +You can filter the results by + +- Finding IDs +- Rego +- Vulnerability Exploitability Exchange (VEX) + +To show the suppressed results, use the `--show-suppressed` flag. + +```bash +$ trivy image --vex debian11.csaf.vex --ignorefile .trivyignore.yaml --show-suppressed debian:11 +... + +Suppressed Vulnerabilities (Total: 9) + +┌───────────────┬───────────────┬──────────┬──────────────┬─────────────────────────────────────────────┬───────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Statement │ Source │ +├───────────────┼───────────────┼──────────┼──────────────┼─────────────────────────────────────────────┼───────────────────┤ +│ libdb5.3 │ CVE-2019-8457 │ CRITICAL │ not_affected │ vulnerable_code_not_in_execute_path │ CSAF VEX │ +├───────────────┼───────────────┼──────────┼──────────────┼─────────────────────────────────────────────┼───────────────────┤ +│ bsdutils │ CVE-2022-0563 │ LOW │ ignored │ Accept the risk │ .trivyignore.yaml │ +├───────────────┤ │ │ │ │ │ +│ libblkid1 │ │ │ │ │ │ +├───────────────┤ │ │ │ │ │ +│ libmount1 │ │ │ │ │ │ +├───────────────┤ │ │ │ │ │ +│ libsmartcols1 │ │ │ │ │ │ +├───────────────┤ │ │ │ │ │ +│ libuuid1 │ │ │ │ │ │ +├───────────────┤ │ │ │ │ │ +│ mount │ │ │ │ │ │ +├───────────────┼───────────────┤ │ ├─────────────────────────────────────────────┤ │ +│ tar │ CVE-2005-2541 │ │ │ The vulnerable configuration is not enabled │ │ +├───────────────┼───────────────┤ │ ├─────────────────────────────────────────────┤ │ +│ util-linux │ CVE-2022-0563 │ │ │ Accept the risk │ │ +└───────────────┴───────────────┴──────────┴──────────────┴─────────────────────────────────────────────┴───────────────────┘ +``` + +### By Finding IDs Trivy supports the [.trivyignore](#trivyignore) and [.trivyignore.yaml](#trivyignoreyaml) ignore files. -### .trivyignore +#### .trivyignore | Scanner | Supported | |:----------------:|:---------:| @@ -254,7 +318,7 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) -### .trivyignore.yaml +#### .trivyignore.yaml | Scanner | Supported | |:----------------:|:---------:| @@ -339,76 +403,7 @@ Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) - -## By Vulnerability Target -| Scanner | Supported | -|:----------------:|:---------:| -| Vulnerability | ✓ | -| Misconfiguration | | -| Secret | | -| License | | - -Use `--vuln-type` option. - -```bash -$ trivy image --vuln-type os ruby:2.4.0 -``` - -Available values: - -- library -- os - -
-Result - -```bash -2019-05-22T19:36:50.530+0200 INFO Updating vulnerability database... -2019-05-22T19:36:51.681+0200 INFO Detecting Alpine vulnerabilities... -2019-05-22T19:36:51.685+0200 INFO Updating npm Security DB... -2019-05-22T19:36:52.389+0200 INFO Detecting npm vulnerabilities... -2019-05-22T19:36:52.390+0200 INFO Updating pipenv Security DB... -2019-05-22T19:36:53.406+0200 INFO Detecting pipenv vulnerabilities... - -ruby:2.4.0 (debian 8.7) -======================= -Total: 7 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 3, CRITICAL: 2) - -+---------+------------------+----------+-------------------+---------------+----------------------------------+ -| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE | -+---------+------------------+----------+-------------------+---------------+----------------------------------+ -| curl | CVE-2018-14618 | CRITICAL | 7.61.0-r0 | 7.61.1-r0 | curl: NTLM password overflow | -| | | | | | via integer overflow | -+ +------------------+----------+ +---------------+----------------------------------+ -| | CVE-2018-16839 | HIGH | | 7.61.1-r1 | curl: Integer overflow leading | -| | | | | | to heap-based buffer overflow in | -| | | | | | Curl_sasl_create_plain_message() | -+---------+------------------+----------+-------------------+---------------+----------------------------------+ -| git | CVE-2018-17456 | HIGH | 2.15.2-r0 | 2.15.3-r0 | git: arbitrary code execution | -| | | | | | via .gitmodules | -+ +------------------+ + + +----------------------------------+ -| | CVE-2018-19486 | | | | git: Improper handling of | -| | | | | | PATH allows for commands to be | -| | | | | | executed from... | -+---------+------------------+----------+-------------------+---------------+----------------------------------+ -| libssh2 | CVE-2019-3855 | CRITICAL | 1.8.0-r2 | 1.8.1-r0 | libssh2: Integer overflow in | -| | | | | | transport read resulting in | -| | | | | | out of bounds write... | -+---------+------------------+----------+-------------------+---------------+----------------------------------+ -| sqlite | CVE-2018-20346 | MEDIUM | 3.21.0-r1 | 3.25.3-r0 | CVE-2018-20505 CVE-2018-20506 | -| | | | | | sqlite: Multiple flaws in | -| | | | | | sqlite which can be triggered | -| | | | | | via... | -+---------+------------------+----------+-------------------+---------------+----------------------------------+ -| tar | CVE-2018-20482 | LOW | 1.29-r1 | 1.31-r0 | tar: Infinite read loop in | -| | | | | | sparse_dump_region function in | -| | | | | | sparse.c | -+---------+------------------+----------+-------------------+---------------+----------------------------------+ -``` - -
- -## By Rego +### By Rego | Scanner | Supported | |:----------------:|:---------:| @@ -483,39 +478,15 @@ More info about the helper functions are in the library [here](https://github.co You can find more example policies [here](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/pkg/result/module.go) -## By Inline Comments - +### By Vulnerability Exploitability Exchange (VEX) | Scanner | Supported | |:----------------:|:---------:| -| Vulnerability | | -| Misconfiguration | ✓ | +| Vulnerability | ✓ | +| Misconfiguration | | | Secret | | | License | | -Some configuration file formats (e.g. Terraform) support inline comments. - -In cases where trivy can detect comments of a specific format immediately adjacent to resource definitions, it is possible to filter/ignore findings from a single point of resource definition (in contrast to `.trivyignore`, which has a directory-wide scope on all of the files scanned). - -The format for these comments is `trivy:ignore:` immediately following the format-specific line-comment token. You can add multiple ignores on the same comment line. - -For example, to filter a Vulnerability ID "AVD-GCP-0051" in a Terraform HCL file: +Please refer to the [VEX documentation](../supply-chain/vex.md) for the details. -```terraform -#trivy:ignore:AVD-GCP-0051 -resource "google_container_cluster" "one_off_test" { - name = var.cluster_name - location = var.region -} -``` - -For example, to filter vulnerabilities "AVD-GCP-0051" and "AVD-GCP-0053" in a Terraform HCL file: - -```terraform -#trivy:ignore:AVD-GCP-0051 trivy:ignore:AVD-GCP-0053 -resource "google_container_cluster" "one_off_test" { - name = var.cluster_name - location = var.region -} -``` [^1]: license name is used as id for `.trivyignore.yaml` files diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index 23c883a70ab1..026d86dc51f7 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -316,15 +316,17 @@ This section describes misconfiguration-specific configuration. Other common options are documented [here](../../configuration/index.md). ### Enabling a subset of misconfiguration scanners -It's possible to only enable certain misconfiguration scanners if you prefer. You can do so by passing the `--misconfig-scanners` option. +It's possible to only enable certain misconfiguration scanners if you prefer. +You can do so by passing the `--misconfig-scanners` option. This flag takes a comma-separated list of configuration scanner types. + ```bash trivy config --misconfig-scanners=terraform,dockerfile . ``` Will only scan for misconfigurations that pertain to Terraform and Dockerfiles. -### Pass custom policies +### Passing custom policies You can pass policy files or directories including your custom policies through `--policy` option. This can be repeated for specifying multiple files or directories. @@ -338,7 +340,7 @@ For more details, see [Custom Policies](./custom/index.md). !!! tip You also need to specify `--namespaces` option. -### Pass custom data +### Passing custom data You can pass directories including your custom data through `--data` option. This can be repeated for specifying multiple directories. @@ -349,7 +351,7 @@ trivy conf --policy ./policy --data ./data --namespaces user ./configs For more details, see [Custom Data](./custom/data.md). -### Pass namespaces +### Passing namespaces By default, Trivy evaluates policies defined in `builtin.*`. If you want to evaluate custom policies in other packages, you have to specify package prefixes through `--namespaces` option. This can be repeated for specifying multiple packages. @@ -358,4 +360,32 @@ This can be repeated for specifying multiple packages. trivy conf --policy ./policy --namespaces main --namespaces user ./configs ``` +### Skipping resources by inline comments +Some configuration file formats (e.g. Terraform) support inline comments. + +In cases where trivy can detect comments of a specific format immediately adjacent to resource definitions, it is possible to filter/ignore findings from a single point of resource definition (in contrast to `.trivyignore`, which has a directory-wide scope on all of the files scanned). + +The format for these comments is `trivy:ignore:` immediately following the format-specific line-comment token. +You can add multiple ignores on the same comment line. + +For example, to filter a misconfiguration ID "AVD-GCP-0051" in a Terraform HCL file: + +```terraform +#trivy:ignore:AVD-GCP-0051 +resource "google_container_cluster" "one_off_test" { + name = var.cluster_name + location = var.region +} +``` + +For example, to filter misconfigurations "AVD-GCP-0051" and "AVD-GCP-0053" in a Terraform HCL file: + +```terraform +#trivy:ignore:AVD-GCP-0051 trivy:ignore:AVD-GCP-0053 +resource "google_container_cluster" "one_off_test" { + name = var.cluster_name + location = var.region +} +``` + [custom]: custom/index.md \ No newline at end of file diff --git a/docs/docs/scanner/vulnerability.md b/docs/docs/scanner/vulnerability.md index 3e3ed617248d..e18fecfcbf30 100644 --- a/docs/docs/scanner/vulnerability.md +++ b/docs/docs/scanner/vulnerability.md @@ -152,6 +152,76 @@ The default is `ghcr.io/aquasecurity/trivy-java-db`. If authentication is required, you need to run `docker login YOUR_REGISTRY`. Currently, specifying a username and password is not supported. +## Configuration +This section describes vulnerability-specific configuration. +Other common options are documented [here](../configuration/index.md). + +### Enabling a subset of package types +It's possible to only enable certain package types if you prefer. +You can do so by passing the `--vuln-type` option. +This flag takes a comma-separated list of package types. + +Available values: + +- os + - Scan OS packages managed by the OS package manager (e.g. `dpkg`, `yum`, `apk`). +- library + - Scan language-specific packages (e.g. packages installed by `pip`, `npm`, or `gem`). + +```bash +$ trivy image --vuln-type os ruby:2.4.0 +``` + + +
+Result + +```bash +2019-05-22T19:36:50.530+0200 INFO Updating vulnerability database... +2019-05-22T19:36:51.681+0200 INFO Detecting Alpine vulnerabilities... +2019-05-22T19:36:51.685+0200 INFO Updating npm Security DB... +2019-05-22T19:36:52.389+0200 INFO Detecting npm vulnerabilities... +2019-05-22T19:36:52.390+0200 INFO Updating pipenv Security DB... +2019-05-22T19:36:53.406+0200 INFO Detecting pipenv vulnerabilities... + +ruby:2.4.0 (debian 8.7) +======================= +Total: 7 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 3, CRITICAL: 2) + ++---------+------------------+----------+-------------------+---------------+----------------------------------+ +| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE | ++---------+------------------+----------+-------------------+---------------+----------------------------------+ +| curl | CVE-2018-14618 | CRITICAL | 7.61.0-r0 | 7.61.1-r0 | curl: NTLM password overflow | +| | | | | | via integer overflow | ++ +------------------+----------+ +---------------+----------------------------------+ +| | CVE-2018-16839 | HIGH | | 7.61.1-r1 | curl: Integer overflow leading | +| | | | | | to heap-based buffer overflow in | +| | | | | | Curl_sasl_create_plain_message() | ++---------+------------------+----------+-------------------+---------------+----------------------------------+ +| git | CVE-2018-17456 | HIGH | 2.15.2-r0 | 2.15.3-r0 | git: arbitrary code execution | +| | | | | | via .gitmodules | ++ +------------------+ + + +----------------------------------+ +| | CVE-2018-19486 | | | | git: Improper handling of | +| | | | | | PATH allows for commands to be | +| | | | | | executed from... | ++---------+------------------+----------+-------------------+---------------+----------------------------------+ +| libssh2 | CVE-2019-3855 | CRITICAL | 1.8.0-r2 | 1.8.1-r0 | libssh2: Integer overflow in | +| | | | | | transport read resulting in | +| | | | | | out of bounds write... | ++---------+------------------+----------+-------------------+---------------+----------------------------------+ +| sqlite | CVE-2018-20346 | MEDIUM | 3.21.0-r1 | 3.25.3-r0 | CVE-2018-20505 CVE-2018-20506 | +| | | | | | sqlite: Multiple flaws in | +| | | | | | sqlite which can be triggered | +| | | | | | via... | ++---------+------------------+----------+-------------------+---------------+----------------------------------+ +| tar | CVE-2018-20482 | LOW | 1.29-r1 | 1.31-r0 | tar: Infinite read loop in | +| | | | | | sparse_dump_region function in | +| | | | | | sparse.c | ++---------+------------------+----------+-------------------+---------------+----------------------------------+ +``` + +
+ [^1]: https://github.com/GoogleContainerTools/distroless [nvd-CVE-2023-0464]: https://nvd.nist.gov/vuln/detail/CVE-2023-0464 diff --git a/mkdocs.yml b/mkdocs.yml index 4e7bf1ee633a..04a6ab3b47ad 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -202,7 +202,11 @@ theme: markdown_extensions: - pymdownx.highlight - - pymdownx.superfences + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format - admonition - footnotes - attr_list From c40ad45c8cad4e65b5b637eae3dd43c6500375da Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 12:02:07 +0400 Subject: [PATCH 11/24] docs: generate CLI references Signed-off-by: knqyf263 --- docs/docs/references/configuration/cli/trivy_aws.md | 1 + docs/docs/references/configuration/cli/trivy_config.md | 1 + docs/docs/references/configuration/cli/trivy_convert.md | 1 + docs/docs/references/configuration/cli/trivy_filesystem.md | 1 + docs/docs/references/configuration/cli/trivy_image.md | 1 + docs/docs/references/configuration/cli/trivy_kubernetes.md | 1 + docs/docs/references/configuration/cli/trivy_repository.md | 1 + docs/docs/references/configuration/cli/trivy_rootfs.md | 1 + docs/docs/references/configuration/cli/trivy_sbom.md | 1 + docs/docs/references/configuration/cli/trivy_vm.md | 1 + pkg/flag/report_flags.go | 2 +- 11 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/docs/references/configuration/cli/trivy_aws.md b/docs/docs/references/configuration/cli/trivy_aws.md index 0218ccb1e987..f3eaebda8def 100644 --- a/docs/docs/references/configuration/cli/trivy_aws.md +++ b/docs/docs/references/configuration/cli/trivy_aws.md @@ -96,6 +96,7 @@ trivy aws [flags] --reset-policy-bundle remove policy bundle --service strings Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc. -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-policy-update skip fetching rego policy updates --skip-service strings Skip selected AWS Service(s) specified with this flag. Can specify multiple services using --skip-service A --skip-service B etc. -t, --template string output template diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 79d99cad7331..cfca3ef6b919 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -44,6 +44,7 @@ trivy config [flags] DIR --report string specify a compliance report format for the output (all,summary) (default "all") --reset-policy-bundle remove policy bundle -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip --skip-policy-update skip fetching rego policy updates diff --git a/docs/docs/references/configuration/cli/trivy_convert.md b/docs/docs/references/configuration/cli/trivy_convert.md index 409e1009951d..457157082c50 100644 --- a/docs/docs/references/configuration/cli/trivy_convert.md +++ b/docs/docs/references/configuration/cli/trivy_convert.md @@ -31,6 +31,7 @@ trivy convert [flags] RESULT_JSON --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --report string specify a report format for the output (all,summary) (default "all") -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings -t, --template string output template ``` diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index c34288188900..a7b001e77cd4 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -75,6 +75,7 @@ trivy filesystem [flags] PATH --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index f016a7fff185..301f9ac272ee 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -95,6 +95,7 @@ trivy image [flags] IMAGE_NAME --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 00657886c681..00500fa0c2df 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -87,6 +87,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: --scanners strings comma-separated list of what security issues to detect (vuln,misconfig,secret,rbac) (default [vuln,misconfig,secret,rbac]) --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index b21ffd326db0..a648794ee2d8 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -74,6 +74,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 47e9a434f075..fb475701412a 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -76,6 +76,7 @@ trivy rootfs [flags] ROOTDIR --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index b0fd202863b0..be6f8be8f5b9 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -52,6 +52,7 @@ trivy sbom [flags] SBOM_PATH --sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor) --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 3c4d8c06ff7d..b7deef2b2f81 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -67,6 +67,7 @@ trivy vm [flags] VM_IMAGE --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 988383eb9ed5..881056128014 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -104,7 +104,7 @@ var ( ShowSuppressedFlag = Flag[bool]{ Name: "show-suppressed", ConfigName: "scan.show-suppressed", - Usage: "show suppressed security findings", + Usage: "[EXPERIMENTAL] show suppressed security findings", } ) From 013cf37e6783e0316471d76bb320ff7f1f6d06b7 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 13:29:08 +0400 Subject: [PATCH 12/24] fix(windows): to slash Signed-off-by: knqyf263 --- pkg/result/filter.go | 3 ++- pkg/result/ignore.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/result/filter.go b/pkg/result/filter.go index 5454ebe69228..df25d2613bb6 100644 --- a/pkg/result/filter.go +++ b/pkg/result/filter.go @@ -232,7 +232,6 @@ func summarize(status types.MisconfStatus, summary *types.MisconfSummary) { } func applyPolicy(ctx context.Context, result *types.Result, policyFile string) error { - policyFile = filepath.Clean(policyFile) policy, err := os.ReadFile(policyFile) if err != nil { return xerrors.Errorf("unable to read the policy file: %w", err) @@ -247,6 +246,8 @@ func applyPolicy(ctx context.Context, result *types.Result, policyFile string) e return xerrors.Errorf("unable to prepare for eval: %w", err) } + policyFile = filepath.ToSlash(filepath.Clean(policyFile)) + // Vulnerabilities var filteredVulns []types.DetectedVulnerability for _, vuln := range result.Vulnerabilities { diff --git a/pkg/result/ignore.go b/pkg/result/ignore.go index f627eed95957..70293fa41cc3 100644 --- a/pkg/result/ignore.go +++ b/pkg/result/ignore.go @@ -167,7 +167,7 @@ func parseIgnoreFile(ctx context.Context, ignoreFile string) (IgnoreConfig, erro conf.Misconfigurations.Filter(ctx) conf.Secrets.Filter(ctx) conf.Licenses.Filter(ctx) - conf.FilePath = filepath.Clean(ignoreFile) + conf.FilePath = filepath.ToSlash(filepath.Clean(ignoreFile)) return conf, nil } From af70c697b22cd9ae1f109a01e86ad3c04e821007 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 8 Feb 2024 15:14:26 +0400 Subject: [PATCH 13/24] Update pkg/result/filter_test.go Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> --- pkg/result/filter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/result/filter_test.go b/pkg/result/filter_test.go index 0da3833491e3..536aec21d360 100644 --- a/pkg/result/filter_test.go +++ b/pkg/result/filter_test.go @@ -543,7 +543,7 @@ func TestFilter(t *testing.T) { { Vulnerabilities: []types.DetectedVulnerability{ vuln1, - vuln2, // ignored by policy + vuln2, // ignored by severity vuln3, // ignored by policy }, }, From 00816fb35e560bda08131ea09a302aca24171459 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 8 Feb 2024 15:14:54 +0400 Subject: [PATCH 14/24] Update pkg/result/filter_test.go Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> --- pkg/result/filter_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/result/filter_test.go b/pkg/result/filter_test.go index 536aec21d360..41eec6efd572 100644 --- a/pkg/result/filter_test.go +++ b/pkg/result/filter_test.go @@ -325,7 +325,7 @@ func TestFilter(t *testing.T) { Target: "deployment.yaml", Class: types.ClassConfig, Misconfigurations: []types.DetectedMisconfiguration{ - misconf1, + misconf1, // filtered by severity misconf2, misconf3, }, From 32191f1f353b377efb1ebb3fcf5c2928a640633e Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 15:13:05 +0400 Subject: [PATCH 15/24] fix: disable '--show-suppressed` for other than vulns Signed-off-by: knqyf263 --- docs/docs/references/configuration/cli/trivy_aws.md | 1 - docs/docs/references/configuration/cli/trivy_config.md | 1 - pkg/commands/app.go | 2 ++ 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_aws.md b/docs/docs/references/configuration/cli/trivy_aws.md index f3eaebda8def..0218ccb1e987 100644 --- a/docs/docs/references/configuration/cli/trivy_aws.md +++ b/docs/docs/references/configuration/cli/trivy_aws.md @@ -96,7 +96,6 @@ trivy aws [flags] --reset-policy-bundle remove policy bundle --service strings Only scan AWS Service(s) specified with this flag. Can specify multiple services using --service A --service B etc. -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-policy-update skip fetching rego policy updates --skip-service strings Skip selected AWS Service(s) specified with this flag. Can specify multiple services using --skip-service A --skip-service B etc. -t, --template string output template diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index cfca3ef6b919..79d99cad7331 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -44,7 +44,6 @@ trivy config [flags] DIR --report string specify a compliance report format for the output (all,summary) (default "all") --reset-policy-bundle remove policy bundle -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip --skip-policy-update skip fetching rego policy updates diff --git a/pkg/commands/app.go b/pkg/commands/app.go index 50ee64c617f4..069c9f8b71cd 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -643,6 +643,7 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { reportFlagGroup.DependencyTree = nil // disable '--dependency-tree' reportFlagGroup.ListAllPkgs = nil // disable '--list-all-pkgs' reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' + reportFlagGroup.ShowSuppressed = nil // disable '--show-suppressed' reportFormat := flag.ReportFormatFlag.Clone() reportFormat.Usage = "specify a compliance report format for the output" // @TODO: support --report summary for non compliance reports reportFlagGroup.ReportFormat = reportFormat @@ -988,6 +989,7 @@ func NewAWSCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { } reportFlagGroup.Compliance = &compliance // override usage as the accepted values differ for each subcommand. reportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' + reportFlagGroup.ShowSuppressed = nil // disable '--show-suppressed' awsFlags := &flag.Flags{ GlobalFlagGroup: globalFlags, From 15b5c257a675a0cce2eeef4664d7a176683b0695 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 15:13:24 +0400 Subject: [PATCH 16/24] docs: fix the description of '--show-suppressed' Signed-off-by: knqyf263 --- pkg/flag/report_flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 881056128014..94b8c2ff689d 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -104,7 +104,7 @@ var ( ShowSuppressedFlag = Flag[bool]{ Name: "show-suppressed", ConfigName: "scan.show-suppressed", - Usage: "[EXPERIMENTAL] show suppressed security findings", + Usage: "[EXPERIMENTAL] show suppressed vulnerabilities", } ) From 07b8fcc42b09aa5cc929dec7f54d34f777378c2c Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 15:15:34 +0400 Subject: [PATCH 17/24] refactor: remove unnecessary log Signed-off-by: knqyf263 --- pkg/vex/cyclonedx.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/vex/cyclonedx.go b/pkg/vex/cyclonedx.go index 5b9db00d13c7..f1a860fe7ae7 100644 --- a/pkg/vex/cyclonedx.go +++ b/pkg/vex/cyclonedx.go @@ -77,10 +77,6 @@ func (v *CycloneDX) affected(vuln types.DetectedVulnerability, stmt Statement) b continue } if vuln.PkgIdentifier.Match(link.Reference()) && (stmt.Status == types.FindingStatusNotAffected || stmt.Status == types.FindingStatusFixed) { - v.logger.Infow("Filtered out the detected vulnerability", - zap.String("vulnerability-id", vuln.VulnerabilityID), - zap.String("status", string(stmt.Status)), - zap.String("justification", stmt.Justification)) return false } } From 872172bc2539d5f49f590f6de8de1d304b5207d8 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 15:19:18 +0400 Subject: [PATCH 18/24] fix: filter vulns by VEX at the end Signed-off-by: knqyf263 --- pkg/result/filter.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/result/filter.go b/pkg/result/filter.go index df25d2613bb6..d1569f720548 100644 --- a/pkg/result/filter.go +++ b/pkg/result/filter.go @@ -35,11 +35,6 @@ type FilterOption struct { // Filter filters out the report func Filter(ctx context.Context, report types.Report, opt FilterOption) error { - // Filter out vulnerabilities based on the given VEX document. - if err := filterByVEX(report, opt); err != nil { - return xerrors.Errorf("VEX error: %w", err) - } - ignoreConf, err := parseIgnoreFile(ctx, opt.IgnoreFile) if err != nil { return xerrors.Errorf("%s error: %w", opt.IgnoreFile, err) @@ -50,6 +45,12 @@ func Filter(ctx context.Context, report types.Report, opt FilterOption) error { return xerrors.Errorf("unable to filter vulnerabilities: %w", err) } } + + // Filter out vulnerabilities based on the given VEX document. + if err = filterByVEX(report, opt); err != nil { + return xerrors.Errorf("VEX error: %w", err) + } + return nil } From 9f84faec0cffc592ab3c2501bf02262a411fc351 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 8 Feb 2024 15:25:23 +0400 Subject: [PATCH 19/24] Update docs/docs/configuration/filtering.md Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> --- docs/docs/configuration/filtering.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index 24af7b53596d..43ad8e5106b9 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -25,8 +25,8 @@ For information on these settings, please refer to the scanner-specific document ## Prioritization You can filter the results by -- Severity -- Status +- [Severity](#by-severity) +- [Status](#by-status) ### By Status From 9ac010c8470ee637d3330a13ed2c14bb1175e240 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 15:27:58 +0400 Subject: [PATCH 20/24] docs: add anchors Signed-off-by: knqyf263 --- docs/docs/configuration/filtering.md | 152 +++++++++++++-------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index 43ad8e5106b9..428220c87dfc 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -28,79 +28,6 @@ You can filter the results by - [Severity](#by-severity) - [Status](#by-status) -### By Status - -| Scanner | Supported | -|:----------------:|:---------:| -| Vulnerability | ✓ | -| Misconfiguration | | -| Secret | | -| License | | - -Trivy supports the following vulnerability statuses: - -- `unknown` -- `not_affected`: this package is not affected by this vulnerability on this platform -- `affected`: this package is affected by this vulnerability on this platform, but there is no patch released yet -- `fixed`: this vulnerability is fixed on this platform -- `under_investigation`: it is currently unknown whether or not this vulnerability affects this package on this platform, and it is under investigation -- `will_not_fix`: this package is affected by this vulnerability on this platform, but there is currently no intention to fix it (this would primarily be for flaws that are of Low or Moderate impact that pose no significant risk to customers) -- `fix_deferred`: this package is affected by this vulnerability on this platform, and may be fixed in the future -- `end_of_life`: this package has been identified to contain the impacted component, but analysis to determine whether it is affected or not by this vulnerability was not performed - -Note that vulnerabilities with the `unknown`, `not_affected` or `under_investigation` status are not detected. -These are only defined for comprehensiveness, and you will not have the opportunity to specify these statuses. - -Some statuses are supported in limited distributions. - -| OS | Fixed | Affected | Under Investigation | Will Not Fix | Fix Deferred | End of Life | -|:----------:|:-----:|:--------:|:-------------------:|:------------:|:------------:|:-----------:| -| Debian | ✓ | ✓ | | | ✓ | ✓ | -| RHEL | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Other OSes | ✓ | ✓ | | | | | - - -To ignore vulnerabilities with specific statuses, use the `--ignore-status ` option. - - -```bash -$ trivy image --ignore-status affected,fixed ruby:2.4.0 -``` - -
-Result - -``` -2019-05-16T12:50:14.786+0900 INFO Detecting Debian vulnerabilities... - -ruby:2.4.0 (debian 8.7) -======================= -Total: 527 (UNKNOWN: 0, LOW: 276, MEDIUM: 83, HIGH: 158, CRITICAL: 10) - -┌─────────────────────────────┬──────────────────┬──────────┬──────────────┬────────────────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐ -│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ -├─────────────────────────────┼──────────────────┼──────────┼──────────────┼────────────────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ -│ binutils │ CVE-2014-9939 │ CRITICAL │ will_not_fix │ 2.25-5 │ │ binutils: buffer overflow in ihex.c │ -│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2014-9939 │ -│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ -│ │ CVE-2017-6969 │ │ │ │ │ binutils: Heap-based buffer over-read in readelf when │ -│ │ │ │ │ │ │ processing corrupt RL78 binaries │ -│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2017-6969 │ -│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ -... -``` - -
- -!!! tip - To skip all unfixed vulnerabilities, you can use the `--ignore-unfixed` flag . - It is a shorthand of `--ignore-status affected,will_not_fix,fix_deferred,end_of_life`. - It displays "fixed" vulnerabilities only. - -```bash -$ trivy image --ignore-unfixed ruby:2.4.0 -``` - ### By Severity | Scanner | Supported | @@ -228,12 +155,85 @@ See https://avd.aquasec.com/misconfig/avd-aws-0081 ``` +### By Status + +| Scanner | Supported | +|:----------------:|:---------:| +| Vulnerability | ✓ | +| Misconfiguration | | +| Secret | | +| License | | + +Trivy supports the following vulnerability statuses: + +- `unknown` +- `not_affected`: this package is not affected by this vulnerability on this platform +- `affected`: this package is affected by this vulnerability on this platform, but there is no patch released yet +- `fixed`: this vulnerability is fixed on this platform +- `under_investigation`: it is currently unknown whether or not this vulnerability affects this package on this platform, and it is under investigation +- `will_not_fix`: this package is affected by this vulnerability on this platform, but there is currently no intention to fix it (this would primarily be for flaws that are of Low or Moderate impact that pose no significant risk to customers) +- `fix_deferred`: this package is affected by this vulnerability on this platform, and may be fixed in the future +- `end_of_life`: this package has been identified to contain the impacted component, but analysis to determine whether it is affected or not by this vulnerability was not performed + +Note that vulnerabilities with the `unknown`, `not_affected` or `under_investigation` status are not detected. +These are only defined for comprehensiveness, and you will not have the opportunity to specify these statuses. + +Some statuses are supported in limited distributions. + +| OS | Fixed | Affected | Under Investigation | Will Not Fix | Fix Deferred | End of Life | +|:----------:|:-----:|:--------:|:-------------------:|:------------:|:------------:|:-----------:| +| Debian | ✓ | ✓ | | | ✓ | ✓ | +| RHEL | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Other OSes | ✓ | ✓ | | | | | + + +To ignore vulnerabilities with specific statuses, use the `--ignore-status ` option. + + +```bash +$ trivy image --ignore-status affected,fixed ruby:2.4.0 +``` + +
+Result + +``` +2019-05-16T12:50:14.786+0900 INFO Detecting Debian vulnerabilities... + +ruby:2.4.0 (debian 8.7) +======================= +Total: 527 (UNKNOWN: 0, LOW: 276, MEDIUM: 83, HIGH: 158, CRITICAL: 10) + +┌─────────────────────────────┬──────────────────┬──────────┬──────────────┬────────────────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────────────────────────┼──────────────────┼──────────┼──────────────┼────────────────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤ +│ binutils │ CVE-2014-9939 │ CRITICAL │ will_not_fix │ 2.25-5 │ │ binutils: buffer overflow in ihex.c │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2014-9939 │ +│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ +│ │ CVE-2017-6969 │ │ │ │ │ binutils: Heap-based buffer over-read in readelf when │ +│ │ │ │ │ │ │ processing corrupt RL78 binaries │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2017-6969 │ +│ ├──────────────────┤ │ │ ├───────────────┼──────────────────────────────────────────────────────────────┤ +... +``` + +
+ +!!! tip + To skip all unfixed vulnerabilities, you can use the `--ignore-unfixed` flag . + It is a shorthand of `--ignore-status affected,will_not_fix,fix_deferred,end_of_life`. + It displays "fixed" vulnerabilities only. + +```bash +$ trivy image --ignore-unfixed ruby:2.4.0 +``` + ## Suppression You can filter the results by -- Finding IDs -- Rego -- Vulnerability Exploitability Exchange (VEX) +- [Finding IDs](#by-finding-ids) +- [Rego](#by-rego) +- [Vulnerability Exploitability Exchange (VEX)](#by-vulnerability-exploitability-exchange-vex) To show the suppressed results, use the `--show-suppressed` flag. From ca63ec9b0331a92dd64222aaf9925a08174b7f78 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 15:58:15 +0400 Subject: [PATCH 21/24] test(table): add a test for suppressed vulns Signed-off-by: knqyf263 --- pkg/report/table/table_test.go | 290 +---------------- pkg/report/table/vulnerability.go | 4 +- pkg/report/table/vulnerability_test.go | 410 +++++++++++++++++++++++++ pkg/types/report.go | 2 +- 4 files changed, 423 insertions(+), 283 deletions(-) create mode 100644 pkg/report/table/vulnerability_test.go diff --git a/pkg/report/table/table_test.go b/pkg/report/table/table_test.go index 90edcdabcb7b..6b357a6d08dc 100644 --- a/pkg/report/table/table_test.go +++ b/pkg/report/table/table_test.go @@ -2,17 +2,17 @@ package table_test import ( "bytes" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "testing" "github.com/stretchr/testify/assert" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" - ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/report/table" "github.com/aquasecurity/trivy/pkg/types" ) -func TestReportWriter_Table(t *testing.T) { +func TestWriter_Write(t *testing.T) { testCases := []struct { name string results types.Results @@ -20,7 +20,7 @@ func TestReportWriter_Table(t *testing.T) { includeNonFailures bool }{ { - name: "happy path full", + name: "vulnerability and custom resource", results: types.Results{ { Target: "test", @@ -39,6 +39,12 @@ func TestReportWriter_Table(t *testing.T) { }, }, }, + CustomResources: []ftypes.CustomResource{ + { + Type: "test", + Data: "test", + }, + }, }, }, expectedOutput: ` @@ -55,291 +61,15 @@ Total: 1 (MEDIUM: 0, HIGH: 1) `, }, { - name: "happy path with filePath in result", + name: "no vulns", results: types.Results{ { Target: "test", Class: types.ClassLangPkg, - Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2020-0001", - PkgName: "foo", - PkgPath: "foo/bar", - InstalledVersion: "1.2.3", - FixedVersion: "3.4.5", - PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", - Status: dbTypes.StatusFixed, - Vulnerability: dbTypes.Vulnerability{ - Title: "foobar", - Description: "baz", - Severity: "HIGH", - }, - }, - }, }, }, - expectedOutput: ` -test () -======= -Total: 1 (MEDIUM: 0, HIGH: 1) - -┌───────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ -│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ -├───────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤ -│ foo (bar) │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │ -│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │ -└───────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ -`, - }, - { - name: "no title for vuln and missing primary link", - results: types.Results{ - { - Target: "test", - Class: types.ClassLangPkg, - Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2020-0001", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "3.4.5", - Status: dbTypes.StatusFixed, - Vulnerability: dbTypes.Vulnerability{ - Description: "foobar", - Severity: "HIGH", - }, - }, - }, - }, - }, - expectedOutput: ` -test () -======= -Total: 1 (MEDIUM: 0, HIGH: 1) - -┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐ -│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ -├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤ -│ foo │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │ -└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘ -`, - }, - { - name: "long title for vuln", - results: types.Results{ - { - Target: "test", - Class: types.ClassLangPkg, - Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2020-1234", - PkgName: "foo", - InstalledVersion: "1.2.3", - FixedVersion: "3.4.5", - PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-1234", - Status: dbTypes.StatusFixed, - Vulnerability: dbTypes.Vulnerability{ - Title: "a b c d e f g h i j k l m n o p q r s t u v", - Description: "foobar", - Severity: "HIGH", - }, - }, - }, - }, - }, - expectedOutput: ` -test () -======= -Total: 1 (MEDIUM: 0, HIGH: 1) - -┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ -│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ -├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤ -│ foo │ CVE-2020-1234 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ a b c d e f g h i j k l... │ -│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-1234 │ -└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ -`, - }, - { - name: "no vulns", expectedOutput: ``, }, - { - name: "happy path with vulnerability origin graph with direct dependency info", - results: types.Results{ - { - Target: "package-lock.json", - Class: types.ClassLangPkg, - Type: "npm", - Packages: []ftypes.Package{ - { - ID: "node-fetch@1.7.3", - Name: "node-fetch", - Version: "1.7.3", - Indirect: true, - }, - { - ID: "isomorphic-fetch@2.2.1", - Name: "isomorphic-fetch", - Version: "2.2.1", - Indirect: true, - DependsOn: []string{ - "node-fetch@1.7.3", - }, - }, - { - ID: "fbjs@0.8.18", - Name: "fbjs", - Version: "0.8.18", - Indirect: true, - DependsOn: []string{ - "isomorphic-fetch@2.2.1", - }, - }, - { - ID: "sanitize-html@1.20.0", - Name: "sanitize-html", - Version: "1.20.0", - }, - { - ID: "styled-components@3.1.3", - Name: "styled-components", - Version: "3.1.3", - DependsOn: []string{ - "fbjs@0.8.18", - }, - }, - }, - Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2022-0235", - PkgID: "node-fetch@1.7.3", - PkgName: "node-fetch", - Vulnerability: dbTypes.Vulnerability{ - Title: "foobar", - Description: "baz", - Severity: "HIGH", - }, - InstalledVersion: "1.7.3", - FixedVersion: "2.6.7, 3.1.1", - Status: dbTypes.StatusFixed, - }, - { - VulnerabilityID: "CVE-2021-26539", - PkgID: "sanitize-html@1.20.0", - PkgName: "sanitize-html", - Vulnerability: dbTypes.Vulnerability{ - Title: "foobar", - Description: "baz", - Severity: "MEDIUM", - }, - InstalledVersion: "1.20.0", - FixedVersion: "2.3.1", - Status: dbTypes.StatusFixed, - }, - }, - }, - }, - expectedOutput: ` -package-lock.json (npm) -======================= -Total: 2 (MEDIUM: 1, HIGH: 1) - -┌───────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐ -│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ -├───────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤ -│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │ -├───────────────┼────────────────┼──────────┤ ├───────────────────┼───────────────┤ │ -│ sanitize-html │ CVE-2021-26539 │ MEDIUM │ │ 1.20.0 │ 2.3.1 │ │ -└───────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘ - -Dependency Origin Tree (Reversed) -================================= -package-lock.json -├── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1) -│ └── ...(omitted)... -│ └── styled-components@3.1.3 -└── sanitize-html@1.20.0, (MEDIUM: 1, HIGH: 0) -`, - }, - { - name: "happy path with vulnerability origin graph without direct dependency info", - results: types.Results{ - { - Target: "package-lock.json", - Class: types.ClassLangPkg, - Type: "npm", - Packages: []ftypes.Package{ - { - ID: "node-fetch@1.7.3", - Name: "node-fetch", - Version: "1.7.3", - Indirect: true, - }, - { - ID: "isomorphic-fetch@2.2.1", - Name: "isomorphic-fetch", - Version: "2.2.1", - Indirect: true, - DependsOn: []string{ - "node-fetch@1.7.3", - }, - }, - { - ID: "fbjs@0.8.18", - Name: "fbjs", - Version: "0.8.18", - Indirect: true, - DependsOn: []string{ - "isomorphic-fetch@2.2.1", - }, - }, - { - ID: "styled-components@3.1.3", - Name: "styled-components", - Version: "3.1.3", - Indirect: true, - DependsOn: []string{ - "fbjs@0.8.18", - }, - }, - }, - Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2022-0235", - PkgID: "node-fetch@1.7.3", - PkgName: "node-fetch", - Vulnerability: dbTypes.Vulnerability{ - Title: "foobar", - Description: "baz", - Severity: "HIGH", - }, - InstalledVersion: "1.7.3", - FixedVersion: "2.6.7, 3.1.1", - Status: dbTypes.StatusFixed, - }, - }, - }, - }, - expectedOutput: ` -package-lock.json (npm) -======================= -Total: 1 (MEDIUM: 0, HIGH: 1) - -┌────────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐ -│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ -├────────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤ -│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │ -└────────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘ - -Dependency Origin Tree (Reversed) -================================= -package-lock.json -└── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1) - └── ...(omitted)... - └── styled-components@3.1.3 -`, - }, } for _, tc := range testCases { diff --git a/pkg/report/table/vulnerability.go b/pkg/report/table/vulnerability.go index c35b56a568ae..4515125efc44 100644 --- a/pkg/report/table/vulnerability.go +++ b/pkg/report/table/vulnerability.go @@ -175,10 +175,10 @@ func (r *vulnerabilityRenderer) renderModifiedVulnerabilities() { var total int for _, m := range r.result.ModifiedFindings { - vuln, ok := m.Finding.(types.DetectedVulnerability) - if !ok { + if m.Type != types.FindingTypeVulnerability { continue } + vuln := m.Finding.(types.DetectedVulnerability) total++ stmt := lo.Ternary(m.Statement != "", m.Statement, "N/A") diff --git a/pkg/report/table/vulnerability_test.go b/pkg/report/table/vulnerability_test.go new file mode 100644 index 000000000000..d941edc796f1 --- /dev/null +++ b/pkg/report/table/vulnerability_test.go @@ -0,0 +1,410 @@ +package table_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/report/table" + "github.com/aquasecurity/trivy/pkg/types" +) + +func Test_vulnerabilityRenderer_Render(t *testing.T) { + tests := []struct { + name string + result types.Result + want string + includeNonFailures bool + showSuppressed bool + }{ + { + name: "happy path full", + result: types.Result{ + Target: "test", + Class: types.ClassLangPkg, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-0001", + PkgName: "foo", + InstalledVersion: "1.2.3", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", + Status: dbTypes.StatusWillNotFix, + Vulnerability: dbTypes.Vulnerability{ + Title: "foobar", + Description: "baz", + Severity: "HIGH", + }, + }, + }, + // It won't be shown as `showSuppressed` is false. + ModifiedFindings: []types.ModifiedFinding{ + { + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Source: ".trivyignore", + Finding: types.DetectedVulnerability{ + VulnerabilityID: "CVE-2020-0002", + }, + }, + }, + }, + want: ` +test () +======= +Total: 1 (MEDIUM: 0, HIGH: 1) + +┌─────────┬───────────────┬──────────┬──────────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────┼───────────────┼──────────┼──────────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤ +│ foo │ CVE-2020-0001 │ HIGH │ will_not_fix │ 1.2.3 │ │ foobar │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │ +└─────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ +`, + }, + { + name: "happy path with filePath in result", + result: types.Result{ + Target: "test", + Class: types.ClassLangPkg, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-0001", + PkgName: "foo", + PkgPath: "foo/bar", + InstalledVersion: "1.2.3", + FixedVersion: "3.4.5", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", + Status: dbTypes.StatusFixed, + Vulnerability: dbTypes.Vulnerability{ + Title: "foobar", + Description: "baz", + Severity: "HIGH", + }, + }, + }, + }, + want: ` +test () +======= +Total: 1 (MEDIUM: 0, HIGH: 1) + +┌───────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├───────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤ +│ foo (bar) │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │ +└───────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ +`, + }, + { + name: "no title for vuln and missing primary link", + result: types.Result{ + Target: "test", + Class: types.ClassLangPkg, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-0001", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "3.4.5", + Status: dbTypes.StatusFixed, + Vulnerability: dbTypes.Vulnerability{ + Description: "foobar", + Severity: "HIGH", + }, + }, + }, + }, + want: ` +test () +======= +Total: 1 (MEDIUM: 0, HIGH: 1) + +┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤ +│ foo │ CVE-2020-0001 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ foobar │ +└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘ +`, + }, + { + name: "long title for vuln", + result: types.Result{ + Target: "test", + Class: types.ClassLangPkg, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-1234", + PkgName: "foo", + InstalledVersion: "1.2.3", + FixedVersion: "3.4.5", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-1234", + Status: dbTypes.StatusFixed, + Vulnerability: dbTypes.Vulnerability{ + Title: "a b c d e f g h i j k l m n o p q r s t u v", + Description: "foobar", + Severity: "HIGH", + }, + }, + }, + }, + want: ` +test () +======= +Total: 1 (MEDIUM: 0, HIGH: 1) + +┌─────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤ +│ foo │ CVE-2020-1234 │ HIGH │ fixed │ 1.2.3 │ 3.4.5 │ a b c d e f g h i j k l... │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-1234 │ +└─────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ +`, + }, + { + name: "happy path with vulnerability origin graph with direct dependency info", + result: types.Result{ + Target: "package-lock.json", + Class: types.ClassLangPkg, + Type: "npm", + Packages: []ftypes.Package{ + { + ID: "node-fetch@1.7.3", + Name: "node-fetch", + Version: "1.7.3", + Indirect: true, + }, + { + ID: "isomorphic-fetch@2.2.1", + Name: "isomorphic-fetch", + Version: "2.2.1", + Indirect: true, + DependsOn: []string{ + "node-fetch@1.7.3", + }, + }, + { + ID: "fbjs@0.8.18", + Name: "fbjs", + Version: "0.8.18", + Indirect: true, + DependsOn: []string{ + "isomorphic-fetch@2.2.1", + }, + }, + { + ID: "sanitize-html@1.20.0", + Name: "sanitize-html", + Version: "1.20.0", + }, + { + ID: "styled-components@3.1.3", + Name: "styled-components", + Version: "3.1.3", + DependsOn: []string{ + "fbjs@0.8.18", + }, + }, + }, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-0235", + PkgID: "node-fetch@1.7.3", + PkgName: "node-fetch", + Vulnerability: dbTypes.Vulnerability{ + Title: "foobar", + Description: "baz", + Severity: "HIGH", + }, + InstalledVersion: "1.7.3", + FixedVersion: "2.6.7, 3.1.1", + Status: dbTypes.StatusFixed, + }, + { + VulnerabilityID: "CVE-2021-26539", + PkgID: "sanitize-html@1.20.0", + PkgName: "sanitize-html", + Vulnerability: dbTypes.Vulnerability{ + Title: "foobar", + Description: "baz", + Severity: "MEDIUM", + }, + InstalledVersion: "1.20.0", + FixedVersion: "2.3.1", + Status: dbTypes.StatusFixed, + }, + }, + }, + want: ` +package-lock.json (npm) +======================= +Total: 2 (MEDIUM: 1, HIGH: 1) + +┌───────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├───────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤ +│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │ +├───────────────┼────────────────┼──────────┤ ├───────────────────┼───────────────┤ │ +│ sanitize-html │ CVE-2021-26539 │ MEDIUM │ │ 1.20.0 │ 2.3.1 │ │ +└───────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘ + +Dependency Origin Tree (Reversed) +================================= +package-lock.json +├── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1) +│ └── ...(omitted)... +│ └── styled-components@3.1.3 +└── sanitize-html@1.20.0, (MEDIUM: 1, HIGH: 0) +`, + }, + { + name: "happy path with vulnerability origin graph without direct dependency info", + result: types.Result{ + Target: "package-lock.json", + Class: types.ClassLangPkg, + Type: "npm", + Packages: []ftypes.Package{ + { + ID: "node-fetch@1.7.3", + Name: "node-fetch", + Version: "1.7.3", + Indirect: true, + }, + { + ID: "isomorphic-fetch@2.2.1", + Name: "isomorphic-fetch", + Version: "2.2.1", + Indirect: true, + DependsOn: []string{ + "node-fetch@1.7.3", + }, + }, + { + ID: "fbjs@0.8.18", + Name: "fbjs", + Version: "0.8.18", + Indirect: true, + DependsOn: []string{ + "isomorphic-fetch@2.2.1", + }, + }, + { + ID: "styled-components@3.1.3", + Name: "styled-components", + Version: "3.1.3", + Indirect: true, + DependsOn: []string{ + "fbjs@0.8.18", + }, + }, + }, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-0235", + PkgID: "node-fetch@1.7.3", + PkgName: "node-fetch", + Vulnerability: dbTypes.Vulnerability{ + Title: "foobar", + Description: "baz", + Severity: "HIGH", + }, + InstalledVersion: "1.7.3", + FixedVersion: "2.6.7, 3.1.1", + Status: dbTypes.StatusFixed, + }, + }, + }, + want: ` +package-lock.json (npm) +======================= +Total: 1 (MEDIUM: 0, HIGH: 1) + +┌────────────┬───────────────┬──────────┬────────┬───────────────────┬───────────────┬────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├────────────┼───────────────┼──────────┼────────┼───────────────────┼───────────────┼────────┤ +│ node-fetch │ CVE-2022-0235 │ HIGH │ fixed │ 1.7.3 │ 2.6.7, 3.1.1 │ foobar │ +└────────────┴───────────────┴──────────┴────────┴───────────────────┴───────────────┴────────┘ + +Dependency Origin Tree (Reversed) +================================= +package-lock.json +└── node-fetch@1.7.3, (MEDIUM: 0, HIGH: 1) + └── ...(omitted)... + └── styled-components@3.1.3 +`, + }, + { + name: "show suppressed vulnerabilities", + result: types.Result{ + Target: "test", + Class: types.ClassLangPkg, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-0001", + PkgName: "foo", + InstalledVersion: "1.2.3", + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", + Status: dbTypes.StatusWillNotFix, + Vulnerability: dbTypes.Vulnerability{ + Title: "title1", + Description: "desc1", + Severity: "HIGH", + }, + }, + }, + ModifiedFindings: []types.ModifiedFinding{ + { + Type: types.FindingTypeVulnerability, + Status: types.FindingStatusIgnored, + Statement: "Not exploitable", + Source: ".trivyignore.yaml", + Finding: types.DetectedVulnerability{ + VulnerabilityID: "CVE-2020-0002", + PkgName: "bar", + InstalledVersion: "1.2.3", + Status: dbTypes.StatusWillNotFix, + Vulnerability: dbTypes.Vulnerability{ + Title: "title2", + Description: "desc2", + Severity: "MEDIUM", + }, + }, + }, + }, + }, + showSuppressed: true, + want: ` +test () +======= +Total: 1 (MEDIUM: 0, HIGH: 1) + +┌─────────┬───────────────┬──────────┬──────────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────┼───────────────┼──────────┼──────────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤ +│ foo │ CVE-2020-0001 │ HIGH │ will_not_fix │ 1.2.3 │ │ title1 │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │ +└─────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ + +Suppressed Vulnerabilities (Total: 1) +===================================== +┌─────────┬───────────────┬──────────┬─────────┬─────────────────┬───────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Statement │ Source │ +├─────────┼───────────────┼──────────┼─────────┼─────────────────┼───────────────────┤ +│ bar │ CVE-2020-0002 │ MEDIUM │ ignored │ Not exploitable │ .trivyignore.yaml │ +└─────────┴───────────────┴──────────┴─────────┴─────────────────┴───────────────────┘ +`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := table.NewVulnerabilityRenderer(tt.result, false, true, tt.showSuppressed, []dbTypes.Severity{ + dbTypes.SeverityHigh, + dbTypes.SeverityMedium, + }) + assert.Equal(t, tt.want, r.Render(), tt.name) + }) + } +} diff --git a/pkg/types/report.go b/pkg/types/report.go index 4db84b6a6084..6b8aae6940b6 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -120,7 +120,7 @@ type Result struct { func (r *Result) IsEmpty() bool { return len(r.Packages) == 0 && len(r.Vulnerabilities) == 0 && len(r.Misconfigurations) == 0 && - len(r.Secrets) == 0 && len(r.Licenses) == 0 && len(r.CustomResources) == 0 + len(r.Secrets) == 0 && len(r.Licenses) == 0 && len(r.CustomResources) == 0 && len(r.ModifiedFindings) == 0 } type MisconfSummary struct { From 49e9d220f6986d83b510abffb6f6cd46e19af006 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Thu, 8 Feb 2024 15:59:45 +0400 Subject: [PATCH 22/24] docs: re-generate Signed-off-by: knqyf263 --- docs/docs/references/configuration/cli/trivy_convert.md | 2 +- docs/docs/references/configuration/cli/trivy_filesystem.md | 2 +- docs/docs/references/configuration/cli/trivy_image.md | 2 +- docs/docs/references/configuration/cli/trivy_kubernetes.md | 2 +- docs/docs/references/configuration/cli/trivy_repository.md | 2 +- docs/docs/references/configuration/cli/trivy_rootfs.md | 2 +- docs/docs/references/configuration/cli/trivy_sbom.md | 2 +- docs/docs/references/configuration/cli/trivy_vm.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_convert.md b/docs/docs/references/configuration/cli/trivy_convert.md index 457157082c50..e8fe589500ea 100644 --- a/docs/docs/references/configuration/cli/trivy_convert.md +++ b/docs/docs/references/configuration/cli/trivy_convert.md @@ -31,7 +31,7 @@ trivy convert [flags] RESULT_JSON --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --report string specify a report format for the output (all,summary) (default "all") -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities -t, --template string output template ``` diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index a7b001e77cd4..217518e18203 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -75,7 +75,7 @@ trivy filesystem [flags] PATH --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 301f9ac272ee..bc27d91213b3 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -95,7 +95,7 @@ trivy image [flags] IMAGE_NAME --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 00500fa0c2df..8ac7b84e08c6 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -87,7 +87,7 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: --scanners strings comma-separated list of what security issues to detect (vuln,misconfig,secret,rbac) (default [vuln,misconfig,secret,rbac]) --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index a648794ee2d8..a497a389ab68 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -74,7 +74,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index fb475701412a..79deabae2a42 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -76,7 +76,7 @@ trivy rootfs [flags] ROOTDIR --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index be6f8be8f5b9..04e024f5e656 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -52,7 +52,7 @@ trivy sbom [flags] SBOM_PATH --sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor) --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index b7deef2b2f81..2ac579ca53bc 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -67,7 +67,7 @@ trivy vm [flags] VM_IMAGE --secret-config string specify a path to config file for secret scanning (default "trivy-secret.yaml") --server string server address in client mode -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed security findings + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities --skip-db-update skip updating vulnerability database --skip-dirs strings specify the directories or glob patterns to skip --skip-files strings specify the files or glob patterns to skip From 44ed73b94800cdddf3c4605ccdef69354074b0c0 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Fri, 9 Feb 2024 06:41:39 +0400 Subject: [PATCH 23/24] refactor: remove unused variable Signed-off-by: knqyf263 --- pkg/compliance/report/table.go | 9 +++------ pkg/k8s/report/table.go | 9 +++------ pkg/report/table/table.go | 5 +---- pkg/report/writer.go | 2 -- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/pkg/compliance/report/table.go b/pkg/compliance/report/table.go index c54f031ef3d6..5a95f11dafa8 100644 --- a/pkg/compliance/report/table.go +++ b/pkg/compliance/report/table.go @@ -2,10 +2,8 @@ package report import ( "context" - "io" - "sync" - "golang.org/x/xerrors" + "io" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" pkgReport "github.com/aquasecurity/trivy/pkg/report/table" @@ -31,9 +29,8 @@ func (tw TableWriter) Write(ctx context.Context, report *ComplianceReport) error switch tw.Report { case allReport: t := pkgReport.Writer{ - Output: tw.Output, - Severities: tw.Severities, - ShowMessageOnce: &sync.Once{}, + Output: tw.Output, + Severities: tw.Severities, } for _, cr := range report.Results { r := types.Report{Results: cr.Results} diff --git a/pkg/k8s/report/table.go b/pkg/k8s/report/table.go index 640d116cbd84..41f772ad3b5b 100644 --- a/pkg/k8s/report/table.go +++ b/pkg/k8s/report/table.go @@ -2,10 +2,8 @@ package report import ( "context" - "io" - "sync" - "golang.org/x/xerrors" + "io" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" pkgReport "github.com/aquasecurity/trivy/pkg/report/table" @@ -48,9 +46,8 @@ func (tw TableWriter) Write(ctx context.Context, report Report) error { switch tw.Report { case AllReport: t := pkgReport.Writer{ - Output: tw.Output, - Severities: tw.Severities, - ShowMessageOnce: &sync.Once{}, + Output: tw.Output, + Severities: tw.Severities, } for _, r := range report.Resources { if r.Report.Results.Failed() { diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index ec13e1f76218..f636b71f9560 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -7,7 +7,6 @@ import ( "os" "runtime" "strings" - "sync" "github.com/fatih/color" "golang.org/x/exp/slices" @@ -39,9 +38,6 @@ type Writer struct { // Show suppressed findings ShowSuppressed bool - // We have to show a message once about using the '-format json' subcommand to get the full pkgPath - ShowMessageOnce *sync.Once - // For misconfigurations IncludeNonFailures bool Trace bool @@ -57,6 +53,7 @@ type Renderer interface { // Write writes the result on standard output func (tw Writer) Write(_ context.Context, report types.Report) error { + for _, result := range report.Results { // Not display a table of custom resources if result.Class == types.ClassCustom { diff --git a/pkg/report/writer.go b/pkg/report/writer.go index 3b25e2d165b9..274688591151 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -5,7 +5,6 @@ import ( "errors" "io" "strings" - "sync" "golang.org/x/xerrors" @@ -50,7 +49,6 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e Severities: option.Severities, Tree: option.DependencyTree, ShowSuppressed: option.ShowSuppressed, - ShowMessageOnce: &sync.Once{}, IncludeNonFailures: option.IncludeNonFailures, Trace: option.Trace, LicenseRiskThreshold: option.LicenseRiskThreshold, From 350191a51a209b74d93325475dca4759539015cd Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Fri, 9 Feb 2024 06:42:00 +0400 Subject: [PATCH 24/24] feat: show a log message about "--show-suppressed" once Signed-off-by: knqyf263 --- pkg/compliance/report/table.go | 3 ++- pkg/k8s/report/table.go | 3 ++- pkg/report/table/vulnerability.go | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/compliance/report/table.go b/pkg/compliance/report/table.go index 5a95f11dafa8..f82571c9b718 100644 --- a/pkg/compliance/report/table.go +++ b/pkg/compliance/report/table.go @@ -2,9 +2,10 @@ package report import ( "context" - "golang.org/x/xerrors" "io" + "golang.org/x/xerrors" + dbTypes "github.com/aquasecurity/trivy-db/pkg/types" pkgReport "github.com/aquasecurity/trivy/pkg/report/table" "github.com/aquasecurity/trivy/pkg/types" diff --git a/pkg/k8s/report/table.go b/pkg/k8s/report/table.go index 41f772ad3b5b..524a1c389b03 100644 --- a/pkg/k8s/report/table.go +++ b/pkg/k8s/report/table.go @@ -2,9 +2,10 @@ package report import ( "context" - "golang.org/x/xerrors" "io" + "golang.org/x/xerrors" + dbTypes "github.com/aquasecurity/trivy-db/pkg/types" pkgReport "github.com/aquasecurity/trivy/pkg/report/table" ) diff --git a/pkg/report/table/vulnerability.go b/pkg/report/table/vulnerability.go index 4515125efc44..bdfa9bf1af1d 100644 --- a/pkg/report/table/vulnerability.go +++ b/pkg/report/table/vulnerability.go @@ -21,6 +21,10 @@ import ( "github.com/aquasecurity/trivy/pkg/types" ) +var showSuppressedOnce = sync.OnceFunc(func() { + log.Logger.Info(`Some vulnerabilities have been ignored/suppressed. Use the "--show-suppressed" flag to display them.`) +}) + type vulnerabilityRenderer struct { w *bytes.Buffer result types.Result @@ -56,6 +60,8 @@ func (r *vulnerabilityRenderer) Render() string { if r.showSuppressed { r.renderModifiedVulnerabilities() + } else if len(r.result.ModifiedFindings) > 0 { + showSuppressedOnce() } return r.w.String()