-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add report summary table #8177
Conversation
Signed-off-by: knqyf263 <[email protected]>
@DmitriyLewen @nikpivkin Before further development, I'd like to hear your thoughts. |
I agree with you. I think we need to discuss this. Initially (I may be wrong) Trivy was crippled by aggregating individual packages to avoid having too many tables in a report.
It seems that having multiple types for a single file is rare, so I suggest using this logic and waiting for feedback from users.
I prefer this way. I also have one idea - some users don't need to see vulnerability/misconfiguration numbers (CVE etc). So we can hide other tables by default and show them only when using a new flag ( As a future update:
|
I like the idea, the summary table looks good. Should the results be sorted by file name or scan type? I noticed that terraform scan results contain directories that we should get rid of. |
Exactly. It will simplify our logic. However, it will probably break something. We should carefully announce it. That's why I didn't want to add the change into this PR.
I already implemented it in this PR unless I'm making a mistake. In the screenshot, |
The current summary table is ordered by scanners, vulnerabilities -> misconfigurations -> secrets -> licenses. Do you want to sort by sub-scanners, such as terraform?
Yes, I actually saw |
Great! |
Looks nice. What's the difference between a I think I understand it as
I think we should change k8s summary output to be more simpler rather than the other way around. To me the k8s summary output is a bit too much especially with so many numbers that it isn't very helpful. |
I actually considered reusing the K8s summary table, but ultimately decided to keep them separate for several reasons: First, as @simar7 pointed out, the K8s summary table contains much information. This isn't necessarily a negative aspect - it's designed this way because K8s doesn't display details in the summary table by default (requires Second, since we plan to make a separate plugin for the K8s cluster scan similar to AWS account scanning, I wanted to avoid core dependencies on K8s. If we were to share code, having the dependency direction flow from K8s to core would be preferable, not the other way around. However, given the different purposes mentioned above, whether we should standardize these tables at all requires further discussion.
Yes, that's correct. I made this distinction because we frequently receive user feedback asking to clarify whether something wasn't scanned at all or was scanned but returned zero findings. I'll add a note beneath the table to clarify this distinction. |
pkg/report/table/table.go
Outdated
@@ -64,6 +80,69 @@ func (tw Writer) Write(_ context.Context, report types.Report) error { | |||
return nil | |||
} | |||
|
|||
func (tw Writer) renderSummary(report types.Report) error { | |||
log.WithPrefix("report").Info("Report Summary table contains special symbols", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added info about -
and 0
into logs:
2025-01-17T14:37:53+06:00 INFO [report] Report Summary table contains special symbols '-'="Target didn't scanned" '0'="Target scanned, but didn't contain vulns/misconfigs/secrets/licenses"
Report Summary
┌─────────────────────────────────────────────┬──────────┬─────────────────┬─────────┐
│ Target │ Type │ Vulnerabilities │ Secrets │
├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
But we can add info before table. e.g.:
Report Summary
Note:
- `-`: Target didn't scanned.
- `0`: Target scanned, but didn't contain vulns/misconfigs/secrets/licenses.
┌─────────────────────────────────────────────┬──────────┬─────────────────┬─────────┐
│ Target │ Type │ Vulnerabilities │ Secrets │
├─────────────────────────────────────────────┼──────────┼─────────────────┼─────────┤
@aquasecurity/trivy wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we elaborate on why a certain file "didn't scan"? Is it because it was unable to get parsed, wasn't valid for the scan (then maybe we shouldn't even traverse it) or something else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can wait for user feedback:
In most cases -
will be used for the case when the file is scanned by another scanner.
e.g., we scanned Dockerfile
, and -
will be for vulnerabilities.
In case the file is invalid (e.g. wrong lock file) - the report will not include the result with this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer putting it in the footer.
Legend:
- `-`: Not scanned
- `0`: Clean (no security findings detected)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed in e11221a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw one case - we show log after summary table:
2025-01-29T17:51:04+06:00 INFO Detected config files num=0
2025-01-29T17:51:04+06:00 DEBUG Specified ignore file does not exist file=".trivyignore"
2025-01-29T17:51:04+06:00 DEBUG [vex] VEX filtering is disabled
Report Summary
┌─────────────────┬──────┬─────────────────┬───────────────────┬─────────┬──────────┐
│ Target │ Type │ Vulnerabilities │ Misconfigurations │ Secrets │ Licenses │
├─────────────────┼──────┼─────────────────┼───────────────────┼─────────┼──────────┤
│ gson-2.11.0.jar │ jar │ 2 │ - │ - │ - │
└─────────────────┴──────┴─────────────────┴───────────────────┴─────────┴──────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
2025-01-29T17:51:04+06:00 INFO Table result includes only package filenames. Use '--format json' option to get the full path to the package file.
Java (jar)
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
┌───────────────────────────────────────────────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────────────┬─────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├───────────────────────────────────────────────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────────────┼─────────────────────────────────────────────────────┤
│ com.fasterxml.jackson.core:jackson-databind │ CVE-2022-42003 │ HIGH │ fixed │ 2.13.4.1 │ 2.12.7.1, 2.13.4.2 │ jackson-databind: deep wrapper array nesting wrt │
│ (gson-2.11.0.jar) │ │ │ │ │ │ UNWRAP_SINGLE_VALUE_ARRAYS │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-42003 │
├───────────────────────────────────────────────────────┼────────────────┼──────────┤ ├───────────────────┼───────────────────────┼─────────────────────────────────────────────────────┤
│ org.apache.logging.log4j:log4j-core (gson-2.11.0.jar) │ CVE-2021-44832 │ MEDIUM │ │ 2.17.0 │ 2.3.2, 2.12.4, 2.17.1 │ log4j-core: remote code execution via JDBC Appender │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2021-44832 │
└───────────────────────────────────────────────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────────────┴─────────────────────────────────────────────────────┘
We might want to add a header (e.g. result tables
) before result tables (after the legend) to separate summary table from other tables.
but on the other hand I think it's redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may need to write the rendered output to a buffer and flush it later to stdout, like we do in each renderer.
trivy/pkg/report/table/table.go
Line 282 in 7f863b9
_, _ = fmt.Fprint(tw.Output, renderer.Render()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used Renderer interface for summary table - 878b9f4
I found that we have same problem in main
branch:
2025-02-05T12:53:12+06:00 INFO Table result includes only package filenames. Use '--format json' option to get the full path to the package file.
Java (jar)
Total: 4 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 2, CRITICAL: 0)
┌─────────────────────────────────────────────────────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────────────┬─────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├─────────────────────────────────────────────────────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────────────┼─────────────────────────────────────────────────────┤
│ com.fasterxml.jackson.core:jackson-databind │ CVE-2022-42003 │ HIGH │ fixed │ 2.13.4.1 │ 2.12.7.1, 2.13.4.2 │ jackson-databind: deep wrapper array nesting wrt │
│ (jackson-databind-2.13.4.1.jar) │ │ │ │ │ │ UNWRAP_SINGLE_VALUE_ARRAYS │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-42003 │
├─────────────────────────────────────────────────────────────┤ │ │ │ │ │ │
│ com.fasterxml.jackson.core:jackson-databind │ │ │ │ │ │ │
│ (gson-2.11.0.jar) │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
├─────────────────────────────────────────────────────────────┼────────────────┼──────────┤ ├───────────────────┼───────────────────────┼─────────────────────────────────────────────────────┤
│ org.apache.logging.log4j:log4j-core (log4j-core-2.17.0.jar) │ CVE-2021-44832 │ MEDIUM │ │ 2.17.0 │ 2.3.2, 2.12.4, 2.17.1 │ log4j-core: remote code execution via JDBC Appender │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2021-44832 │
├─────────────────────────────────────────────────────────────┤ │ │ │ │ │ │
│ org.apache.logging.log4j:log4j-core (gson-2.11.0.jar) │ │ │ │ │ │ │
│ │ │ │ │ │ │ │
└─────────────────────────────────────────────────────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────────────┴─────────────────────────────────────────────────────┘
2025-02-05T12:53:12+06:00 INFO Table result includes only package filenames. Use '--format json' option to get the full path to the package file.
Node.js (node-pkg)
Total: 5 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 2, CRITICAL: 1)
┌─────────────────────────────┬────────────────┬──────────┬────────┬───────────────────┬─────────────────────┬─────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├─────────────────────────────┼────────────────┼──────────┼────────┼───────────────────┼─────────────────────┼─────────────────────────────────────────────────────────────┤
│ loader-utils (package.json) │ CVE-2022-37601 │ CRITICAL │ fixed │ 2.0.2 │ 2.0.3, 1.4.1 │ loader-utils: prototype pollution in function parseQuery in │
│ │ │ │ │ │ │ parseQuery.js │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-37601 │
│ ├────────────────┼──────────┤ │ ├─────────────────────┼─────────────────────────────────────────────────────────────┤
│ │ CVE-2022-37599 │ HIGH │ │ │ 1.4.2, 2.0.4, 3.2.1 │ loader-utils: regular expression denial of service in │
│ │ │ │ │ │ │ interpolateName.js │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-37599 │
│ ├────────────────┤ │ │ │ ├─────────────────────────────────────────────────────────────┤
│ │ CVE-2022-37603 │ │ │ │ │ loader-utils: Regular expression denial of service │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-37603 │
├─────────────────────────────┼────────────────┼──────────┤ ├───────────────────┼─────────────────────┼─────────────────────────────────────────────────────────────┤
│ nanoid (package.json) │ CVE-2021-23566 │ MEDIUM │ │ 3.1.25 │ 3.1.31 │ nanoid: Information disclosure via valueOf() function │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2021-23566 │
│ ├────────────────┤ │ │ ├─────────────────────┼─────────────────────────────────────────────────────────────┤
│ │ CVE-2024-55565 │ │ │ │ 5.0.9, 3.3.8 │ nanoid: nanoid mishandles non-integer values │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2024-55565 │
└─────────────────────────────┴────────────────┴──────────┴────────┴───────────────────┴─────────────────────┴─────────────────────────────────────────────────────────────┘
So i want to fix that in separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@knqyf263 I rebased and updated PR with updated interface
├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ | ||
│ test (alpine 3.20.3) │ alpine │ 2 │ - │ - │ - │ | ||
├───────────────────────┼────────────┼─────────────────┼───────────────────┼─────────┼──────────┤ | ||
│ Java │ jar │ 2 │ - │ - │ - │ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The summary table contains aggregated targets.
Do we want to split them by filePath
in this PR or just start working on removing the aggregation (in another PR)?
cc. @knqyf263
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't split aggregated results, but, actually yes, we can split them in the table writer. I think we should do that in this PR. We will not need the logic after removing the aggregation, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have 1 more question: Do we need to show empty table? ➜ ./trivy -q fs ./pkg/fanal/analyzer/language/nodejs/npm/testdata/sad
Report Summary
┌────────┬──────┬─────────────────┬─────────┐
│ Target │ Type │ Vulnerabilities │ Secrets │
└────────┴──────┴─────────────────┴─────────┘
Or we can hide table and write Info/warn log or something else. |
Showing only the header is probably unclear for users. I'd opt for log messages. |
convertFlags.ScanFlagGroup.Scanners = flag.ScannersFlag.Clone() | ||
convertFlags.ScanFlagGroup.Scanners.Default = nil // disable default scanners | ||
convertFlags.ScanFlagGroup.Scanners.Usage = "List of scanners included when generating the json report. Used only for rendering the summary table." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we could just enable all scanners. But I think we need to use the same format(logic) for convert
and other subcommands.
So i enabled --scanners
that users can get summary table as for table
format.
pkg/report/table/summary.go
Outdated
var warnStrings []string | ||
if scanners := lo.Intersect(resultByFiles, r.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, r.scanners); len(scanners) > 0 { | ||
warnStrings = append(warnStrings, fmt.Sprintf("No results found for %s scanner(s).", | ||
strings.Join(xstrings.ToStringSlice(scanners), "/"))) | ||
} | ||
|
||
log.WithPrefix("report").Info(strings.Join(warnStrings, " ")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var warnStrings []string | |
if scanners := lo.Intersect(resultByFiles, r.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, r.scanners); len(scanners) > 0 { | |
warnStrings = append(warnStrings, fmt.Sprintf("No results found for %s scanner(s).", | |
strings.Join(xstrings.ToStringSlice(scanners), "/"))) | |
} | |
log.WithPrefix("report").Info(strings.Join(warnStrings, " ")) | |
if scanners := lo.Intersect(resultByFiles, r.scanners); len(scanners) > 0 { | |
r.logger.Warn("Supported files for scanner(s) not found.", log.Any("scanners", scanners)) | |
} | |
if scanners := lo.Intersect(resultByFindings, r.scanners); len(scanners) > 0 { | |
r.logger.Warn("No issues detected with scanner(s).", log.Any("scanners", scanners)) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed in 67a729c
type summaryRenderer struct { | ||
w *bytes.Buffer | ||
isTerminal bool | ||
scanners []Scanner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scanners []Scanner | |
scanners []Scanner | |
loggers *log.Logger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed in 67a729c
return &summaryRenderer{ | ||
w: buf, | ||
isTerminal: isTerminal, | ||
scanners: ss, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scanners: ss, | |
scanners: ss, | |
logger: log.WithPrefix("report"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed in 67a729c
pkg/report/table/summary.go
Outdated
|
||
func (r *summaryRenderer) Render(report types.Report) { | ||
if len(r.scanners) == 0 { | ||
log.WithPrefix("report").Warn("No enabled scanners found. Summary table will not be displayed.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log.WithPrefix("report").Warn("No enabled scanners found. Summary table will not be displayed.") | |
r.logger..Warn("No enabled scanners found. Summary table will not be displayed.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed in 67a729c
pkg/flag/report_flags.go
Outdated
NoSummaryTableFlag = Flag[bool]{ | ||
Name: "no-summary-table", | ||
ConfigName: "no-summary-table", | ||
Usage: "hide summary table", | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a major UI change, so there might be some backlash from the community. In that case, since switching from opt-out to opt-in is possible, it might be a good idea to mark it as experimental.
Also, as @simar7 pointed out, boolean flags are not very flexible. Specifying it as something like --table summary,detail
could be an alternative option. This approach would allow us to meet future requests from users who may only want to display the summary table, and by changing the default values, it would be easy to switch between opt-in and opt-out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm... it make sense. I will update PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several options:
- --table
- --table-view
- --table-format
- --table-mode
Also,
- summary|detail
- summary|detailed
- etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a good idea.
In the trivy-aws
plugin, the report flag takes an enumeration:
--report string specify a report format for the output (all,summary) (default “all”)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--table-mode
+ summary|details
(with s
suffix) are my favorite.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My friend :) recommended detailed
, but you can decide it.
When deciding on terminology to distinguish between a concise summary output and a more exhaustive one, many tools and UIs use the terms “Summary” and “Detailed.” While “Detail” or “Details” might seem similar at first glance, “detailed” is often chosen for the following reasons:
-
Consistent Adjective Pairing
- In English, it’s common to describe views or reports using adjectives. For instance, many interfaces provide a “Summary View” and a “Detailed View,” or a “Summary Report” and a “Detailed Report.” Using “detailed” as an adjective aligns naturally with “summary” in such contexts.
-
Clear Mode Indicator
- When specifying a mode in a CLI or configuration file, saying
detailed
conveys that you want the more comprehensive or in-depth version of the output. An adjective like “detailed” feels more intuitive than the noun form “details,” which might be perceived as describing the objects being displayed rather than the mode or style of display.
- When specifying a mode in a CLI or configuration file, saying
-
Established Convention
- Many existing tools (even if they don’t directly use the exact words “summary” and “detailed”) follow the pattern of an abbreviated or condensed output versus a more verbose output. Where explicit labels are used, it’s more common to see “Detailed” than “Details” for the extended version.
-
Smoother Documentation
- Documentation and user guides often refer to “Detailed mode” (or a “Detailed report”), making it very clear that it’s an expanded form of the output. Conversely, “Details mode” or “Details report” can sound slightly off in English usage, as it doesn’t match the typical way we describe different presentation modes.
In short, “detailed” pairs nicely with “summary” and is more recognizable to users as the counterpart for a “deep-dive” option, while “detail” or “details” tend to read more like nouns referring to the actual data rather than the presentation style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--table-mode
also looks good to me. Then, the pairing of "summary mode" and "detailed mode" may be straightforward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the interest of not committing bike shedding... I'll vote for --table-mode
flag with =detailed,summary
as values. 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed --no-summary-table
to --table-mode
- ea453d8
Perhaps you will have more ideas.
Co-authored-by: Teppei Fukuda <[email protected]>
Co-authored-by: Teppei Fukuda <[email protected]>
Co-authored-by: Teppei Fukuda <[email protected]>
Co-authored-by: Teppei Fukuda <[email protected]>
pkg/report/table/summary.go
Outdated
if len(report.Results) == 0 { | ||
r.showEmptyResultsWarning() | ||
t.AddRows(slices.Repeat([]string{"-"}, len(r.scanners)+2)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: It's no big deal, but the alignment looks a bit strange when -
is used in all columns.
┌────────┬──────┬─────────────────┬─────────┐
│ Target │ Type │ Vulnerabilities │ Secrets │
├────────┼──────┼─────────────────┼─────────┤
│ - │ - │ - │ - │
└────────┴──────┴─────────────────┴─────────┘
if len(report.Results) == 0 { | |
r.showEmptyResultsWarning() | |
t.AddRows(slices.Repeat([]string{"-"}, len(r.scanners)+2)) | |
} | |
if len(report.Results) == 0 { | |
r.showEmptyResultsWarning() | |
alignments[0] = table.AlignCenter | |
t.SetAlignment(alignments...) | |
t.AddRows(slices.Repeat([]string{"-"}, len(r.scanners)+2)) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch.
I somehow didn't pay attention to it.
Updated 014e4c4
The rest looks good to me. @DmitriyLewen Feel free to merge this PR whenever you're ready (I cannot approve my PR). |
Signed-off-by: knqyf263 <[email protected]> Co-authored-by: DmitriyLewen <[email protected]> Co-authored-by: DmitriyLewen <[email protected]>
Signed-off-by: knqyf263 <[email protected]> Co-authored-by: DmitriyLewen <[email protected]> Co-authored-by: DmitriyLewen <[email protected]>
This PR introduces a summary table that displays all scan results, including those with zero findings, such as vulnerabilities and misconfiguration, to improve visibility and reduce user anxiety about the scanning process.
Background
Historically, Trivy followed the Unix philosophy where "silence is golden" and didn't output anything when no vulnerabilities were found. However, this led to user confusion about whether scans were working correctly. While we previously addressed this by showing results for OS packages with zero vulnerabilities, the inconsistency between OS and language-specific package outputs has created new confusion.
Proposed Changes
This PR adds a summary table at the beginning of the output that:
Example output:
Considerations
Aggregated Results for Individual Files
Result Aggregation Strategy
Default Behavior
--no-summary-table
)--show-summary-table
Implementation Notes
TODOs
Add--no-summary-table
Error out on--no-summary-table
with the formats other than--format table
--table-mode
flag-table-mode
with the formats other than--format table
0
and-
in the summary tableExamples
Related issues
Checklist