1
0
mirror of https://github.com/aquasecurity/kube-bench.git synced 2024-11-26 01:49:28 +00:00

Support actual result in json output.

This commit adds the actual value of the result
of the value which was returned by the test.
This commit is contained in:
Itai Ben-Natan 2018-07-30 12:16:28 +00:00
parent b1e41d345f
commit e9076233dd
5 changed files with 68 additions and 43 deletions

View File

@ -60,16 +60,17 @@ func handleError(err error, context string) (errmsg string) {
// Check contains information about a recommendation in the // Check contains information about a recommendation in the
// CIS Kubernetes 1.6+ document. // CIS Kubernetes 1.6+ document.
type Check struct { type Check struct {
ID string `yaml:"id" json:"test_number"` ID string `yaml:"id" json:"test_number"`
Text string `json:"test_desc"` Text string `json:"test_desc"`
Audit string `json:"omit"` Audit string `json:"omit"`
Type string `json:"type"` Type string `json:"type"`
Commands []*exec.Cmd `json:"omit"` Commands []*exec.Cmd `json:"omit"`
Tests *tests `json:"omit"` Tests *tests `json:"omit"`
Set bool `json:"omit"` Set bool `json:"omit"`
Remediation string `json:"-"` Remediation string `json:"-"`
TestInfo []string `json:"test_info"` TestInfo []string `json:"test_info"`
State `json:"status"` State `json:"status"`
ActualValue string `json:"actual_value"`
} }
// Run executes the audit commands specified in a check and outputs // Run executes the audit commands specified in a check and outputs
@ -157,15 +158,25 @@ func (c *Check) Run() {
i++ i++
} }
if errmsgs != "" { finalOutput := c.Tests.execute(out.String())
glog.V(2).Info(errmsgs) 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 errmsgs != "" {
if res { glog.V(2).Info(errmsgs)
c.State = PASS
} else {
c.State = FAIL
} }
} }

View File

@ -23,9 +23,9 @@ import (
// Controls holds all controls to check for master nodes. // Controls holds all controls to check for master nodes.
type Controls struct { type Controls struct {
ID string `yaml:"id" json:"id"` ID string `yaml:"id" json:"id"`
Version string `json:"version"` Version string `json:"version"`
Text string `json:"text"` Text string `json:"text"`
Type NodeType `json:"node_type"` Type NodeType `json:"node_type"`
Groups []*Group `json:"tests"` Groups []*Group `json:"tests"`
Summary Summary
@ -43,9 +43,9 @@ type Group struct {
// Summary is a summary of the results of control checks run. // Summary is a summary of the results of control checks run.
type Summary struct { type Summary struct {
Pass int `json:"total_pass"` Pass int `json:"total_pass"`
Fail int `json:"total_fail"` Fail int `json:"total_fail"`
Warn int `json:"total_warn"` Warn int `json:"total_warn"`
} }
// NewControls instantiates a new master Controls object. // NewControls instantiates a new master Controls object.

View File

@ -17,7 +17,7 @@ groups:
- id: 1 - id: 1
text: "flag is not set" text: "flag is not set"
tests: tests:
test_item: test_items:
- flag: "--basic-auth" - flag: "--basic-auth"
set: false set: false

View File

@ -49,8 +49,13 @@ type compare struct {
Value string Value string
} }
func (t *testItem) execute(s string) (result bool) { type testOutput struct {
result = false testResult bool
actualResult string
}
func (t *testItem) execute(s string) *testOutput {
result := &testOutput{}
match := strings.Contains(s, t.Flag) match := strings.Contains(s, t.Flag)
if t.Set { if t.Set {
@ -78,57 +83,57 @@ func (t *testItem) execute(s string) (result bool) {
os.Exit(1) os.Exit(1)
} }
result.actualResult = strings.ToLower(flagVal)
switch t.Compare.Op { switch t.Compare.Op {
case "eq": case "eq":
value := strings.ToLower(flagVal) value := strings.ToLower(flagVal)
// Do case insensitive comparaison for booleans ... // Do case insensitive comparaison for booleans ...
if value == "false" || value == "true" { if value == "false" || value == "true" {
result = value == t.Compare.Value result.testResult = value == t.Compare.Value
} else { } else {
result = flagVal == t.Compare.Value result.testResult = flagVal == t.Compare.Value
} }
case "noteq": case "noteq":
value := strings.ToLower(flagVal) value := strings.ToLower(flagVal)
// Do case insensitive comparaison for booleans ... // Do case insensitive comparaison for booleans ...
if value == "false" || value == "true" { if value == "false" || value == "true" {
result = !(value == t.Compare.Value) result.testResult = !(value == t.Compare.Value)
} else { } else {
result = !(flagVal == t.Compare.Value) result.testResult = !(flagVal == t.Compare.Value)
} }
case "gt": case "gt":
a, b := toNumeric(flagVal, t.Compare.Value) a, b := toNumeric(flagVal, t.Compare.Value)
result = a > b result.testResult = a > b
case "gte": case "gte":
a, b := toNumeric(flagVal, t.Compare.Value) a, b := toNumeric(flagVal, t.Compare.Value)
result = a >= b result.testResult = a >= b
case "lt": case "lt":
a, b := toNumeric(flagVal, t.Compare.Value) a, b := toNumeric(flagVal, t.Compare.Value)
result = a < b result.testResult = a < b
case "lte": case "lte":
a, b := toNumeric(flagVal, t.Compare.Value) a, b := toNumeric(flagVal, t.Compare.Value)
result = a <= b result.testResult = a <= b
case "has": case "has":
result = strings.Contains(flagVal, t.Compare.Value) result.testResult = strings.Contains(flagVal, t.Compare.Value)
case "nothave": case "nothave":
result = !strings.Contains(flagVal, t.Compare.Value) result.testResult = !strings.Contains(flagVal, t.Compare.Value)
} }
} else { } else {
result = isset result.testResult = isset
} }
} else { } else {
notset := !match notset := !match
result = notset result.testResult = notset
} }
return result
return
} }
type tests struct { type tests struct {
@ -136,13 +141,19 @@ type tests struct {
BinOp binOp `yaml:"bin_op"` BinOp binOp `yaml:"bin_op"`
} }
func (ts *tests) execute(s string) (result bool) { func (ts *tests) execute(s string) *testOutput {
res := make([]bool, len(ts.TestItems)) finalOutput := &testOutput{}
for i, t := range ts.TestItems { res := make([]testOutput, len(ts.TestItems))
res[i] = t.execute(s) if len(res) == 0 {
return finalOutput
} }
for i, t := range ts.TestItems {
res[i] = *(t.execute(s))
}
var result bool
// If no binary operation is specified, default to AND // If no binary operation is specified, default to AND
switch ts.BinOp { switch ts.BinOp {
default: default:
@ -151,16 +162,19 @@ func (ts *tests) execute(s string) (result bool) {
case and, "": case and, "":
result = true result = true
for i := range res { for i := range res {
result = result && res[i] result = result && res[i].testResult
} }
case or: case or:
result = false result = false
for i := range res { 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) { func toNumeric(a, b string) (c, d int) {

View File

@ -113,7 +113,7 @@ func TestTestExecute(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
res := c.Tests.execute(c.str) res := c.Tests.execute(c.str).testResult
if !res { if !res {
t.Errorf("%s, expected:%v, got:%v\n", c.Text, true, res) t.Errorf("%s, expected:%v, got:%v\n", c.Text, true, res)
} }