Skip to content

Commit

Permalink
refactor(k8s): custom reports (#3076)
Browse files Browse the repository at this point in the history
  • Loading branch information
knqyf263 committed Oct 25, 2022
1 parent f4e970f commit af89249
Show file tree
Hide file tree
Showing 41 changed files with 1,047 additions and 1,786 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ require (
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/neurosnap/sentences.v1 v1.0.6 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v2 v2.4.0 // indirect
gotest.tools v2.2.0+incompatible
gotest.tools/v3 v3.2.0 // indirect
helm.sh/helm/v3 v3.10.0 // indirect
Expand Down
6 changes: 4 additions & 2 deletions pkg/compliance/report/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ func (jw JSONWriter) Write(report *ComplianceReport) error {
var output []byte
var err error

var v interface{}
switch jw.Report {
case allReport:
output, err = json.MarshalIndent(report, "", " ")
v = report
case summaryReport:
output, err = json.MarshalIndent(BuildSummary(report), "", " ")
v = BuildSummary(report)
default:
return xerrors.Errorf(`report %q not supported. Use "summary" or "all"`, jw.Report)
}

output, err = json.MarshalIndent(v, "", " ")
if err != nil {
return xerrors.Errorf("failed to marshal json: %w", err)
}
Expand Down
96 changes: 66 additions & 30 deletions pkg/compliance/report/json_test.go
Original file line number Diff line number Diff line change
@@ -1,46 +1,82 @@
package report
package report_test

import (
"bytes"
"encoding/json"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/stretchr/testify/assert"
"io"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"

"github.com/aquasecurity/trivy/pkg/compliance/report"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/stretchr/testify/assert"
)

func TestJSONReport(t *testing.T) {
func TestJSONWriter_Write(t *testing.T) {
input := &report.ComplianceReport{
ID: "1234",
Title: "NSA",
RelatedResources: []string{"https://example.com"},
Results: []*report.ControlCheckResult{
{
ID: "1.0",
Name: "Non-root containers",
Severity: "MEDIUM",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{AVDID: "AVD-KSV012", Status: types.StatusFailure},
},
},
},
},
{
ID: "1.1",
Name: "Immutable container file systems",
Severity: "LOW",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{AVDID: "AVD-KSV013", Status: types.StatusFailure},
},
},
},
},
},
}

tests := []struct {
name string
specPath string
resultPath string
reportType string
wantJsonReportPath string
name string
reportType string
input *report.ComplianceReport
want string
}{
{name: "build summary json output report", specPath: "./testdata/config_spec.yaml", reportType: "summary", resultPath: "./testdata/results_config.json", wantJsonReportPath: "./testdata/json_summary.json"},
{name: "build full json output report", specPath: "./testdata/config_spec.yaml", reportType: "all", resultPath: "./testdata/results_config.json", wantJsonReportPath: "./testdata/json_view.json"},
{
name: "build summary json output report",
reportType: "summary",
input: input,
want: filepath.Join("testdata", "summary.json"),
},
{
name: "build full json output report",
reportType: "all",
input: input,
want: filepath.Join("testdata", "all.json"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
specfile, err := os.ReadFile(tt.specPath)
assert.NoError(t, err)
var res types.Results
resultByte, err := os.ReadFile(tt.resultPath)
err = json.Unmarshal(resultByte, &res)
assert.NoError(t, err)
complianceResults, err := BuildComplianceReport([]types.Results{res}, string(specfile))
assert.NoError(t, err)
ioWriter := new(bytes.Buffer)
tr := JSONWriter{Report: tt.reportType, Output: ioWriter}
err = tr.Write(complianceResults)
assert.NoError(t, err)
bt, err := io.ReadAll(ioWriter)
assert.NoError(t, err)
r, err := os.ReadFile(tt.wantJsonReportPath)
assert.NoError(t, err)
assert.Equal(t, string(bt), string(r))
buf := new(bytes.Buffer)
tr := report.JSONWriter{Report: tt.reportType, Output: buf}
err := tr.Write(tt.input)
require.NoError(t, err)

want, err := os.ReadFile(tt.want)
require.NoError(t, err)

assert.JSONEq(t, string(want), buf.String())
})
}
}
74 changes: 32 additions & 42 deletions pkg/compliance/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"io"

