From 0feaa5d75f93e38e50be6c49e2380cc16355d31a Mon Sep 17 00:00:00 2001 From: Manuel Tiago Pereira Date: Sat, 23 Oct 2021 17:35:50 +0100 Subject: [PATCH 1/6] Add --status flag --- cmd/root.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/root.go b/cmd/root.go index 99b802ddb..3952e3f26 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -59,6 +59,7 @@ var ( filterOpts FilterOpts includeTestOutput bool outputFile string + statusList string configFileError error controlsCollection []*check.Controls ) @@ -174,6 +175,7 @@ func init() { RootCmd.PersistentFlags().StringVar(&skipIds, "skip", "", "List of comma separated values of checks to be skipped") RootCmd.PersistentFlags().BoolVar(&includeTestOutput, "include-test-output", false, "Prints the actual result when test fails") RootCmd.PersistentFlags().StringVar(&outputFile, "outputfile", "", "Writes the JSON results to output file") + RootCmd.PersistentFlags().StringVar(&statusList, "status", "", "List of comma separated status to be printed") RootCmd.PersistentFlags().StringVarP( &filterOpts.CheckList, From fe50154f17f08069c64fd5f902d726fa7a125578 Mon Sep 17 00:00:00 2001 From: Manuel Tiago Pereira Date: Sat, 23 Oct 2021 17:36:48 +0100 Subject: [PATCH 2/6] Do not log lines whose check.State is in --status --- cmd/common.go | 21 ++++++++++++++++++++ cmd/common_test.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/cmd/common.go b/cmd/common.go index 60f291332..e6fab3823 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -157,8 +157,29 @@ func parseSkipIds(skipIds string) map[string]bool { return skipIdMap } +func parseStatus(statusList string) map[check.State]bool { + var statusMap = make(map[check.State]bool, 0) + if statusList != "" { + for _, status := range strings.Split(statusList, ",") { + statusMap[check.State(strings.ToUpper(strings.Trim(status, " ")))] = true + } + } + return statusMap +} + +func printStatus(state check.State) bool { + if statusList == "" { + return true + } + statusMap := parseStatus(statusList) + return statusMap[state] +} + // colorPrint outputs the state in a specific colour, along with a message string func colorPrint(state check.State, s string) { + if !printStatus(state) { + return + } colors[state].Printf("[%s] ", state) fmt.Printf("%s", s) } diff --git a/cmd/common_test.go b/cmd/common_test.go index e0f38d049..0887d221c 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -750,6 +750,55 @@ func TestWriteStdoutOutputTotal(t *testing.T) { assert.Contains(t, string(out), "49 checks PASS") } +func TestWriteStdoutOutputStatusList(t *testing.T) { + type testCase struct { + name string + statusList string + + notContains []string + } + testCases := []testCase{ + { + name: "statusList PASS", + statusList: "PASS", + notContains: []string{"INFO", "WARN", "ERRO"}, + }, + { + name: "statusList PASS,INFO", + statusList: "PASS,INFO", + notContains: []string{"WARN", "ERRO"}, + }, + { + name: "statusList empty", + statusList: "", + notContains: nil, + }, + } + + controlsCollection, err := parseControlsJsonFile("./testdata/controlsCollection.json") + if err != nil { + t.Error(err) + } + + for _, tt := range testCases { + rescueStdout := os.Stdout + + r, w, _ := os.Pipe() + + os.Stdout = w + statusList = tt.statusList + writeStdoutOutput(controlsCollection) + w.Close() + out, _ := ioutil.ReadAll(r) + + os.Stdout = rescueStdout + + for _, n := range tt.notContains { + assert.NotContains(t, string(out), fmt.Sprintf("[%s]", n)) + } + } +} + func parseControlsJsonFile(filepath string) ([]*check.Controls, error) { var result []*check.Controls From 8f174192ead26b6d375d7be246c9cf2211c262f2 Mon Sep 17 00:00:00 2001 From: Manuel Tiago Pereira Date: Sat, 30 Oct 2021 10:33:37 +0100 Subject: [PATCH 3/6] Check for FAIL status on status flag test --- cmd/common_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/common_test.go b/cmd/common_test.go index 0887d221c..cf39e2569 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -761,12 +761,12 @@ func TestWriteStdoutOutputStatusList(t *testing.T) { { name: "statusList PASS", statusList: "PASS", - notContains: []string{"INFO", "WARN", "ERRO"}, + notContains: []string{"INFO", "WARN", "FAIL"}, }, { name: "statusList PASS,INFO", statusList: "PASS,INFO", - notContains: []string{"WARN", "ERRO"}, + notContains: []string{"WARN", "FAIL"}, }, { name: "statusList empty", From e2cf08aaadbcf9da92258537878401a6717875d2 Mon Sep 17 00:00:00 2001 From: Manuel Tiago Pereira Date: Sat, 30 Oct 2021 10:34:38 +0100 Subject: [PATCH 4/6] Add test for --status FAIL --- cmd/common_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/common_test.go b/cmd/common_test.go index cf39e2569..7152ac27a 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -768,6 +768,11 @@ func TestWriteStdoutOutputStatusList(t *testing.T) { statusList: "PASS,INFO", notContains: []string{"WARN", "FAIL"}, }, + { + name: "statusList FAIL", + statusList: "FAIL", + notContains: []string{"INFO", "WARN", "PASS"}, + }, { name: "statusList empty", statusList: "", From 0c1c5aa2e07a9af85c93df652c3615fb4fbdebb3 Mon Sep 17 00:00:00 2001 From: Manuel Tiago Pereira Date: Mon, 1 Nov 2021 17:28:41 +0000 Subject: [PATCH 5/6] Only print summary messages from --status Added a Summary.Results method to make it possible to get a specific State result. --- check/controls.go | 15 +++++++++++++++ cmd/common.go | 16 +++++++++++++--- cmd/common_test.go | 2 +- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/check/controls.go b/check/controls.go index f84acf7b6..6151b8501 100644 --- a/check/controls.go +++ b/check/controls.go @@ -76,6 +76,21 @@ type Summary struct { Info int `json:"total_info"` } +func (s Summary) Results(c State) int { + var r int + switch c { + case "PASS": + r = s.Pass + case "FAIL": + r = s.Fail + case "WARN": + r = s.Warn + case "INFO": + r = s.Info + } + return r +} + // Predicate a predicate on the given Group and Check arguments. type Predicate func(group *Group, check *Check) bool diff --git a/cmd/common.go b/cmd/common.go index e6fab3823..fff30c765 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -243,9 +243,19 @@ func printSummary(summary check.Summary, sectionName string) { } colors[res].Printf("== Summary %s ==\n", sectionName) - fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n\n", - summary.Pass, summary.Fail, summary.Warn, summary.Info, - ) + if statusList == "" { + fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n\n", summary.Pass, summary.Fail, summary.Warn, summary.Info) + return + } + statusMap := parseStatus(statusList) + var summaryBuilder strings.Builder + for s, b := range statusMap { + if b { + summaryBuilder.WriteString(fmt.Sprintf("%d checks %v\n", summary.Results(s), s)) + } + } + summaryBuilder.WriteString("\n") + fmt.Printf(summaryBuilder.String()) } // loadConfig finds the correct config dir based on the kubernetes version, diff --git a/cmd/common_test.go b/cmd/common_test.go index 7152ac27a..c9b4a4fea 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -799,7 +799,7 @@ func TestWriteStdoutOutputStatusList(t *testing.T) { os.Stdout = rescueStdout for _, n := range tt.notContains { - assert.NotContains(t, string(out), fmt.Sprintf("[%s]", n)) + assert.NotContains(t, string(out), n) } } } From 5ed6c78c81e3ab35cdcbee16b36f23d5ce967a50 Mon Sep 17 00:00:00 2001 From: Manuel Tiago Pereira Date: Fri, 5 Nov 2021 09:01:20 +0000 Subject: [PATCH 6/6] Do not print remediation messages not on --status --- cmd/common.go | 19 ++++++++++++------- cmd/common_test.go | 18 +++++++++++++++--- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/cmd/common.go b/cmd/common.go index fff30c765..eb4c5bbe4 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -205,24 +205,29 @@ func prettyPrint(r *check.Controls, summary check.Summary) { // Print remediations. if !noRemediations { + var remediationOutput strings.Builder if summary.Fail > 0 || summary.Warn > 0 { - colors[check.WARN].Printf("== Remediations %s ==\n", r.Type) for _, g := range r.Groups { for _, c := range g.Checks { - if c.State == check.FAIL { - fmt.Printf("%s %s\n", c.ID, c.Remediation) + if c.State == check.FAIL && printStatus(check.FAIL) { + remediationOutput.WriteString(fmt.Sprintf("%s %s\n", c.ID, c.Remediation)) } - if c.State == check.WARN { + if c.State == check.WARN && printStatus(check.WARN) { // Print the error if test failed due to problem with the audit command if c.Reason != "" && c.Type != "manual" { - fmt.Printf("%s audit test did not run: %s\n", c.ID, c.Reason) + remediationOutput.WriteString(fmt.Sprintf("%s audit test did not run: %s\n", c.ID, c.Reason)) } else { - fmt.Printf("%s %s\n", c.ID, c.Remediation) + remediationOutput.WriteString(fmt.Sprintf("%s %s\n", c.ID, c.Remediation)) } } } } - fmt.Println() + output := remediationOutput.String() + if len(output) > 0 { + remediationOutput.WriteString("\n") + fmt.Printf(colors[check.WARN].Sprintf("== Remediations %s ==\n", r.Type)) + fmt.Printf(remediationOutput.String()) + } } } diff --git a/cmd/common_test.go b/cmd/common_test.go index c9b4a4fea..459b5c0f0 100644 --- a/cmd/common_test.go +++ b/cmd/common_test.go @@ -756,27 +756,35 @@ func TestWriteStdoutOutputStatusList(t *testing.T) { statusList string notContains []string + contains []string } testCases := []testCase{ { name: "statusList PASS", statusList: "PASS", - notContains: []string{"INFO", "WARN", "FAIL"}, + notContains: []string{"INFO", "WARN", "FAIL", "== Remediations controlplane =="}, }, { name: "statusList PASS,INFO", statusList: "PASS,INFO", - notContains: []string{"WARN", "FAIL"}, + notContains: []string{"WARN", "FAIL", "== Remediations controlplane =="}, + }, + { + name: "statusList WARN", + statusList: "WARN", + notContains: []string{"INFO", "FAIL", "PASS"}, + contains: []string{"== Remediations controlplane =="}, }, { name: "statusList FAIL", statusList: "FAIL", - notContains: []string{"INFO", "WARN", "PASS"}, + notContains: []string{"INFO", "WARN", "PASS", "== Remediations controlplane =="}, }, { name: "statusList empty", statusList: "", notContains: nil, + contains: []string{"== Remediations controlplane =="}, }, } @@ -801,6 +809,10 @@ func TestWriteStdoutOutputStatusList(t *testing.T) { for _, n := range tt.notContains { assert.NotContains(t, string(out), n) } + + for _, c := range tt.contains { + assert.Contains(t, string(out), c) + } } }