diff --git a/check/check.go b/check/check.go index fdcd886..a1b67f8 100644 --- a/check/check.go +++ b/check/check.go @@ -60,16 +60,17 @@ func handleError(err error, context string) (errmsg string) { // Check contains information about a recommendation in the // CIS Kubernetes 1.6+ document. type Check struct { - ID string `yaml:"id" json:"test_number"` - Text string `json:"test_desc"` + ID string `yaml:"id" json:"test_number"` + Text string `json:"test_desc"` Audit string `json:"omit"` Type string `json:"type"` Commands []*exec.Cmd `json:"omit"` Tests *tests `json:"omit"` Set bool `json:"omit"` - Remediation string `json:"-"` - TestInfo []string `json:"test_info"` - State `json:"status"` + Remediation string `json:"-"` + TestInfo []string `json:"test_info"` + State `json:"status"` + ActualValue string `json:"actual_value"` } // Run executes the audit commands specified in a check and outputs @@ -157,15 +158,25 @@ func (c *Check) Run() { i++ } - if errmsgs != "" { - glog.V(2).Info(errmsgs) + finalOutput := c.Tests.execute(out.String()) + if finalOutput != nil { + c.ActualValue = finalOutput.actualResult + if finalOutput.testResult { + c.State = PASS + } else { + c.State = FAIL + } + } else { + errmsgs += handleError( + fmt.Errorf("final output is nil"), + fmt.Sprintf("failed to run: %s\n", + c.Audit, + ), + ) } - res := c.Tests.execute(out.String()) - if res { - c.State = PASS - } else { - c.State = FAIL + if errmsgs != "" { + glog.V(2).Info(errmsgs) } } diff --git a/check/controls.go b/check/controls.go index a246791..640278f 100644 --- a/check/controls.go +++ b/check/controls.go @@ -23,9 +23,9 @@ import ( // Controls holds all controls to check for master nodes. type Controls struct { - ID string `yaml:"id" json:"id"` - Version string `json:"version"` - Text string `json:"text"` + ID string `yaml:"id" json:"id"` + Version string `json:"version"` + Text string `json:"text"` Type NodeType `json:"node_type"` Groups []*Group `json:"tests"` Summary @@ -43,9 +43,9 @@ type Group struct { // Summary is a summary of the results of control checks run. type Summary struct { - Pass int `json:"total_pass"` - Fail int `json:"total_fail"` - Warn int `json:"total_warn"` + Pass int `json:"total_pass"` + Fail int `json:"total_fail"` + Warn int `json:"total_warn"` } // NewControls instantiates a new master Controls object. diff --git a/check/data b/check/data index 435940e..88bdc85 100644 --- a/check/data +++ b/check/data @@ -17,7 +17,7 @@ groups: - id: 1 text: "flag is not set" tests: - test_item: + test_items: - flag: "--basic-auth" set: false diff --git a/check/test.go b/check/test.go index 2470721..ca762bb 100644 --- a/check/test.go +++ b/check/test.go @@ -49,8 +49,13 @@ type compare struct { Value string } -func (t *testItem) execute(s string) (result bool) { - result = false +type testOutput struct { + testResult bool + actualResult string +} + +func (t *testItem) execute(s string) *testOutput { + result := &testOutput{} match := strings.Contains(s, t.Flag) if t.Set { @@ -78,57 +83,57 @@ func (t *testItem) execute(s string) (result bool) { os.Exit(1) } + result.actualResult = strings.ToLower(flagVal) switch t.Compare.Op { case "eq": value := strings.ToLower(flagVal) // Do case insensitive comparaison for booleans ... if value == "false" || value == "true" { - result = value == t.Compare.Value + result.testResult = value == t.Compare.Value } else { - result = flagVal == t.Compare.Value + result.testResult = flagVal == t.Compare.Value } case "noteq": value := strings.ToLower(flagVal) // Do case insensitive comparaison for booleans ... if value == "false" || value == "true" { - result = !(value == t.Compare.Value) + result.testResult = !(value == t.Compare.Value) } else { - result = !(flagVal == t.Compare.Value) + result.testResult = !(flagVal == t.Compare.Value) } case "gt": a, b := toNumeric(flagVal, t.Compare.Value) - result = a > b + result.testResult = a > b case "gte": a, b := toNumeric(flagVal, t.Compare.Value) - result = a >= b + result.testResult = a >= b case "lt": a, b := toNumeric(flagVal, t.Compare.Value) - result = a < b + result.testResult = a < b case "lte": a, b := toNumeric(flagVal, t.Compare.Value) - result = a <= b + result.testResult = a <= b case "has": - result = strings.Contains(flagVal, t.Compare.Value) + result.testResult = strings.Contains(flagVal, t.Compare.Value) case "nothave": - result = !strings.Contains(flagVal, t.Compare.Value) + result.testResult = !strings.Contains(flagVal, t.Compare.Value) } } else { - result = isset + result.testResult = isset } } else { notset := !match - result = notset + result.testResult = notset } - - return + return result } type tests struct { @@ -136,13 +141,19 @@ type tests struct { BinOp binOp `yaml:"bin_op"` } -func (ts *tests) execute(s string) (result bool) { - res := make([]bool, len(ts.TestItems)) +func (ts *tests) execute(s string) *testOutput { + finalOutput := &testOutput{} + + res := make([]testOutput, len(ts.TestItems)) + if len(res) == 0 { + return finalOutput + } for i, t := range ts.TestItems { - res[i] = t.execute(s) + res[i] = *(t.execute(s)) } + var result bool // If no binary operation is specified, default to AND switch ts.BinOp { default: @@ -151,16 +162,19 @@ func (ts *tests) execute(s string) (result bool) { case and, "": result = true for i := range res { - result = result && res[i] + result = result && res[i].testResult } case or: result = false for i := range res { - result = result || res[i] + result = result || res[i].testResult } } - return + finalOutput.testResult = result + finalOutput.actualResult = res[0].actualResult + + return finalOutput } func toNumeric(a, b string) (c, d int) { diff --git a/check/test_test.go b/check/test_test.go index b2d9ac8..4b96e07 100644 --- a/check/test_test.go +++ b/check/test_test.go @@ -113,7 +113,7 @@ func TestTestExecute(t *testing.T) { } for _, c := range cases { - res := c.Tests.execute(c.str) + res := c.Tests.execute(c.str).testResult if !res { t.Errorf("%s, expected:%v, got:%v\n", c.Text, true, res) }