"golang.org/x/xerrors"
"gopkg.in/yaml.v2"

dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/compliance/spec"
Expand All @@ -29,37 +28,37 @@ type Option struct {

// ComplianceReport represents a kubernetes scan report
type ComplianceReport struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Version string `json:"severity"`
RelatedResources []string `json:"relatedResources"`
Results []*ControlCheckResult `json:"results"`
ID string
Title string
Description string
Version string
RelatedResources []string
Results []*ControlCheckResult
}

type ControlCheckResult struct {
ControlCheckID string `json:"id"`
ControlName string `json:"name"`
ControlDescription string `json:"description"`
DefaultStatus spec.ControlStatus `json:"defaultStatus,omitempty"`
ControlSeverity string `json:"severity"`
Results types.Results `json:"results"`
ID string
Name string
Description string
DefaultStatus spec.ControlStatus `json:",omitempty"`
Severity string
Results types.Results
}

// ConsolidatedReport represents a kubernetes scan report with consolidated findings
// SummaryReport represents a kubernetes scan report with consolidated findings
type SummaryReport struct {
SchemaVersion int `json:",omitempty"`
ReportID string
ReportTitle string
ID string
Title string
SummaryControls []ControlCheckSummary `json:",omitempty"`
}

type ControlCheckSummary struct {
ControlCheckID string `json:"id"`
ControlName string `json:"name"`
ControlSeverity string `json:"severity"`
TotalPass float32 `json:"totalPass"`
TotalFail float32 `json:"totalFail"`
ID string
Name string
Severity string
TotalPass float32
TotalFail float32
}

// Writer defines the result write operation
Expand Down Expand Up @@ -99,16 +98,18 @@ func (r ComplianceReport) empty() bool {
func buildControlCheckResults(checksMap map[string]types.Results, controls []spec.Control) []*ControlCheckResult {
complianceResults := make([]*ControlCheckResult, 0)
for _, control := range controls {
cr := ControlCheckResult{}
cr.ControlName = control.Name
cr.ControlCheckID = control.ID
cr.ControlDescription = control.Description
cr.ControlSeverity = string(control.Severity)
cr.DefaultStatus = control.DefaultStatus
var results types.Results
for _, c := range control.Checks {
cr.Results = append(cr.Results, checksMap[c.ID]...)
results = append(results, checksMap[c.ID]...)
}
complianceResults = append(complianceResults, &cr)
complianceResults = append(complianceResults, &ControlCheckResult{
Name: control.Name,
ID: control.ID,
Description: control.Description,
Severity: string(control.Severity),
DefaultStatus: control.DefaultStatus,
Results: results,
})
}
return complianceResults
}
Expand All @@ -126,20 +127,9 @@ func buildComplianceReportResults(checksMap map[string]types.Results, spec spec.
}
}

func BuildComplianceReport(scanResults []types.Results, complianceSpec string) (*ComplianceReport, error) {
// load compliance spec
cs := spec.ComplianceSpec{}
err := yaml.Unmarshal([]byte(complianceSpec), &cs)
if err != nil {
return nil, err
}
// validate scanners types (vuln and config) define in spec supported
err = spec.ValidateScanners(cs.Spec.Controls)
if err != nil {
return nil, err
}
func BuildComplianceReport(scanResults []types.Results, cs spec.ComplianceSpec) (*ComplianceReport, error) {
// aggregate checks by ID
aggregateChecksByID := spec.AggregateAllChecksBySpecID(scanResults, cs.Spec.Controls)
aggregateChecksByID := spec.AggregateAllChecksBySpecID(scanResults, cs)

// build compliance report results
return buildComplianceReportResults(aggregateChecksByID, cs.Spec), nil
Expand Down

0 comments on commit af89249

Please sign in to comment.