From e26749dad8be9bcb29b8e58d69e69f7fd255976c Mon Sep 17 00:00:00 2001 From: 06kellyjac Date: Mon, 11 May 2020 17:50:19 +0100 Subject: [PATCH 1/5] fix: corrected shellcheck errors --- test/1_cli.bats | 91 ++++++++++++++++++------------------------ test/2_regression.bats | 42 +++++++++---------- test/3_todo.bats | 6 +-- 3 files changed, 63 insertions(+), 76 deletions(-) diff --git a/test/1_cli.bats b/test/1_cli.bats index 4de62a2c4..5ac14609d 100644 --- a/test/1_cli.bats +++ b/test/1_cli.bats @@ -11,142 +11,137 @@ teardown() { } @test "fails Pod with unconfined seccomp" { - run _app ${TEST_DIR}/asset/score-0-pod-seccomp-unconfined.yml + run _app "${TEST_DIR}/asset/score-0-pod-seccomp-unconfined.yml" assert_lt_zero_points } @test "fails with CAP_SYS_ADMIN" { - run _app ${TEST_DIR}/asset/score-0-cap-sys-admin.yml + run _app "${TEST_DIR}/asset/score-0-cap-sys-admin.yml" assert_lt_zero_points } @test "fails with CAP_CHOWN" { - run _app ${TEST_DIR}/asset/score-0-cap-chown.yml + run _app "${TEST_DIR}/asset/score-0-cap-chown.yml" assert_zero_points } @test "fails with CAP_SYS_ADMIN and CAP_CHOWN" { - run _app ${TEST_DIR}/asset/score-0-cap-sys-admin-and-cap-chown.yml + run _app "${TEST_DIR}/asset/score-0-cap-sys-admin-and-cap-chown.yml" assert_lt_zero_points } @test "passes with securityContext capabilities drop all" { - run _app ${TEST_DIR}/asset/score-1-cap-drop-all.yml + run _app "${TEST_DIR}/asset/score-1-cap-drop-all.yml" assert_gt_zero_points } @test "passes deployment with securitycontext readOnlyRootFilesystem" { - run _app ${TEST_DIR}/asset/score-1-dep-ro-root-fs.yml + run _app "${TEST_DIR}/asset/score-1-dep-ro-root-fs.yml" assert_gt_zero_points } @test "passes deployment with securitycontext runAsNonRoot" { - run _app ${TEST_DIR}/asset/score-1-dep-seccon-run-as-non-root.yml + run _app "${TEST_DIR}/asset/score-1-dep-seccon-run-as-non-root.yml" assert_gt_zero_points } @test "fails deployment with securitycontext runAsUser 1" { - run _app ${TEST_DIR}/asset/score-1-dep-seccon-run-as-user-1.yml + run _app "${TEST_DIR}/asset/score-1-dep-seccon-run-as-user-1.yml" assert_zero_points } @test "passes deployment with securitycontext runAsUser > 10000" { - run _app ${TEST_DIR}/asset/score-1-dep-seccon-run-as-user-10001.yml + run _app "${TEST_DIR}/asset/score-1-dep-seccon-run-as-user-10001.yml" assert_gt_zero_points } @test "fails deployment with empty security context" { - run _app ${TEST_DIR}/asset/score-1-dep-empty-security-context.yml + run _app "${TEST_DIR}/asset/score-1-dep-empty-security-context.yml" assert_zero_points } @test "fails deployment with invalid security context" { - run _app ${TEST_DIR}/asset/score-1-dep-invalid-security-context.yml + run _app "${TEST_DIR}/asset/score-1-dep-invalid-security-context.yml" assert_line --index 4 --regexp 'fake: Additional property fake is not allowed' } @test "passes deployment with cgroup resource limits" { - run _app ${TEST_DIR}/asset/score-1-dep-resource-limit-cpu.yml + run _app "${TEST_DIR}/asset/score-1-dep-resource-limit-cpu.yml" assert_gt_zero_points } @test "passes deployment with cgroup memory limits" { - run _app ${TEST_DIR}/asset/score-1-dep-resource-limit-memory.yml + run _app "${TEST_DIR}/asset/score-1-dep-resource-limit-memory.yml" assert_gt_zero_points } @test "passes StatefulSet with volumeClaimTemplate" { - run _app ${TEST_DIR}/asset/score-1-statefulset-volumeclaimtemplate.yml + run _app "${TEST_DIR}/asset/score-1-statefulset-volumeclaimtemplate.yml" assert_gt_zero_points } @test "fails StatefulSet with no security" { - run _app ${TEST_DIR}/asset/score-0-statefulset-no-sec.yml + run _app "${TEST_DIR}/asset/score-0-statefulset-no-sec.yml" assert_zero_points } @test "fails DaemonSet with securityContext.privileged = true" { - run _app ${TEST_DIR}/asset/score-0-daemonset-securitycontext-privileged.yml + run _app "${TEST_DIR}/asset/score-0-daemonset-securitycontext-privileged.yml" assert_lt_zero_points } @test "fails DaemonSet with mounted host docker.sock" { - run _app ${TEST_DIR}/asset/score-0-daemonset-mount-docker-socket.yml + run _app "${TEST_DIR}/asset/score-0-daemonset-mount-docker-socket.yml" assert_lt_zero_points } @test "passes Pod with apparmor annotation" { - run _app ${TEST_DIR}/asset/score-3-pod-apparmor.yaml + run _app "${TEST_DIR}/asset/score-3-pod-apparmor.yaml" assert_gt_zero_points } @test "fails Pod with unconfined seccomp for all containers" { - run _app ${TEST_DIR}/asset/score-0-pod-seccomp-unconfined.yml + run _app "${TEST_DIR}/asset/score-0-pod-seccomp-unconfined.yml" assert_lt_zero_points } @test "passes Pod with non-unconfined seccomp for all containers" { - run _app ${TEST_DIR}/asset/score-0-pod-seccomp-non-unconfined.yml + run _app "${TEST_DIR}/asset/score-0-pod-seccomp-non-unconfined.yml" assert_gt_zero_points } @test "fails DaemonSet with hostNetwork" { - run _app ${TEST_DIR}/asset/score-0-daemonset-host-network.yml + run _app "${TEST_DIR}/asset/score-0-daemonset-host-network.yml" assert_lt_zero_points } @test "fails DaemonSet with hostPid" { - run _app ${TEST_DIR}/asset/score-0-daemonset-host-pid.yml + run _app "${TEST_DIR}/asset/score-0-daemonset-host-pid.yml" assert_lt_zero_points } @test "fails DaemonSet with host docker.socket" { - run _app ${TEST_DIR}/asset/score-0-daemonset-volume-host-docker-socket.yml + run _app "${TEST_DIR}/asset/score-0-daemonset-volume-host-docker-socket.yml" assert_lt_zero_points } @test "passes Deployment with serviceaccountname" { - run _app ${TEST_DIR}/asset/score-2-dep-serviceaccount.yml - + run _app "${TEST_DIR}/asset/score-2-dep-serviceaccount.yml" assert_gt_zero_points } @test "passes pod with serviceaccountname" { - run _app ${TEST_DIR}/asset/score-2-pod-serviceaccount.yml - + run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" assert_gt_zero_points } @test "fails deployment with allowPrivilegeEscalation" { - run _app ${TEST_DIR}/asset/allowPrivilegeEscalation.yaml - + run _app "${TEST_DIR}/asset/allowPrivilegeEscalation.yaml" assert_lt_zero_points } @test "returns integer point score for specific response lines" { - # ordering of scoring rules output currently non-determinstic, to be ordered in #44 - run \ - _app ${TEST_DIR}/asset/score-2-pod-serviceaccount.yml + run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" for LINE in 11 16 21 26 31 36 41 46 51 56 61; do assert_line --index ${LINE} --regexp '^.*"points": [0-9]+$' @@ -154,8 +149,7 @@ teardown() { } @test "returns an ordered point score for all responses" { - run \ - _app ${TEST_DIR}/asset/score-2-pod-serviceaccount.yml + run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" assert_line --index 11 --regexp '^.*\"points\": 3$' @@ -165,8 +159,7 @@ teardown() { } @test "check critical and advisory points listed by magnitude" { - run \ - _app ${TEST_DIR}/asset/critical-double.yml + run _app "${TEST_DIR}/asset/critical-double.yml" # criticals - magnitude sort/lowest number first assert_line --index 11 --regexp '^.*\"points\": -30$' @@ -175,12 +168,11 @@ teardown() { # advisories - magnitude sort/highest number first assert_line --index 23 --regexp '^.*\"points\": 3$' assert_line --index 28 --regexp '^.*\"points\": 3$' - assert_line --index 33 --regexp '^.*\"points\": 1$' + assert_line --index 33 --regexp '^.*\"points\": 1$' } @test "check critical and advisory points as multi-yaml" { - run \ - _app ${TEST_DIR}/asset/critical-double-multiple.yml + run _app "${TEST_DIR}/asset/critical-double-multiple.yml" # report 1 - criticals - magnitude sort/lowest number first assert_line --index 11 --regexp '^.*\"points\": -30$' @@ -189,7 +181,7 @@ teardown() { # report 1 - advisories - magnitude sort/highest number first assert_line --index 23 --regexp '^.*\"points\": 3$' assert_line --index 28 --regexp '^.*\"points\": 3$' - assert_line --index 33 --regexp '^.*\"points\": 1$' + assert_line --index 33 --regexp '^.*\"points\": 1$' # report 2 - criticals - magnitude sort/lowest number first assert_line --index 93 --regexp '^.*\"points\": -30$' @@ -198,30 +190,25 @@ teardown() { # report 2 - advisories - magnitude sort/highest number first assert_line --index 105 --regexp '^.*\"points\": 3$' assert_line --index 110 --regexp '^.*\"points\": 3$' - assert_line --index 115 --regexp '^.*\"points\": 1$' + assert_line --index 115 --regexp '^.*\"points\": 1$' } @test "returns deterministic report output" { - run \ - _app ${TEST_DIR}/asset/score-2-pod-serviceaccount.yml - + run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" assert_success RUN_1_SIGNATURE=$(echo "${output}" | sha1sum) - run \ - _app ${TEST_DIR}/asset/score-2-pod-serviceaccount.yml - + run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" assert_success RUN_2_SIGNATURE=$(echo "${output}" | sha1sum) - run \ - _app ${TEST_DIR}/asset/score-2-pod-serviceaccount.yml - + run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" assert_success RUN_3_SIGNATURE=$(echo "${output}" | sha1sum) - [ "${RUN_1_SIGNATURE}" == "${RUN_2_SIGNATURE}" ] - [ "${RUN_1_SIGNATURE}" == "${RUN_3_SIGNATURE}" ] + + assert [ "${RUN_1_SIGNATURE}" = "${RUN_2_SIGNATURE}" ] + assert [ "${RUN_1_SIGNATURE}" = "${RUN_3_SIGNATURE}" ] } diff --git a/test/2_regression.bats b/test/2_regression.bats index 67a1f7100..5d415f2d5 100644 --- a/test/2_regression.bats +++ b/test/2_regression.bats @@ -11,35 +11,35 @@ teardown() { } @test "only valid types - allow Pod" { - run _app ${TEST_DIR}/asset/score-1-pod-default.yml + run _app "${TEST_DIR}/asset/score-1-pod-default.yml" refute_output --regexp ".*Only kinds .* accepted.*" \ || assert_output --regexp ".*This resource kind is not supported.*" assert_success } @test "only valid types - allow Deployment" { - run _app ${TEST_DIR}/asset/score-1-dep-default.yml + run _app "${TEST_DIR}/asset/score-1-dep-default.yml" refute_output --regexp ".*Only kinds .* accepted.*" \ || assert_output --regexp ".*This resource kind is not supported.*" assert_success } @test "only valid types - allow StatefulSet" { - run _app ${TEST_DIR}/asset/score-1-statefulset-default.yml + run _app "${TEST_DIR}/asset/score-1-statefulset-default.yml" refute_output --regexp ".*Only kinds .* accepted.*" \ || assert_output --regexp ".*This resource kind is not supported.*" assert_success } @test "only valid types - allow DaemonSet" { - run _app ${TEST_DIR}/asset/score-1-daemonset-default.yml + run _app "${TEST_DIR}/asset/score-1-daemonset-default.yml" refute_output --regexp ".*Only kinds .* accepted.*" \ || assert_output --regexp ".*This resource kind is not supported.*" assert_success } @test "only valid types - deny PodSecurityPolicy" { - run _app ${TEST_DIR}/asset/score-0-podsecuritypolicy-permissive.yml + run _app "${TEST_DIR}/asset/score-0-podsecuritypolicy-permissive.yml" assert_output --regexp ".*Only kinds .* accepted.*" \ || assert_output --regexp ".*This resource kind is not supported.*" if _is_local; then @@ -48,19 +48,19 @@ teardown() { } @test "passes 1.11 format daemonset" { - run _app ${TEST_DIR}/asset/versioned/score-0-daemonset-v1.11.yml + run _app "${TEST_DIR}/asset/versioned/score-0-daemonset-v1.11.yml" assert_zero_points } @test "passes 1.11 format statefulset" { - run _app ${TEST_DIR}/asset/versioned/score-0-statefulset-v1.11.yml + run _app "${TEST_DIR}/asset/versioned/score-0-statefulset-v1.11.yml" assert_zero_points } # --- @test "returns error for invalid JSON" { - run _app ${TEST_DIR}/asset/invalid-input-pod-dump.json + run _app "${TEST_DIR}/asset/invalid-input-pod-dump.json" assert_output --regexp "Missing 'apiVersion' key" \ || assert_output --regexp ".*: Invalid type\. .*" @@ -69,19 +69,19 @@ teardown() { } @test "returns error YAML control characters" { - run _app ${TEST_DIR}/asset/invalid-input-no-control-characters.json + run _app "${TEST_DIR}/asset/invalid-input-no-control-characters.json" assert_invalid_input } @test "passes bug dump twice [1/2]" { - run _app ${TEST_DIR}/asset/bug-dump-2.json + run _app "${TEST_DIR}/asset/bug-dump-2.json" assert_success assert_gt_zero_points } @test "passes bug dump twice [2/2]" { - run _app ${TEST_DIR}/asset/bug-dump-2.json + run _app "${TEST_DIR}/asset/bug-dump-2.json" assert_success assert_gt_zero_points } @@ -100,7 +100,7 @@ teardown() { } @test "errors with empty file" { - run _app ${TEST_DIR}/asset/empty-file + run _app "${TEST_DIR}/asset/empty-file" assert_failure_local assert_invalid_input } @@ -110,7 +110,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/empty-file --json + run _app "${TEST_DIR}/asset/empty-file" --json assert_invalid_input assert_failure_local } @@ -120,7 +120,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/empty-file + run _app "${TEST_DIR}/asset/empty-file" assert_invalid_input assert_failure_local } @@ -130,7 +130,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/empty-json-file --json + run _app "${TEST_DIR}/asset/empty-json-file" --json assert_invalid_input assert_failure } @@ -140,7 +140,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/empty-json-file + run _app "${TEST_DIR}/asset/empty-json-file" assert_invalid_input assert_success } @@ -151,7 +151,7 @@ teardown() { fi run _app \ - ${TEST_DIR}/asset/score-0-daemonset-volume-host-docker-socket.yml \ + "${TEST_DIR}/asset/score-0-daemonset-volume-host-docker-socket.yml" \ -w '%{content_type}' \ -o /dev/null @@ -163,7 +163,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/form-prefix-file.yml + run _app "${TEST_DIR}/asset/form-prefix-file.yml" assert_gt_zero_points assert_success } @@ -173,7 +173,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/form-prefix-file.json + run _app "${TEST_DIR}/asset/form-prefix-file.json" assert_gt_zero_points assert_success } @@ -183,7 +183,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/form-prefix-not-file.yml + run _app "${TEST_DIR}/asset/form-prefix-not-file.yml" assert_output --regexp ".*resource.json: Missing 'apiVersion' key.*" assert_success } @@ -193,7 +193,7 @@ teardown() { skip fi - run _app ${TEST_DIR}/asset/form-prefix-not-file.json + run _app "${TEST_DIR}/asset/form-prefix-not-file.json" assert_output "yaml: line 2: mapping values are not allowed in this context" assert_success } diff --git a/test/3_todo.bats b/test/3_todo.bats index a44814275..65a236db4 100644 --- a/test/3_todo.bats +++ b/test/3_todo.bats @@ -53,7 +53,7 @@ teardown() { @test "TODO: passes DaemonSet with apparmor loader" { skip https://github.com/kubernetes/contrib/blob/master/apparmor/loader/example-daemon.yaml - run _app ${TEST_DIR}/asset/score-0-daemonset- + run _app "${TEST_DIR}/asset/score-0-daemonset-" assert_zero_points } @@ -62,14 +62,14 @@ teardown() { # TODO: deployment serviceAccountName pass @test "TODO: passes Deployment with serviceaccountname" { skip - run _app ${TEST_DIR}/asset/score-2-dep-serviceaccount.yml + run _app "${TEST_DIR}/asset/score-2-dep-serviceaccount.yml" assert_zero_points } # TODO: tests for all the permutations of this file @test "TODO: fails DaemonSet with loads o' permutations" { skip - run _app ${TEST_DIR}/asset/score-0-daemonset- + run _app "${TEST_DIR}/asset/score-0-daemonset-" assert_zero_points } From 3365d53f065987e2745e6f627d4a32f7fb7847f8 Mon Sep 17 00:00:00 2001 From: 06kellyjac Date: Mon, 11 May 2020 17:52:29 +0100 Subject: [PATCH 2/5] feat: added passed section to json output Many users are confused about the scoring. Score comes from the passed checks, not advised checks. This change allows people to see the passed checks now --- pkg/ruler/report.go | 4 ++-- pkg/ruler/ruleset.go | 18 +++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/pkg/ruler/report.go b/pkg/ruler/report.go index ead75c08c..f6f55ce40 100644 --- a/pkg/ruler/report.go +++ b/pkg/ruler/report.go @@ -10,6 +10,7 @@ type Report struct { type RuleScoring struct { Critical []RuleRef `json:"critical,omitempty"` + Passed []RuleRef `json:"passed,omitempty"` Advise []RuleRef `json:"advise,omitempty"` } @@ -39,9 +40,8 @@ func (rr RuleRefCustomOrder) Less(i, j int) bool { // no integer absolute fn in golang if rr[i].Points > 0 || rr[j].Points > 0 { return rr[i].Points > rr[j].Points - } else { - return rr[i].Points < rr[j].Points } + return rr[i].Points < rr[j].Points } return rr[i].Selector < rr[j].Selector } diff --git a/pkg/ruler/ruleset.go b/pkg/ruler/ruleset.go index 8d1c49d7c..f6f31836b 100644 --- a/pkg/ruler/ruleset.go +++ b/pkg/ruler/ruleset.go @@ -5,17 +5,18 @@ import ( "crypto/sha256" "encoding/json" "fmt" + "os" + "runtime" + "sort" + "strings" + "sync" + "github.com/controlplaneio/kubesec/pkg/rules" "github.com/ghodss/yaml" "github.com/in-toto/in-toto-golang/in_toto" "github.com/instrumenta/kubeval/kubeval" "github.com/thedevsaddam/gojsonq" "go.uber.org/zap" - "os" - "runtime" - "sort" - "strings" - "sync" ) type Ruleset struct { @@ -252,8 +253,8 @@ func NewRuleset(logger *zap.SugaredLogger) *Ruleset { func (rs *Ruleset) Run(fileBytes []byte) ([]Report, error) { reports := make([]Report, 0) - isJson := json.Valid(fileBytes) - if isJson { + isJSON := json.Valid(fileBytes) + if isJSON { report := rs.generateReport(fileBytes) reports = append(reports, report) } else { @@ -312,6 +313,7 @@ func (rs *Ruleset) generateReport(json []byte) Report { Score: 0, Scoring: RuleScoring{ Advise: make([]RuleRef, 0), + Passed: make([]RuleRef, 0), Critical: make([]RuleRef, 0), }, } @@ -373,6 +375,7 @@ func (rs *Ruleset) generateReport(json []byte) Report { if ruleRef.Points >= 0 { rs.logger.Debugf("positive score rule matched %v (%v points)", ruleRef.Selector, ruleRef.Points) report.Score += ruleRef.Points + report.Scoring.Passed = append(report.Scoring.Passed, ruleRef) } if ruleRef.Points < 0 { @@ -398,6 +401,7 @@ func (rs *Ruleset) generateReport(json []byte) Report { // sort results into priority order sort.Sort(RuleRefCustomOrder(report.Scoring.Critical)) + sort.Sort(RuleRefCustomOrder(report.Scoring.Passed)) sort.Sort(RuleRefCustomOrder(report.Scoring.Advise)) return report From f66f1fb24543b095378d4dedbf937fedb624a032 Mon Sep 17 00:00:00 2001 From: 06kellyjac Date: Mon, 11 May 2020 17:59:52 +0100 Subject: [PATCH 3/5] fix: updated tests to read the advice score more resiliently Previous iteration was using exact indexes. Most changes to the output could fail the test. A snapshot test can be this fragile but these ones shouldn't. Now uses jq to grab scores. Other tests should migrate across to jq eventually. --- test/1_cli.bats | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/test/1_cli.bats b/test/1_cli.bats index 5ac14609d..0070147d7 100644 --- a/test/1_cli.bats +++ b/test/1_cli.bats @@ -140,21 +140,25 @@ teardown() { assert_lt_zero_points } -@test "returns integer point score for specific response lines" { - run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" +@test "returns integer point score for each advice element" { + JSON=$(_app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml") + + run jq -r .[].scoring.advise[].points <<<"${JSON}" - for LINE in 11 16 21 26 31 36 41 46 51 56 61; do - assert_line --index ${LINE} --regexp '^.*"points": [0-9]+$' + for SCORE in $output; do + assert bash -c "[[ $SCORE =~ ^[0-9]+$ ]]" done } -@test "returns an ordered point score for all responses" { - run _app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml" +@test "returns an ordered point score for all advice" { + JSON=$(_app "${TEST_DIR}/asset/score-2-pod-serviceaccount.yml") - assert_line --index 11 --regexp '^.*\"points\": 3$' + run jq -r .[].scoring.advise[].points <<<"${JSON}" - for LINE in 16 21 26 31 36 41 46 51 56 61; do - assert_line --index ${LINE} --regexp '^.*\"points\": 1$' + PREVIOUS="" + for CURRENT in $output; do + [ "${PREVIOUS}" = "" ] || assert [ "$CURRENT" -le "${PREVIOUS}" ] + PREVIOUS="${CURRENT}" done } From 60a4ee7d643e3915e4159e83c29e6b0cfe88461a Mon Sep 17 00:00:00 2001 From: 06kellyjac Date: Mon, 11 May 2020 20:28:06 +0100 Subject: [PATCH 4/5] test: added base tests for passed * All pass scores are integers * All passed are in order --- test/1_cli.bats | 22 ++++++++++++++++++++++ test/asset/score-5-pod-serviceaccount.yml | 15 +++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 test/asset/score-5-pod-serviceaccount.yml diff --git a/test/1_cli.bats b/test/1_cli.bats index 0070147d7..9e84b44b1 100644 --- a/test/1_cli.bats +++ b/test/1_cli.bats @@ -162,6 +162,28 @@ teardown() { done } +@test "returns integer point score for each pass element" { + JSON=$(_app "${TEST_DIR}/asset/score-5-pod-serviceaccount.yml") + + run jq -r .[].scoring.passed[].points <<<"${JSON}" + + for SCORE in $output; do + assert bash -c "[[ $SCORE =~ ^[0-9]+$ ]]" + done +} + +@test "returns an ordered point score for all passed" { + JSON=$(_app "${TEST_DIR}/asset/score-5-pod-serviceaccount.yml") + + run jq -r .[].scoring.passed[].points <<<"${JSON}" + + PREVIOUS="" + for CURRENT in $output; do + [ "${PREVIOUS}" = "" ] || assert [ "$CURRENT" -le "${PREVIOUS}" ] + PREVIOUS="${CURRENT}" + done +} + @test "check critical and advisory points listed by magnitude" { run _app "${TEST_DIR}/asset/critical-double.yml" diff --git a/test/asset/score-5-pod-serviceaccount.yml b/test/asset/score-5-pod-serviceaccount.yml new file mode 100644 index 000000000..ed24e1372 --- /dev/null +++ b/test/asset/score-5-pod-serviceaccount.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: my-pod +spec: + serviceAccountName: build-robot + automountServiceAccountToken: false + containers: + - name: nginx + image: nginx + securityContext: + runAsNonRoot: true + readOnlyRootFilesystem: true + ports: + - containerPort: 80 From 223236f29ce2a0f0f26374f7baef69c731ad1379 Mon Sep 17 00:00:00 2001 From: 06kellyjac Date: Mon, 11 May 2020 18:01:01 +0100 Subject: [PATCH 5/5] chore: bump version in README -> 2.4.0 Also fixed minor formatting issues --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7866e993..c9d967ad8 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Kubesec is available as a: - [Kubernetes Admission Controller](https://github.com/controlplaneio/kubesec-webhook) - [Kubectl plugin](https://github.com/controlplaneio/kubectl-kubesec) -Or install the latest commit from Github with `go get -u github.com/controlplaneio/kubesec/cmd/kubesec` +Or install the latest commit from GitHub with `go get -u github.com/controlplaneio/kubesec/cmd/kubesec` #### Command line usage: @@ -235,7 +235,7 @@ Thanks to our awesome contributors! ## Contributing -Kubesecis Apache 2.0 licensed and accepts contributions via GitHub pull requests. +Kubesec is Apache 2.0 licensed and accepts contributions via GitHub pull requests. When submitting bug reports please include as much details as possible: @@ -255,6 +255,11 @@ Your feedback is always welcome! # Release Notes +## 2.4.0 + +- added passed to the JSON output +- note: repo tests now require `jq` - **only concerns maintainers** + ## 2.3.1 - patch to accept form data from the webpage sample form