From b91a353a7f0096e7eaaa7f5ef00dc5d80e846d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Greinhofer?= Date: Tue, 28 Jun 2022 11:54:14 -0500 Subject: [PATCH 1/2] Add metedata to the report file This patch adds a new metadata section to the report file being generated by chain-bench. This initial version adds the generation date, and the check statistics which is useful to compare different scans and their evolutions over time. Fixes aquasecurity/chain-bench#38 --- internal/printer/helpers.go | 60 +++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/internal/printer/helpers.go b/internal/printer/helpers.go index 22d641a..d6c431f 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" ) @@ -16,10 +17,12 @@ var ( ) type Statistics struct { - Passed int - Failed int + Passed int + Failed int + Unknown int + Total int } -type displayResult struct { +type reportResult struct { ID string Name string Descrition string @@ -29,23 +32,53 @@ 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 := Statistics{ + Passed: 0, + Failed: 0, + Unknown: 0, + Total: len(results), + } + for _, r := range results { - resultsToDisplay = append(resultsToDisplay, displayResult{ + resultsToDisplay = append(resultsToDisplay, reportResult{ Name: r.Metadata.Title, ID: r.ID, Descrition: r.Metadata.Description, @@ -53,13 +86,22 @@ func getPrintFormat(results []checkmodels.CheckRunResult) []displayResult { Result: string(r.Result.Status), Reason: r.Result.Details, Url: r.Metadata.Url}) + + switch r.Result.Status { + case "Passed": + statistics.Passed += 1 + case "Failed": + statistics.Failed += 1 + case "Unknown": + statistics.Unknown += 1 + } } - return resultsToDisplay + return resultsToDisplay, statistics } func initializeStatistics() Statistics { - return Statistics{Passed: 0, Failed: 0} + return Statistics{Passed: 0, Failed: 0, Unknown: 0, Total: 0} } func addToStatistics(s *Statistics, r checkmodels.ResultStatus) { From adb273d38bbb2c9f302ab0d5dea9d4f70407050c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Greinhofer?= Date: Wed, 29 Jun 2022 10:11:27 -0500 Subject: [PATCH 2/2] Split statistics struc --- internal/printer/helpers.go | 34 ++------------------- internal/printer/printer.go | 4 +-- internal/printer/statistics.go | 54 ++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 34 deletions(-) create mode 100644 internal/printer/statistics.go diff --git a/internal/printer/helpers.go b/internal/printer/helpers.go index d6c431f..7e5f626 100644 --- a/internal/printer/helpers.go +++ b/internal/printer/helpers.go @@ -16,12 +16,6 @@ var ( output io.Writer = os.Stdout ) -type Statistics struct { - Passed int - Failed int - Unknown int - Total int -} type reportResult struct { ID string Name string @@ -70,12 +64,7 @@ func PrintOutputToFile(data []checkmodels.CheckRunResult, outputFilePath string) func getPrintFormat(results []checkmodels.CheckRunResult) ([]reportResult, Statistics) { resultsToDisplay := []reportResult{} - statistics := Statistics{ - Passed: 0, - Failed: 0, - Unknown: 0, - Total: len(results), - } + statistics := NewStatistics() for _, r := range results { resultsToDisplay = append(resultsToDisplay, reportResult{ @@ -87,31 +76,12 @@ func getPrintFormat(results []checkmodels.CheckRunResult) ([]reportResult, Stati Reason: r.Result.Details, Url: r.Metadata.Url}) - switch r.Result.Status { - case "Passed": - statistics.Passed += 1 - case "Failed": - statistics.Failed += 1 - case "Unknown": - statistics.Unknown += 1 - } + statistics.Add(r.Result.Status) } return resultsToDisplay, statistics } -func initializeStatistics() Statistics { - return Statistics{Passed: 0, Failed: 0, Unknown: 0, Total: 0} -} - -func addToStatistics(s *Statistics, r checkmodels.ResultStatus) { - if r == checkmodels.Passed { - s.Passed++ - } else { - s.Failed++ - } -} - // PrintErrorf prints a message with error color func PrintError(msg string) { println(fmt.Sprint(ColorRed, msg)) 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 +}