1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-15 17:51:20 +00:00
kyverno/pkg/engine/validation_test.go

3098 lines
107 KiB
Go
Raw Normal View History

2019-05-16 18:37:54 +00:00
package engine
import (
"encoding/json"
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
"strings"
2019-05-16 18:37:54 +00:00
"testing"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
feat: mutate existing resources (#3669) * feat: mutate existing, replace GR by UR in webhook server (#3601) * add attributes for post mutation Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR informer to webhook server Signed-off-by: ShutingZhao <shuting@nirmata.com> * - replace gr with ur in the webhook server; - create ur for mutateExsiting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace gr by ur across entire packages Signed-off-by: ShutingZhao <shuting@nirmata.com> * add YAMLs Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs & fix unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR deletion handler Signed-off-by: ShutingZhao <shuting@nirmata.com> * add api docs for v1beta1 Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix clientset method Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix v1beta1 client registration Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing - generates UR for admission requests (#3623) Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace with UR in policy controller generate rules (#3635) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * - enable mutate engine to process mutateExisting rules; - add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * implemented ur background reconciliation for mutateExisting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix webhook update error Signed-off-by: ShutingZhao <shuting@nirmata.com> * temporary comment out new unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing, replace GR by UR in webhook server (#3601) * add attributes for post mutation Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR informer to webhook server Signed-off-by: ShutingZhao <shuting@nirmata.com> * - replace gr with ur in the webhook server; - create ur for mutateExsiting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace gr by ur across entire packages Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix missing policy.kyverno.io/policy-name label (#3599) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * refactor cli code from pkg to cmd (#3591) * refactor cli code from pkg to cmd Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixes in imports Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixes tests Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixed conflicts Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * moved non-commands to utils Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> * add YAMLs Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs & fix unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR deletion handler Signed-off-by: ShutingZhao <shuting@nirmata.com> * add api docs for v1beta1 Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix clientset method Signed-off-by: ShutingZhao <shuting@nirmata.com> * add-kms-libraries for cosign (#3603) * add-kms-libraries Signed-off-by: anushkamittal20 <anumittal4641@gmail.com> * Shifted providers to cosign package Signed-off-by: anushkamittal20 <anumittal4641@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Add support for custom image extractors (#3596) Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net> * Update vulnerable dependencies (#3577) Signed-off-by: Shubham Gupta <shubham.gupta2956@gmail.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix v1beta1 client registration Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing - generates UR for admission requests (#3623) Signed-off-by: ShutingZhao <shuting@nirmata.com> * updating version in Chart.yaml (#3618) * updatimg version in Chart.yaml Signed-off-by: Prateeknandle <prateeknandle@gmail.com> * changes from, make gen-helm Signed-off-by: Prateeknandle <prateeknandle@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Allow kyverno-policies to have preconditions defined (#3606) * Allow kyverno-policies to have preconditions defined Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Fix docs Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace with UR in policy controller generate rules (#3635) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * - enable mutate engine to process mutateExisting rules; - add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * implemented ur background reconciliation for mutateExisting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix webhook update error Signed-off-by: ShutingZhao <shuting@nirmata.com> * temporary comment out new unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * Image verify attestors (#3614) * fix logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * support multiple attestors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * rm CLI tests (not currently supported) Signed-off-by: Jim Bugwadia <jim@nirmata.com> * apply attestor repo Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix entryError assignment Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add intermediary certs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Allow defining imagePullSecrets (#3633) * Allow defining imagePullSecrets Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Use dict for imagePullSecrets Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Simplify how imagePullSecrets is defined Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Fix race condition in pCache (#3632) * fix race condition in pCache Signed-off-by: ShutingZhao <shuting@nirmata.com> * refact: remove unused Run function from generate (#3638) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * Remove helm mode setting (#3628) Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * refactor: image utils (#3630) Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * -resolve lift comments; -fix informer sync issue Signed-off-by: ShutingZhao <shuting@nirmata.com> * refact the update request cleanup controller Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * - fix delete request for mutateExisting; - fix context variable substitution; - improve logging Signed-off-by: ShutingZhao <shuting@nirmata.com> * - enable events; - add last applied annotation Signed-off-by: ShutingZhao <shuting@nirmata.com> * enable mutate existing on policy creation Signed-off-by: ShutingZhao <shuting@nirmata.com> * update autogen code Signed-off-by: ShutingZhao <shuting@nirmata.com> * merge main Signed-off-by: ShutingZhao <shuting@nirmata.com> * add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * address list comments Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix "Implicit memory aliasing in for loop" Signed-off-by: ShutingZhao <shuting@nirmata.com> * remove unused definitions Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs Signed-off-by: ShutingZhao <shuting@nirmata.com> Co-authored-by: Prateek Pandey <prateek.pandey@nirmata.com> Co-authored-by: Mritunjay Kumar Sharma <mritunjaysharma394@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> Co-authored-by: Anushka Mittal <55237170+anushkamittal20@users.noreply.github.com> Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com> Co-authored-by: Shubham Gupta <shubham.gupta2956@gmail.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Prateek Nandle <56027872+Prateeknandle@users.noreply.github.com> Co-authored-by: treydock <tdockendorf@osc.edu> Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
2022-04-25 12:20:40 +00:00
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
"github.com/kyverno/kyverno/pkg/engine/context"
feat: mutate existing resources (#3669) * feat: mutate existing, replace GR by UR in webhook server (#3601) * add attributes for post mutation Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR informer to webhook server Signed-off-by: ShutingZhao <shuting@nirmata.com> * - replace gr with ur in the webhook server; - create ur for mutateExsiting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace gr by ur across entire packages Signed-off-by: ShutingZhao <shuting@nirmata.com> * add YAMLs Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs & fix unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR deletion handler Signed-off-by: ShutingZhao <shuting@nirmata.com> * add api docs for v1beta1 Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix clientset method Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix v1beta1 client registration Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing - generates UR for admission requests (#3623) Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace with UR in policy controller generate rules (#3635) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * - enable mutate engine to process mutateExisting rules; - add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * implemented ur background reconciliation for mutateExisting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix webhook update error Signed-off-by: ShutingZhao <shuting@nirmata.com> * temporary comment out new unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing, replace GR by UR in webhook server (#3601) * add attributes for post mutation Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR informer to webhook server Signed-off-by: ShutingZhao <shuting@nirmata.com> * - replace gr with ur in the webhook server; - create ur for mutateExsiting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace gr by ur across entire packages Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix missing policy.kyverno.io/policy-name label (#3599) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * refactor cli code from pkg to cmd (#3591) * refactor cli code from pkg to cmd Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixes in imports Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixes tests Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixed conflicts Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * moved non-commands to utils Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> * add YAMLs Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs & fix unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR deletion handler Signed-off-by: ShutingZhao <shuting@nirmata.com> * add api docs for v1beta1 Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix clientset method Signed-off-by: ShutingZhao <shuting@nirmata.com> * add-kms-libraries for cosign (#3603) * add-kms-libraries Signed-off-by: anushkamittal20 <anumittal4641@gmail.com> * Shifted providers to cosign package Signed-off-by: anushkamittal20 <anumittal4641@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Add support for custom image extractors (#3596) Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net> * Update vulnerable dependencies (#3577) Signed-off-by: Shubham Gupta <shubham.gupta2956@gmail.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix v1beta1 client registration Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing - generates UR for admission requests (#3623) Signed-off-by: ShutingZhao <shuting@nirmata.com> * updating version in Chart.yaml (#3618) * updatimg version in Chart.yaml Signed-off-by: Prateeknandle <prateeknandle@gmail.com> * changes from, make gen-helm Signed-off-by: Prateeknandle <prateeknandle@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Allow kyverno-policies to have preconditions defined (#3606) * Allow kyverno-policies to have preconditions defined Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Fix docs Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace with UR in policy controller generate rules (#3635) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * - enable mutate engine to process mutateExisting rules; - add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * implemented ur background reconciliation for mutateExisting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix webhook update error Signed-off-by: ShutingZhao <shuting@nirmata.com> * temporary comment out new unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * Image verify attestors (#3614) * fix logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * support multiple attestors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * rm CLI tests (not currently supported) Signed-off-by: Jim Bugwadia <jim@nirmata.com> * apply attestor repo Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix entryError assignment Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add intermediary certs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Allow defining imagePullSecrets (#3633) * Allow defining imagePullSecrets Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Use dict for imagePullSecrets Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Simplify how imagePullSecrets is defined Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Fix race condition in pCache (#3632) * fix race condition in pCache Signed-off-by: ShutingZhao <shuting@nirmata.com> * refact: remove unused Run function from generate (#3638) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * Remove helm mode setting (#3628) Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * refactor: image utils (#3630) Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * -resolve lift comments; -fix informer sync issue Signed-off-by: ShutingZhao <shuting@nirmata.com> * refact the update request cleanup controller Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * - fix delete request for mutateExisting; - fix context variable substitution; - improve logging Signed-off-by: ShutingZhao <shuting@nirmata.com> * - enable events; - add last applied annotation Signed-off-by: ShutingZhao <shuting@nirmata.com> * enable mutate existing on policy creation Signed-off-by: ShutingZhao <shuting@nirmata.com> * update autogen code Signed-off-by: ShutingZhao <shuting@nirmata.com> * merge main Signed-off-by: ShutingZhao <shuting@nirmata.com> * add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * address list comments Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix "Implicit memory aliasing in for loop" Signed-off-by: ShutingZhao <shuting@nirmata.com> * remove unused definitions Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs Signed-off-by: ShutingZhao <shuting@nirmata.com> Co-authored-by: Prateek Pandey <prateek.pandey@nirmata.com> Co-authored-by: Mritunjay Kumar Sharma <mritunjaysharma394@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> Co-authored-by: Anushka Mittal <55237170+anushkamittal20@users.noreply.github.com> Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com> Co-authored-by: Shubham Gupta <shubham.gupta2956@gmail.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Prateek Nandle <56027872+Prateeknandle@users.noreply.github.com> Co-authored-by: treydock <tdockendorf@osc.edu> Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
2022-04-25 12:20:40 +00:00
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
utils2 "github.com/kyverno/kyverno/pkg/utils"
2019-05-16 18:37:54 +00:00
"gotest.tools/assert"
admissionv1 "k8s.io/api/admission/v1"
2019-05-16 18:37:54 +00:00
)
func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
2019-06-04 14:33:21 +00:00
rawMap := []byte(`{
"(name)":"nirmata-*",
"notAnchor1":123,
"(namespace)":"kube-?olicy",
"notAnchor2":"sample-text",
"object":{
"key1":"value1",
"(key2)":"value2"
}
}`)
2019-05-16 18:37:54 +00:00
var unmarshalled map[string]interface{}
err := json.Unmarshal(rawMap, &unmarshalled)
assert.NilError(t, err)
2019-05-16 18:37:54 +00:00
actualMap := utils.GetAnchorsFromMap(unmarshalled)
2019-05-16 18:37:54 +00:00
assert.Equal(t, len(actualMap), 2)
assert.Equal(t, actualMap["(name)"].(string), "nirmata-*")
assert.Equal(t, actualMap["(namespace)"].(string), "kube-?olicy")
}
2019-09-25 22:12:33 +00:00
func TestValidate_image_tag_fail(t *testing.T) {
// If image tag is latest then imagepull policy needs to be checked
rawPolicy := []byte(`{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-image"
},
"spec": {
"rules": [
{
"name": "validate-tag",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "An image tag is required",
"pattern": {
"spec": {
"containers": [
{
"image": "*:*"
}
]
}
}
}
},
{
"name": "validate-latest",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "imagePullPolicy 'Always' required with tag 'latest'",
"pattern": {
"spec": {
"containers": [
{
2019-09-26 18:00:30 +00:00
"(image)": "*latest",
2019-09-25 22:12:33 +00:00
"imagePullPolicy": "NotPresent"
}
]
}
}
}
}
]
}
}
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "myapp"
}
},
"spec": {
"containers": [
{
"name": "nginx",
2019-09-25 22:12:33 +00:00
"image": "nginx:latest",
"imagePullPolicy": "Always"
}
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
2019-10-01 19:35:14 +00:00
msgs := []string{
"validation rule 'validate-tag' passed.",
"validation error: imagePullPolicy 'Always' required with tag 'latest'. rule validate-latest failed at path /spec/containers/0/imagePullPolicy/",
2019-10-01 19:35:14 +00:00
}
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
2019-10-01 19:35:14 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, !er.IsSuccessful())
}
2019-09-25 22:12:33 +00:00
func TestValidate_image_tag_pass(t *testing.T) {
// If image tag is latest then imagepull policy needs to be checked
rawPolicy := []byte(`{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-25 22:12:33 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-image"
},
"spec": {
"rules": [
{
"name": "validate-tag",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "An image tag is required",
"pattern": {
"spec": {
"containers": [
{
"image": "*:*"
}
]
}
}
}
},
{
"name": "validate-latest",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "imagePullPolicy 'Always' required with tag 'latest'",
"pattern": {
"spec": {
"containers": [
{
2019-09-26 18:00:30 +00:00
"(image)": "*latest",
2019-09-25 22:12:33 +00:00
"imagePullPolicy": "Always"
}
]
}
}
}
}
]
}
}
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "myapp"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest",
"imagePullPolicy": "Always"
}
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-25 22:12:33 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-25 22:12:33 +00:00
assert.NilError(t, err)
2019-10-01 19:35:14 +00:00
msgs := []string{
"validation rule 'validate-tag' passed.",
"validation rule 'validate-latest' passed.",
2019-10-01 19:35:14 +00:00
}
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
2019-10-01 19:35:14 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
2019-09-25 22:12:33 +00:00
}
func TestValidate_Fail_anyPattern(t *testing.T) {
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-namespace"
},
"spec": {
"rules": [
{
"name": "check-default-namespace",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "A namespace is required",
"anyPattern": [
{
"metadata": {
"namespace": "?*"
}
},
{
"metadata": {
"namespace": "!default"
}
}
]
}
}
]
}
}
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "myapp"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx"
}
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
2020-12-23 23:10:07 +00:00
assert.Assert(t, !er.IsSuccessful())
msgs := []string{"validation error: A namespace is required. rule check-default-namespace[0] failed at path /metadata/namespace/ rule check-default-namespace[1] failed at path /metadata/namespace/"}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
}
func TestValidate_host_network_port(t *testing.T) {
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-host-network-port"
},
"spec": {
"rules": [
{
"name": "validate-host-network-port",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "Host network and port are not allowed",
"pattern": {
"spec": {
"hostNetwork": false,
"containers": [
{
"name": "*",
"ports": [
{
"hostPort": null
}
]
}
]
}
}
}
}
]
}
}
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "nginx-host-network"
},
"spec": {
"hostNetwork": false,
"containers": [
{
"name": "nginx-host-network",
"image": "nginx",
"ports": [
{
"containerPort": 80,
"hostPort": 80
}
]
}
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation error: Host network and port are not allowed. rule validate-host-network-port failed at path /spec/containers/0/ports/0/hostPort/"}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, !er.IsSuccessful())
}
2019-09-25 22:12:33 +00:00
func TestValidate_anchor_arraymap_pass(t *testing.T) {
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-25 22:12:33 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-host-path"
},
"spec": {
"rules": [
{
"name": "validate-host-path",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "Host path '/var/lib/' is not allowed",
"pattern": {
"spec": {
"volumes": [
{
"name": "*",
2019-10-01 20:08:34 +00:00
"=(hostPath)": {
2019-09-25 22:12:33 +00:00
"path": "!/var/lib"
}
}
]
}
}
}
}
]
}
}
2019-09-25 22:12:33 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "image-with-hostpath",
"labels": {
"app.type": "prod",
"namespace": "my-namespace"
}
},
"spec": {
"containers": [
{
"name": "image-with-hostpath",
"image": "docker.io/nautiker/curl",
"volumeMounts": [
{
"name": "var-lib-etcd",
"mountPath": "/var/lib"
}
]
}
],
"volumes": [
{
"name": "var-lib-etcd",
"hostPath": {
"path": "/var/lib1"
}
}
]
}
} `)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-25 22:12:33 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-25 22:12:33 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'validate-host-path' passed."}
2019-09-25 22:12:33 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
2019-09-25 22:12:33 +00:00
}
func TestValidate_anchor_arraymap_fail(t *testing.T) {
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-25 22:12:33 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-host-path"
},
"spec": {
"rules": [
{
"name": "validate-host-path",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "Host path '/var/lib/' is not allowed",
"pattern": {
"spec": {
"volumes": [
{
2019-10-01 20:08:34 +00:00
"=(hostPath)": {
2019-09-25 22:12:33 +00:00
"path": "!/var/lib"
}
}
]
}
}
}
}
]
}
}
2019-09-25 22:12:33 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "image-with-hostpath",
"labels": {
"app.type": "prod",
"namespace": "my-namespace"
}
},
"spec": {
"containers": [
{
"name": "image-with-hostpath",
"image": "docker.io/nautiker/curl",
"volumeMounts": [
{
"name": "var-lib-etcd",
"mountPath": "/var/lib"
}
]
}
],
"volumes": [
{
"name": "var-lib-etcd",
"hostPath": {
"path": "/var/lib"
}
}
]
}
} `)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-25 22:12:33 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation error: Host path '/var/lib/' is not allowed. rule validate-host-path failed at path /spec/volumes/0/hostPath/path/"}
2019-09-25 22:12:33 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, !er.IsSuccessful())
2019-09-25 22:12:33 +00:00
}
func TestValidate_anchor_map_notfound(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-25 22:12:33 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod rule 2",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "pod: validate run as non root user",
"pattern": {
"spec": {
2019-10-01 20:08:34 +00:00
"=(securityContext)": {
2019-09-25 22:12:33 +00:00
"runAsNonRoot": true
}
}
}
}
}
]
}
} `)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx"
}
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-25 22:12:33 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-25 22:12:33 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
2019-09-25 22:12:33 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
2019-09-25 22:12:33 +00:00
}
func TestValidate_anchor_map_found_valid(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-25 22:12:33 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod rule 2",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "pod: validate run as non root user",
"pattern": {
"spec": {
2019-10-01 20:08:34 +00:00
"=(securityContext)": {
2019-09-25 22:12:33 +00:00
"runAsNonRoot": true
}
}
}
}
}
]
}
} `)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx"
}
],
"securityContext": {
"runAsNonRoot": true
}
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-25 22:12:33 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-25 22:12:33 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
2019-09-25 22:12:33 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
2020-12-23 23:10:07 +00:00
assert.Assert(t, er.IsSuccessful())
}
func TestValidate_inequality_List_Processing(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod rule 2",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "pod: validate run as non root user",
"pattern": {
"spec": {
"=(supplementalGroups)": ">0"
}
}
}
}
]
}
} `)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx"
}
],
"supplementalGroups": [
"2",
"5",
"10"
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
}
func TestValidate_inequality_List_ProcessingBrackets(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod rule 2",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "pod: validate run as non root user",
"pattern": {
"spec": {
"=(supplementalGroups)": [
">0 & <100001"
]
}
}
}
}
]
}
} `)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx"
}
],
"supplementalGroups": [
"2",
"5",
"10",
"100",
"10000",
"1000",
"543"
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'pod rule 2' passed."}
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
2019-09-25 22:12:33 +00:00
}
func TestValidate_anchor_map_found_invalid(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-25 22:12:33 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod rule 2",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "pod: validate run as non root user",
"pattern": {
"spec": {
2019-10-01 20:08:34 +00:00
"=(securityContext)": {
2019-09-25 22:12:33 +00:00
"runAsNonRoot": true
}
}
}
}
}
]
}
} `)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx"
}
],
"securityContext": {
"runAsNonRoot": false
}
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-25 22:12:33 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-25 22:12:33 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation error: pod: validate run as non root user. rule pod rule 2 failed at path /spec/securityContext/runAsNonRoot/"}
2019-09-25 22:12:33 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, !er.IsSuccessful())
2019-09-25 22:12:33 +00:00
}
2019-09-26 04:01:45 +00:00
func TestValidate_AnchorList_pass(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-26 04:01:45 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod image rule",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"pattern": {
"spec": {
2019-10-01 20:08:34 +00:00
"=(containers)": [
2019-09-26 04:01:45 +00:00
{
"name": "nginx"
}
]
}
}
}
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx"
},
{
"name": "nginx"
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-26 04:01:45 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-26 04:01:45 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'pod image rule' passed."}
2019-09-26 04:01:45 +00:00
2019-10-01 19:35:14 +00:00
for index, r := range er.PolicyResponse.Rules {
t.Log(r.Message)
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
2019-09-26 04:01:45 +00:00
}
func TestValidate_AnchorList_fail(t *testing.T) {
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-26 04:01:45 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod image rule",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"pattern": {
"spec": {
2019-10-01 20:08:34 +00:00
"=(containers)": [
2019-09-26 04:01:45 +00:00
{
"name": "nginx"
}
]
}
}
}
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx"
},
{
"name": "busy"
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-26 04:01:45 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-26 04:01:45 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
assert.Assert(t, !er.IsSuccessful())
2019-09-26 04:01:45 +00:00
}
func TestValidate_existenceAnchor_fail(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-26 04:01:45 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod image rule",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"pattern": {
"spec": {
"^(containers)": [
{
"name": "nginx"
}
]
}
}
}
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "busy1"
},
{
"name": "busy"
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-26 04:01:45 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-26 04:01:45 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
assert.Assert(t, !er.IsSuccessful())
2019-09-26 04:01:45 +00:00
}
func TestValidate_existenceAnchor_pass(t *testing.T) {
// anchor not present in resource
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-09-26 04:01:45 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "policy-secaas-k8s"
},
"spec": {
"rules": [
{
"name": "pod image rule",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"pattern": {
"spec": {
"^(containers)": [
{
"name": "nginx"
}
]
}
}
}
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "myapp-pod",
"labels": {
"app": "v1"
}
},
"spec": {
"containers": [
{
"name": "nginx"
},
{
"name": "busy"
}
]
}
}
2019-09-26 04:01:45 +00:00
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-09-26 04:01:45 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-09-26 04:01:45 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'pod image rule' passed."}
2019-09-26 04:01:45 +00:00
2019-10-01 19:35:14 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
2019-09-26 04:01:45 +00:00
}
2019-10-11 00:34:20 +00:00
func TestValidate_negationAnchor_deny(t *testing.T) {
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-10-11 00:34:20 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-host-path"
},
"spec": {
"rules": [
{
"name": "validate-host-path",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "Host path is not allowed",
"pattern": {
"spec": {
"volumes": [
{
"name": "*",
"X(hostPath)": null
}
]
}
}
}
}
]
}
}
2019-10-11 00:34:20 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "image-with-hostpath",
"labels": {
"app.type": "prod",
"namespace": "my-namespace"
}
},
"spec": {
"containers": [
{
"name": "image-with-hostpath",
"image": "docker.io/nautiker/curl",
"volumeMounts": [
{
"name": "var-lib-etcd",
"mountPath": "/var/lib"
}
]
}
],
"volumes": [
{
"name": "var-lib-etcd",
"hostPath": {
"path": "/var/lib1"
}
}
]
}
} `)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-10-11 00:34:20 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-10-11 00:34:20 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation error: Host path is not allowed. rule validate-host-path failed at path /spec/volumes/0/hostPath/"}
2019-10-11 00:34:20 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, !er.IsSuccessful())
2019-10-11 00:34:20 +00:00
}
func TestValidate_negationAnchor_pass(t *testing.T) {
rawPolicy := []byte(`
{
2019-11-13 21:56:07 +00:00
"apiVersion": "kyverno.io/v1",
2019-10-11 00:34:20 +00:00
"kind": "ClusterPolicy",
"metadata": {
"name": "validate-host-path"
},
"spec": {
"rules": [
{
"name": "validate-host-path",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "Host path is not allowed",
"pattern": {
"spec": {
"volumes": [
{
"name": "*",
"X(hostPath)": null
}
]
}
}
}
}
]
}
}
2019-10-11 00:34:20 +00:00
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "image-with-hostpath",
"labels": {
"app.type": "prod",
"namespace": "my-namespace"
}
},
"spec": {
"containers": [
{
"name": "image-with-hostpath",
"image": "docker.io/nautiker/curl",
"volumeMounts": [
{
"name": "var-lib-etcd",
"mountPath": "/var/lib"
}
]
}
],
"volumes": [
{
"name": "var-lib-etcd",
"emptyDir": {}
}
]
}
}
`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
2019-10-11 00:34:20 +00:00
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
2019-10-11 00:34:20 +00:00
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
msgs := []string{"validation rule 'validate-host-path' passed."}
2019-10-11 00:34:20 +00:00
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, er.IsSuccessful())
2019-10-11 00:34:20 +00:00
}
func Test_VariableSubstitutionPathNotExistInPattern(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "check-root-user"
},
"spec": {
"containers": [
{
"name": "check-root-user-a",
"image": "nginxinc/nginx-unprivileged",
"securityContext": {
"runAsNonRoot": true
}
}
]
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitute-variable"
},
"spec": {
"rules": [
{
"name": "test-path-not-exist",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"pattern": {
"spec": {
"containers": [
{
"name": "{{request.object.metadata.name1}}*"
}
]
}
}
}
}
]
}
}`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(policyraw, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
2020-12-23 23:10:07 +00:00
policyContext := &PolicyContext{
Policy: &policy,
2020-12-23 23:10:07 +00:00
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path"))
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfiesButSubstitutionFails(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {
"name": "test"
},
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "test-pod",
"image": "nginxinc/nginx-unprivileged"
}
]
}
}
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitute-variable"
},
"spec": {
"rules": [
{
"name": "test-path-not-exist",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"anyPattern": [
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "{{request.object.metadata.name1}}*"
}
]
}
}
}
},
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "{{request.object.metadata.name}}*"
}
]
}
}
}
}
]
}
}
]
}
}`)
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyraw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
2020-12-23 23:10:07 +00:00
policyContext := &PolicyContext{
Policy: &policy,
2020-12-23 23:10:07 +00:00
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path"))
}
func Test_VariableSubstitution_NotOperatorWithStringVariable(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {
"name": "test"
},
"spec": {
"content": "sample text"
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitute-variable"
},
"spec": {
"rules": [
{
"name": "not-operator-with-variable-should-alway-fail-validation",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"pattern": {
"spec": {
"content": "!{{ request.object.spec.content }}"
}
}
}
}
]
}
}`)
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyraw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "validation error: rule not-operator-with-variable-should-alway-fail-validation failed at path /spec/content/")
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {
"name": "test"
},
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "test-pod",
"image": "nginxinc/nginx-unprivileged"
}
]
}
}
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitute-variable"
},
"spec": {
"rules": [
{
"name": "test-path-not-exist",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"anyPattern": [
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "{{request.object.metadata.name1}}*"
}
]
}
}
}
},
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "{{request.object.metadata.name2}}*"
}
]
}
}
}
}
]
}
}
]
}
}`)
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyraw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
2020-12-23 23:10:07 +00:00
policyContext := &PolicyContext{
Policy: &policy,
2020-12-23 23:10:07 +00:00
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusError)
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path"))
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatternSatisfy(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {
"name": "test"
},
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "pod-test-pod",
"image": "nginxinc/nginx-unprivileged"
}
]
}
}
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "substitute-variable"
},
"spec": {
"rules": [
{
"name": "test-path-not-exist",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"anyPattern": [
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "{{request.object.metadata.name}}*"
}
]
}
}
}
},
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "{{request.object.metadata.name}}*"
}
]
}
}
}
}
]
}
}
]
}
}`)
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyraw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
2020-12-23 23:10:07 +00:00
policyContext := &PolicyContext{
Policy: &policy,
2020-12-23 23:10:07 +00:00
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
assert.Equal(t, er.PolicyResponse.Rules[0].Message,
"validation error: rule test-path-not-exist[0] failed at path /spec/template/spec/containers/0/name/ rule test-path-not-exist[1] failed at path /spec/template/spec/containers/0/name/")
}
2020-05-06 21:05:24 +00:00
func Test_VariableSubstitutionValidate_VariablesInMessageAreResolved(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "busybox",
"labels": {
"app": "busybox",
"color": "red",
"animal": "cow",
"food": "pizza",
"car": "jeep",
"env": "qa"
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "busybox"
}
},
"template": {
"metadata": {
"labels": {
"app": "busybox"
}
},
"spec": {
"containers": [
{
"image": "busybox:1.28",
"name": "busybox",
"command": [
"sleep",
"9999"
]
}
]
}
}
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "cm-array-example"
},
"spec": {
"validationFailureAction": "enforce",
"background": false,
"rules": [
{
"name": "validate-role-annotation",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"message": "The animal {{ request.object.metadata.labels.animal }} is not in the allowed list of animals.",
"deny": {
"conditions": [
{
"key": "{{ request.object.metadata.labels.animal }}",
"operator": "NotIn",
"value": [
"snake",
"bear",
"cat",
"dog"
]
}
]
}
}
}
]
}
}`)
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyraw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
assert.Equal(t, er.PolicyResponse.Rules[0].Message, "The animal cow is not in the allowed list of animals.")
}
func Test_Flux_Kustomization_PathNotPresent(t *testing.T) {
tests := []struct {
name string
policyRaw []byte
resourceRaw []byte
expectedResults []response.RuleStatus
expectedMessages []string
}{
{
name: "path-not-present",
policyRaw: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"flux-multi-tenancy"},"spec":{"validationFailureAction":"enforce","rules":[{"name":"serviceAccountName","exclude":{"resources":{"namespaces":["flux-system"]}},"match":{"resources":{"kinds":["Kustomization","HelmRelease"]}},"validate":{"message":".spec.serviceAccountName is required","pattern":{"spec":{"serviceAccountName":"?*"}}}},{"name":"sourceRefNamespace","exclude":{"resources":{"namespaces":["flux-system"]}},"match":{"resources":{"kinds":["Kustomization","HelmRelease"]}},"validate":{"message":"spec.sourceRef.namespace must be the same as metadata.namespace","deny":{"conditions":[{"key":"{{request.object.spec.sourceRef.namespace}}","operator":"NotEquals","value":"{{request.object.metadata.namespace}}"}]}}}]}}`),
// referred variable path not present
resourceRaw: []byte(`{"apiVersion":"kustomize.toolkit.fluxcd.io/v1beta1","kind":"Kustomization","metadata":{"name":"dev-team","namespace":"apps"},"spec":{"serviceAccountName":"dev-team","interval":"5m","sourceRef":{"kind":"GitRepository","name":"dev-team"},"prune":true,"validation":"client"}}`),
expectedResults: []response.RuleStatus{response.RuleStatusPass, response.RuleStatusError},
updates for foreach and mutate (#2891) * updates for foreach and mutate Signed-off-by: Jim Bugwadia <jim@nirmata.com> * allow tests to pass on Windows Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add elementIndex variable Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix jsonResult usage Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add mutate validation and fix error in validate.foreach Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * do not skip validation for all array entries when one is skipped Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add foreach tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix fmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format errors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove unused declarations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * revert namespaceWithLabelYaml Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix mutate of element list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update CRDs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Update api/kyverno/v1/policy_types.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/forceMutate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/mutation.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update pkg/engine/validate/validate.go Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/custom-functions/policy.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * Update test/cli/test/foreach/policies.yaml Co-authored-by: Steven E. Harris <seh@panix.com> * accept review comments and format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add comments to strategicMergePatch buffer Signed-off-by: Jim Bugwadia <jim@nirmata.com> * load context and evaluate preconditions foreach element Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add test for foreach mutate context and precondition * precondition testcase * address review comments Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Steven E. Harris <seh@panix.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com>
2022-01-05 01:36:33 +00:00
expectedMessages: []string{"validation rule 'serviceAccountName' passed.", "failed to substitute variables in deny conditions: failed to resolve request.object.spec.sourceRef.namespace at path /0/key: JMESPath query failed: Unknown key \"namespace\" in path"},
},
{
name: "resource-with-violation",
policyRaw: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"flux-multi-tenancy"},"spec":{"validationFailureAction":"enforce","rules":[{"name":"serviceAccountName","exclude":{"resources":{"namespaces":["flux-system"]}},"match":{"resources":{"kinds":["Kustomization","HelmRelease"]}},"validate":{"message":".spec.serviceAccountName is required","pattern":{"spec":{"serviceAccountName":"?*"}}}},{"name":"sourceRefNamespace","exclude":{"resources":{"namespaces":["flux-system"]}},"match":{"resources":{"kinds":["Kustomization","HelmRelease"]}},"validate":{"message":"spec.sourceRef.namespace {{request.object.spec.sourceRef.namespace}} must be the same as metadata.namespace {{request.object.metadata.namespace}}","deny":{"conditions":[{"key":"{{request.object.spec.sourceRef.namespace}}","operator":"NotEquals","value":"{{request.object.metadata.namespace}}"}]}}}]}}`),
// referred variable path present with different value
resourceRaw: []byte(`{"apiVersion":"kustomize.toolkit.fluxcd.io/v1beta1","kind":"Kustomization","metadata":{"name":"dev-team","namespace":"apps"},"spec":{"serviceAccountName":"dev-team","interval":"5m","sourceRef":{"kind":"GitRepository","name":"dev-team","namespace":"default"},"prune":true,"validation":"client"}}`),
expectedResults: []response.RuleStatus{response.RuleStatusPass, response.RuleStatusFail},
expectedMessages: []string{"validation rule 'serviceAccountName' passed.", "spec.sourceRef.namespace default must be the same as metadata.namespace apps"},
},
{
name: "resource-comply",
policyRaw: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"flux-multi-tenancy"},"spec":{"validationFailureAction":"enforce","rules":[{"name":"serviceAccountName","exclude":{"resources":{"namespaces":["flux-system"]}},"match":{"resources":{"kinds":["Kustomization","HelmRelease"]}},"validate":{"message":".spec.serviceAccountName is required","pattern":{"spec":{"serviceAccountName":"?*"}}}},{"name":"sourceRefNamespace","exclude":{"resources":{"namespaces":["flux-system"]}},"match":{"resources":{"kinds":["Kustomization","HelmRelease"]}},"validate":{"message":"spec.sourceRef.namespace must be the same as metadata.namespace","deny":{"conditions":[{"key":"{{request.object.spec.sourceRef.namespace}}","operator":"NotEquals","value":"{{request.object.metadata.namespace}}"}]}}}]}}`),
// referred variable path present with same value - validate passes
resourceRaw: []byte(`{"apiVersion":"kustomize.toolkit.fluxcd.io/v1beta1","kind":"Kustomization","metadata":{"name":"dev-team","namespace":"apps"},"spec":{"serviceAccountName":"dev-team","interval":"5m","sourceRef":{"kind":"GitRepository","name":"dev-team","namespace":"apps"},"prune":true,"validation":"client"}}`),
expectedResults: []response.RuleStatus{response.RuleStatusPass, response.RuleStatusPass},
expectedMessages: []string{"validation rule 'serviceAccountName' passed.", "validation rule 'sourceRefNamespace' passed."},
},
}
for _, test := range tests {
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(test.policyRaw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(test.resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, test.resourceRaw)
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
for i, rule := range er.PolicyResponse.Rules {
assert.Equal(t, er.PolicyResponse.Rules[i].Status, test.expectedResults[i], "\ntest %s failed\nexpected: %s\nactual: %s", test.name, test.expectedResults[i].String(), er.PolicyResponse.Rules[i].Status.String())
assert.Equal(t, er.PolicyResponse.Rules[i].Message, test.expectedMessages[i], "\ntest %s failed\nexpected: %s\nactual: %s", test.name, test.expectedMessages[i], rule.Message)
}
}
}
2020-12-23 23:10:07 +00:00
type testCase struct {
description string
policy []byte
request []byte
userInfo []byte
requestDenied bool
}
func Test_denyFeatureIssue744_BlockUpdate(t *testing.T) {
testcases := []testCase{
2020-05-06 21:05:24 +00:00
{
description: "Blocks update requests for resources with label allow-updates(success case)",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"block-updates-success"},"spec":{"validationFailureAction":"enforce","background":false,"rules":[{"name":"check-allow-updates","match":{"resources":{"selector":{"matchLabels":{"allow-updates":"false"}}}},"exclude":{"clusterRoles":["random"]},"validate":{"message":"Updating {{request.object.kind}} / {{request.object.metadata.name}} is not allowed","deny":{"conditions":{"all":[{"key":"{{request.operation}}","operator":"Equals","value":"UPDATE"}]}}}}]}}`),
2020-05-19 17:32:42 +00:00
request: []byte(`{"uid":"7b0600b7-0258-4ecb-9666-c2839bd19612","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"subResource":"status","requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"requestSubResource":"status","name":"hello-world","namespace":"default","operation":"UPDATE","userInfo":{"username":"system:node:kind-control-plane","groups":["system:authenticated"]},"object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"2b42971e-6fcf-41a7-ae44-80963f957eae","resourceVersion":"3438","creationTimestamp":"2020-05-06T20:41:37Z","labels":{"allow-updates":"false","something":"hereeeeeseee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"hereeeeeseee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","nodeName":"kind-control-plane","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Running","conditions":[{"type":"Initialized","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:41:37Z"},{"type":"Ready","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:41:37Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"ContainersReady","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:41:37Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"PodScheduled","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:41:37Z"}],"hostIP":"172.17.0.2","podIP":"10.244.0.8","podIPs":[{"ip":"10.244.0.8"}],"startTime":"2020-05-06T20:41:37Z","containerStatuses":[{"name":"hello-world","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2020-05-06T20:42:01Z","finishedAt":"2020-05-06T20:42:01Z","containerID":"containerd://46dc1c3dead976b5cc6e5f6a8dc86988e8ce401e6fd903d4637848dd4baac0c4"}},"lastState":{},"ready":false,"restartCount":0,"image":"docker.io/library/hello-world:latest","imageID":"docker.io/library/hello-world@sha256:8e3114318a995a1ee497790535e7b88365222a21771ae7e53687ad76563e8e76","containerID":"containerd://46dc1c3dead976b5cc6e5f6a8dc86988e8ce401e6fd903d4637848dd4baac0c4","started":false}],"qosClass":"Burstable"}},"oldObject":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"2b42971e-6fcf-41a7-ae44-80963f957eae","resourceVersion":"3438","creationTimestamp":"2020-05-06T20:41:37Z","labels":{"allow-updates":"false","something":"hereeeeeseee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\
userInfo: []byte(`{"roles":["kube-system:kubeadm:kubelet-config-1.17","kube-system:kubeadm:nodes-kubeadm-config"],"clusterRoles":["system:basic-user","system:certificates.k8s.io:certificatesigningrequests:selfnodeclient","system:public-info-viewer","system:discovery"],"userInfo":{"username":"kubernetes-admin","groups":["system:authenticated"]}}`),
requestDenied: true,
2020-05-06 21:05:24 +00:00
},
{
description: "Blocks update requests for resources with label allow-updates(failure case)",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"block-updates-failure"},"spec":{"validationFailureAction":"enforce","background":false,"rules":[{"name":"check-allow-deletes","match":{"resources":{"selector":{"matchLabels":{"allow-deletes":"false"}}}},"exclude":{"clusterRoles":["random"]},"validate":{"message":"Deleting {{request.oldObject.kind}} / {{request.oldObject.metadata.name}} is not allowed","deny":{"conditions":{"all":[{"key":"{{request.operation}}","operator":"Equal","value":"DELETE"}]}}}}]}}`),
2020-05-06 21:05:24 +00:00
request: []byte(`{"uid":"9c284cdb-b0de-42aa-adf5-649a44bc861b","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"name":"hello-world","namespace":"default","operation":"CREATE","userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]},"object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"41a928a7-73f4-419f-bd64-de11f4f0a8ca","creationTimestamp":"2020-05-06T20:43:50Z","labels":{"allow-updates":"false","something":"hereeeeeseee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"hereeeeeseee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj"}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Pending","qosClass":"Burstable"}},"oldObject":null,"dryRun":false,"options":{"kind":"CreateOptions","apiVersion":"meta.k8s.io/v1"}}`),
userInfo: []byte(`{"roles":null,"clusterRoles":["system:public-info-viewer","cluster-admin","system:discovery","system:basic-user"],"userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}}`),
2020-05-19 17:32:42 +00:00
requestDenied: false,
2020-05-06 21:05:24 +00:00
},
2020-12-23 23:10:07 +00:00
}
for _, testcase := range testcases {
executeTest(t, testcase)
2020-12-23 23:10:07 +00:00
}
}
func Test_denyFeatureIssue744_DenyAll(t *testing.T) {
testcases := []testCase{
{
description: "Deny all requests on a namespace",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"block-request"},"spec":{"validationFailureAction":"enforce","rules":[{"name":"block-request","match":{"resources":{"namespaces":["kube-system"]}},"validate":{"deny":{}}}]}}`),
request: []byte(`{"uid":"2cf2b192-2c25-4f14-ac3a-315408d398f2","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"name":"hello-world","namespace":"default","operation":"UPDATE","userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]},"object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"f5c33eaf-79d8-4bc0-8819-749b3606012c","resourceVersion":"5470","creationTimestamp":"2020-05-06T20:57:15Z","labels":{"allow-updates":"false","something":"existes","something2":"feeereeeeeeeee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"existes\",\"something2\":\"feeereeeeeeeee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","nodeName":"kind-control-plane","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Pending","conditions":[{"type":"Initialized","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:57:15Z"},{"type":"Ready","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:57:15Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"ContainersReady","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:57:15Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"PodScheduled","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:57:15Z"}],"hostIP":"172.17.0.2","startTime":"2020-05-06T20:57:15Z","containerStatuses":[{"name":"hello-world","state":{"waiting":{"reason":"ContainerCreating"}},"lastState":{},"ready":false,"restartCount":0,"image":"hello-world:latest","imageID":"","started":false}],"qosClass":"Burstable"}},"oldObject":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"f5c33eaf-79d8-4bc0-8819-749b3606012c","resourceVersion":"5470","creationTimestamp":"2020-05-06T20:57:15Z","labels":{"allow-updates":"false","something":"existes","something2":"feeereeeeeeeee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"existes\",\"something2\":\"feeereeeeeeeee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}
userInfo: []byte(`{"roles":null,"clusterRoles":null,"userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}}`),
requestDenied: false,
},
}
for _, testcase := range testcases {
executeTest(t, testcase)
2020-12-23 23:10:07 +00:00
}
}
func Test_denyFeatureIssue744_BlockFields(t *testing.T) {
testcases := []testCase{
2020-05-06 21:05:24 +00:00
{
description: "Blocks certain fields(success case)",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"prevent-field-update-success"},"spec":{"validationFailureAction":"enforce","background":false,"rules":[{"name":"prevent-field-update","match":{"resources":{"selector":{"matchLabels":{"allow-updates":"false"}}}},"validate":{"message":"Updating field label 'something' is not allowed","deny":{"conditions":{"all":[{"key":"{{request.object.metadata.labels.something}}","operator":"NotEqual","value":""},{"key":"{{request.object.metadata.labels.something}}","operator":"NotEquals","value":"{{request.oldObject.metadata.labels.something}}"}]}}}}]}}`),
2020-05-06 21:05:24 +00:00
request: []byte(`{"uid":"11d46f83-a31b-444e-8209-c43b24f1af8a","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"name":"hello-world","namespace":"default","operation":"UPDATE","userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]},"object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"42bd0f0a-4b1f-4f7c-a40d-4dbed5522732","resourceVersion":"4333","creationTimestamp":"2020-05-06T20:51:58Z","labels":{"allow-updates":"false","something":"existes","something2":"feeereeeeeeeee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"existes\",\"something2\":\"feeereeeeeeeee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Pending","qosClass":"Burstable"}},"oldObject":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"42bd0f0a-4b1f-4f7c-a40d-4dbed5522732","resourceVersion":"4333","creationTimestamp":"2020-05-06T20:51:58Z","labels":{"allow-updates":"false","something":"exists","something2":"feeereeeeeeeee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"exists\",\"something2\":\"feeereeeeeeeee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node
userInfo: []byte(`{"roles":null,"clusterRoles":null,"userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}}`),
2020-05-19 17:32:42 +00:00
requestDenied: true,
2020-05-06 21:05:24 +00:00
},
{
description: "Blocks certain fields(failure case)",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"prevent-field-update-failure"},"spec":{"validationFailureAction":"enforce","background":false,"rules":[{"name":"prevent-field-update","match":{"resources":{"selector":{"matchLabels":{"allow-updates":"false"}}}},"validate":{"message":"Updating field label 'something' is not allowed","deny":{"conditions":{"all":[{"key":"{{request.object.metadata.labels.something}}","operator":"NotEqual","value":""},{"key":"{{request.object.metadata.labels.something}}","operator":"NotEquals","value":"{{request.oldObject.metadata.labels.something}}"}]}}}}]}}`),
2020-05-06 21:05:24 +00:00
request: []byte(`{"uid":"cbdce9bb-741d-466a-a440-36155eb4b45b","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"name":"hello-world","namespace":"kube-system","operation":"CREATE","userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]},"object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"kube-system","uid":"490c240c-f96a-4d5a-8860-75597bab0a7e","creationTimestamp":"2020-05-06T21:01:50Z","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"hello-world\",\"namespace\":\"kube-system\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-8h2h8","secret":{"secretName":"default-token-8h2h8"}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-8h2h8","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Pending","qosClass":"Burstable"}},"oldObject":null,"dryRun":false,"options":{"kind":"CreateOptions","apiVersion":"meta.k8s.io/v1"}}`),
userInfo: []byte(`{"roles":null,"clusterRoles":null,"userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}}`),
2020-05-19 17:32:42 +00:00
requestDenied: false,
2020-05-06 21:05:24 +00:00
},
2020-12-23 23:10:07 +00:00
}
for _, testcase := range testcases {
executeTest(t, testcase)
2020-12-23 23:10:07 +00:00
}
}
2020-12-23 23:57:12 +00:00
func Test_BlockLabelRemove(t *testing.T) {
testcases := []testCase{
{
description: "Blocks certain fields(success case)",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"prevent-label-remove"},"spec":{"validationFailureAction":"enforce","background":false,"rules":[{"name":"prevent-field-update","match":{"resources":{"selector":{"matchLabels":{"allow-updates":"false"}}}},"validate":{"message":"not allowed","deny":{"conditions":{"all":[{"key":"{{ request.operation }}","operator":"In","value":"[\"DELETE\", \"UPDATE\"]"}]}}}}]}}`),
2020-12-23 23:57:12 +00:00
request: []byte(`{"uid":"11d46f83-a31b-444e-8209-c43b24f1af8a","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"name":"hello-world","namespace":"default","operation":"UPDATE","userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]},"object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"42bd0f0a-4b1f-4f7c-a40d-4dbed5522732","resourceVersion":"4333","creationTimestamp":"2020-05-06T20:51:58Z","labels":{"something":"exists","something2":"feeereeeeeeeee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"existes\",\"something2\":\"feeereeeeeeeee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Pending","qosClass":"Burstable"}},"oldObject":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"42bd0f0a-4b1f-4f7c-a40d-4dbed5522732","resourceVersion":"4333","creationTimestamp":"2020-05-06T20:51:58Z","labels":{"allow-updates":"false","something":"exists","something2":"feeereeeeeeeee"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-updates\":\"false\",\"something\":\"exists\",\"something2\":\"feeereeeeeeeee\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachabl
userInfo: []byte(`{"roles":null,"clusterRoles":null,"userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}}`),
requestDenied: true,
},
}
for _, testcase := range testcases {
executeTest(t, testcase)
2020-12-23 23:57:12 +00:00
}
}
2020-12-23 23:10:07 +00:00
func Test_denyFeatureIssue744_BlockDelete(t *testing.T) {
testcases := []testCase{
2020-05-06 21:05:24 +00:00
{
2020-12-23 23:10:07 +00:00
description: "Blocks delete requests for resources with label allow-deletes(success case)",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"block-deletes-success"},"spec":{"validationFailureAction":"enforce","background":false,"rules":[{"name":"check-allow-deletes","match":{"resources":{"selector":{"matchLabels":{"allow-deletes":"false"}}}},"exclude":{"clusterRoles":["random"]},"validate":{"message":"Deleting {{request.oldObject.kind}} / {{request.oldObject.metadata.name}} is not allowed","deny":{"conditions":{"all":[{"key":"{{request.operation}}","operator":"Equal","value":"DELETE"}]}}}}]}}`),
2020-12-23 23:10:07 +00:00
request: []byte(`{"uid":"b553344a-172a-4257-8ec4-a8f379f8b844","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"name":"hello-world","namespace":"default","operation":"DELETE","userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]},"object":null,"oldObject":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"f093e3da-f13a-474f-87e8-43e98fe363bf","resourceVersion":"1983","creationTimestamp":"2020-05-06T20:28:43Z","labels":{"allow-deletes":"false"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-deletes\":\"false\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","nodeName":"kind-control-plane","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Pending","conditions":[{"type":"Initialized","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:28:43Z"},{"type":"Ready","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:28:43Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"ContainersReady","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:28:43Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"PodScheduled","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:28:43Z"}],"hostIP":"172.17.0.2","startTime":"2020-05-06T20:28:43Z","containerStatuses":[{"name":"hello-world","state":{"waiting":{"reason":"ContainerCreating"}},"lastState":{},"ready":false,"restartCount":0,"image":"hello-world:latest","imageID":"","started":false}],"qosClass":"Burstable"}},"dryRun":false,"options":{"kind":"DeleteOptions","apiVersion":"meta.k8s.io/v1","gracePeriodSeconds":30,"propagationPolicy":"Background"}}`),
userInfo: []byte(`{"roles":null,"clusterRoles":["cluster-admin","system:basic-user","system:discovery","system:public-info-viewer"],"userInfo":{"username":"kubernetes-admin","groups":["system:masters","system:authenticated"]}}`),
requestDenied: true,
},
{
description: "Blocks delete requests for resources with label allow-deletes(failure case)",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"ClusterPolicy","metadata":{"name":"block-deletes-failure"},"spec":{"validationFailureAction":"enforce","background":false,"rules":[{"name":"check-allow-deletes","match":{"resources":{"selector":{"matchLabels":{"allow-deletes":"false"}}}},"exclude":{"clusterRoles":["random"]},"validate":{"message":"Deleting {{request.oldObject.kind}} / {{request.oldObject.metadata.name}} is not allowed","deny":{"conditions":{"all":[{"key":"{{request.operation}}","operator":"Equal","value":"DELETE"}]}}}}]}}`),
2020-12-23 23:10:07 +00:00
request: []byte(`{"uid":"9a83234d-95d1-4105-b6bf-7d72fd0183ce","kind":{"group":"","version":"v1","kind":"Pod"},"resource":{"group":"","version":"v1","resource":"pods"},"subResource":"status","requestKind":{"group":"","version":"v1","kind":"Pod"},"requestResource":{"group":"","version":"v1","resource":"pods"},"requestSubResource":"status","name":"hello-world","namespace":"default","operation":"UPDATE","userInfo":{"username":"system:node:kind-control-plane","groups":["system:nodes","system:authenticated"]},"object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"10fb7e1f-3710-43fa-9b7d-fc532b5ff70e","resourceVersion":"2829","creationTimestamp":"2020-05-06T20:36:51Z","labels":{"allow-deletes":"false"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-deletes\":\"false\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","image":"hello-world:latest","ports":[{"containerPort":80,"protocol":"TCP"}],"resources":{"limits":{"cpu":"200m","memory":"30Mi"},"requests":{"cpu":"100m","memory":"20Mi"}},"volumeMounts":[{"name":"default-token-4q2mj","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"Always"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","serviceAccountName":"default","serviceAccount":"default","nodeName":"kind-control-plane","securityContext":{},"schedulerName":"default-scheduler","tolerations":[{"key":"node.kubernetes.io/not-ready","operator":"Exists","effect":"NoExecute","tolerationSeconds":300},{"key":"node.kubernetes.io/unreachable","operator":"Exists","effect":"NoExecute","tolerationSeconds":300}],"priority":0,"enableServiceLinks":true},"status":{"phase":"Pending","conditions":[{"type":"Initialized","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:36:51Z"},{"type":"Ready","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:36:51Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"ContainersReady","status":"False","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:36:51Z","reason":"ContainersNotReady","message":"containers with unready status: [hello-world]"},{"type":"PodScheduled","status":"True","lastProbeTime":null,"lastTransitionTime":"2020-05-06T20:36:51Z"}],"hostIP":"172.17.0.2","startTime":"2020-05-06T20:36:51Z","containerStatuses":[{"name":"hello-world","state":{"waiting":{"reason":"ContainerCreating"}},"lastState":{},"ready":false,"restartCount":0,"image":"hello-world:latest","imageID":"","started":false}],"qosClass":"Burstable"}},"oldObject":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"hello-world","namespace":"default","uid":"10fb7e1f-3710-43fa-9b7d-fc532b5ff70e","resourceVersion":"2829","creationTimestamp":"2020-05-06T20:36:51Z","labels":{"allow-deletes":"false"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"labels\":{\"allow-deletes\":\"false\"},\"name\":\"hello-world\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"image\":\"hello-world:latest\",\"name\":\"hello-world\",\"ports\":[{\"containerPort\":80}],\"resources\":{\"limits\":{\"cpu\":\"0.2\",\"memory\":\"30Mi\"},\"requests\":{\"cpu\":\"0.1\",\"memory\":\"20Mi\"}}}]}}\n"}},"spec":{"volumes":[{"name":"default-token-4q2mj","secret":{"secretName":"default-token-4q2mj","defaultMode":420}}],"containers":[{"name":"hello-world","
userInfo: []byte(`{"roles":["kube-system:kubeadm:nodes-kubeadm-config","kube-system:kubeadm:kubelet-config-1.17"],"clusterRoles":["system:discovery","system:certificates.k8s.io:certificatesigningrequests:selfnodeclient","system:public-info-viewer","system:basic-user"],"userInfo":{"username":"kubernetes-admin","groups":["system:nodes","system:authenticated"]}}`),
2020-05-19 17:32:42 +00:00
requestDenied: false,
2020-05-06 21:05:24 +00:00
},
}
for _, testcase := range testcases {
executeTest(t, testcase)
2020-12-23 23:10:07 +00:00
}
}
2020-05-06 21:05:24 +00:00
func executeTest(t *testing.T, test testCase) {
2020-12-23 23:10:07 +00:00
var policy kyverno.ClusterPolicy
err := json.Unmarshal(test.policy, &policy)
2020-12-23 23:10:07 +00:00
if err != nil {
t.Fatal(err)
}
2020-05-06 21:05:24 +00:00
var request *admissionv1.AdmissionRequest
2020-12-23 23:10:07 +00:00
err = json.Unmarshal(test.request, &request)
if err != nil {
t.Fatal(err)
}
2020-05-06 21:05:24 +00:00
feat: mutate existing resources (#3669) * feat: mutate existing, replace GR by UR in webhook server (#3601) * add attributes for post mutation Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR informer to webhook server Signed-off-by: ShutingZhao <shuting@nirmata.com> * - replace gr with ur in the webhook server; - create ur for mutateExsiting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace gr by ur across entire packages Signed-off-by: ShutingZhao <shuting@nirmata.com> * add YAMLs Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs & fix unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR deletion handler Signed-off-by: ShutingZhao <shuting@nirmata.com> * add api docs for v1beta1 Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix clientset method Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix v1beta1 client registration Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing - generates UR for admission requests (#3623) Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace with UR in policy controller generate rules (#3635) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * - enable mutate engine to process mutateExisting rules; - add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * implemented ur background reconciliation for mutateExisting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix webhook update error Signed-off-by: ShutingZhao <shuting@nirmata.com> * temporary comment out new unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing, replace GR by UR in webhook server (#3601) * add attributes for post mutation Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR informer to webhook server Signed-off-by: ShutingZhao <shuting@nirmata.com> * - replace gr with ur in the webhook server; - create ur for mutateExsiting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace gr by ur across entire packages Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix missing policy.kyverno.io/policy-name label (#3599) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * refactor cli code from pkg to cmd (#3591) * refactor cli code from pkg to cmd Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixes in imports Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixes tests Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * fixed conflicts Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> * moved non-commands to utils Signed-off-by: Mritunjay Sharma <mritunjaysharma394@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> * add YAMLs Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs & fix unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * add UR deletion handler Signed-off-by: ShutingZhao <shuting@nirmata.com> * add api docs for v1beta1 Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix clientset method Signed-off-by: ShutingZhao <shuting@nirmata.com> * add-kms-libraries for cosign (#3603) * add-kms-libraries Signed-off-by: anushkamittal20 <anumittal4641@gmail.com> * Shifted providers to cosign package Signed-off-by: anushkamittal20 <anumittal4641@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Add support for custom image extractors (#3596) Signed-off-by: Sambhav Kothari <skothari44@bloomberg.net> * Update vulnerable dependencies (#3577) Signed-off-by: Shubham Gupta <shubham.gupta2956@gmail.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix v1beta1 client registration Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: mutate existing - generates UR for admission requests (#3623) Signed-off-by: ShutingZhao <shuting@nirmata.com> * updating version in Chart.yaml (#3618) * updatimg version in Chart.yaml Signed-off-by: Prateeknandle <prateeknandle@gmail.com> * changes from, make gen-helm Signed-off-by: Prateeknandle <prateeknandle@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Allow kyverno-policies to have preconditions defined (#3606) * Allow kyverno-policies to have preconditions defined Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Fix docs Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: ShutingZhao <shuting@nirmata.com> * replace with UR in policy controller generate rules (#3635) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * - enable mutate engine to process mutateExisting rules; - add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * implemented ur background reconciliation for mutateExisting policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix webhook update error Signed-off-by: ShutingZhao <shuting@nirmata.com> * temporary comment out new unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * Image verify attestors (#3614) * fix logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * support multiple attestors Signed-off-by: Jim Bugwadia <jim@nirmata.com> * rm CLI tests (not currently supported) Signed-off-by: Jim Bugwadia <jim@nirmata.com> * apply attestor repo Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix entryError assignment Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add intermediary certs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * Allow defining imagePullSecrets (#3633) * Allow defining imagePullSecrets Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Use dict for imagePullSecrets Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> * Simplify how imagePullSecrets is defined Signed-off-by: Trey Dockendorf <tdockendorf@osc.edu> Signed-off-by: ShutingZhao <shuting@nirmata.com> * Fix race condition in pCache (#3632) * fix race condition in pCache Signed-off-by: ShutingZhao <shuting@nirmata.com> * refact: remove unused Run function from generate (#3638) Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * Remove helm mode setting (#3628) Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * refactor: image utils (#3630) Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> * -resolve lift comments; -fix informer sync issue Signed-off-by: ShutingZhao <shuting@nirmata.com> * refact the update request cleanup controller Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com> * - fix delete request for mutateExisting; - fix context variable substitution; - improve logging Signed-off-by: ShutingZhao <shuting@nirmata.com> * - enable events; - add last applied annotation Signed-off-by: ShutingZhao <shuting@nirmata.com> * enable mutate existing on policy creation Signed-off-by: ShutingZhao <shuting@nirmata.com> * update autogen code Signed-off-by: ShutingZhao <shuting@nirmata.com> * merge main Signed-off-by: ShutingZhao <shuting@nirmata.com> * add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * address list comments Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix "Implicit memory aliasing in for loop" Signed-off-by: ShutingZhao <shuting@nirmata.com> * remove unused definitions Signed-off-by: ShutingZhao <shuting@nirmata.com> * update api docs Signed-off-by: ShutingZhao <shuting@nirmata.com> Co-authored-by: Prateek Pandey <prateek.pandey@nirmata.com> Co-authored-by: Mritunjay Kumar Sharma <mritunjaysharma394@gmail.com> Co-authored-by: Vyankatesh Kudtarkar <vyankateshkd@gmail.com> Co-authored-by: Anushka Mittal <55237170+anushkamittal20@users.noreply.github.com> Co-authored-by: Sambhav Kothari <sambhavs.email@gmail.com> Co-authored-by: Shubham Gupta <shubham.gupta2956@gmail.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Prateek Nandle <56027872+Prateeknandle@users.noreply.github.com> Co-authored-by: treydock <tdockendorf@osc.edu> Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
2022-04-25 12:20:40 +00:00
var userInfo urkyverno.RequestInfo
2020-12-23 23:10:07 +00:00
err = json.Unmarshal(test.userInfo, &userInfo)
if err != nil {
t.Fatal(err)
}
2020-05-06 21:05:24 +00:00
2020-12-23 23:10:07 +00:00
ctx := context.NewContext()
err = ctx.AddRequest(request)
if err != nil {
t.Fatal(err)
}
2020-05-06 21:05:24 +00:00
2020-12-23 23:10:07 +00:00
err = ctx.AddUserInfo(userInfo)
if err != nil {
t.Fatal(err)
}
err = ctx.AddServiceAccount(userInfo.AdmissionUserInfo.Username)
if err != nil {
t.Fatal(err)
}
newR, oldR, err := utils2.ExtractResources(nil, request)
if err != nil {
t.Fatal(err)
}
pc := &PolicyContext{
Policy: &policy,
2020-12-23 23:10:07 +00:00
NewResource: newR,
OldResource: oldR,
AdmissionInfo: userInfo,
JSONContext: ctx,
}
2020-05-19 17:32:42 +00:00
2020-12-23 23:10:07 +00:00
resp := Validate(pc)
if resp.IsSuccessful() && test.requestDenied {
2020-05-19 17:32:42 +00:00
t.Errorf("Testcase has failed, policy: %v", policy.Name)
2020-05-06 21:05:24 +00:00
}
}
func TestValidate_context_variable_substitution_CLI(t *testing.T) {
rawPolicy := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "restrict-pod-count"
},
"spec": {
"validationFailureAction": "enforce",
"background": false,
"rules": [
{
"name": "restrict-pod-count",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"context": [
{
"name": "podcounts",
"apiCall": {
"urlPath": "/api/v1/pods",
"jmesPath": "items[?spec.nodeName=='minikube'] | length(@)"
}
}
],
"validate": {
"message": "restrict pod counts to be no more than 10 on node minikube",
"deny": {
"conditions": [
{
"key": "{{ podcounts }}",
"operator": "GreaterThanOrEquals",
"value": 10
}
]
}
}
}
]
}
}
`)
rawResource := []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "nginx-config-test"
},
"spec": {
"containers": [
{
"image": "nginx:latest",
"name": "test-nginx"
}
]
}
}
`)
configMapVariableContext := store.Context{
Policies: []store.Policy{
{
Name: "restrict-pod-count",
Rules: []store.Rule{
{
Name: "restrict-pod-count",
Values: map[string]interface{}{
"podcounts": "12",
},
},
},
},
},
}
store.SetContext(configMapVariableContext)
store.SetMock(true)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(rawResource)
assert.NilError(t, err)
msgs := []string{
"restrict pod counts to be no more than 10 on node minikube",
}
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: context.NewContext()})
for index, r := range er.PolicyResponse.Rules {
assert.Equal(t, r.Message, msgs[index])
}
assert.Assert(t, !er.IsSuccessful())
}
func Test_EmptyStringInDenyCondition(t *testing.T) {
policyRaw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"annotations": {
"meta.helm.sh/release-name": "kyverno-policies",
"meta.helm.sh/release-namespace": "kyverno",
"pod-policies.kyverno.io/autogen-controllers": "none"
},
"labels": {
"app.kubernetes.io/managed-by": "Helm"
},
"name": "if-baltic-restrict-external-load-balancer"
},
"spec": {
"background": true,
"rules": [
{
"match": {
"resources": {
"kinds": [
"Service"
]
}
},
"name": "match-service-type",
"preconditions": [
{
"key": "{{request.object.spec.type}}",
"operator": "Equals",
"value": "LoadBalancer"
}
],
"validate": {
"deny": {
"conditions": [
{
"key": "{{ request.object.metadata.annotations.\"service.beta.kubernetes.io/azure-load-balancer-internal\"}}",
"operator": "NotEquals",
"value": "true"
}
]
}
}
}
],
"validationFailureAction": "enforce"
}
}`)
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "example-service"
},
"spec": {
"selector": {
"app": "example"
},
"ports": [
{
"port": 8765,
"targetPort": 9376
}
],
"type": "LoadBalancer"
}
}`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(policyRaw, &policy)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: ctx})
assert.Assert(t, !er.IsSuccessful())
}
func Test_StringInDenyCondition(t *testing.T) {
policyRaw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"annotations": {
"meta.helm.sh/release-name": "kyverno-policies",
"meta.helm.sh/release-namespace": "kyverno",
"pod-policies.kyverno.io/autogen-controllers": "none"
},
"labels": {
"app.kubernetes.io/managed-by": "Helm"
},
"name": "if-baltic-restrict-external-load-balancer"
},
"spec": {
"background": true,
"rules": [
{
"match": {
"resources": {
"kinds": [
"Service"
]
}
},
"name": "match-service-type",
"preconditions": [
{
"key": "{{request.object.spec.type}}",
"operator": "Equals",
"value": "LoadBalancer"
}
],
"validate": {
"deny": {
"conditions": [
{
"key": "{{ request.object.metadata.annotations.\"service.beta.kubernetes.io/azure-load-balancer-internal\"}}",
"operator": "NotEquals",
"value": "true"
}
]
}
}
}
],
"validationFailureAction": "enforce"
}
}`)
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "example-service",
"annotations": {
"service.beta.kubernetes.io/azure-load-balancer-internal": "true"
}
},
"spec": {
"selector": {
"app": "example"
},
"ports": [
{
"port": 8765,
"targetPort": 9376
}
],
"type": "LoadBalancer"
}
}`)
var policy kyverno.ClusterPolicy
err := json.Unmarshal(policyRaw, &policy)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
er := Validate(&PolicyContext{Policy: &policy, NewResource: *resourceUnstructured, JSONContext: ctx})
assert.Assert(t, er.IsSuccessful())
}
func Test_foreach_container_pass(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "pod1-valid", "image": "nginx/nginx:v1"},
{"name": "pod2-valid", "image": "nginx/nginx:v2"},
{"name": "pod3-valid", "image": "nginx/nginx:v3"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test"
},
"spec": {
"rules": [
{
"name": "test-path-not-exist",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"pattern": {
"name": "*-valid"
}
}
]
}
}
]
}
}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusPass)
}
func Test_foreach_container_fail(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "pod1-valid", "image": "nginx/nginx:v1"},
{"name": "pod2-invalid", "image": "nginx/nginx:v2"},
{"name": "pod3-valid", "image": "nginx/nginx:v3"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {"name": "test"},
"spec": {
"rules": [
{
"name": "test",
"match": {"resources": { "kinds": [ "Deployment" ] } },
"validate": {
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"pattern": {
"name": "*-valid"
}
}
]
}}]}}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusFail)
}
func Test_foreach_container_deny_fail(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "pod1-valid", "image": "nginx/nginx:v1"},
{"name": "pod2-invalid", "image": "docker.io/nginx/nginx:v2"},
{"name": "pod3-valid", "image": "nginx/nginx:v3"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test"
},
"spec": {
"rules": [
{
"name": "test",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"deny": {
"conditions": [
{
"key": "{{ regex_match('{{element.image}}', 'docker.io') }}",
"operator": "Equals",
"value": false
}
]
}
}
]
}
}
]
}
}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusFail)
}
func Test_foreach_container_deny_success(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "pod1-valid", "image": "nginx/nginx:v1"},
{"name": "pod2-invalid", "image": "nginx/nginx:v2"},
{"name": "pod3-valid", "image": "nginx/nginx:v3"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {"name": "test"},
"spec": {
"rules": [
{
"name": "test",
"match": {"resources": { "kinds": [ "Deployment" ] } },
"validate": {
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"deny": {
"conditions": [
{
"key": "{{ regex_match('{{element.image}}', 'docker.io') }}",
"operator": "Equals",
"value": false
}
]
}
}
]
}}]}}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusFail)
}
func Test_foreach_container_deny_error(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "pod1-valid", "image": "nginx/nginx:v1"},
{"name": "pod2-invalid", "image": "nginx/nginx:v2"},
{"name": "pod3-valid", "image": "nginx/nginx:v3"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test"
},
"spec": {
"rules": [
{
"name": "test",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"deny": {
"conditions": [
{
"key": "{{ regex_match_INVALID('{{request.object.image}}', 'docker.io') }}",
"operator": "Equals",
"value": false
}
]
}
}
]
}
}
]
}
}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusError)
}
func Test_foreach_context_preconditions(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "podvalid", "image": "nginx/nginx:v1"},
{"name": "podinvalid", "image": "nginx/nginx:v2"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test"
},
"spec": {
"rules": [
{
"name": "test",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"context": [
{
"name": "img",
"configMap": {
"name": "mycmap",
"namespace": "default"
}
}
],
"preconditions": {
"all": [
{
"key": "{{element.name}}",
"operator": "In",
"value": [
"podvalid"
]
}
]
},
"deny": {
"conditions": [
{
"key": "{{ element.image }}",
"operator": "NotEquals",
"value": "{{ img.data.{{ element.name }} }}"
}
]
}
}
]
}
}
]
}
}`)
configMapVariableContext := store.Context{
Policies: []store.Policy{
{
Name: "test",
Rules: []store.Rule{
{
Name: "test",
Values: map[string]interface{}{
"img.data.podvalid": "nginx/nginx:v1",
"img.data.podinvalid": "nginx/nginx:v2",
},
},
},
},
},
}
store.SetContext(configMapVariableContext)
store.SetMock(true)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusPass)
}
func Test_foreach_context_preconditions_fail(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "podvalid", "image": "nginx/nginx:v1"},
{"name": "podinvalid", "image": "nginx/nginx:v2"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "test"
},
"spec": {
"rules": [
{
"name": "test",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"context": [
{
"name": "img",
"configMap": {
"name": "mycmap",
"namespace": "default"
}
}
],
"preconditions": {
"all": [
{
"key": "{{element.name}}",
"operator": "In",
"value": [
"podvalid",
"podinvalid"
]
}
]
},
"deny": {
"conditions": [
{
"key": "{{ element.image }}",
"operator": "NotEquals",
"value": "{{ img.data.{{ element.name }} }}"
}
]
}
}
]
}
}
]
}
}`)
configMapVariableContext := store.Context{
Policies: []store.Policy{
{
Name: "test",
Rules: []store.Rule{
{
Name: "test",
Values: map[string]interface{}{
"img.data.podvalid": "nginx/nginx:v1",
"img.data.podinvalid": "nginx/nginx:v1",
},
},
},
},
},
}
store.SetContext(configMapVariableContext)
store.SetMock(true)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusFail)
}
func Test_foreach_element_validation(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "nginx"
},
"spec": {
"containers": [
{
"name": "nginx1",
"image": "nginx"
},
{
"name": "nginx2",
"image": "nginx"
}
]
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {"name": "check-container-names"},
"spec": {
"validationFailureAction": "enforce",
"background": false,
"rules": [
{
"name": "test",
"match": {"resources": { "kinds": [ "Pod" ] } },
"validate": {
"message": "Invalid name",
"foreach": [
{
"list": "request.object.spec.containers",
"pattern": {
"name": "{{ element.name }}"
}
}
]
}}]}}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusPass)
}
func Test_outof_foreach_element_validation(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "nginx"
},
"spec": {
"containers": [
{
"name": "nginx1",
"image": "nginx"
},
{
"name": "nginx2",
"image": "nginx"
}
]
}
}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {"name": "check-container-names"},
"spec": {
"validationFailureAction": "enforce",
"background": false,
"rules": [
{
"name": "test",
"match": {"resources": { "kinds": [ "Pod" ] } },
"validate": {
"message": "Invalid name",
"pattern": {
"name": "{{ element.name }}"
}
}}]}}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusError)
}
2021-10-19 10:04:53 +00:00
func Test_foreach_skip_initContainer_pass(t *testing.T) {
resourceRaw := []byte(`{"apiVersion": "v1",
"kind": "Deployment",
"metadata": {"name": "test"},
"spec": { "template": { "spec": {
"containers": [
{"name": "podvalid", "image": "nginx"}
]
}}}}`)
policyraw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-images"
},
"spec": {
"validationFailureAction": "enforce",
"background": false,
"rules": [
{
"name": "check-registry",
"match": {
"resources": {
"kinds": [
"Deployment"
]
}
},
"validate": {
"message": "unknown registry",
"foreach": [
{
"list": "request.object.spec.template.spec.containers",
"pattern": {
"image": "nginx"
}
},
{
"list": "request.object.spec.template.spec..initContainers",
"pattern": {
"image": "trusted-registry.io/*"
}
}
]
}
}
]
}
}`)
testForEach(t, policyraw, resourceRaw, "", response.RuleStatusPass)
}
func testForEach(t *testing.T, policyraw []byte, resourceRaw []byte, msg string, status response.RuleStatus) {
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyraw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
policyContext := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
er := Validate(policyContext)
assert.Equal(t, er.PolicyResponse.Rules[0].Status, status)
if msg != "" {
assert.Equal(t, er.PolicyResponse.Rules[0].Message, msg)
}
}
func Test_delete_ignore_pattern(t *testing.T) {
resourceRaw := []byte(`{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "nginx",
"labels": {"app.kubernetes.io/foo" : "myapp-pod"}
},
"spec": {
"containers": [
{
"name": "nginx1",
"image": "nginx"
},
{
"name": "nginx2",
"image": "nginx"
}
]
}
}`)
policyRaw := []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {"name": "check-container-labels"},
"spec": {
"validationFailureAction": "enforce",
"background": false,
"rules": [
{
"name": "test",
"match": {"resources": { "kinds": [ "Pod" ] } },
"validate": {
"message": "Invalid label",
"pattern": {
"metadata" : {
"labels": {"app.kubernetes.io/name" : "myapp-pod"}
}
}
}}]}}`)
var policy kyverno.ClusterPolicy
assert.NilError(t, json.Unmarshal(policyRaw, &policy))
resourceUnstructured, err := utils.ConvertToUnstructured(resourceRaw)
assert.NilError(t, err)
ctx := context.NewContext()
err = context.AddResource(ctx, resourceRaw)
assert.NilError(t, err)
policyContextCreate := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
NewResource: *resourceUnstructured}
engineResponseCreate := Validate(policyContextCreate)
assert.Equal(t, len(engineResponseCreate.PolicyResponse.Rules), 1)
assert.Equal(t, engineResponseCreate.PolicyResponse.Rules[0].Status, response.RuleStatusFail)
policyContextDelete := &PolicyContext{
Policy: &policy,
JSONContext: ctx,
OldResource: *resourceUnstructured}
engineResponseDelete := Validate(policyContextDelete)
assert.Equal(t, len(engineResponseDelete.PolicyResponse.Rules), 0)
}
func Test_block_bypass(t *testing.T) {
testcases := []testCase{
{
description: "Blocks bypass of policy by manipulating pre-conditions",
policy: []byte(`{"apiVersion":"kyverno.io/v1","kind":"Policy","metadata":{"name":"configmap-policy"},"spec":{"rules":[{"match":{"resources":{"kinds":["ConfigMap"]}},"name":"key-abc","preconditions":{"any":[{"key":"admin","operator":"Equals","value":"{{request.object.data.lock}}"}]},"validate":{"anyPattern":[{"data":{"key":"abc"}}],"message":"Configmap key must be \"abc\""}}]}}`),
request: []byte(`{"uid":"7b0600b7-0258-4ecb-9666-c2839bd19612","kind":{"group":"","version":"v1","kind":"ConfigMap"},"resource":{"group":"","version":"v1","resource":"configmaps"},"subResource":"status","requestKind":{"group":"","version":"v1","kind":"configmaps"},"requestResource":{"group":"","version":"v1","resource":"configmaps"},"name":"test-configmap","namespace":"default","operation":"UPDATE","userInfo":{"username":"system:node:kind-control-plane","groups":["system:authenticated"]},"object":{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"test-configmap"},"data":{"key":"xyz","lock":"admin"}},"oldObject":{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"test-configmap"},"data":{"key":"xyz"}},"dryRun":false,"options":{"kind":"UpdateOptions","apiVersion":"meta.k8s.io/v1"}}`),
userInfo: []byte(`{"roles":["kube-system:kubeadm:kubelet-config-1.17","kube-system:kubeadm:nodes-kubeadm-config"],"clusterRoles":["system:basic-user","system:certificates.k8s.io:certificatesigningrequests:selfnodeclient","system:public-info-viewer","system:discovery"],"userInfo":{"username":"kubernetes-admin","groups":["system:authenticated"]}}`),
requestDenied: true,
},
}
for _, testcase := range testcases {
executeTest(t, testcase)
}
}