mirror of
https://github.com/aquasecurity/kube-bench.git
synced 2025-01-31 01:51:00 +00:00
Support multiple values flag when check the audit output (#652)
This commit is contained in:
parent
ea4eaa6fd5
commit
db109daf43
@ -74,6 +74,7 @@ type Check struct {
|
|||||||
State `json:"status"`
|
State `json:"status"`
|
||||||
ActualValue string `json:"actual_value"`
|
ActualValue string `json:"actual_value"`
|
||||||
Scored bool `json:"scored"`
|
Scored bool `json:"scored"`
|
||||||
|
IsMultiple bool `yaml:"use_multiple_values"`
|
||||||
ExpectedResult string `json:"expected_result"`
|
ExpectedResult string `json:"expected_result"`
|
||||||
Reason string `json:"reason,omitempty"`
|
Reason string `json:"reason,omitempty"`
|
||||||
}
|
}
|
||||||
@ -125,7 +126,7 @@ func (c *Check) run() State {
|
|||||||
lastCommand := c.Audit
|
lastCommand := c.Audit
|
||||||
hasAuditConfig := c.AuditConfig != ""
|
hasAuditConfig := c.AuditConfig != ""
|
||||||
|
|
||||||
state, finalOutput, retErrmsgs := performTest(c.Audit, c.Tests)
|
state, finalOutput, retErrmsgs := performTest(c.Audit, c.Tests, c.IsMultiple)
|
||||||
if len(state) > 0 {
|
if len(state) > 0 {
|
||||||
c.Reason = retErrmsgs
|
c.Reason = retErrmsgs
|
||||||
c.State = state
|
c.State = state
|
||||||
@ -161,7 +162,7 @@ func (c *Check) run() State {
|
|||||||
currentTests.TestItems[i] = nti
|
currentTests.TestItems[i] = nti
|
||||||
}
|
}
|
||||||
|
|
||||||
state, finalOutput, retErrmsgs = performTest(c.AuditConfig, currentTests)
|
state, finalOutput, retErrmsgs = performTest(c.AuditConfig, currentTests, c.IsMultiple)
|
||||||
if len(state) > 0 {
|
if len(state) > 0 {
|
||||||
c.Reason = retErrmsgs
|
c.Reason = retErrmsgs
|
||||||
c.State = state
|
c.State = state
|
||||||
@ -195,7 +196,7 @@ func (c *Check) run() State {
|
|||||||
return c.State
|
return c.State
|
||||||
}
|
}
|
||||||
|
|
||||||
func performTest(audit string, tests *tests) (State, *testOutput, string) {
|
func performTest(audit string, tests *tests, isMultipleOutput bool) (State, *testOutput, string) {
|
||||||
if len(strings.TrimSpace(audit)) == 0 {
|
if len(strings.TrimSpace(audit)) == 0 {
|
||||||
return "", failTestItem("missing command"), "missing audit command"
|
return "", failTestItem("missing command"), "missing audit command"
|
||||||
}
|
}
|
||||||
@ -203,7 +204,7 @@ func performTest(audit string, tests *tests) (State, *testOutput, string) {
|
|||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
errmsgs := runAudit(audit, &out)
|
errmsgs := runAudit(audit, &out)
|
||||||
|
|
||||||
finalOutput := tests.execute(out.String())
|
finalOutput := tests.execute(out.String(), isMultipleOutput)
|
||||||
if finalOutput == nil {
|
if finalOutput == nil {
|
||||||
errmsgs += fmt.Sprintf("Final output is <<EMPTY>>. Failed to run: %s\n", audit)
|
errmsgs += fmt.Sprintf("Final output is <<EMPTY>>. Failed to run: %s\n", audit)
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,18 @@ func TestCheckAuditConfig(t *testing.T) {
|
|||||||
controls.Groups[1].Checks[8],
|
controls.Groups[1].Checks[8],
|
||||||
"FAIL",
|
"FAIL",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[1].Checks[9],
|
||||||
|
"PASS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[1].Checks[10],
|
||||||
|
"FAIL",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
controls.Groups[1].Checks[11],
|
||||||
|
"FAIL",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
|
@ -184,7 +184,7 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
||||||
<testcase name="check1id check1text" classname="" time="0">
|
<testcase name="check1id check1text" classname="" time="0">
|
||||||
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
</testsuite>`),
|
</testsuite>`),
|
||||||
}, {
|
}, {
|
||||||
@ -207,7 +207,7 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expect: []byte(`<testsuite name="" tests="402" failures="99" errors="0" time="0">
|
expect: []byte(`<testsuite name="" tests="402" failures="99" errors="0" time="0">
|
||||||
<testcase name="check1id check1text" classname="" time="0">
|
<testcase name="check1id check1text" classname="" time="0">
|
||||||
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
</testsuite>`),
|
</testsuite>`),
|
||||||
}, {
|
}, {
|
||||||
@ -227,19 +227,19 @@ func TestControls_JUnitIncludesJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
expect: []byte(`<testsuite name="" tests="0" failures="0" errors="0" time="0">
|
||||||
<testcase name="check1id check1text" classname="" time="0">
|
<testcase name="check1id check1text" classname="" time="0">
|
||||||
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check1id","test_desc":"check1text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"PASS","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase name="check2id check2text" classname="" time="0">
|
<testcase name="check2id check2text" classname="" time="0">
|
||||||
<skipped></skipped>
|
<skipped></skipped>
|
||||||
<system-out>{"test_number":"check2id","test_desc":"check2text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"INFO","actual_value":"","scored":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check2id","test_desc":"check2text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"INFO","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase name="check3id check3text" classname="" time="0">
|
<testcase name="check3id check3text" classname="" time="0">
|
||||||
<skipped></skipped>
|
<skipped></skipped>
|
||||||
<system-out>{"test_number":"check3id","test_desc":"check3text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"WARN","actual_value":"","scored":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check3id","test_desc":"check3text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"WARN","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
<testcase name="check4id check4text" classname="" time="0">
|
<testcase name="check4id check4text" classname="" time="0">
|
||||||
<failure type=""></failure>
|
<failure type=""></failure>
|
||||||
<system-out>{"test_number":"check4id","test_desc":"check4text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"FAIL","actual_value":"","scored":false,"expected_result":""}</system-out>
|
<system-out>{"test_number":"check4id","test_desc":"check4text","audit":"","AuditConfig":"","type":"","remediation":"","test_info":null,"status":"FAIL","actual_value":"","scored":false,"IsMultiple":false,"expected_result":""}</system-out>
|
||||||
</testcase>
|
</testcase>
|
||||||
</testsuite>`),
|
</testsuite>`),
|
||||||
},
|
},
|
||||||
|
36
check/data
36
check/data
@ -440,3 +440,39 @@ groups:
|
|||||||
value: "correct"
|
value: "correct"
|
||||||
set: true
|
set: true
|
||||||
scored: true
|
scored: true
|
||||||
|
- id: 9
|
||||||
|
text: "test use_multiple_values is correct -> pass"
|
||||||
|
audit: "printf 'permissions=600\npermissions=600\npermissions=600'"
|
||||||
|
use_multiple_values: true
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "permissions"
|
||||||
|
compare:
|
||||||
|
op: bitmask
|
||||||
|
value: "600"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 10
|
||||||
|
text: "test use_multiple_values is wrong -> fail"
|
||||||
|
audit: "printf 'permissions=600\npermissions=600\npermissions=644'"
|
||||||
|
use_multiple_values: true
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "permissions"
|
||||||
|
compare:
|
||||||
|
op: bitmask
|
||||||
|
value: "600"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
- id: 11
|
||||||
|
text: "test use_multiple_values include empty value -> fail"
|
||||||
|
audit: "printf 'permissions=600\n\npermissions=600'"
|
||||||
|
use_multiple_values: true
|
||||||
|
tests:
|
||||||
|
test_items:
|
||||||
|
- flag: "permissions"
|
||||||
|
compare:
|
||||||
|
op: bitmask
|
||||||
|
value: "600"
|
||||||
|
set: true
|
||||||
|
scored: true
|
||||||
|
@ -67,7 +67,28 @@ func failTestItem(s string) *testOutput {
|
|||||||
return &testOutput{testResult: false, actualResult: s}
|
return &testOutput{testResult: false, actualResult: s}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testItem) execute(s string) *testOutput {
|
func (t *testItem) execute(s string, isMultipleOutput bool) *testOutput {
|
||||||
|
result := &testOutput{}
|
||||||
|
s = strings.TrimRight(s, " \n")
|
||||||
|
|
||||||
|
// If the test has output that should be evaluated for each row
|
||||||
|
if isMultipleOutput {
|
||||||
|
output := strings.Split(s, "\n")
|
||||||
|
for _, op := range output {
|
||||||
|
result = t.evaluate(op)
|
||||||
|
// If the test failed for the current row, no need to keep testing for this output
|
||||||
|
if !result.testResult {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = t.evaluate(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testItem) evaluate(s string) *testOutput {
|
||||||
result := &testOutput{}
|
result := &testOutput{}
|
||||||
var match bool
|
var match bool
|
||||||
var flagVal string
|
var flagVal string
|
||||||
@ -310,7 +331,7 @@ type tests struct {
|
|||||||
BinOp binOp `yaml:"bin_op"`
|
BinOp binOp `yaml:"bin_op"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *tests) execute(s string) *testOutput {
|
func (ts *tests) execute(s string, isMultipleOutput bool) *testOutput {
|
||||||
finalOutput := &testOutput{}
|
finalOutput := &testOutput{}
|
||||||
|
|
||||||
// If no tests are defined return with empty finalOutput.
|
// If no tests are defined return with empty finalOutput.
|
||||||
@ -327,7 +348,7 @@ func (ts *tests) execute(s string) *testOutput {
|
|||||||
expectedResultArr := make([]string, len(res))
|
expectedResultArr := make([]string, len(res))
|
||||||
|
|
||||||
for i, t := range ts.TestItems {
|
for i, t := range ts.TestItems {
|
||||||
res[i] = *(t.execute(s))
|
res[i] = *(t.execute(s, isMultipleOutput))
|
||||||
expectedResultArr[i] = res[i].ExpectedResult
|
expectedResultArr[i] = res[i].ExpectedResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ func TestTestExecute(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
res := c.Tests.execute(c.str).testResult
|
res := c.Tests.execute(c.str, c.IsMultiple).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)
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ func TestTestExecuteExceptions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
res := c.Tests.execute(c.str).testResult
|
res := c.Tests.execute(c.str, c.IsMultiple).testResult
|
||||||
if res {
|
if res {
|
||||||
t.Errorf("%s, expected:%v, got:%v\n", c.Text, false, res)
|
t.Errorf("%s, expected:%v, got:%v\n", c.Text, false, res)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user