github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/compliance/report/report.go (about) 1 package report 2 3 import ( 4 "io" 5 6 "golang.org/x/xerrors" 7 8 defsecTypes "github.com/aquasecurity/defsec/pkg/types" 9 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 10 "github.com/devseccon/trivy/pkg/compliance/spec" 11 "github.com/devseccon/trivy/pkg/types" 12 ) 13 14 const ( 15 allReport = "all" 16 summaryReport = "summary" 17 ) 18 19 type Option struct { 20 Format types.Format 21 Report string 22 Output io.Writer 23 Severities []dbTypes.Severity 24 ColumnHeading []string 25 } 26 27 // ComplianceReport represents a kubernetes scan report 28 type ComplianceReport struct { 29 ID string 30 Title string 31 Description string 32 Version string 33 RelatedResources []string 34 Results []*ControlCheckResult 35 } 36 37 type ControlCheckResult struct { 38 ID string 39 Name string 40 Description string 41 DefaultStatus defsecTypes.ControlStatus `json:",omitempty"` 42 Severity string 43 Results types.Results 44 } 45 46 // SummaryReport represents a kubernetes scan report with consolidated findings 47 type SummaryReport struct { 48 SchemaVersion int `json:",omitempty"` 49 ID string 50 Title string 51 SummaryControls []ControlCheckSummary `json:",omitempty"` 52 } 53 54 type ControlCheckSummary struct { 55 ID string 56 Name string 57 Severity string 58 TotalFail *int `json:",omitempty"` 59 } 60 61 // Writer defines the result write operation 62 type Writer interface { 63 Write(ComplianceReport) error 64 } 65 66 // Write writes the results in the give format 67 func Write(report *ComplianceReport, option Option) error { 68 switch option.Format { 69 case types.FormatJSON: 70 jwriter := JSONWriter{ 71 Output: option.Output, 72 Report: option.Report, 73 } 74 return jwriter.Write(report) 75 case types.FormatTable: 76 if !report.empty() { 77 complianceWriter := &TableWriter{ 78 Output: option.Output, 79 Report: option.Report, 80 Severities: option.Severities, 81 } 82 err := complianceWriter.Write(report) 83 if err != nil { 84 return err 85 } 86 } 87 return nil 88 default: 89 return xerrors.Errorf(`unknown format %q. Use "json" or "table"`, option.Format) 90 } 91 } 92 93 func (r ComplianceReport) empty() bool { 94 return len(r.Results) == 0 95 } 96 97 // buildControlCheckResults create compliance results data 98 func buildControlCheckResults(checksMap map[string]types.Results, controls []defsecTypes.Control) []*ControlCheckResult { 99 var complianceResults []*ControlCheckResult 100 for _, control := range controls { 101 var results types.Results 102 for _, c := range control.Checks { 103 results = append(results, checksMap[c.ID]...) 104 } 105 complianceResults = append(complianceResults, &ControlCheckResult{ 106 Name: control.Name, 107 ID: control.ID, 108 Description: control.Description, 109 Severity: string(control.Severity), 110 DefaultStatus: control.DefaultStatus, 111 Results: results, 112 }) 113 } 114 return complianceResults 115 } 116 117 // buildComplianceReportResults create compliance results data 118 func buildComplianceReportResults(checksMap map[string]types.Results, s defsecTypes.Spec) *ComplianceReport { 119 controlCheckResult := buildControlCheckResults(checksMap, s.Controls) 120 return &ComplianceReport{ 121 ID: s.ID, 122 Title: s.Title, 123 Description: s.Description, 124 Version: s.Version, 125 RelatedResources: s.RelatedResources, 126 Results: controlCheckResult, 127 } 128 } 129 130 func BuildComplianceReport(scanResults []types.Results, cs spec.ComplianceSpec) (*ComplianceReport, error) { 131 // aggregate checks by ID 132 aggregateChecksByID := spec.AggregateAllChecksBySpecID(scanResults, cs) 133 134 // build compliance report results 135 return buildComplianceReportResults(aggregateChecksByID, cs.Spec), nil 136 }