fix: present control status instead of compliance percentage in compliance report (#3181)

Signed-off-by: chenk <hen.keinan@gmail.com>
This commit is contained in:
chenk
2022-11-20 13:46:16 +02:00
committed by GitHub
parent cc8cef1936
commit f115895d30
9 changed files with 36 additions and 58 deletions

View File

@@ -49,9 +49,8 @@ $ trivy k8s cluster --compliance=nsa --report summary
![k8s Summary Report](../../../imgs/trivy-nsa-summary.png)
***Note*** : The `compliance` column represent the calculation of all tests pass vs. fail for all resources per control check in percentage format.
***Note*** : The `Issues` column represent the total number of failed checks for this control.
Example: if I have two resources in cluster and one resource scan result show pass while the other one show fail for `1.0 Non-root Containers` then it compliance will show 50%
An additional report is supported to get all of the detail the output contains, use `--report all`
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 318 KiB

View File

@@ -57,8 +57,7 @@ type ControlCheckSummary struct {
ID string
Name string
Severity string
TotalPass float32
TotalFail float32
TotalFail *int `json:",omitempty"`
}
// Writer defines the result write operation

View File

@@ -3,15 +3,16 @@ package report
import (
"fmt"
"io"
"strconv"
"strings"
"golang.org/x/xerrors"
"k8s.io/utils/pointer"
"github.com/aquasecurity/table"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/compliance/spec"
pkgReport "github.com/aquasecurity/trivy/pkg/report/table"
"github.com/aquasecurity/trivy/pkg/types"
)
func BuildSummary(cr *ComplianceReport) *SummaryReport {
@@ -22,23 +23,8 @@ func BuildSummary(cr *ComplianceReport) *SummaryReport {
Name: control.Name,
Severity: control.Severity,
}
if len(control.Results) == 0 { // this validation is mainly for vuln type
if control.DefaultStatus == spec.PassStatus {
ccm.TotalPass = 1
}
ccma = append(ccma, ccm)
continue
}
for _, check := range control.Results {
for _, m := range check.Misconfigurations {
if m.Status == types.StatusPassed {
ccm.TotalPass++
continue
}
ccm.TotalFail++
}
// Detected vulnerabilities are always failure.
ccm.TotalFail += float32(len(check.Vulnerabilities))
if !strings.Contains(control.Name, "Manual") {
ccm.TotalFail = pointer.Int(len(control.Results))
}
ccma = append(ccma, ccm)
}
@@ -101,16 +87,17 @@ func (s SummaryWriter) Write(report *ComplianceReport) error {
}
func (s SummaryWriter) generateSummary(summaryControls ControlCheckSummary) []string {
percentage := calculatePercentage(summaryControls.TotalFail, summaryControls.TotalPass)
return []string{summaryControls.ID, summaryControls.Severity, summaryControls.Name, percentage}
}
func calculatePercentage(totalFail float32, totalPass float32) string {
if totalPass == 0 && totalFail == 0 {
return fmt.Sprintf("%.2f", 0.00) + "%"
var numOfIssues string
var status string
if summaryControls.TotalFail != nil {
if *summaryControls.TotalFail == 0 {
status = "PASS"
} else {
status = "FAIL"
}
numOfIssues = strconv.Itoa(*summaryControls.TotalFail)
}
relPass := totalPass / (totalFail + totalPass)
return fmt.Sprintf("%.2f", relPass*100.0) + "%"
return []string{summaryControls.ID, summaryControls.Severity, summaryControls.Name, status, numOfIssues}
}
func getRequiredSeverities(requiredSevs []dbTypes.Severity) ([]string, []string) {

View File

@@ -6,6 +6,7 @@ import (
"github.com/aquasecurity/trivy/pkg/compliance/report"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/stretchr/testify/assert"
"k8s.io/utils/pointer"
)
func TestBuildSummary(t *testing.T) {
@@ -58,15 +59,13 @@ func TestBuildSummary(t *testing.T) {
ID: "1.0",
Name: "Non-root containers",
Severity: "MEDIUM",
TotalPass: 0,
TotalFail: 1,
TotalFail: pointer.Int(1),
},
{
ID: "1.1",
Name: "Immutable container file systems",
Severity: "LOW",
TotalPass: 0,
TotalFail: 1,
TotalFail: pointer.Int(1),
},
},
},
@@ -127,22 +126,19 @@ func TestBuildSummary(t *testing.T) {
ID: "1.0",
Name: "Non-root containers",
Severity: "MEDIUM",
TotalPass: 0,
TotalFail: 1,
TotalFail: pointer.Int(1),
},
{
ID: "1.1",
Name: "Immutable container file systems",
Severity: "LOW",
TotalPass: 0,
TotalFail: 1,
TotalFail: pointer.Int(1),
},
{
ID: "1.2",
Name: "tzdata - new upstream version",
Severity: "LOW",
TotalPass: 0,
TotalFail: 2,
TotalFail: pointer.Int(1),
},
},
},

View File

@@ -22,11 +22,12 @@ const (
ControlIDColumn = "ID"
SeverityColumn = "Severity"
ControlNameColumn = "Control Name"
ComplianceColumn = "Compliance"
StatusColumn = "Status"
IssuesColumn = "Issues"
)
func (tw TableWriter) columns() []string {
return []string{ControlIDColumn, SeverityColumn, ControlNameColumn, ComplianceColumn}
return []string{ControlIDColumn, SeverityColumn, ControlNameColumn, StatusColumn, IssuesColumn}
}
func (tw TableWriter) Write(report *ComplianceReport) error {

View File

@@ -6,15 +6,13 @@
"ID": "1.0",
"Name": "Non-root containers",
"Severity": "MEDIUM",
"TotalPass": 0,
"TotalFail": 1
},
{
"ID": "1.1",
"Name": "Immutable container file systems",
"Severity": "LOW",
"TotalPass": 0,
"TotalFail": 1
}
]
}
}

View File

@@ -1,10 +1,10 @@
Summary Report for compliance: NSA
┌─────┬──────────┬──────────────────────────────────┬────────────┐
│ ID │ Severity │ Control Name │ Compliance
├─────┼──────────┼──────────────────────────────────┼────────────┤
│ 1.0 │ MEDIUM │ Non-root containers │ 0.00%
│ 1.1 │ LOW │ Immutable container file systems │ 0.00%
└─────┴──────────┴──────────────────────────────────┴────────────┘
┌─────┬──────────┬──────────────────────────────────┬────────┬────────┐
│ ID │ Severity │ Control Name │ Status │ Issues
├─────┼──────────┼──────────────────────────────────┼────────┼────────┤
│ 1.0 │ MEDIUM │ Non-root containers │ FAIL │ 1
│ 1.1 │ LOW │ Immutable container file systems │ FAIL │ 1
└─────┴──────────┴──────────────────────────────────┴────────┴────────┘

View File

@@ -130,11 +130,9 @@ func (s *Scanner) scanMisconfigs(ctx context.Context, artifact *artifacts.Artifa
}
func (s *Scanner) filter(ctx context.Context, r types.Report, artifact *artifacts.Artifact) (report.Resource, error) {
var err error
if len(s.opts.ReportOptions.Compliance) == 0 {
r, err = s.runner.Filter(ctx, s.opts, r)
if err != nil {
return report.Resource{}, xerrors.Errorf("filter error: %w", err)
}
r, err = s.runner.Filter(ctx, s.opts, r)
if err != nil {
return report.Resource{}, xerrors.Errorf("filter error: %w", err)
}
return report.CreateResource(artifact, r, nil), nil
}