diff --git a/internal/printer/helpers.go b/internal/printer/helpers.go index 22d641a..7e5f626 100644 --- a/internal/printer/helpers.go +++ b/internal/printer/helpers.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "os" + "time" "github.com/aquasecurity/chain-bench/internal/models/checkmodels" ) @@ -15,11 +16,7 @@ var ( output io.Writer = os.Stdout ) -type Statistics struct { - Passed int - Failed int -} -type displayResult struct { +type reportResult struct { ID string Name string Descrition string @@ -29,23 +26,48 @@ type displayResult struct { Url string } +type reportMetadata struct { + Date string + Statistics Statistics +} + +type reportResults struct { + Metadata reportMetadata + Results []reportResult +} + // println prints a string to the current configured output func println(msg string) { fmt.Fprintln(output, msg) } func PrintOutputToFile(data []checkmodels.CheckRunResult, outputFilePath string) { - file, _ := json.MarshalIndent(getPrintFormat(data), "", "") + reportRes, statistics := getPrintFormat(data) + + // Populate the report metadata. + reportMetadata := reportMetadata{ + Date: time.Now().Format(time.RFC3339), + Statistics: statistics, + } + + // Populate the report. + report := reportResults{ + reportMetadata, + reportRes, + } + file, _ := json.MarshalIndent(report, "", "") err := ioutil.WriteFile(outputFilePath, file, 0644) if err != nil { PrintError("Failed to write to output file, make sure your path is valid") } } -func getPrintFormat(results []checkmodels.CheckRunResult) []displayResult { - resultsToDisplay := []displayResult{} +func getPrintFormat(results []checkmodels.CheckRunResult) ([]reportResult, Statistics) { + resultsToDisplay := []reportResult{} + statistics := NewStatistics() + for _, r := range results { - resultsToDisplay = append(resultsToDisplay, displayResult{ + resultsToDisplay = append(resultsToDisplay, reportResult{ Name: r.Metadata.Title, ID: r.ID, Descrition: r.Metadata.Description, @@ -53,21 +75,11 @@ func getPrintFormat(results []checkmodels.CheckRunResult) []displayResult { Result: string(r.Result.Status), Reason: r.Result.Details, Url: r.Metadata.Url}) - } - - return resultsToDisplay -} - -func initializeStatistics() Statistics { - return Statistics{Passed: 0, Failed: 0} -} -func addToStatistics(s *Statistics, r checkmodels.ResultStatus) { - if r == checkmodels.Passed { - s.Passed++ - } else { - s.Failed++ + statistics.Add(r.Result.Status) } + + return resultsToDisplay, statistics } // PrintErrorf prints a message with error color diff --git a/internal/printer/printer.go b/internal/printer/printer.go index d7a53cb..f54f289 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -29,7 +29,7 @@ func PrintFindings(results []checkmodels.CheckRunResult, outputFilePath string, PrintOutputToFile(results, outputFilePath) } if !isQuiet { - s := initializeStatistics() + s := NewStatistics() table.Header = CreateHeader([]string{"ID", "Name", "Result", "Reason"}) for _, row := range results { rowData := []CellData{ @@ -39,7 +39,7 @@ func PrintFindings(results []checkmodels.CheckRunResult, outputFilePath string, {text: row.Result.Details}, } table.Body.Cells = append(table.Body.Cells, CreateBodyRow(rowData)) - addToStatistics(&s, row.Result.Status) + s.Add(row.Result.Status) } table.Footer = CreateFooter(s, len(table.Header.Cells)) fmt.Println(table.String()) diff --git a/internal/printer/statistics.go b/internal/printer/statistics.go new file mode 100644 index 0000000..493dac5 --- /dev/null +++ b/internal/printer/statistics.go @@ -0,0 +1,54 @@ +package printer + +import ( + "fmt" + + "github.com/aquasecurity/chain-bench/internal/models/checkmodels" +) + +type Statistics struct { + Passed int + Failed int + Unknown int + Total int +} + +// NewStatistics initializes a new Statistics struct. +func NewStatistics() Statistics { + return Statistics{Passed: 0, Failed: 0, Unknown: 0, Total: 0} +} + +// Add increments the value of a specific field as well as the total value. +func (s *Statistics) Add(value checkmodels.ResultStatus) error { + switch value { + case checkmodels.Passed: + s.Passed++ + case checkmodels.Failed: + s.Failed++ + case checkmodels.Unknown: + s.Unknown++ + default: + return fmt.Errorf("unknown statistical value: %s", value) + } + s.Total++ + + return nil +} + +// Sub decrements the value of a specific field as well as the total value. +func (s *Statistics) Sub(value checkmodels.ResultStatus) error { + switch value { + case checkmodels.Passed: + s.Passed-- + case checkmodels.Failed: + s.Failed-- + case checkmodels.Unknown: + s.Unknown-- + default: + return fmt.Errorf("unknown statistical value: %s", value) + } + + s.Total-- + + return nil +}