fix(report): don't panic when report contains vulns, but doesn't contain packages for table format (#8549)

This commit is contained in:
DmitriyLewen
2025-06-10 11:22:35 +06:00
committed by GitHub
parent 875ec3a9d2
commit 87fda76f38
2 changed files with 109 additions and 5 deletions

View File

@@ -171,7 +171,7 @@ func (r *summaryRenderer) Render(report types.Report) {
t.SetHeaders(headers...)
t.SetAlignment(alignments...)
for _, result := range splitAggregatedPackages(report.Results) {
for _, result := range r.splitAggregatedPackages(report.Results) {
resultType := string(result.Type)
switch result.Class {
case types.ClassSecret:
@@ -232,7 +232,7 @@ func (r *summaryRenderer) showEmptyResultsWarning() {
// 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 {
func (r *summaryRenderer) splitAggregatedPackages(results types.Results) types.Results {
var newResults types.Results
for _, result := range results {
@@ -243,14 +243,22 @@ func splitAggregatedPackages(results types.Results) types.Results {
continue
}
newResults = append(newResults, splitAggregatedVulns(result)...)
newResults = append(newResults, r.splitAggregatedVulns(result)...)
newResults = append(newResults, splitAggregatedLicenses(result)...)
}
return newResults
}
func splitAggregatedVulns(result types.Result) types.Results {
func (r *summaryRenderer) splitAggregatedVulns(result types.Result) types.Results {
// Handle case when result doesn't contain Package
// cf. https://github.com/aquasecurity/trivy/discussions/8537
if len(result.Packages) == 0 && len(result.Vulnerabilities) > 0 {
r.logger.Warn("Packages not found unexpectedly", log.String("target", result.Target))
return types.Results{
result,
}
}
// Save packages to display them in the table even if no vulnerabilities were found
resultMap := lo.SliceToMap(result.Packages, func(pkg ftypes.Package) (string, *types.Result) {
filePath := rootJarFromPath(pkg.FilePath)
@@ -262,7 +270,12 @@ func splitAggregatedVulns(result types.Result) types.Results {
})
for _, vuln := range result.Vulnerabilities {
pkgPath := rootJarFromPath(vuln.PkgPath)
resultMap[pkgPath].Vulnerabilities = append(resultMap[pkgPath].Vulnerabilities, vuln)
if res, ok := resultMap[pkgPath]; !ok {
r.logger.Warn("Package not found unexpectedly", log.String("package_path", pkgPath), log.String("vuln_id", vuln.VulnerabilityID))
} else {
res.Vulnerabilities = append(res.Vulnerabilities, vuln)
}
}
newResults := lo.Values(resultMap)
sort.Slice(newResults, func(i, j int) bool {

View File

@@ -59,6 +59,49 @@ var (
},
}
jarVulnsWithoutPackages = 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/jackson-databind-2.13.4.1.jar/nested/app2/log4j-core-2.17.0.jar",
},
},
}
jarVulnsWithMissedPackage = types.Result{
Target: "Java",
Class: types.ClassLangPkg,
Type: ftypes.Jar,
Packages: []ftypes.Package{
{
Name: "com.fasterxml.jackson.core:jackson-databind",
Version: "2.13.4.1",
FilePath: "app/jackson-databind-2.13.4.1.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",
},
},
}
npmVulns = types.Result{
Target: "Node.js",
Class: types.ClassLangPkg,
@@ -285,6 +328,54 @@ Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
`,
},
{
name: "happy path when Result doesn't include Packages",
scanners: []types.Scanner{
types.VulnerabilityScanner,
},
report: types.Report{
Results: []types.Result{
jarVulnsWithoutPackages,
},
},
want: `
Report Summary
┌────────┬──────┬─────────────────┐
│ Target │ Type │ Vulnerabilities │
├────────┼──────┼─────────────────┤
│ Java │ jar │ 2 │
└────────┴──────┴─────────────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
`,
},
{
name: "happy path when Result doesn't include all required Packages",
scanners: []types.Scanner{
types.VulnerabilityScanner,
},
report: types.Report{
Results: []types.Result{
jarVulnsWithMissedPackage,
},
},
want: `
Report Summary
┌───────────────────────────────────┬──────┬─────────────────┐
│ Target │ Type │ Vulnerabilities │
├───────────────────────────────────┼──────┼─────────────────┤
│ app/jackson-databind-2.13.4.1.jar │ jar │ 1 │
└───────────────────────────────────┴──────┴─────────────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
`,
},
{