From ff62336fe08a6ae0196216fcf7b4a3be042c1cf7 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Wed, 25 Dec 2024 14:02:39 +0400 Subject: [PATCH 01/27] feat(cli): add report summary Signed-off-by: knqyf263 --- pkg/report/table/summary.go | 86 +++++++++++++++++++++++++++++++++++++ pkg/report/table/table.go | 75 ++++++++++++++++++++++++++++++++ pkg/report/writer.go | 1 + 3 files changed, 162 insertions(+) create mode 100644 pkg/report/table/summary.go diff --git a/pkg/report/table/summary.go b/pkg/report/table/summary.go new file mode 100644 index 000000000000..e9bffc242050 --- /dev/null +++ b/pkg/report/table/summary.go @@ -0,0 +1,86 @@ +package table + +import ( + "github.com/aquasecurity/table" + "github.com/aquasecurity/trivy/pkg/types" +) + +type Scanner interface { + Header() string + Alignment() table.Alignment + + // Count returns the number of findings, but -1 if the scanner is not applicable + Count(result types.Result) int +} + +func NewScanner(scanner types.Scanner) Scanner { + switch scanner { + case types.VulnerabilityScanner: + return VulnerabilityScanner{} + case types.MisconfigScanner: + return MisconfigScanner{} + case types.SecretScanner: + return SecretScanner{} + case types.LicenseScanner: + return LicenseScanner{} + } + return nil +} + +type scannerAlignment struct{} + +func (s scannerAlignment) Alignment() table.Alignment { + return table.AlignCenter +} + +type VulnerabilityScanner struct{ scannerAlignment } + +func (s VulnerabilityScanner) Header() string { + return "Vulnerabilities" +} + +func (s VulnerabilityScanner) Count(result types.Result) int { + if result.Class == types.ClassOSPkg || result.Class == types.ClassLangPkg { + return len(result.Vulnerabilities) + } + return -1 +} + +type MisconfigScanner struct{ scannerAlignment } + +func (s MisconfigScanner) Header() string { + return "Misconfigurations" +} + +func (s MisconfigScanner) Count(result types.Result) int { + if result.Class == types.ClassConfig { + return len(result.Misconfigurations) + } + return -1 +} + +type SecretScanner struct{ scannerAlignment } + +func (s SecretScanner) Header() string { + return "Secrets" +} + +func (s SecretScanner) Count(result types.Result) int { + if result.Class == types.ClassSecret { + return len(result.Secrets) + } + return -1 +} + +type LicenseScanner struct{ scannerAlignment } + +func (s LicenseScanner) Header() string { + return "Licenses" +} + +func (s LicenseScanner) Count(result types.Result) int { + if result.Class == types.ClassLicense { + return len(result.Licenses) + } + return -1 +} diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 8bfa75922013..08f7651b5173 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -10,6 +10,8 @@ import ( "strings" "github.com/fatih/color" + "github.com/samber/lo" + "golang.org/x/xerrors" "github.com/aquasecurity/table" "github.com/aquasecurity/tml" @@ -29,6 +31,7 @@ var ( // Writer implements Writer and output in tabular form type Writer struct { + Scanners types.Scanners Severities []dbTypes.Severity Output io.Writer @@ -53,6 +56,13 @@ type Renderer interface { // Write writes the result on standard output func (tw Writer) Write(_ context.Context, report types.Report) error { + if !tw.isOutputToTerminal() { + tml.DisableFormatting() + } + + if err := tw.renderSummary(report); err != nil { + return xerrors.Errorf("failed to render summary: %w", err) + } for _, result := range report.Results { // Not display a table of custom resources @@ -64,6 +74,60 @@ func (tw Writer) Write(_ context.Context, report types.Report) error { return nil } +func (tw Writer) renderSummary(report types.Report) error { + // Fprintln has a bug + if err := tml.Fprintf(tw.Output, "\nReport Summary\n\n"); err != nil { + return err + } + + t := newTableWriter(tw.Output, tw.isOutputToTerminal()) + t.SetAutoMerge(false) + t.SetColumnMaxWidth(80) + + var scanners []Scanner + for _, scanner := range tw.Scanners { + s := NewScanner(scanner) + if lo.IsNil(s) { + continue + } + scanners = append(scanners, s) + } + + headers := []string{ + "Target", + "Type", + } + alignments := []table.Alignment{ + table.AlignLeft, + table.AlignCenter, + } + for _, scanner := range scanners { + headers = append(headers, scanner.Header()) + alignments = append(alignments, scanner.Alignment()) + } + t.SetHeaders(headers...) + t.SetAlignment(alignments...) + + for _, result := range report.Results { + resultType := string(result.Type) + if result.Class == types.ClassSecret { + resultType = "text" + } else if result.Class == types.ClassLicense { + resultType = "-" + } + rows := []string{ + result.Target, + resultType, + } + for _, scanner := range scanners { + rows = append(rows, tw.colorizeCount(scanner.Count(result))) + } + t.AddRows(rows) + } + t.Render() + return nil +} + func (tw Writer) write(result types.Result) { if result.IsEmpty() && result.Class != types.ClassOSPkg { return @@ -97,6 +161,17 @@ func (tw Writer) isOutputToTerminal() bool { return IsOutputToTerminal(tw.Output) } +func (tw Writer) colorizeCount(count int) string { + if count < 0 { + return "-" + } + sprintf := fmt.Sprintf + if count != 0 && tw.isOutputToTerminal() { + sprintf = color.New(color.FgHiRed).SprintfFunc() + } + return sprintf("%d", count) +} + func newTableWriter(output io.Writer, isTerminal bool) *table.Table { tableWriter := table.New(output) if isTerminal { // use ansi output if we're not piping elsewhere diff --git a/pkg/report/writer.go b/pkg/report/writer.go index f25d579d66ef..c8079fa0f969 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -45,6 +45,7 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e switch option.Format { case types.FormatTable: writer = &table.Writer{ + Scanners: option.Scanners, Output: output, Severities: option.Severities, Tree: option.DependencyTree, From ca75fc90900dd483269f2c662850128292bd146f Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 16 Jan 2025 11:26:29 +0600 Subject: [PATCH 02/27] test: fix table tests --- pkg/report/table/table.go | 6 ++++ pkg/report/table/table_test.go | 55 ++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 08f7651b5173..6b8fd86a51e9 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -93,6 +93,12 @@ func (tw Writer) renderSummary(report types.Report) error { scanners = append(scanners, s) } + // It should be an impossible case. + // But it is possible when Trivy is used as a library. + if len(scanners) == 0 { + return xerrors.Errorf("unable to find scanners") + } + headers := []string{ "Target", "Type", diff --git a/pkg/report/table/table_test.go b/pkg/report/table/table_test.go index d52dda0dc232..0da0bd361b5b 100644 --- a/pkg/report/table/table_test.go +++ b/pkg/report/table/table_test.go @@ -16,15 +16,21 @@ import ( func TestWriter_Write(t *testing.T) { testCases := []struct { name string + scanners types.Scanners results types.Results - expectedOutput string + wantOutput string + wantError string includeNonFailures bool }{ { name: "vulnerability and custom resource", + scanners: types.Scanners{ + types.VulnerabilityScanner, + }, results: types.Results{ { Target: "test", + Type: ftypes.Jar, Class: types.ClassLangPkg, Vulnerabilities: []types.DetectedVulnerability{ { @@ -48,9 +54,17 @@ func TestWriter_Write(t *testing.T) { }, }, }, - expectedOutput: ` -test () -======= + wantOutput: ` +Report Summary + +┌────────┬──────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├────────┼──────┼─────────────────┤ +│ test │ jar │ 1 │ +└────────┴──────┴─────────────────┘ + +test (jar) +========== Total: 1 (MEDIUM: 0, HIGH: 1) ┌─────────┬───────────────┬──────────┬──────────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ @@ -63,13 +77,36 @@ Total: 1 (MEDIUM: 0, HIGH: 1) }, { name: "no vulns", + scanners: types.Scanners{ + types.VulnerabilityScanner, + }, + results: types.Results{ + { + Target: "test", + Class: types.ClassLangPkg, + Type: ftypes.Jar, + }, + }, + wantOutput: ` +Report Summary + +┌────────┬──────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├────────┼──────┼─────────────────┤ +│ test │ jar │ 0 │ +└────────┴──────┴─────────────────┘ +`, + }, + { + name: "no scanners", results: types.Results{ { Target: "test", Class: types.ClassLangPkg, + Type: ftypes.Jar, }, }, - expectedOutput: ``, + wantError: "unable to find scanners", }, } @@ -85,10 +122,16 @@ Total: 1 (MEDIUM: 0, HIGH: 1) dbTypes.SeverityHigh, dbTypes.SeverityMedium, }, + Scanners: tc.scanners, } err := writer.Write(nil, types.Report{Results: tc.results}) + if tc.wantError != "" { + require.Error(t, err) + return + } + require.NoError(t, err) - assert.Equal(t, tc.expectedOutput, tableWritten.String(), tc.name) + assert.Equal(t, tc.wantOutput, tableWritten.String(), tc.name) }) } } From ef269402e73eea8836c4388f981fb32ec926c678 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 16 Jan 2025 11:59:10 +0600 Subject: [PATCH 03/27] feat: add `--no-summary` flag --- pkg/flag/report_flags.go | 17 +++++++++++++++++ pkg/flag/report_flags_test.go | 17 +++++++++++++++++ pkg/report/table/table.go | 9 +++++++-- pkg/report/table/table_test.go | 19 ++++++++++++++++++- pkg/report/writer.go | 1 + 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index d69443e89547..52db8e050574 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -109,6 +109,11 @@ var ( ConfigName: "scan.show-suppressed", Usage: "[EXPERIMENTAL] show suppressed vulnerabilities", } + NoSummaryFlag = Flag[bool]{ + Name: "no-summary", + ConfigName: "no-summary", + Usage: "hide summary table", + } ) // ReportFlagGroup composes common printer flag structs @@ -128,6 +133,7 @@ type ReportFlagGroup struct { Severity *Flag[[]string] Compliance *Flag[string] ShowSuppressed *Flag[bool] + NoSummary *Flag[bool] } type ReportOptions struct { @@ -145,6 +151,7 @@ type ReportOptions struct { Severities []dbTypes.Severity Compliance spec.ComplianceSpec ShowSuppressed bool + NoSummary bool } func NewReportFlagGroup() *ReportFlagGroup { @@ -163,6 +170,7 @@ func NewReportFlagGroup() *ReportFlagGroup { Severity: SeverityFlag.Clone(), Compliance: ComplianceFlag.Clone(), ShowSuppressed: ShowSuppressedFlag.Clone(), + NoSummary: NoSummaryFlag.Clone(), } } @@ -186,6 +194,7 @@ func (f *ReportFlagGroup) Flags() []Flagger { f.Severity, f.Compliance, f.ShowSuppressed, + f.NoSummary, } } @@ -198,6 +207,7 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { template := f.Template.Value() dependencyTree := f.DependencyTree.Value() listAllPkgs := f.ListAllPkgs.Value() + noSummary := f.NoSummary.Value() if template != "" { if format == "" { @@ -227,6 +237,12 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { } } + // "--so-summary" option is available only with "--format table". + if noSummary && format != types.FormatTable { + noSummary = false + log.Warn(`"--no-summary" can be used only with "--format table".`) + } + cs, err := loadComplianceTypes(f.Compliance.Value()) if err != nil { return ReportOptions{}, xerrors.Errorf("unable to load compliance spec: %w", err) @@ -259,6 +275,7 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { Severities: toSeverity(f.Severity.Value()), Compliance: cs, ShowSuppressed: f.ShowSuppressed.Value(), + NoSummary: noSummary, }, nil } diff --git a/pkg/flag/report_flags_test.go b/pkg/flag/report_flags_test.go index ab4baa53fbff..ded87412f590 100644 --- a/pkg/flag/report_flags_test.go +++ b/pkg/flag/report_flags_test.go @@ -32,6 +32,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { compliance string debug bool pkgTypes string + noSummary bool } tests := []struct { name string @@ -115,6 +116,20 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { ListAllPkgs: true, }, }, + { + name: "invalid option combination: --no-summary with --format json", + fields: fields{ + format: "json", + noSummary: true, + }, + wantLogs: []string{ + `"--no-summary" can be used only with "--format table".`, + }, + want: flag.ReportOptions{ + Format: "json", + NoSummary: false, + }, + }, { name: "happy path with output plugin args", fields: fields{ @@ -184,6 +199,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { setValue(flag.OutputPluginArgFlag.ConfigName, tt.fields.outputPluginArgs) setValue(flag.SeverityFlag.ConfigName, tt.fields.severities) setValue(flag.ComplianceFlag.ConfigName, tt.fields.compliance) + setValue(flag.NoSummaryFlag.ConfigName, tt.fields.noSummary) // Assert options f := &flag.ReportFlagGroup{ @@ -199,6 +215,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { OutputPluginArg: flag.OutputPluginArgFlag.Clone(), Severity: flag.SeverityFlag.Clone(), Compliance: flag.ComplianceFlag.Clone(), + NoSummary: flag.NoSummaryFlag.Clone(), } got, err := f.ToOptions() diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 6b8fd86a51e9..ca9442d32616 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -41,6 +41,9 @@ type Writer struct { // Show suppressed findings ShowSuppressed bool + // Hide summary table + NoSummary bool + // For misconfigurations IncludeNonFailures bool Trace bool @@ -60,8 +63,10 @@ func (tw Writer) Write(_ context.Context, report types.Report) error { tml.DisableFormatting() } - if err := tw.renderSummary(report); err != nil { - return xerrors.Errorf("failed to render summary: %w", err) + if !tw.NoSummary { + if err := tw.renderSummary(report); err != nil { + return xerrors.Errorf("failed to render summary: %w", err) + } } for _, result := range report.Results { diff --git a/pkg/report/table/table_test.go b/pkg/report/table/table_test.go index 0da0bd361b5b..78f3ae63c126 100644 --- a/pkg/report/table/table_test.go +++ b/pkg/report/table/table_test.go @@ -17,6 +17,7 @@ func TestWriter_Write(t *testing.T) { testCases := []struct { name string scanners types.Scanners + noSummary bool results types.Results wantOutput string wantError string @@ -97,6 +98,21 @@ Report Summary └────────┴──────┴─────────────────┘ `, }, + { + name: "no summary", + scanners: types.Scanners{ + types.VulnerabilityScanner, + }, + noSummary: true, + results: types.Results{ + { + Target: "test", + Class: types.ClassLangPkg, + Type: ftypes.Jar, + }, + }, + wantOutput: ``, + }, { name: "no scanners", results: types.Results{ @@ -122,7 +138,8 @@ Report Summary dbTypes.SeverityHigh, dbTypes.SeverityMedium, }, - Scanners: tc.scanners, + Scanners: tc.scanners, + NoSummary: tc.noSummary, } err := writer.Write(nil, types.Report{Results: tc.results}) if tc.wantError != "" { diff --git a/pkg/report/writer.go b/pkg/report/writer.go index c8079fa0f969..38cb16fdb8a0 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -54,6 +54,7 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e Trace: option.Trace, LicenseRiskThreshold: option.LicenseRiskThreshold, IgnoredLicenses: option.IgnoredLicenses, + NoSummary: option.NoSummary, } case types.FormatJSON: writer = &JSONWriter{ From 3ea064f9fdd1b59bdcbf601efa4b8c7a50558c7f Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 16 Jan 2025 15:13:30 +0600 Subject: [PATCH 04/27] test: add test for `renderSummary` --- pkg/report/table/table.go | 2 +- pkg/report/table/table_private_test.go | 227 +++++++++++++++++++++++++ 2 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 pkg/report/table/table_private_test.go diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index ca9442d32616..0da4b4a2c1c2 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -123,7 +123,7 @@ func (tw Writer) renderSummary(report types.Report) error { resultType := string(result.Type) if result.Class == types.ClassSecret { resultType = "text" - } else if result.Class == types.ClassLicense { + } else if result.Class == types.ClassLicense || result.Class == types.ClassLicenseFile { resultType = "-" } rows := []string{ diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go new file mode 100644 index 000000000000..d732c298ac2d --- /dev/null +++ b/pkg/report/table/table_private_test.go @@ -0,0 +1,227 @@ +package table + +import ( + "bytes" + "testing" + + "github.com/aquasecurity/tml" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + osVuln = types.Result{ + Target: "test (alpine 3.20.3)", + Class: types.ClassOSPkg, + Type: ftypes.Alpine, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2024-9143", + PkgName: "libcrypto3", + }, + { + VulnerabilityID: "CVE-2024-9143", + PkgName: "libssl3", + }, + }, + } + jarVuln = types.Result{ + Target: "Java", + Class: types.ClassLangPkg, + Type: ftypes.Jar, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-42003", + PkgName: "com.fasterxml.jackson.core:jackson-databind", + PkgPath: "app/jackson-databind-2.13.4.1.jar", + }, + { + VulnerabilityID: "CVE-2021-44832", + PkgName: "org.apache.logging.log4j:log4j-core", + PkgPath: "app/log4j-core-2.17.0.jar", + }, + }, + } + + noVuln = types.Result{ + Target: "requirements.txt", + Class: types.ClassLangPkg, + Type: ftypes.Pip, + } + + dockerfileMisconfig = types.Result{ + Target: "app/Dockerfile", + Class: types.ClassConfig, + Type: ftypes.Dockerfile, + Misconfigurations: []types.DetectedMisconfiguration{ + { + ID: "DS002", + }, + { + ID: "DS026", + }, + }, + } + secret = types.Result{ + Target: "/app/aws-secrets.txt", + Class: types.ClassSecret, + Secrets: []types.DetectedSecret{ + { + RuleID: "aws-access-key-id", + }, + }, + } + osLicense = types.Result{ + Target: "OS Packages", + Class: types.ClassLicense, + Licenses: []types.DetectedLicense{ + { + Name: "GPL-2.0-only", + }, + }, + } + + jarLicense = types.Result{ + Target: "Java", + Class: types.ClassLicense, + } + fileLicense = types.Result{ + Target: "Loose File License(s)", + Class: types.ClassLicenseFile, + } +) + +func Test_renderSummary(t *testing.T) { + tests := []struct { + name string + scanners types.Scanners + noSummary bool + report types.Report + want string + }{ + { + name: "happy path all scanners", + scanners: []types.Scanner{ + types.VulnerabilityScanner, + types.MisconfigScanner, + types.SecretScanner, + types.LicenseScanner, + }, + report: types.Report{ + Results: []types.Result{ + osVuln, + jarVuln, + dockerfileMisconfig, + secret, + osLicense, + jarLicense, + fileLicense, + }, + }, + want: ` +Report Summary + +┌───────────────────────┬────────────┬─────────────────┬───────────────────┬─────────┬──────────┐ +│ Target │ Type │ Vulnerabilities │ Misconfigurations │ Secrets │ Licenses │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ test (alpine 3.20.3) │ alpine │ 2 │ - │ - │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ Java │ jar │ 2 │ - │ - │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ app/Dockerfile │ dockerfile │ - │ 2 │ - │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ /app/aws-secrets.txt │ text │ - │ - │ 1 │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ OS Packages │ - │ - │ - │ - │ 1 │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ Java │ - │ - │ - │ - │ 0 │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ Loose File License(s) │ - │ - │ - │ - │ - │ +└───────────────────────┴────────────┴─────────────────┴───────────────────┴─────────┴──────────┘ +`, + }, + { + name: "happy path vuln scanner only", + scanners: []types.Scanner{ + types.VulnerabilityScanner, + }, + report: types.Report{ + Results: []types.Result{ + osVuln, + jarVuln, + }, + }, + want: ` +Report Summary + +┌──────────────────────┬────────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├──────────────────────┼────────┼─────────────────┤ +│ test (alpine 3.20.3) │ alpine │ 2 │ +├──────────────────────┼────────┼─────────────────┤ +│ Java │ jar │ 2 │ +└──────────────────────┴────────┴─────────────────┘ +`, + }, + { + name: "happy path vuln scanner only without vulnerabilities", + scanners: []types.Scanner{ + types.VulnerabilityScanner, + }, + report: types.Report{ + Results: []types.Result{ + noVuln, + }, + }, + want: ` +Report Summary + +┌──────────────────┬──────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├──────────────────┼──────┼─────────────────┤ +│ requirements.txt │ pip │ 0 │ +└──────────────────┴──────┴─────────────────┘ +`, + }, + { + name: "happy path vuln scanner only", + scanners: []types.Scanner{ + types.VulnerabilityScanner, + }, + report: types.Report{ + Results: []types.Result{ + osVuln, + jarVuln, + }, + }, + want: ` +Report Summary + +┌──────────────────────┬────────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├──────────────────────┼────────┼─────────────────┤ +│ test (alpine 3.20.3) │ alpine │ 2 │ +├──────────────────────┼────────┼─────────────────┤ +│ Java │ jar │ 2 │ +└──────────────────────┴────────┴─────────────────┘ +`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tml.DisableFormatting() + tableWritten := bytes.Buffer{} + writer := Writer{ + Output: &tableWritten, + Scanners: tt.scanners, + NoSummary: tt.noSummary, + } + err := writer.renderSummary(tt.report) + require.NoError(t, err) + assert.Equal(t, tt.want, tableWritten.String()) + }) + } +} From 8b2acf7169a847ec2dd26102c4ac7f040b9604dc Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Thu, 16 Jan 2025 15:18:59 +0600 Subject: [PATCH 05/27] mage docs:generate --- 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 + docs/docs/references/configuration/config-file.md | 3 +++ 10 files changed, 12 insertions(+) diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 7cc65a04e949..8ae258d3806c 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -36,6 +36,7 @@ trivy config [flags] DIR --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") + --no-summary hide summary table -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. diff --git a/docs/docs/references/configuration/cli/trivy_convert.md b/docs/docs/references/configuration/cli/trivy_convert.md index d76d303e3b03..3c53495d27f5 100644 --- a/docs/docs/references/configuration/cli/trivy_convert.md +++ b/docs/docs/references/configuration/cli/trivy_convert.md @@ -27,6 +27,7 @@ trivy convert [flags] RESULT_JSON --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs output all packages in the JSON report regardless of vulnerability + --no-summary hide summary table -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --report string specify a report format for the output (all,summary) (default "all") diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index dab87fc541fc..e3aa97ed4a3c 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -64,6 +64,7 @@ trivy filesystem [flags] PATH --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar + --no-summary hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index d9c312602190..b426621d0b02 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -82,6 +82,7 @@ trivy image [flags] IMAGE_NAME --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar + --no-summary hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 959532e1c806..4b5ee8fdc092 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -77,6 +77,7 @@ trivy kubernetes [flags] [CONTEXT] --list-all-pkgs output all packages in the JSON report regardless of vulnerability --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --no-progress suppress progress bar + --no-summary hide summary table --node-collector-imageref string indicate the image reference for the node-collector scan job (default "ghcr.io/aquasecurity/node-collector:0.3.1") --node-collector-namespace string specify the namespace in which the node-collector job should be deployed (default "trivy-temp") --offline-scan do not issue API requests to identify dependencies diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 38ae6611b595..99f37c1ee5b5 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -63,6 +63,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar + --no-summary hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 35cc54ff66a3..45c34d3a5a6a 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -66,6 +66,7 @@ trivy rootfs [flags] ROOTDIR --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar + --no-summary hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 63f855b13335..5fc019e7fa06 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -45,6 +45,7 @@ trivy sbom [flags] SBOM_PATH --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [mirror.gcr.io/aquasec/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1]) --list-all-pkgs output all packages in the JSON report regardless of vulnerability --no-progress suppress progress bar + --no-summary hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 6fe9de30fcd8..5441bee3d9c4 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -58,6 +58,7 @@ trivy vm [flags] VM_IMAGE --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar + --no-summary hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index fe6332522ee0..41b3153e5462 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -521,6 +521,9 @@ ignorefile: ".trivyignore" # Same as '--list-all-pkgs' list-all-pkgs: false +# Same as '--no-summary' +no-summary: false + # Same as '--output' output: "" From 751823ab5b640bda9303c6f506a50aa474c0e50c Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 17 Jan 2025 13:29:05 +0600 Subject: [PATCH 06/27] refactor: rename `no-summary` to `no-summary-table` --- .../configuration/cli/trivy_config.md | 2 +- .../configuration/cli/trivy_convert.md | 2 +- .../configuration/cli/trivy_filesystem.md | 2 +- .../configuration/cli/trivy_image.md | 2 +- .../configuration/cli/trivy_kubernetes.md | 2 +- .../configuration/cli/trivy_repository.md | 2 +- .../configuration/cli/trivy_rootfs.md | 2 +- .../configuration/cli/trivy_sbom.md | 2 +- .../references/configuration/cli/trivy_vm.md | 2 +- .../references/configuration/config-file.md | 4 ++-- pkg/flag/report_flags.go | 24 +++++++++---------- pkg/flag/report_flags_test.go | 18 +++++++------- pkg/report/table/table.go | 4 ++-- pkg/report/table/table_private_test.go | 16 ++++++------- pkg/report/table/table_test.go | 8 +++---- pkg/report/writer.go | 2 +- 16 files changed, 47 insertions(+), 47 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 8ae258d3806c..fb9d40a8cf69 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -36,7 +36,7 @@ trivy config [flags] DIR --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") - --no-summary hide summary table + --no-summary-table hide summary table -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. diff --git a/docs/docs/references/configuration/cli/trivy_convert.md b/docs/docs/references/configuration/cli/trivy_convert.md index 3c53495d27f5..ec01f6014eaf 100644 --- a/docs/docs/references/configuration/cli/trivy_convert.md +++ b/docs/docs/references/configuration/cli/trivy_convert.md @@ -27,7 +27,7 @@ trivy convert [flags] RESULT_JSON --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --list-all-pkgs output all packages in the JSON report regardless of vulnerability - --no-summary hide summary table + --no-summary-table hide summary table -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --report string specify a report format for the output (all,summary) (default "all") diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index e3aa97ed4a3c..409b30357fee 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -64,7 +64,7 @@ trivy filesystem [flags] PATH --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar - --no-summary hide summary table + --no-summary-table hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index b426621d0b02..8cace7ae9eef 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -82,7 +82,7 @@ trivy image [flags] IMAGE_NAME --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar - --no-summary hide summary table + --no-summary-table hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 4b5ee8fdc092..27f372ae3b89 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -77,7 +77,7 @@ trivy kubernetes [flags] [CONTEXT] --list-all-pkgs output all packages in the JSON report regardless of vulnerability --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --no-progress suppress progress bar - --no-summary hide summary table + --no-summary-table hide summary table --node-collector-imageref string indicate the image reference for the node-collector scan job (default "ghcr.io/aquasecurity/node-collector:0.3.1") --node-collector-namespace string specify the namespace in which the node-collector job should be deployed (default "trivy-temp") --offline-scan do not issue API requests to identify dependencies diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 99f37c1ee5b5..4df9b3798d56 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -63,7 +63,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar - --no-summary hide summary table + --no-summary-table hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 45c34d3a5a6a..a02dc2b289e8 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -66,7 +66,7 @@ trivy rootfs [flags] ROOTDIR --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar - --no-summary hide summary table + --no-summary-table hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 5fc019e7fa06..0ecd234ab457 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -45,7 +45,7 @@ trivy sbom [flags] SBOM_PATH --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [mirror.gcr.io/aquasec/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1]) --list-all-pkgs output all packages in the JSON report regardless of vulnerability --no-progress suppress progress bar - --no-summary hide summary table + --no-summary-table hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 5441bee3d9c4..3d2349a78ca6 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -58,7 +58,7 @@ trivy vm [flags] VM_IMAGE --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar - --no-summary hide summary table + --no-summary-table hide summary table --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 41b3153e5462..01cf1a9a27cd 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -521,8 +521,8 @@ ignorefile: ".trivyignore" # Same as '--list-all-pkgs' list-all-pkgs: false -# Same as '--no-summary' -no-summary: false +# Same as '--no-summary-table' +no-summary-table: false # Same as '--output' output: "" diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 52db8e050574..ee7db0198c77 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -109,9 +109,9 @@ var ( ConfigName: "scan.show-suppressed", Usage: "[EXPERIMENTAL] show suppressed vulnerabilities", } - NoSummaryFlag = Flag[bool]{ - Name: "no-summary", - ConfigName: "no-summary", + NoSummaryTableFlag = Flag[bool]{ + Name: "no-summary-table", + ConfigName: "no-summary-table", Usage: "hide summary table", } ) @@ -133,7 +133,7 @@ type ReportFlagGroup struct { Severity *Flag[[]string] Compliance *Flag[string] ShowSuppressed *Flag[bool] - NoSummary *Flag[bool] + NoSummaryTable *Flag[bool] } type ReportOptions struct { @@ -151,7 +151,7 @@ type ReportOptions struct { Severities []dbTypes.Severity Compliance spec.ComplianceSpec ShowSuppressed bool - NoSummary bool + NoSummaryTable bool } func NewReportFlagGroup() *ReportFlagGroup { @@ -170,7 +170,7 @@ func NewReportFlagGroup() *ReportFlagGroup { Severity: SeverityFlag.Clone(), Compliance: ComplianceFlag.Clone(), ShowSuppressed: ShowSuppressedFlag.Clone(), - NoSummary: NoSummaryFlag.Clone(), + NoSummaryTable: NoSummaryTableFlag.Clone(), } } @@ -194,7 +194,7 @@ func (f *ReportFlagGroup) Flags() []Flagger { f.Severity, f.Compliance, f.ShowSuppressed, - f.NoSummary, + f.NoSummaryTable, } } @@ -207,7 +207,7 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { template := f.Template.Value() dependencyTree := f.DependencyTree.Value() listAllPkgs := f.ListAllPkgs.Value() - noSummary := f.NoSummary.Value() + noSummaryTable := f.NoSummaryTable.Value() if template != "" { if format == "" { @@ -238,9 +238,9 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { } // "--so-summary" option is available only with "--format table". - if noSummary && format != types.FormatTable { - noSummary = false - log.Warn(`"--no-summary" can be used only with "--format table".`) + if noSummaryTable && format != types.FormatTable { + noSummaryTable = false + log.Warn(`"--no-summary-table" can be used only with "--format table".`) } cs, err := loadComplianceTypes(f.Compliance.Value()) @@ -275,7 +275,7 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { Severities: toSeverity(f.Severity.Value()), Compliance: cs, ShowSuppressed: f.ShowSuppressed.Value(), - NoSummary: noSummary, + NoSummaryTable: noSummaryTable, }, nil } diff --git a/pkg/flag/report_flags_test.go b/pkg/flag/report_flags_test.go index ded87412f590..4cd99fe8aef7 100644 --- a/pkg/flag/report_flags_test.go +++ b/pkg/flag/report_flags_test.go @@ -32,7 +32,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { compliance string debug bool pkgTypes string - noSummary bool + noSummaryTable bool } tests := []struct { name string @@ -117,17 +117,17 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { }, }, { - name: "invalid option combination: --no-summary with --format json", + name: "invalid option combination: --no-summary-table with --format json", fields: fields{ - format: "json", - noSummary: true, + format: "json", + noSummaryTable: true, }, wantLogs: []string{ - `"--no-summary" can be used only with "--format table".`, + `"--no-summary-table" can be used only with "--format table".`, }, want: flag.ReportOptions{ - Format: "json", - NoSummary: false, + Format: "json", + NoSummaryTable: false, }, }, { @@ -199,7 +199,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { setValue(flag.OutputPluginArgFlag.ConfigName, tt.fields.outputPluginArgs) setValue(flag.SeverityFlag.ConfigName, tt.fields.severities) setValue(flag.ComplianceFlag.ConfigName, tt.fields.compliance) - setValue(flag.NoSummaryFlag.ConfigName, tt.fields.noSummary) + setValue(flag.NoSummaryTableFlag.ConfigName, tt.fields.noSummaryTable) // Assert options f := &flag.ReportFlagGroup{ @@ -215,7 +215,7 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { OutputPluginArg: flag.OutputPluginArgFlag.Clone(), Severity: flag.SeverityFlag.Clone(), Compliance: flag.ComplianceFlag.Clone(), - NoSummary: flag.NoSummaryFlag.Clone(), + NoSummaryTable: flag.NoSummaryTableFlag.Clone(), } got, err := f.ToOptions() diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 0da4b4a2c1c2..a4aeac332266 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -42,7 +42,7 @@ type Writer struct { ShowSuppressed bool // Hide summary table - NoSummary bool + NoSummaryTable bool // For misconfigurations IncludeNonFailures bool @@ -63,7 +63,7 @@ func (tw Writer) Write(_ context.Context, report types.Report) error { tml.DisableFormatting() } - if !tw.NoSummary { + if !tw.NoSummaryTable { if err := tw.renderSummary(report); err != nil { return xerrors.Errorf("failed to render summary: %w", err) } diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index d732c298ac2d..77a5ca064996 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -95,11 +95,11 @@ var ( func Test_renderSummary(t *testing.T) { tests := []struct { - name string - scanners types.Scanners - noSummary bool - report types.Report - want string + name string + scanners types.Scanners + noSummaryTable bool + report types.Report + want string }{ { name: "happy path all scanners", @@ -215,9 +215,9 @@ Report Summary tml.DisableFormatting() tableWritten := bytes.Buffer{} writer := Writer{ - Output: &tableWritten, - Scanners: tt.scanners, - NoSummary: tt.noSummary, + Output: &tableWritten, + Scanners: tt.scanners, + NoSummaryTable: tt.noSummaryTable, } err := writer.renderSummary(tt.report) require.NoError(t, err) diff --git a/pkg/report/table/table_test.go b/pkg/report/table/table_test.go index 78f3ae63c126..d88e8ee355c0 100644 --- a/pkg/report/table/table_test.go +++ b/pkg/report/table/table_test.go @@ -17,7 +17,7 @@ func TestWriter_Write(t *testing.T) { testCases := []struct { name string scanners types.Scanners - noSummary bool + noSummaryTable bool results types.Results wantOutput string wantError string @@ -103,7 +103,7 @@ Report Summary scanners: types.Scanners{ types.VulnerabilityScanner, }, - noSummary: true, + noSummaryTable: true, results: types.Results{ { Target: "test", @@ -138,8 +138,8 @@ Report Summary dbTypes.SeverityHigh, dbTypes.SeverityMedium, }, - Scanners: tc.scanners, - NoSummary: tc.noSummary, + Scanners: tc.scanners, + NoSummaryTable: tc.noSummaryTable, } err := writer.Write(nil, types.Report{Results: tc.results}) if tc.wantError != "" { diff --git a/pkg/report/writer.go b/pkg/report/writer.go index 38cb16fdb8a0..81d76dca69c7 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -54,7 +54,7 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e Trace: option.Trace, LicenseRiskThreshold: option.LicenseRiskThreshold, IgnoredLicenses: option.IgnoredLicenses, - NoSummary: option.NoSummary, + NoSummaryTable: option.NoSummaryTable, } case types.FormatJSON: writer = &JSONWriter{ From 37a072d2223fd01c575fe57eba13b709ae8fe89b Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 17 Jan 2025 13:34:07 +0600 Subject: [PATCH 07/27] fix: linter errors --- pkg/report/table/table_private_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index 77a5ca064996..15fc4d5c8e6f 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -4,11 +4,12 @@ import ( "bytes" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/aquasecurity/tml" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) var ( From f4f46a5045d52eb9dd9b7b746cbe9598c4cb33e8 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 17 Jan 2025 14:02:44 +0600 Subject: [PATCH 08/27] test: refactor secret result --- pkg/report/table/table_private_test.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index 15fc4d5c8e6f..c54c3ea5fb4c 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -66,7 +66,7 @@ var ( }, } secret = types.Result{ - Target: "/app/aws-secrets.txt", + Target: "requirements.txt", Class: types.ClassSecret, Secrets: []types.DetectedSecret{ { @@ -133,7 +133,7 @@ Report Summary ├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ │ app/Dockerfile │ dockerfile │ - │ 2 │ - │ - │ ├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ /app/aws-secrets.txt │ text │ - │ - │ 1 │ - │ +│ requirements.txt │ text │ - │ - │ 1 │ - │ ├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ │ OS Packages │ - │ - │ - │ - │ 1 │ ├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ @@ -167,23 +167,27 @@ Report Summary `, }, { - name: "happy path vuln scanner only without vulnerabilities", + name: "happy path no vulns + secret", scanners: []types.Scanner{ types.VulnerabilityScanner, + types.SecretScanner, }, report: types.Report{ Results: []types.Result{ noVuln, + secret, }, }, want: ` Report Summary -┌──────────────────┬──────┬─────────────────┐ -│ Target │ Type │ Vulnerabilities │ -├──────────────────┼──────┼─────────────────┤ -│ requirements.txt │ pip │ 0 │ -└──────────────────┴──────┴─────────────────┘ +┌──────────────────┬──────┬─────────────────┬─────────┐ +│ Target │ Type │ Vulnerabilities │ Secrets │ +├──────────────────┼──────┼─────────────────┼─────────┤ +│ requirements.txt │ pip │ 0 │ - │ +├──────────────────┼──────┼─────────────────┼─────────┤ +│ requirements.txt │ text │ - │ 1 │ +└──────────────────┴──────┴─────────────────┴─────────┘ `, }, { From 19fc0fe95eeb0e0ffe3f06660930f5b654506401 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 17 Jan 2025 14:35:33 +0600 Subject: [PATCH 09/27] docs: add info about summary table --- docs/docs/configuration/reporting.md | 73 +++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/docs/docs/configuration/reporting.md b/docs/docs/configuration/reporting.md index c6ddc1727a71..389731c6f107 100644 --- a/docs/docs/configuration/reporting.md +++ b/docs/docs/configuration/reporting.md @@ -19,10 +19,81 @@ Trivy supports the following formats: | Secret | ✓ | | License | ✓ | +```bash +$ trivy image -f table golang:1.22.11-alpine3.21 ``` -$ trivy image -f table golang:1.12-alpine + +
+Result + +``` +... + + +Report Summary + +┌─────────────────────────────────────────────┬──────────┬─────────────────┬─────────┐ +│ Target │ Type │ Vulnerabilities │ Secrets │ +├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤ +│ golang:1.22.11-alpine3.21 (alpine 3.21.2) │ alpine │ 0 │ - │ +├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤ +│ Node.js │ node-pkg │ 0 │ - │ +├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤ +│ usr/local/go/bin/go │ gobinary │ 0 │ - │ +├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤ +│ usr/local/go/bin/gofmt │ gobinary │ 0 │ - │ +├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤ +... +├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤ +│ usr/local/go/pkg/tool/linux_amd64/vet │ gobinary │ 0 │ - │ +└─────────────────────────────────────────────┴──────────┴─────────────────┴─────────┘ + +golang:1.22.11-alpine3.21 (alpine 3.21.2) + +Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) + ``` +
+ +#### Summary table +Before result tables Trivy shows summary table. + +
+Report Summary + +``` +┌───────────────────────┬────────────┬─────────────────┬───────────────────┬─────────┬──────────┐ +│ Target │ Type │ Vulnerabilities │ Misconfigurations │ Secrets │ Licenses │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ test (alpine 3.20.3) │ alpine │ 2 │ - │ - │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ Java │ jar │ 2 │ - │ - │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ app/Dockerfile │ dockerfile │ - │ 2 │ - │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ requirements.txt │ text │ 0 │ - │ - │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ requirements.txt │ text │ - │ - │ 1 │ - │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ OS Packages │ - │ - │ - │ - │ 1 │ +├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ Java │ - │ - │ - │ - │ 0 │ +└───────────────────────┴────────────┴─────────────────┴───────────────────┴─────────┴──────────┘ +``` + +
+ +This table: + +- include columns for enabled [scanners](../references/terminology.md#scanner) only. +- Contains separate lines for the same targets but different scanners. +- `-` means that Trivy didn't scan this target. +- `0` means that Trivy scanned this target, but found no vulns/misconfigs. + +!!! note + Use `--no-summary-table` flag to hide summary table. + #### Show origins of vulnerable dependencies | Scanner | Supported | From a27f879092d5e3f3dd08efd2b68666633416d0bd Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 17 Jan 2025 14:38:38 +0600 Subject: [PATCH 10/27] feat: add logs about `-` and `0` in summary table --- pkg/report/table/table.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index a4aeac332266..8b1b7804563b 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -9,6 +9,7 @@ import ( "slices" "strings" + "github.com/aquasecurity/trivy/pkg/log" "github.com/fatih/color" "github.com/samber/lo" "golang.org/x/xerrors" @@ -80,6 +81,9 @@ func (tw Writer) Write(_ context.Context, report types.Report) error { } func (tw Writer) renderSummary(report types.Report) error { + log.WithPrefix("report").Info("Report Summary table contains special symbols", + log.String("'-'", "Target didn't scanned"), + log.String("'0'", "Target scanned, but didn't contain vulns/misconfigs/secrets/licenses")) // Fprintln has a bug if err := tml.Fprintf(tw.Output, "\nReport Summary\n\n"); err != nil { return err From 239251bde638e6697e0beda1549c5c64bb8730d9 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Fri, 17 Jan 2025 14:51:16 +0600 Subject: [PATCH 11/27] fix: linter error --- pkg/report/table/table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 8b1b7804563b..eeac9794da5f 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -9,7 +9,6 @@ import ( "slices" "strings" - "github.com/aquasecurity/trivy/pkg/log" "github.com/fatih/color" "github.com/samber/lo" "golang.org/x/xerrors" @@ -17,6 +16,7 @@ import ( "github.com/aquasecurity/table" "github.com/aquasecurity/tml" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" ) From e11221a1af736f987de1aa165f28d1658efdacdf Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 11:52:47 +0600 Subject: [PATCH 12/27] refactor: use footer instead of log for legend --- pkg/report/table/table.go | 9 ++++---- pkg/report/table/table_private_test.go | 32 ++++++++------------------ 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index eeac9794da5f..3c5c59a33bde 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -16,7 +16,6 @@ import ( "github.com/aquasecurity/table" "github.com/aquasecurity/tml" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" - "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" ) @@ -81,11 +80,11 @@ func (tw Writer) Write(_ context.Context, report types.Report) error { } func (tw Writer) renderSummary(report types.Report) error { - log.WithPrefix("report").Info("Report Summary table contains special symbols", - log.String("'-'", "Target didn't scanned"), - log.String("'0'", "Target scanned, but didn't contain vulns/misconfigs/secrets/licenses")) // Fprintln has a bug - if err := tml.Fprintf(tw.Output, "\nReport Summary\n\n"); err != nil { + if err := tml.Fprintf(tw.Output, "\nReport Summary\n\n"+ + "Legend:\n"+ + "- '-': Not scanned\n"+ + "- '0': Clean (no security findings detected)\n"); err != nil { return err } diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index c54c3ea5fb4c..30a5842f8f2e 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -124,6 +124,9 @@ func Test_renderSummary(t *testing.T) { want: ` Report Summary +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) ┌───────────────────────┬────────────┬─────────────────┬───────────────────┬─────────┬──────────┐ │ Target │ Type │ Vulnerabilities │ Misconfigurations │ Secrets │ Licenses │ ├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ @@ -157,6 +160,9 @@ Report Summary want: ` Report Summary +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) ┌──────────────────────┬────────┬─────────────────┐ │ Target │ Type │ Vulnerabilities │ ├──────────────────────┼────────┼─────────────────┤ @@ -181,6 +187,9 @@ Report Summary want: ` Report Summary +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) ┌──────────────────┬──────┬─────────────────┬─────────┐ │ Target │ Type │ Vulnerabilities │ Secrets │ ├──────────────────┼──────┼─────────────────┼─────────┤ @@ -188,29 +197,6 @@ Report Summary ├──────────────────┼──────┼─────────────────┼─────────┤ │ requirements.txt │ text │ - │ 1 │ └──────────────────┴──────┴─────────────────┴─────────┘ -`, - }, - { - name: "happy path vuln scanner only", - scanners: []types.Scanner{ - types.VulnerabilityScanner, - }, - report: types.Report{ - Results: []types.Result{ - osVuln, - jarVuln, - }, - }, - want: ` -Report Summary - -┌──────────────────────┬────────┬─────────────────┐ -│ Target │ Type │ Vulnerabilities │ -├──────────────────────┼────────┼─────────────────┤ -│ test (alpine 3.20.3) │ alpine │ 2 │ -├──────────────────────┼────────┼─────────────────┤ -│ Java │ jar │ 2 │ -└──────────────────────┴────────┴─────────────────┘ `, }, } From 5f61893c4a1597c8fbc4a305b97086e37ea6c0ad Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 12:37:21 +0600 Subject: [PATCH 13/27] refactor: use log when results array is empty --- pkg/report/table/table.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 3c5c59a33bde..542f1098781d 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -9,6 +9,8 @@ import ( "slices" "strings" + "github.com/aquasecurity/trivy/pkg/log" + xstrings "github.com/aquasecurity/trivy/pkg/x/strings" "github.com/fatih/color" "github.com/samber/lo" "golang.org/x/xerrors" @@ -80,6 +82,11 @@ func (tw Writer) Write(_ context.Context, report types.Report) error { } func (tw Writer) renderSummary(report types.Report) error { + if len(report.Results) == 0 { + tw.showEmptyResultsWarning() + return nil + } + // Fprintln has a bug if err := tml.Fprintf(tw.Output, "\nReport Summary\n\n"+ "Legend:\n"+ @@ -142,6 +149,34 @@ func (tw Writer) renderSummary(report types.Report) error { return nil } +// showEmptyResultsWarning +func (tw Writer) showEmptyResultsWarning() { + resultByFiles := []types.Scanner{ + types.VulnerabilityScanner, + types.MisconfigScanner, + } + resultByFindings := []types.Scanner{ + types.SecretScanner, + types.LicenseScanner, + } + + var warnStrings []string + if scanners := lo.Intersect(resultByFiles, tw.Scanners); len(scanners) > 0 { + warnStrings = append(warnStrings, fmt.Sprintf("Supported files for %s scanner(s) not found", + strings.Join(xstrings.ToStringSlice(scanners), "/"))) + } + if scanners := lo.Intersect(resultByFindings, tw.Scanners); len(scanners) > 0 { + warnStrings = append(warnStrings, fmt.Sprintf("No results found for %s scanner(s)", + strings.Join(xstrings.ToStringSlice(scanners), "/"))) + } + + if len(warnStrings) == 0 { + warnStrings = append(warnStrings, "Scanners are not enabled.") + } + + log.WithPrefix("report").Warn(strings.Join(warnStrings, ". ")) +} + func (tw Writer) write(result types.Result) { if result.IsEmpty() && result.Class != types.ClassOSPkg { return From 85edf167684f538e4ffc63e5fa7bfff94641ff0e Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 12:41:12 +0600 Subject: [PATCH 14/27] chore: add comment for showEmptyResultsWarning --- pkg/report/table/table.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 542f1098781d..a3ae206a5435 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -149,7 +149,9 @@ func (tw Writer) renderSummary(report types.Report) error { return nil } -// showEmptyResultsWarning +// showEmptyResultsWarning shows WARN why the results array is empty based on the enabled scanners. +// We need to separate the vuln/misconfig and secret/license scanners, +// because the results array contains results without findings for vulns/misconfig only. func (tw Writer) showEmptyResultsWarning() { resultByFiles := []types.Scanner{ types.VulnerabilityScanner, From d5ca9660c17933cba0414171f917d2ce847d74a7 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 12:46:47 +0600 Subject: [PATCH 15/27] refactor --- pkg/report/table/table.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index a3ae206a5435..d9caca9c86aa 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -164,11 +164,11 @@ func (tw Writer) showEmptyResultsWarning() { var warnStrings []string if scanners := lo.Intersect(resultByFiles, tw.Scanners); len(scanners) > 0 { - warnStrings = append(warnStrings, fmt.Sprintf("Supported files for %s scanner(s) not found", + warnStrings = append(warnStrings, fmt.Sprintf("Supported files for %s scanner(s) not found.", strings.Join(xstrings.ToStringSlice(scanners), "/"))) } if scanners := lo.Intersect(resultByFindings, tw.Scanners); len(scanners) > 0 { - warnStrings = append(warnStrings, fmt.Sprintf("No results found for %s scanner(s)", + warnStrings = append(warnStrings, fmt.Sprintf("No results found for %s scanner(s).", strings.Join(xstrings.ToStringSlice(scanners), "/"))) } @@ -176,7 +176,7 @@ func (tw Writer) showEmptyResultsWarning() { warnStrings = append(warnStrings, "Scanners are not enabled.") } - log.WithPrefix("report").Warn(strings.Join(warnStrings, ". ")) + log.WithPrefix("report").Warn(strings.Join(warnStrings, " ")) } func (tw Writer) write(result types.Result) { From eb4d2faa7cb052f85f7a5804d4efb3b3fe4a7c19 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 13:31:28 +0600 Subject: [PATCH 16/27] refactor: hide empty results for OS packages license and file licenses --- pkg/flag/options.go | 1 + pkg/rpc/client/client.go | 1 + pkg/rpc/server/server.go | 1 + pkg/scanner/local/scan.go | 63 ++++++++++-------- pkg/scanner/local/scan_test.go | 1 + pkg/types/scan.go | 3 +- rpc/scanner/service.pb.go | 116 ++++++++++++++++++--------------- rpc/scanner/service.proto | 1 + rpc/scanner/service.twirp.go | 89 ++++++++++++------------- 9 files changed, 152 insertions(+), 124 deletions(-) diff --git a/pkg/flag/options.go b/pkg/flag/options.go index 775eec1366cd..4a21450fd5eb 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -460,6 +460,7 @@ func (o *Options) ScanOpts() types.ScanOptions { ImageConfigScanners: o.ImageConfigScanners, // this is valid only for 'image' subcommand ScanRemovedPackages: o.ScanRemovedPkgs, // this is valid only for 'image' subcommand LicenseCategories: o.LicenseCategories, + LicenseFull: o.LicenseFull, FilePatterns: o.FilePatterns, IncludeDevDeps: o.IncludeDevDeps, Distro: o.Distro, diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index dd13b145878f..9f64df447613 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -97,6 +97,7 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys PkgRelationships: xstrings.ToStringSlice(opts.PkgRelationships), Scanners: xstrings.ToStringSlice(opts.Scanners), LicenseCategories: licenseCategories, + LicenseFull: opts.LicenseFull, IncludeDevDeps: opts.IncludeDevDeps, Distro: distro, }, diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 0bc7492783d8..9a9eb62fa9ec 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -87,6 +87,7 @@ func (s *ScanServer) ToOptions(in *rpcScanner.ScanOptions) types.ScanOptions { Scanners: scanners, IncludeDevDeps: in.IncludeDevDeps, LicenseCategories: licenseCategories, + LicenseFull: in.LicenseFull, Distro: distro, } } diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index 1d117999ede1..55178e30d032 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -262,17 +262,22 @@ func (s Scanner) scanLicenses(target types.ScanTarget, options types.ScanOptions scanner := licensing.NewScanner(options.LicenseCategories) // License - OS packages - var osPkgLicenses []types.DetectedLicense - for _, pkg := range target.Packages { - for _, license := range pkg.Licenses { - osPkgLicenses = append(osPkgLicenses, toDetectedLicense(scanner, license, pkg.Name, "")) + if len(target.Packages) > 0 { + var osPkgLicenses []types.DetectedLicense + for _, pkg := range target.Packages { + for _, license := range pkg.Licenses { + osPkgLicenses = append(osPkgLicenses, toDetectedLicense(scanner, license, pkg.Name, "")) + } } + // We only need to add result with OS package licenses if Packages were found. + // This is to avoid user confusion. + // e.g. when we didn't find packages but show that we didn't find licenses in the Packages. + results = append(results, types.Result{ + Target: "OS Packages", + Class: types.ClassLicense, + Licenses: osPkgLicenses, + }) } - results = append(results, types.Result{ - Target: "OS Packages", - Class: types.ClassLicense, - Licenses: osPkgLicenses, - }) // License - language-specific packages for _, app := range target.Applications { @@ -300,26 +305,32 @@ func (s Scanner) scanLicenses(target types.ScanTarget, options types.ScanOptions } // License - file header or license file - var fileLicenses []types.DetectedLicense - for _, license := range target.Licenses { - for _, finding := range license.Findings { - category, severity := scanner.Scan(finding.Name) - fileLicenses = append(fileLicenses, types.DetectedLicense{ - Severity: severity, - Category: category, - FilePath: license.FilePath, - Name: finding.Name, - Confidence: finding.Confidence, - Link: finding.Link, - }) + if options.LicenseFull { + var fileLicenses []types.DetectedLicense + for _, license := range target.Licenses { + for _, finding := range license.Findings { + category, severity := scanner.Scan(finding.Name) + fileLicenses = append(fileLicenses, types.DetectedLicense{ + Severity: severity, + Category: category, + FilePath: license.FilePath, + Name: finding.Name, + Confidence: finding.Confidence, + Link: finding.Link, + }) + } } + + // We only need to add the result with license files if the `--license-full` flag is enabled. + // This is to avoid user confusion. + // e.g. the user might think that we were looking for licenses but didn't find them. + results = append(results, types.Result{ + Target: "Loose File License(s)", + Class: types.ClassLicenseFile, + Licenses: fileLicenses, + }) } - results = append(results, types.Result{ - Target: "Loose File License(s)", - Class: types.ClassLicenseFile, - Licenses: fileLicenses, - }) return results } diff --git a/pkg/scanner/local/scan_test.go b/pkg/scanner/local/scan_test.go index 0e904806fbd4..1de72044f21e 100644 --- a/pkg/scanner/local/scan_test.go +++ b/pkg/scanner/local/scan_test.go @@ -298,6 +298,7 @@ func TestScanner_Scan(t *testing.T) { options: types.ScanOptions{ PkgRelationships: ftypes.Relationships, Scanners: types.Scanners{types.LicenseScanner}, + LicenseFull: true, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, diff --git a/pkg/types/scan.go b/pkg/types/scan.go index 4dedbce6fcf1..cdb161f407c5 100644 --- a/pkg/types/scan.go +++ b/pkg/types/scan.go @@ -111,7 +111,7 @@ type ScanTarget struct { CustomResources []types.CustomResource } -// ScanOptions holds the attributes for scanning vulnerabilities +// ScanOptions holds the attributes for scanning vulnerabilities/licenses type ScanOptions struct { PkgTypes []string PkgRelationships []types.Relationship @@ -119,6 +119,7 @@ type ScanOptions struct { ImageConfigScanners Scanners // Scanners for container image configuration ScanRemovedPackages bool LicenseCategories map[types.LicenseCategory][]string + LicenseFull bool FilePatterns []string IncludeDevDeps bool Distro types.OS // Forced OS diff --git a/rpc/scanner/service.pb.go b/rpc/scanner/service.pb.go index 00ff3485240c..4c27ba8c0600 100644 --- a/rpc/scanner/service.pb.go +++ b/rpc/scanner/service.pb.go @@ -152,6 +152,7 @@ type ScanOptions struct { IncludeDevDeps bool `protobuf:"varint,5,opt,name=include_dev_deps,json=includeDevDeps,proto3" json:"include_dev_deps,omitempty"` PkgRelationships []string `protobuf:"bytes,6,rep,name=pkg_relationships,json=pkgRelationships,proto3" json:"pkg_relationships,omitempty"` Distro *common.OS `protobuf:"bytes,7,opt,name=distro,proto3" json:"distro,omitempty"` + LicenseFull bool `protobuf:"varint,8,opt,name=license_full,json=licenseFull,proto3" json:"license_full,omitempty"` } func (x *ScanOptions) Reset() { @@ -228,6 +229,13 @@ func (x *ScanOptions) GetDistro() *common.OS { return nil } +func (x *ScanOptions) GetLicenseFull() bool { + if x != nil { + return x.LicenseFull + } + return false +} + type ScanResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -414,7 +422,7 @@ var file_rpc_scanner_service_proto_rawDesc = []byte{ 0x53, 0x63, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x20, 0x0a, 0x08, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6e, 0x4f, + 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xb7, 0x03, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6b, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6b, 0x67, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x18, @@ -433,58 +441,60 @@ var file_rpc_scanner_service_proto_rawDesc = []byte{ 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x73, 0x12, 0x28, 0x0a, 0x06, 0x64, 0x69, 0x73, 0x74, 0x72, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x53, 0x52, 0x06, 0x64, - 0x69, 0x73, 0x74, 0x72, 0x6f, 0x1a, 0x60, 0x0a, 0x16, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, - 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x64, 0x0a, - 0x0c, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, - 0x02, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, 0x69, 0x76, - 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x53, 0x52, 0x02, 0x6f, 0x73, 0x12, - 0x32, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x73, 0x22, 0xd5, 0x03, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x45, 0x0a, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, - 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, - 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0f, 0x76, 0x75, - 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x54, 0x0a, - 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x31, 0x0a, - 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, - 0x12, 0x47, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, - 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x07, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, - 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, - 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, - 0x12, 0x39, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, - 0x65, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x32, 0x50, 0x0a, 0x07, 0x53, - 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x04, 0x53, 0x63, 0x61, 0x6e, 0x12, 0x1d, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, - 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, - 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, - 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, - 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, - 0x70, 0x63, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x3b, 0x73, 0x63, 0x61, 0x6e, 0x6e, - 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x73, 0x74, 0x72, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x5f, 0x66, 0x75, 0x6c, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x46, 0x75, 0x6c, 0x6c, 0x1a, 0x60, 0x0a, 0x16, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, + 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, + 0x22, 0x64, 0x0a, 0x0c, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x20, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, + 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x53, 0x52, 0x02, + 0x6f, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, + 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xd5, 0x03, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x45, 0x0a, 0x0f, 0x76, 0x75, 0x6c, + 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, + 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x12, 0x54, 0x0a, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x74, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x31, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0f, 0x63, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x07, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x18, + 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x32, 0x50, + 0x0a, 0x07, 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x04, 0x53, 0x63, 0x61, + 0x6e, 0x12, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, + 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, + 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x3b, 0x73, 0x63, + 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/rpc/scanner/service.proto b/rpc/scanner/service.proto index d809d36610ee..5e43ea997d8b 100644 --- a/rpc/scanner/service.proto +++ b/rpc/scanner/service.proto @@ -29,6 +29,7 @@ message ScanOptions { bool include_dev_deps = 5; repeated string pkg_relationships = 6; common.OS distro = 7; + bool license_full = 8; reserved 3; // deleted 'list_all_packages' } diff --git a/rpc/scanner/service.twirp.go b/rpc/scanner/service.twirp.go index d7525d23c45e..6c8ab44bd09b 100644 --- a/rpc/scanner/service.twirp.go +++ b/rpc/scanner/service.twirp.go @@ -1094,48 +1094,49 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) } var twirpFileDescriptor0 = []byte{ - // 685 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0x51, 0x6f, 0x1a, 0x47, - 0x10, 0x16, 0x1c, 0x86, 0x63, 0xa8, 0x6a, 0xbc, 0x6a, 0xad, 0x35, 0xae, 0x5b, 0xc4, 0x43, 0x85, - 0x54, 0x09, 0x6a, 0xdc, 0xaa, 0x4d, 0xf2, 0x16, 0xdb, 0x89, 0x1c, 0x25, 0xb2, 0xb5, 0x58, 0x79, - 0xc8, 0x0b, 0x59, 0xf6, 0xc6, 0xe7, 0x15, 0xc7, 0xed, 0x79, 0x77, 0x0f, 0x89, 0xff, 0x91, 0xa7, - 0xfc, 0xaf, 0xfc, 0x9f, 0x68, 0xf7, 0x0e, 0x64, 0x30, 0xce, 0x13, 0x3b, 0x33, 0xdf, 0xcc, 0x7c, - 0xcc, 0x7c, 0x37, 0x70, 0xa4, 0x33, 0x31, 0x34, 0x82, 0xa7, 0x29, 0xea, 0xa1, 0x41, 0xbd, 0x90, - 0x02, 0x07, 0x99, 0x56, 0x56, 0x91, 0xb6, 0xd5, 0x72, 0xb1, 0x1c, 0x94, 0xc1, 0xc1, 0xe2, 0xb4, - 0x43, 0x1d, 0x58, 0xa8, 0xf9, 0x5c, 0xa5, 0x9b, 0xd8, 0xde, 0xd7, 0x0a, 0xb4, 0xc6, 0x82, 0xa7, - 0x0c, 0x1f, 0x72, 0x34, 0x96, 0x1c, 0x42, 0xdd, 0x72, 0x1d, 0xa3, 0xa5, 0x95, 0x6e, 0xa5, 0xdf, - 0x64, 0xa5, 0x45, 0xfe, 0x80, 0x16, 0xd7, 0x56, 0xde, 0x71, 0x61, 0x27, 0x32, 0xa2, 0x55, 0x1f, - 0x84, 0x95, 0xeb, 0x2a, 0x22, 0x47, 0x10, 0x4e, 0x13, 0x35, 0x9d, 0xc8, 0xc8, 0xd0, 0xa0, 0x1b, - 0xf4, 0x9b, 0xac, 0xe1, 0xec, 0xab, 0xc8, 0x90, 0xff, 0xa0, 0xa1, 0x32, 0x2b, 0x55, 0x6a, 0x68, - 0xad, 0x5b, 0xe9, 0xb7, 0x46, 0x27, 0x83, 0x6d, 0x86, 0x03, 0xc7, 0xe1, 0xba, 0x00, 0xb1, 0x15, - 0xba, 0xd7, 0x85, 0xf0, 0xbd, 0x14, 0x98, 0x1a, 0x34, 0xe4, 0x17, 0xd8, 0x4b, 0xf9, 0x1c, 0x0d, - 0xad, 0xf8, 0xe2, 0x85, 0xd1, 0xfb, 0x12, 0x14, 0xf4, 0xcb, 0x54, 0x72, 0x0c, 0xcd, 0x6c, 0x16, - 0x4f, 0xec, 0x32, 0x5b, 0x23, 0xc3, 0x6c, 0x16, 0xdf, 0x3a, 0x9b, 0x74, 0x20, 0x2c, 0x3b, 0x1a, - 0x5a, 0x2d, 0x62, 0x2b, 0x9b, 0x08, 0x20, 0x49, 0xd1, 0x6a, 0x22, 0xb8, 0xc5, 0x58, 0x69, 0x89, - 0x8e, 0x6e, 0xd0, 0x6f, 0x8d, 0xfe, 0xf9, 0x21, 0xdd, 0x41, 0x49, 0xf1, 0x7c, 0x9d, 0x76, 0x99, - 0x5a, 0xbd, 0x64, 0x07, 0xc9, 0xb6, 0x9f, 0xf4, 0xa1, 0x2d, 0x53, 0x91, 0xe4, 0x11, 0x4e, 0x22, - 0x5c, 0x4c, 0x22, 0xcc, 0x0c, 0xdd, 0xeb, 0x56, 0xfa, 0x21, 0xfb, 0xb9, 0xf4, 0x5f, 0xe0, 0xe2, - 0x02, 0x33, 0x43, 0xfe, 0x82, 0x03, 0xf7, 0x3f, 0x34, 0x26, 0xdc, 0x37, 0xb9, 0x97, 0x99, 0xa1, - 0x75, 0xcf, 0xb9, 0x9d, 0xcd, 0x62, 0xf6, 0xd8, 0x4f, 0xfa, 0x50, 0x8f, 0xa4, 0xb1, 0x5a, 0xd1, - 0x86, 0x1f, 0x6f, 0xbb, 0xe4, 0x5b, 0x2c, 0x7c, 0x70, 0x3d, 0x66, 0x65, 0xbc, 0xf3, 0x19, 0x0e, - 0x77, 0xb3, 0x25, 0x6d, 0x08, 0x66, 0xb8, 0x2c, 0x97, 0xee, 0x9e, 0xe4, 0x6f, 0xd8, 0x5b, 0xf0, - 0x24, 0x47, 0xbf, 0xeb, 0xd6, 0xa8, 0xf3, 0x74, 0x08, 0xab, 0xdd, 0xb0, 0x02, 0xf8, 0xb2, 0xfa, - 0x7f, 0xe5, 0x5d, 0x2d, 0x0c, 0xda, 0xb5, 0x5e, 0x04, 0x3f, 0x15, 0xa2, 0x32, 0x99, 0x4a, 0x0d, - 0x92, 0x2e, 0x54, 0x95, 0xf1, 0xc5, 0x77, 0xb1, 0xab, 0x2a, 0x43, 0x46, 0xd0, 0xd0, 0x68, 0xf2, - 0xc4, 0x16, 0xea, 0x69, 0x8d, 0xe8, 0xd3, 0x7e, 0xcc, 0x03, 0xd8, 0x0a, 0xd8, 0xfb, 0x16, 0x40, - 0xbd, 0xf0, 0x3d, 0x2b, 0xdb, 0x4b, 0xd8, 0x5f, 0xe4, 0x49, 0x8a, 0x9a, 0x4f, 0x65, 0x22, 0xad, - 0xdb, 0x69, 0xd5, 0x97, 0x3f, 0xde, 0x64, 0xf1, 0xf1, 0x11, 0x68, 0xc9, 0xb6, 0x73, 0xc8, 0x2d, - 0x1c, 0xcc, 0xa5, 0x11, 0x2a, 0xbd, 0x93, 0x71, 0xae, 0xf9, 0x4a, 0xcb, 0xae, 0xd0, 0x9f, 0x9b, - 0x85, 0x2e, 0xd0, 0xa2, 0xb0, 0x18, 0x7d, 0xd8, 0x82, 0xb3, 0xa7, 0x05, 0x9c, 0xa4, 0x45, 0xc2, - 0x8d, 0x5b, 0xac, 0xe3, 0x5c, 0x18, 0x84, 0x40, 0xcd, 0xc9, 0x97, 0x06, 0xde, 0xe9, 0xdf, 0xe4, - 0x14, 0xc2, 0x8c, 0x8b, 0x19, 0x8f, 0xd1, 0x09, 0xc6, 0xb5, 0xfd, 0x75, 0xb3, 0xed, 0x4d, 0x11, - 0x65, 0x6b, 0x18, 0x79, 0x0b, 0x6d, 0x91, 0x1b, 0xab, 0xe6, 0x13, 0x8d, 0x46, 0xe5, 0x5a, 0xa0, - 0xa1, 0x0d, 0x9f, 0xfa, 0xdb, 0x66, 0xea, 0xb9, 0x47, 0xb1, 0x12, 0xc4, 0xf6, 0xc5, 0x86, 0x6d, - 0xc8, 0xbf, 0xd0, 0x30, 0x28, 0x34, 0x5a, 0x43, 0xc3, 0x5d, 0xa3, 0x1b, 0xfb, 0xe0, 0x1b, 0x99, - 0x46, 0x32, 0x8d, 0xd9, 0x0a, 0x4b, 0x5e, 0x40, 0x58, 0x7e, 0x00, 0x86, 0x36, 0x7d, 0xde, 0xc9, - 0xee, 0x49, 0x95, 0x2a, 0x62, 0x6b, 0xf8, 0xe8, 0x06, 0x1a, 0xe3, 0x62, 0xeb, 0xe4, 0x12, 0x6a, - 0xee, 0x49, 0x9e, 0xb9, 0x18, 0xe5, 0xd5, 0xea, 0xfc, 0xfe, 0x5c, 0xb8, 0xd0, 0xdf, 0xeb, 0xb3, - 0x4f, 0xa7, 0xb1, 0xb4, 0xf7, 0xf9, 0xd4, 0x35, 0x1f, 0xf2, 0x87, 0x9c, 0x1b, 0x14, 0xb9, 0x96, - 0x76, 0x39, 0xf4, 0x89, 0xc3, 0x47, 0xc7, 0xf4, 0x55, 0xf9, 0x3b, 0xad, 0xfb, 0x0b, 0x79, 0xf6, - 0x3d, 0x00, 0x00, 0xff, 0xff, 0x40, 0xd0, 0xe7, 0xda, 0x6a, 0x05, 0x00, 0x00, + // 704 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xdb, 0x6e, 0xdb, 0x38, + 0x10, 0x85, 0x2d, 0xc7, 0x96, 0xc7, 0xc1, 0xc6, 0x21, 0x76, 0x03, 0xc6, 0xd9, 0xec, 0x7a, 0xfd, + 0xb0, 0x30, 0xb0, 0x80, 0xbd, 0x71, 0x76, 0xd1, 0xdb, 0x5b, 0x73, 0x29, 0x52, 0xb4, 0x48, 0x40, + 0x07, 0x7d, 0xe8, 0x8b, 0x4b, 0x53, 0x13, 0x85, 0xb0, 0x2c, 0x29, 0x24, 0x65, 0xc0, 0xbf, 0xd2, + 0x1f, 0xe9, 0x97, 0xf4, 0x7f, 0x0a, 0x52, 0x92, 0x11, 0x3b, 0x4e, 0x9f, 0xa4, 0x99, 0x39, 0x33, + 0xe7, 0x90, 0x73, 0x40, 0x38, 0x54, 0xa9, 0x18, 0x6a, 0xc1, 0xe3, 0x18, 0xd5, 0x50, 0xa3, 0x5a, + 0x48, 0x81, 0x83, 0x54, 0x25, 0x26, 0x21, 0x6d, 0xa3, 0xe4, 0x62, 0x39, 0x28, 0x8a, 0x83, 0xc5, + 0x49, 0x87, 0x5a, 0xb0, 0x48, 0xe6, 0xf3, 0x24, 0x5e, 0xc7, 0xf6, 0xbe, 0x56, 0xa0, 0x35, 0x16, + 0x3c, 0x66, 0xf8, 0x90, 0xa1, 0x36, 0xe4, 0x00, 0xea, 0x86, 0xab, 0x10, 0x0d, 0xad, 0x74, 0x2b, + 0xfd, 0x26, 0x2b, 0x22, 0xf2, 0x27, 0xb4, 0xb8, 0x32, 0xf2, 0x8e, 0x0b, 0x33, 0x91, 0x01, 0xad, + 0xba, 0x22, 0x94, 0xa9, 0xab, 0x80, 0x1c, 0x82, 0x3f, 0x8d, 0x92, 0xe9, 0x44, 0x06, 0x9a, 0x7a, + 0x5d, 0xaf, 0xdf, 0x64, 0x0d, 0x1b, 0x5f, 0x05, 0x9a, 0xbc, 0x80, 0x46, 0x92, 0x1a, 0x99, 0xc4, + 0x9a, 0xd6, 0xba, 0x95, 0x7e, 0x6b, 0x74, 0x3c, 0xd8, 0x54, 0x38, 0xb0, 0x1a, 0xae, 0x73, 0x10, + 0x2b, 0xd1, 0xbd, 0x2e, 0xf8, 0x1f, 0xa4, 0xc0, 0x58, 0xa3, 0x26, 0xbf, 0xc2, 0x4e, 0xcc, 0xe7, + 0xa8, 0x69, 0xc5, 0x0d, 0xcf, 0x83, 0xde, 0x37, 0x2f, 0x97, 0x5f, 0xb4, 0x92, 0x23, 0x68, 0xa6, + 0xb3, 0x70, 0x62, 0x96, 0xe9, 0x0a, 0xe9, 0xa7, 0xb3, 0xf0, 0xd6, 0xc6, 0xa4, 0x03, 0x7e, 0xc1, + 0xa8, 0x69, 0x35, 0xaf, 0x95, 0x31, 0x11, 0x40, 0xa2, 0x9c, 0x6a, 0x22, 0xb8, 0xc1, 0x30, 0x51, + 0x12, 0xad, 0x5c, 0xaf, 0xdf, 0x1a, 0xfd, 0xf7, 0x53, 0xb9, 0x83, 0x42, 0xe2, 0xd9, 0xaa, 0xed, + 0x22, 0x36, 0x6a, 0xc9, 0xf6, 0xa3, 0xcd, 0x3c, 0xe9, 0x43, 0x5b, 0xc6, 0x22, 0xca, 0x02, 0x9c, + 0x04, 0xb8, 0x98, 0x04, 0x98, 0x6a, 0xba, 0xd3, 0xad, 0xf4, 0x7d, 0xf6, 0x4b, 0x91, 0x3f, 0xc7, + 0xc5, 0x39, 0xa6, 0x9a, 0xfc, 0x03, 0xfb, 0xf6, 0x1c, 0x0a, 0x23, 0xee, 0x48, 0xee, 0x65, 0xaa, + 0x69, 0xdd, 0x69, 0x6e, 0xa7, 0xb3, 0x90, 0x3d, 0xce, 0x93, 0x3e, 0xd4, 0x03, 0xa9, 0x8d, 0x4a, + 0x68, 0xc3, 0x5d, 0x6f, 0xbb, 0xd0, 0x9b, 0x2f, 0x7c, 0x70, 0x3d, 0x66, 0x45, 0x9d, 0xfc, 0x05, + 0xbb, 0xe5, 0x29, 0xef, 0xb2, 0x28, 0xa2, 0xbe, 0x23, 0x6f, 0x15, 0xb9, 0xcb, 0x2c, 0x8a, 0x3a, + 0x5f, 0xe0, 0x60, 0xfb, 0x81, 0x48, 0x1b, 0xbc, 0x19, 0x2e, 0x0b, 0x5f, 0xd8, 0x5f, 0xf2, 0x2f, + 0xec, 0x2c, 0x78, 0x94, 0xa1, 0xb3, 0x43, 0x6b, 0xd4, 0x79, 0x7a, 0x4f, 0xe5, 0xfa, 0x58, 0x0e, + 0x7c, 0x5d, 0x7d, 0x59, 0x79, 0x5f, 0xf3, 0xbd, 0x76, 0xad, 0x17, 0xc0, 0x6e, 0xee, 0x3b, 0x9d, + 0x26, 0xb1, 0x46, 0xd2, 0x85, 0x6a, 0xa2, 0xdd, 0xf0, 0x6d, 0x07, 0xa8, 0x26, 0x9a, 0x8c, 0xa0, + 0xa1, 0x50, 0x67, 0x91, 0xc9, 0x0d, 0xd6, 0x1a, 0xd1, 0xa7, 0x7c, 0xcc, 0x01, 0x58, 0x09, 0xec, + 0x7d, 0xf7, 0xa0, 0x9e, 0xe7, 0x9e, 0x75, 0xf6, 0x05, 0xec, 0x2d, 0xb2, 0x28, 0x46, 0xc5, 0xa7, + 0x32, 0x92, 0xc6, 0xae, 0xbd, 0xea, 0xc6, 0x1f, 0xad, 0xab, 0xf8, 0xf4, 0x08, 0xb4, 0x64, 0x9b, + 0x3d, 0xe4, 0x16, 0xf6, 0xe7, 0x52, 0x8b, 0x24, 0xbe, 0x93, 0x61, 0xa6, 0x78, 0x69, 0x77, 0x3b, + 0xe8, 0xef, 0xf5, 0x41, 0xe7, 0x68, 0x50, 0x18, 0x0c, 0x3e, 0x6e, 0xc0, 0xd9, 0xd3, 0x01, 0xd6, + 0xf5, 0x22, 0xe2, 0xda, 0xee, 0xde, 0x6a, 0xce, 0x03, 0x42, 0xa0, 0x66, 0x1d, 0x4e, 0x3d, 0x97, + 0x74, 0xff, 0xe4, 0x04, 0xfc, 0x94, 0x8b, 0x19, 0x0f, 0xd1, 0x7a, 0xca, 0xd2, 0xfe, 0xb6, 0x4e, + 0x7b, 0x93, 0x57, 0xd9, 0x0a, 0x46, 0xde, 0x41, 0x5b, 0x64, 0xda, 0x24, 0xf3, 0x89, 0x42, 0x9d, + 0x64, 0x4a, 0xa0, 0xa6, 0x0d, 0xd7, 0xfa, 0xfb, 0x7a, 0xeb, 0x99, 0x43, 0xb1, 0x02, 0xc4, 0xf6, + 0xc4, 0x5a, 0xac, 0xc9, 0xff, 0xd0, 0xd0, 0x28, 0x14, 0x1a, 0x4d, 0xfd, 0x6d, 0x57, 0x37, 0x76, + 0xc5, 0x4b, 0x19, 0x07, 0x32, 0x0e, 0x59, 0x89, 0x25, 0xaf, 0xc0, 0x2f, 0x9c, 0xa7, 0x69, 0xd3, + 0xf5, 0x1d, 0x6f, 0xbf, 0xa9, 0xc2, 0x45, 0x6c, 0x05, 0x1f, 0xdd, 0x40, 0x63, 0x9c, 0x6f, 0x9d, + 0x5c, 0x40, 0xcd, 0xfe, 0x92, 0x67, 0x1e, 0x95, 0xe2, 0x61, 0xeb, 0xfc, 0xf1, 0x5c, 0x39, 0xf7, + 0xdf, 0xdb, 0xd3, 0xcf, 0x27, 0xa1, 0x34, 0xf7, 0xd9, 0xd4, 0x92, 0x0f, 0xf9, 0x43, 0xc6, 0x35, + 0x8a, 0x4c, 0x49, 0xb3, 0x1c, 0xba, 0xc6, 0xe1, 0xa3, 0xf7, 0xf6, 0x4d, 0xf1, 0x9d, 0xd6, 0xdd, + 0x23, 0x7a, 0xfa, 0x23, 0x00, 0x00, 0xff, 0xff, 0x41, 0x7e, 0x12, 0x20, 0x8d, 0x05, 0x00, 0x00, } From a57dcc69729674ca2c56558ff2182368b17f1661 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 13:35:26 +0600 Subject: [PATCH 17/27] fix: add LicenseFiles into summary table --- pkg/report/table/summary.go | 2 +- pkg/report/table/table.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/report/table/summary.go b/pkg/report/table/summary.go index e9bffc242050..1cc617c6e563 100644 --- a/pkg/report/table/summary.go +++ b/pkg/report/table/summary.go @@ -79,7 +79,7 @@ func (s LicenseScanner) Header() string { } func (s LicenseScanner) Count(result types.Result) int { - if result.Class == types.ClassLicense { + if result.Class == types.ClassLicense || result.Class == types.ClassLicenseFile { return len(result.Licenses) } return -1 diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index d9caca9c86aa..b5d2bc74061b 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -9,8 +9,6 @@ import ( "slices" "strings" - "github.com/aquasecurity/trivy/pkg/log" - xstrings "github.com/aquasecurity/trivy/pkg/x/strings" "github.com/fatih/color" "github.com/samber/lo" "golang.org/x/xerrors" @@ -18,7 +16,9 @@ import ( "github.com/aquasecurity/table" "github.com/aquasecurity/tml" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" + xstrings "github.com/aquasecurity/trivy/pkg/x/strings" ) var ( From 4f349c5246f5be441af832444a9e9a6316ac7cd0 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 13:49:17 +0600 Subject: [PATCH 18/27] test: add LicenseFiles in test --- pkg/report/table/table_private_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index 30a5842f8f2e..8307e69dfac6 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -91,6 +91,11 @@ var ( fileLicense = types.Result{ Target: "Loose File License(s)", Class: types.ClassLicenseFile, + Licenses: []types.DetectedLicense{ + { + FilePath: "LICENSE", + }, + }, } ) @@ -142,7 +147,7 @@ Legend: ├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ │ Java │ - │ - │ - │ - │ 0 │ ├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ Loose File License(s) │ - │ - │ - │ - │ - │ +│ Loose File License(s) │ - │ - │ - │ - │ 1 │ └───────────────────────┴────────────┴─────────────────┴───────────────────┴─────────┴──────────┘ `, }, From 84169b4fc9922ebb285938dc0403b16ef5680764 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 16:11:10 +0600 Subject: [PATCH 19/27] feat: split aggregated pkgs --- pkg/report/table/table.go | 68 ++++++++++++++- pkg/report/table/table_private_test.go | 110 ++++++++++++++++++------- pkg/report/table/table_test.go | 6 ++ pkg/report/table/vulnerability.go | 4 +- 4 files changed, 157 insertions(+), 31 deletions(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index b5d2bc74061b..e276a26434b5 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -7,8 +7,10 @@ import ( "os" "runtime" "slices" + "sort" "strings" + "github.com/aquasecurity/trivy/pkg/scanner/langpkg" "github.com/fatih/color" "github.com/samber/lo" "golang.org/x/xerrors" @@ -16,6 +18,7 @@ import ( "github.com/aquasecurity/table" "github.com/aquasecurity/tml" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" xstrings "github.com/aquasecurity/trivy/pkg/x/strings" @@ -129,7 +132,7 @@ func (tw Writer) renderSummary(report types.Report) error { t.SetHeaders(headers...) t.SetAlignment(alignments...) - for _, result := range report.Results { + for _, result := range splitAggregatedPackages(report.Results) { resultType := string(result.Type) if result.Class == types.ClassSecret { resultType = "text" @@ -179,6 +182,69 @@ func (tw Writer) showEmptyResultsWarning() { log.WithPrefix("report").Warn(strings.Join(warnStrings, " ")) } +// splitAggregatedPackages splits aggregated packages into different results with path as target. +// Other results will be returned as is. +func splitAggregatedPackages(results types.Results) types.Results { + var newResults types.Results + + for _, result := range results { + if !slices.Contains(ftypes.AggregatingTypes, result.Type) && + // License results from applications don't have `Type`. + (result.Class != types.ClassLicense || !slices.Contains(lo.Values(langpkg.PkgTargets), result.Target)) { + newResults = append(newResults, result) + continue + } + + newResults = append(newResults, splitAggregatedVulns(result)...) + newResults = append(newResults, splitAggregatedLicenses(result)...) + + } + return newResults +} + +func splitAggregatedVulns(result types.Result) types.Results { + var newResults types.Results + + vulns := make(map[string][]types.DetectedVulnerability) + for _, vuln := range result.Vulnerabilities { + pkgPath := rootJarFromPath(vuln.PkgPath) + vulns[pkgPath] = append(vulns[pkgPath], vuln) + } + for pkgPath, v := range vulns { + newResult := result + newResult.Target = lo.Ternary(pkgPath != "", pkgPath, result.Target) + newResult.Vulnerabilities = v + + newResults = append(newResults, newResult) + } + + sort.Slice(newResults, func(i, j int) bool { + return newResults[i].Target < newResults[j].Target + }) + return newResults +} + +func splitAggregatedLicenses(result types.Result) types.Results { + var newResults types.Results + + licenses := make(map[string][]types.DetectedLicense) + for _, license := range result.Licenses { + licenses[license.FilePath] = append(licenses[license.FilePath], license) + } + for filePath, l := range licenses { + newResult := result + newResult.Target = lo.Ternary(filePath != "", filePath, result.Target) + newResult.Licenses = l + + newResults = append(newResults, newResult) + } + + sort.Slice(newResults, func(i, j int) bool { + return newResults[i].Target < newResults[j].Target + }) + return newResults +} + func (tw Writer) write(result types.Result) { if result.IsEmpty() && result.Class != types.ClassOSPkg { return diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index 8307e69dfac6..f6c54818d2e2 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -28,7 +28,7 @@ var ( }, }, } - jarVuln = types.Result{ + jarVulns = types.Result{ Target: "Java", Class: types.ClassLangPkg, Type: ftypes.Jar, @@ -41,7 +41,35 @@ var ( { VulnerabilityID: "CVE-2021-44832", PkgName: "org.apache.logging.log4j:log4j-core", - PkgPath: "app/log4j-core-2.17.0.jar", + PkgPath: "app/jackson-databind-2.13.4.1.jar/nested/app2/log4j-core-2.17.0.jar", + }, + }, + } + + npmVulns = types.Result{ + Target: "Node.js", + Class: types.ClassLangPkg, + Type: ftypes.NodePkg, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-37601", + PkgName: "loader-utils", + PkgPath: "loader-utils/package.json", + }, + { + VulnerabilityID: "CVE-2022-37599", + PkgName: "loader-utils", + PkgPath: "loader-utils/package.json", + }, + { + VulnerabilityID: "CVE-2021-23566", + PkgName: "nanoid", + PkgPath: "nanoid/package.json", + }, + { + VulnerabilityID: "CVE-2024-55565", + PkgName: "nanoid", + PkgPath: "nanoid/package.json", }, }, } @@ -88,6 +116,24 @@ var ( Target: "Java", Class: types.ClassLicense, } + + npmLicenses = types.Result{ + Target: "Node.js", + Class: types.ClassLicense, + Licenses: []types.DetectedLicense{ + { + Name: "MIT", + FilePath: "loader-utils/package.json", + Category: "notice", + }, + { + Name: "MIT", + FilePath: "nanoid/package.json", + Category: "notice", + }, + }, + } + fileLicense = types.Result{ Target: "Loose File License(s)", Class: types.ClassLicenseFile, @@ -118,11 +164,13 @@ func Test_renderSummary(t *testing.T) { report: types.Report{ Results: []types.Result{ osVuln, - jarVuln, + jarVulns, + npmVulns, dockerfileMisconfig, secret, osLicense, jarLicense, + npmLicenses, fileLicense, }, }, @@ -132,23 +180,29 @@ Report Summary Legend: - '-': Not scanned - '0': Clean (no security findings detected) -┌───────────────────────┬────────────┬─────────────────┬───────────────────┬─────────┬──────────┐ -│ Target │ Type │ Vulnerabilities │ Misconfigurations │ Secrets │ Licenses │ -├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ test (alpine 3.20.3) │ alpine │ 2 │ - │ - │ - │ -├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ Java │ jar │ 2 │ - │ - │ - │ -├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ app/Dockerfile │ dockerfile │ - │ 2 │ - │ - │ -├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ requirements.txt │ text │ - │ - │ 1 │ - │ -├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ OS Packages │ - │ - │ - │ - │ 1 │ -├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ Java │ - │ - │ - │ - │ 0 │ -├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ -│ Loose File License(s) │ - │ - │ - │ - │ 1 │ -└───────────────────────┴────────────┴─────────────────┴───────────────────┴─────────┴──────────┘ +┌───────────────────────────────────┬────────────┬─────────────────┬───────────────────┬─────────┬──────────┐ +│ Target │ Type │ Vulnerabilities │ Misconfigurations │ Secrets │ Licenses │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ test (alpine 3.20.3) │ alpine │ 2 │ - │ - │ - │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ app/jackson-databind-2.13.4.1.jar │ jar │ 2 │ - │ - │ - │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ loader-utils/package.json │ node-pkg │ 2 │ - │ - │ - │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ nanoid/package.json │ node-pkg │ 2 │ - │ - │ - │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ app/Dockerfile │ dockerfile │ - │ 2 │ - │ - │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ requirements.txt │ text │ - │ - │ 1 │ - │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ OS Packages │ - │ - │ - │ - │ 1 │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ loader-utils/package.json │ - │ - │ - │ - │ 1 │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ nanoid/package.json │ - │ - │ - │ - │ 1 │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ Loose File License(s) │ - │ - │ - │ - │ 1 │ +└───────────────────────────────────┴────────────┴─────────────────┴───────────────────┴─────────┴──────────┘ `, }, { @@ -159,7 +213,7 @@ Legend: report: types.Report{ Results: []types.Result{ osVuln, - jarVuln, + jarVulns, }, }, want: ` @@ -168,13 +222,13 @@ Report Summary Legend: - '-': Not scanned - '0': Clean (no security findings detected) -┌──────────────────────┬────────┬─────────────────┐ -│ Target │ Type │ Vulnerabilities │ -├──────────────────────┼────────┼─────────────────┤ -│ test (alpine 3.20.3) │ alpine │ 2 │ -├──────────────────────┼────────┼─────────────────┤ -│ Java │ jar │ 2 │ -└──────────────────────┴────────┴─────────────────┘ +┌───────────────────────────────────┬────────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├───────────────────────────────────┼────────┼─────────────────┤ +│ test (alpine 3.20.3) │ alpine │ 2 │ +├───────────────────────────────────┼────────┼─────────────────┤ +│ app/jackson-databind-2.13.4.1.jar │ jar │ 2 │ +└───────────────────────────────────┴────────┴─────────────────┘ `, }, { diff --git a/pkg/report/table/table_test.go b/pkg/report/table/table_test.go index d88e8ee355c0..911b27f01f10 100644 --- a/pkg/report/table/table_test.go +++ b/pkg/report/table/table_test.go @@ -58,6 +58,9 @@ func TestWriter_Write(t *testing.T) { wantOutput: ` Report Summary +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) ┌────────┬──────┬─────────────────┐ │ Target │ Type │ Vulnerabilities │ ├────────┼──────┼─────────────────┤ @@ -91,6 +94,9 @@ Total: 1 (MEDIUM: 0, HIGH: 1) wantOutput: ` Report Summary +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) ┌────────┬──────┬─────────────────┐ │ Target │ Type │ Vulnerabilities │ ├────────┼──────┼─────────────────┤ diff --git a/pkg/report/table/vulnerability.go b/pkg/report/table/vulnerability.go index 1c08236a033c..786b719ff09a 100644 --- a/pkg/report/table/vulnerability.go +++ b/pkg/report/table/vulnerability.go @@ -139,8 +139,6 @@ func (r *vulnerabilityRenderer) setVulnerabilityRows(tw *table.Table, vulns []ty for _, v := range vulns { lib := v.PkgName if v.PkgPath != "" { - // get path to root jar - // for other languages return unchanged path pkgPath := rootJarFromPath(v.PkgPath) fileName := filepath.Base(pkgPath) lib = fmt.Sprintf("%s (%s)", v.PkgName, fileName) @@ -373,6 +371,8 @@ var jarExtensions = []string{ ".ear", } +// rootJarFromPath returns path to root jar. +// For other languages return unchanged path func rootJarFromPath(path string) string { // File paths are always forward-slashed in Trivy paths := strings.Split(path, "/") From 892d6de100872ccb3e9f2019366a4555c86176c9 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 16:53:28 +0600 Subject: [PATCH 20/27] fix: show packages without vulns --- pkg/report/table/table.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index e276a26434b5..7c684f3a7b7c 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -10,7 +10,6 @@ import ( "sort" "strings" - "github.com/aquasecurity/trivy/pkg/scanner/langpkg" "github.com/fatih/color" "github.com/samber/lo" "golang.org/x/xerrors" @@ -20,6 +19,7 @@ import ( dbTypes "github.com/aquasecurity/trivy-db/pkg/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/scanner/langpkg" "github.com/aquasecurity/trivy/pkg/types" xstrings "github.com/aquasecurity/trivy/pkg/x/strings" ) @@ -205,7 +205,11 @@ func splitAggregatedPackages(results types.Results) types.Results { func splitAggregatedVulns(result types.Result) types.Results { var newResults types.Results - vulns := make(map[string][]types.DetectedVulnerability) + // Save packages to display them in the table even if no vulnerabilities were found + vulns := lo.SliceToMap(result.Packages, func(pkg ftypes.Package) (string, []types.DetectedVulnerability) { + return rootJarFromPath(pkg.FilePath), []types.DetectedVulnerability{} + }) + for _, vuln := range result.Vulnerabilities { pkgPath := rootJarFromPath(vuln.PkgPath) vulns[pkgPath] = append(vulns[pkgPath], vuln) From db0cbe1e0a34f622db9ddfb35943f1f60043fcd1 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 16:53:33 +0600 Subject: [PATCH 21/27] fix: tests --- .../testdata/license-cyclonedx.json.golden | 11 ++--- pkg/report/table/table_private_test.go | 18 +++++++ pkg/report/table/table_test.go | 47 ++++++++++++------- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/integration/testdata/license-cyclonedx.json.golden b/integration/testdata/license-cyclonedx.json.golden index 95f8acd896b1..6371e7961789 100644 --- a/integration/testdata/license-cyclonedx.json.golden +++ b/integration/testdata/license-cyclonedx.json.golden @@ -16,10 +16,6 @@ } }, "Results": [ - { - "Target": "OS Packages", - "Class": "license" - }, { "Target": "pom.xml", "Class": "license" @@ -34,6 +30,7 @@ "PkgName": "org.eclipse.sisu:org.eclipse.sisu.plexus", "FilePath": "", "Name": "EPL-1.0", + "Text": "", "Confidence": 1, "Link": "" }, @@ -43,6 +40,7 @@ "PkgName": "org.ow2.asm:asm", "FilePath": "", "Name": "BSD-3-Clause", + "Text": "", "Confidence": 1, "Link": "" }, @@ -52,14 +50,11 @@ "PkgName": "org.slf4j:slf4j-api", "FilePath": "", "Name": "MIT License", + "Text": "", "Confidence": 1, "Link": "" } ] - }, - { - "Target": "Loose File License(s)", - "Class": "license-file" } ] } diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index f6c54818d2e2..5e200ef14e3d 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -32,6 +32,20 @@ var ( Target: "Java", Class: types.ClassLangPkg, Type: ftypes.Jar, + Packages: []ftypes.Package{ + { + Name: "com.fasterxml.jackson.core:jackson-databind", + FilePath: "app/jackson-databind-2.13.4.1.jar", + }, + { + Name: "com.google.code.gson:gson", + FilePath: "app/gson-2.11.0.jar", + }, + { + Name: "org.apache.logging.log4j:log4j-core", + FilePath: "app/jackson-databind-2.13.4.1.jar/nested/app2/log4j-core-2.17.0.jar", + }, + }, Vulnerabilities: []types.DetectedVulnerability{ { VulnerabilityID: "CVE-2022-42003", @@ -185,6 +199,8 @@ Legend: ├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ │ test (alpine 3.20.3) │ alpine │ 2 │ - │ - │ - │ ├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ +│ app/gson-2.11.0.jar │ jar │ 0 │ - │ - │ - │ +├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ │ app/jackson-databind-2.13.4.1.jar │ jar │ 2 │ - │ - │ - │ ├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ │ loader-utils/package.json │ node-pkg │ 2 │ - │ - │ - │ @@ -227,6 +243,8 @@ Legend: ├───────────────────────────────────┼────────┼─────────────────┤ │ test (alpine 3.20.3) │ alpine │ 2 │ ├───────────────────────────────────┼────────┼─────────────────┤ +│ app/gson-2.11.0.jar │ jar │ 0 │ +├───────────────────────────────────┼────────┼─────────────────┤ │ app/jackson-databind-2.13.4.1.jar │ jar │ 2 │ └───────────────────────────────────┴────────┴─────────────────┘ `, diff --git a/pkg/report/table/table_test.go b/pkg/report/table/table_test.go index 911b27f01f10..bcf14a867269 100644 --- a/pkg/report/table/table_test.go +++ b/pkg/report/table/table_test.go @@ -33,6 +33,13 @@ func TestWriter_Write(t *testing.T) { Target: "test", Type: ftypes.Jar, Class: types.ClassLangPkg, + Packages: []ftypes.Package{ + { + Name: "foo", + Version: "1.2.3", + FilePath: "test.jar", + }, + }, Vulnerabilities: []types.DetectedVulnerability{ { VulnerabilityID: "CVE-2020-0001", @@ -40,6 +47,7 @@ func TestWriter_Write(t *testing.T) { InstalledVersion: "1.2.3", PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001", Status: dbTypes.StatusWillNotFix, + PkgPath: "test.jar", Vulnerability: dbTypes.Vulnerability{ Title: "foobar", Description: "baz", @@ -61,22 +69,22 @@ Report Summary Legend: - '-': Not scanned - '0': Clean (no security findings detected) -┌────────┬──────┬─────────────────┐ -│ Target │ Type │ Vulnerabilities │ -├────────┼──────┼─────────────────┤ -│ test │ jar │ 1 │ -└────────┴──────┴─────────────────┘ +┌──────────┬──────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├──────────┼──────┼─────────────────┤ +│ test.jar │ jar │ 1 │ +└──────────┴──────┴─────────────────┘ test (jar) ========== 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 │ -└─────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ +┌────────────────┬───────────────┬──────────┬──────────────┬───────────────────┬───────────────┬───────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├────────────────┼───────────────┼──────────┼──────────────┼───────────────────┼───────────────┼───────────────────────────────────────────┤ +│ foo (test.jar) │ CVE-2020-0001 │ HIGH │ will_not_fix │ 1.2.3 │ │ foobar │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-0001 │ +└────────────────┴───────────────┴──────────┴──────────────┴───────────────────┴───────────────┴───────────────────────────────────────────┘ `, }, { @@ -89,6 +97,13 @@ Total: 1 (MEDIUM: 0, HIGH: 1) Target: "test", Class: types.ClassLangPkg, Type: ftypes.Jar, + Packages: []ftypes.Package{ + { + Name: "foo", + Version: "1.2.3", + FilePath: "test.jar", + }, + }, }, }, wantOutput: ` @@ -97,11 +112,11 @@ Report Summary Legend: - '-': Not scanned - '0': Clean (no security findings detected) -┌────────┬──────┬─────────────────┐ -│ Target │ Type │ Vulnerabilities │ -├────────┼──────┼─────────────────┤ -│ test │ jar │ 0 │ -└────────┴──────┴─────────────────┘ +┌──────────┬──────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├──────────┼──────┼─────────────────┤ +│ test.jar │ jar │ 0 │ +└──────────┴──────┴─────────────────┘ `, }, { From 28ebb248359928ee4e1dd65409ec0fb17fecc4fc Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 16:57:28 +0600 Subject: [PATCH 22/27] refactor: don't show empty vuln table title for OS pkgs --- pkg/report/table/vulnerability.go | 5 ++--- pkg/report/table/vulnerability_test.go | 7 +------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/pkg/report/table/vulnerability.go b/pkg/report/table/vulnerability.go index 786b719ff09a..cad983a2ad33 100644 --- a/pkg/report/table/vulnerability.go +++ b/pkg/report/table/vulnerability.go @@ -72,11 +72,10 @@ func NewVulnerabilityRenderer(result types.Result, isTerminal, tree, suppressed } func (r *vulnerabilityRenderer) Render() string { - // There are 3 cases when we show the vulnerability table (or only target and `Total: 0...`): + // There are 2 cases when we show the vulnerability table (or only target and `Total: 0...`): // When Result contains vulnerabilities; - // When Result target is OS packages even if no vulnerabilities are found; // When we show non-empty `Suppressed Vulnerabilities` table. - if len(r.result.Vulnerabilities) > 0 || r.result.Class == types.ClassOSPkg || (r.showSuppressed && len(r.result.ModifiedFindings) > 0) { + if len(r.result.Vulnerabilities) > 0 || (r.showSuppressed && len(r.result.ModifiedFindings) > 0) { r.renderDetectedVulnerabilities() if r.tree { diff --git a/pkg/report/table/vulnerability_test.go b/pkg/report/table/vulnerability_test.go index 9a773c90eafe..b75d05d07c23 100644 --- a/pkg/report/table/vulnerability_test.go +++ b/pkg/report/table/vulnerability_test.go @@ -425,12 +425,7 @@ Suppressed Vulnerabilities (Total: 1) }, }, showSuppressed: false, - want: ` -test -==== -Total: 0 (MEDIUM: 0, HIGH: 0) - -`, + want: "s", }, { name: "suppressed all language package vulnerabilities without `showSuppressed` flag", From 0166a455e483fc26658f47e250c3e970a16bd9d7 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 16:59:24 +0600 Subject: [PATCH 23/27] refactor: use info log when results didn't find --- pkg/report/table/table.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index 7c684f3a7b7c..afb65f9ab3df 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -179,7 +179,7 @@ func (tw Writer) showEmptyResultsWarning() { warnStrings = append(warnStrings, "Scanners are not enabled.") } - log.WithPrefix("report").Warn(strings.Join(warnStrings, " ")) + log.WithPrefix("report").Info(strings.Join(warnStrings, " ")) } // splitAggregatedPackages splits aggregated packages into different results with path as target. From 5f13964afc7e20cfc2f0a065bcb4e06fe9bd1380 Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 17:20:05 +0600 Subject: [PATCH 24/27] fix: typo --- pkg/report/table/vulnerability_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/report/table/vulnerability_test.go b/pkg/report/table/vulnerability_test.go index b75d05d07c23..bc1c9ab5dda0 100644 --- a/pkg/report/table/vulnerability_test.go +++ b/pkg/report/table/vulnerability_test.go @@ -425,7 +425,7 @@ Suppressed Vulnerabilities (Total: 1) }, }, showSuppressed: false, - want: "s", + want: "", }, { name: "suppressed all language package vulnerabilities without `showSuppressed` flag", From 7f863b96ec4101f3bba1a6ebd4a0cf8aa07e1a4b Mon Sep 17 00:00:00 2001 From: DmitriyLewen Date: Wed, 29 Jan 2025 17:50:33 +0600 Subject: [PATCH 25/27] refactor: show legend after table --- pkg/report/table/table.go | 12 ++++++++---- pkg/report/table/table_private_test.go | 21 ++++++++++++--------- pkg/report/table/table_test.go | 14 ++++++++------ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/pkg/report/table/table.go b/pkg/report/table/table.go index afb65f9ab3df..186aaaa9669e 100644 --- a/pkg/report/table/table.go +++ b/pkg/report/table/table.go @@ -91,10 +91,7 @@ func (tw Writer) renderSummary(report types.Report) error { } // Fprintln has a bug - if err := tml.Fprintf(tw.Output, "\nReport Summary\n\n"+ - "Legend:\n"+ - "- '-': Not scanned\n"+ - "- '0': Clean (no security findings detected)\n"); err != nil { + if err := tml.Fprintf(tw.Output, "\nReport Summary\n\n"); err != nil { return err } @@ -149,6 +146,13 @@ func (tw Writer) renderSummary(report types.Report) error { t.AddRows(rows) } t.Render() + + // Show legend + if err := tml.Fprintf(tw.Output, "Legend:\n"+ + "- '-': Not scanned\n"+ + "- '0': Clean (no security findings detected)\n\n"); err != nil { + return err + } return nil } diff --git a/pkg/report/table/table_private_test.go b/pkg/report/table/table_private_test.go index 5e200ef14e3d..8a269d71fc62 100644 --- a/pkg/report/table/table_private_test.go +++ b/pkg/report/table/table_private_test.go @@ -191,9 +191,6 @@ func Test_renderSummary(t *testing.T) { want: ` Report Summary -Legend: -- '-': Not scanned -- '0': Clean (no security findings detected) ┌───────────────────────────────────┬────────────┬─────────────────┬───────────────────┬─────────┬──────────┐ │ Target │ Type │ Vulnerabilities │ Misconfigurations │ Secrets │ Licenses │ ├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ @@ -219,6 +216,10 @@ Legend: ├───────────────────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ │ Loose File License(s) │ - │ - │ - │ - │ 1 │ └───────────────────────────────────┴────────────┴─────────────────┴───────────────────┴─────────┴──────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + `, }, { @@ -235,9 +236,6 @@ Legend: want: ` Report Summary -Legend: -- '-': Not scanned -- '0': Clean (no security findings detected) ┌───────────────────────────────────┬────────┬─────────────────┐ │ Target │ Type │ Vulnerabilities │ ├───────────────────────────────────┼────────┼─────────────────┤ @@ -247,6 +245,10 @@ Legend: ├───────────────────────────────────┼────────┼─────────────────┤ │ app/jackson-databind-2.13.4.1.jar │ jar │ 2 │ └───────────────────────────────────┴────────┴─────────────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + `, }, { @@ -264,9 +266,6 @@ Legend: want: ` Report Summary -Legend: -- '-': Not scanned -- '0': Clean (no security findings detected) ┌──────────────────┬──────┬─────────────────┬─────────┐ │ Target │ Type │ Vulnerabilities │ Secrets │ ├──────────────────┼──────┼─────────────────┼─────────┤ @@ -274,6 +273,10 @@ Legend: ├──────────────────┼──────┼─────────────────┼─────────┤ │ requirements.txt │ text │ - │ 1 │ └──────────────────┴──────┴─────────────────┴─────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + `, }, } diff --git a/pkg/report/table/table_test.go b/pkg/report/table/table_test.go index bcf14a867269..f8ca0a02cfb6 100644 --- a/pkg/report/table/table_test.go +++ b/pkg/report/table/table_test.go @@ -66,14 +66,15 @@ func TestWriter_Write(t *testing.T) { wantOutput: ` Report Summary -Legend: -- '-': Not scanned -- '0': Clean (no security findings detected) ┌──────────┬──────┬─────────────────┐ │ Target │ Type │ Vulnerabilities │ ├──────────┼──────┼─────────────────┤ │ test.jar │ jar │ 1 │ └──────────┴──────┴─────────────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + test (jar) ========== @@ -109,14 +110,15 @@ Total: 1 (MEDIUM: 0, HIGH: 1) wantOutput: ` Report Summary -Legend: -- '-': Not scanned -- '0': Clean (no security findings detected) ┌──────────┬──────┬─────────────────┐ │ Target │ Type │ Vulnerabilities │ ├──────────┼──────┼─────────────────┤ │ test.jar │ jar │ 0 │ └──────────┴──────┴─────────────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + `, }, { From 2628b70a9b8cf652bc27b0e653251719122a00ce Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Tue, 4 Feb 2025 16:17:24 +0600 Subject: [PATCH 26/27] docs: fix typo Co-authored-by: Teppei Fukuda --- docs/docs/configuration/reporting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/configuration/reporting.md b/docs/docs/configuration/reporting.md index 389731c6f107..f1e2373d668f 100644 --- a/docs/docs/configuration/reporting.md +++ b/docs/docs/configuration/reporting.md @@ -86,7 +86,7 @@ Before result tables Trivy shows summary table. This table: -- include columns for enabled [scanners](../references/terminology.md#scanner) only. +- Includes columns for enabled [scanners](../references/terminology.md#scanner) only. - Contains separate lines for the same targets but different scanners. - `-` means that Trivy didn't scan this target. - `0` means that Trivy scanned this target, but found no vulns/misconfigs. From c78bfe5d138f7235f7969bec2f8e79ae25282343 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Tue, 4 Feb 2025 16:17:58 +0600 Subject: [PATCH 27/27] fix: nested list Co-authored-by: Teppei Fukuda --- docs/docs/configuration/reporting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/configuration/reporting.md b/docs/docs/configuration/reporting.md index f1e2373d668f..d0573dc271c0 100644 --- a/docs/docs/configuration/reporting.md +++ b/docs/docs/configuration/reporting.md @@ -88,8 +88,8 @@ This table: - Includes columns for enabled [scanners](../references/terminology.md#scanner) only. - Contains separate lines for the same targets but different scanners. -- `-` means that Trivy didn't scan this target. -- `0` means that Trivy scanned this target, but found no vulns/misconfigs. + - `-` means that the scanner didn't scan this target. + - `0` means that the scanner scanned this target, but found no security issues. !!! note Use `--no-summary-table` flag to hide summary table.