From 49f745af8ed97aa627d1c6c09484904a89deed8d Mon Sep 17 00:00:00 2001
From: Yoav Hizkiahou <yoav.hizkiahou@aquasec.com>
Date: Tue, 29 Jan 2019 16:33:58 +0200
Subject: [PATCH] Support new check type - skip: If a check is marked with type
 "skip", it will be marked as Info.

Support scored property:
If a check is not scored and is not marked with type skip, it will be marked as Warn.
---
 check/check.go      | 11 +++++++++--
 check/check_test.go | 30 ++++++++++++++++++++++++++++++
 check/controls.go   | 10 ++++++++--
 cmd/common.go       |  8 ++++----
 4 files changed, 51 insertions(+), 8 deletions(-)
 create mode 100644 check/check_test.go

diff --git a/check/check.go b/check/check.go
index a1b67f8..7ef0e50 100644
--- a/check/check.go
+++ b/check/check.go
@@ -71,13 +71,20 @@ type Check struct {
 	TestInfo    []string    `json:"test_info"`
 	State       `json:"status"`
 	ActualValue string `json:"actual_value"`
+	Scored      bool   `json:"scored"`
 }
 
 // Run executes the audit commands specified in a check and outputs
 // the results.
 func (c *Check) Run() {
-	// If check type is manual, force result to WARN.
-	if c.Type == "manual" {
+
+	if c.Type == "skip" {
+		c.State = INFO
+		return
+	}
+
+	// If check type is manual or the check is not scored, force result to WARN
+	if c.Type == "manual" || !c.Scored {
 		c.State = WARN
 		return
 	}
diff --git a/check/check_test.go b/check/check_test.go
new file mode 100644
index 0000000..ab74656
--- /dev/null
+++ b/check/check_test.go
@@ -0,0 +1,30 @@
+package check
+
+import (
+	"testing"
+)
+
+func TestCheck_Run(t *testing.T) {
+	type TestCase struct {
+		check    Check
+		Expected State
+	}
+
+	testCases := []TestCase{
+		{check: Check{Type: "manual"}, Expected: WARN},
+		{check: Check{Type: "skip"}, Expected: INFO},
+		{check: Check{Type: "", Scored: false}, Expected: WARN}, // Not scored checks with no type should be marked warn
+		{check: Check{Type: "", Scored: true}, Expected: WARN},  // If there are no tests in the check, warn
+		{check: Check{Type: "manual", Scored: false}, Expected: WARN},
+		{check: Check{Type: "skip", Scored: false}, Expected: INFO},
+	}
+
+	for _, testCase := range testCases {
+
+		testCase.check.Run()
+
+		if testCase.check.State != testCase.Expected {
+			t.Errorf("test failed, expected %s, actual %s\n", testCase.Expected, testCase.check.State)
+		}
+	}
+}
diff --git a/check/controls.go b/check/controls.go
index 640278f..f6d4ab9 100644
--- a/check/controls.go
+++ b/check/controls.go
@@ -37,6 +37,7 @@ type Group struct {
 	Pass   int      `json:"pass"`
 	Fail   int      `json:"fail"`
 	Warn   int      `json:"warn"`
+	Info   int      `json:"info"`
 	Text   string   `json:"desc"`
 	Checks []*Check `json:"results"`
 }
@@ -46,6 +47,7 @@ type Summary struct {
 	Pass int `json:"total_pass"`
 	Fail int `json:"total_fail"`
 	Warn int `json:"total_warn"`
+	Info int `json:"total_info"`
 }
 
 // NewControls instantiates a new master Controls object.
@@ -74,7 +76,7 @@ func NewControls(t NodeType, in []byte) (*Controls, error) {
 // RunGroup runs all checks in a group.
 func (controls *Controls) RunGroup(gids ...string) Summary {
 	g := []*Group{}
-	controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn = 0, 0, 0
+	controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
 
 	// If no groupid is passed run all group checks.
 	if len(gids) == 0 {
@@ -105,7 +107,7 @@ func (controls *Controls) RunGroup(gids ...string) Summary {
 func (controls *Controls) RunChecks(ids ...string) Summary {
 	g := []*Group{}
 	m := make(map[string]*Group)
-	controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn = 0, 0, 0
+	controls.Summary.Pass, controls.Summary.Fail, controls.Summary.Warn, controls.Info = 0, 0, 0, 0
 
 	// If no groupid is passed run all group checks.
 	if len(ids) == 0 {
@@ -182,6 +184,8 @@ func summarize(controls *Controls, check *Check) {
 		controls.Summary.Fail++
 	case WARN:
 		controls.Summary.Warn++
+	case INFO:
+		controls.Summary.Info++
 	}
 }
 
@@ -193,5 +197,7 @@ func summarizeGroup(group *Group, check *Check) {
 		group.Fail++
 	case WARN:
 		group.Warn++
+	case INFO:
+		group.Info++
 	}
 }
diff --git a/cmd/common.go b/cmd/common.go
index e038efe..b7e9622 100644
--- a/cmd/common.go
+++ b/cmd/common.go
@@ -108,7 +108,7 @@ func runChecks(nodetype check.NodeType) {
 	}
 
 	// if we successfully ran some tests and it's json format, ignore the warnings
-	if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0) && jsonFmt {
+	if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
 		out, err := controls.JSON()
 		if err != nil {
 			exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
@@ -117,7 +117,7 @@ func runChecks(nodetype check.NodeType) {
 		fmt.Println(string(out))
 	} else {
 		// if we want to store in PostgreSQL, convert to JSON and save it
-		if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0) && pgSQL {
+		if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && pgSQL {
 			out, err := controls.JSON()
 			if err != nil {
 				exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
@@ -178,8 +178,8 @@ func prettyPrint(r *check.Controls, summary check.Summary) {
 		}
 
 		colors[res].Printf("== Summary ==\n")
-		fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n",
-			summary.Pass, summary.Fail, summary.Warn,
+		fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n",
+			summary.Pass, summary.Fail, summary.Warn, summary.Info,
 		)
 	}
 }
-- 
GitLab