diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index d1aa7c6288..9e7dc29588 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -40,6 +40,16 @@ jobs: exit 1 fi + - name: goimports + run: | + if [ "$(goimports -l . | wc -l)" -ne 0 ] + then + echo "The following files were found to have import formatting issues:" + goimports -l -l . + echo "Please run 'make fmt' to go format the above files." + exit 1 + fi + - name: golangci-lint uses: reviewdog/action-golangci-lint@v1 @@ -115,7 +125,7 @@ jobs: - name: Trivy Scan Image uses: aquasecurity/trivy-action@master - with: + with: image-ref: 'ghcr.io/kyverno/kyverno:latest' format: 'table' exit-code: '1' diff --git a/Makefile b/Makefile index e0ca884294..7791d41cd5 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ docker-publish-sbom: docker-build-sbom docker-push-sbom docker-build-sbom: @docker buildx build --file $(PWD)/$(ALPINE_PATH)/Dockerfile --tag $(REPO)/$(SBOM_IMAGE):$(IMAGE_TAG) . -docker-push-signature: +docker-push-sbom: @docker buildx build --file $(PWD)/$(ALPINE_PATH)/Dockerfile --push --tag $(REPO)/$(SBOM_IMAGE):$(IMAGE_TAG) . @docker buildx build --file $(PWD)/$(ALPINE_PATH)/Dockerfile --push --tag $(REPO)/$(SBOM_IMAGE):latest . @@ -308,9 +308,20 @@ endif deepcopy-autogen: controller-gen $(CONTROLLER_GEN) object:headerFile="scripts/boilerplate.go.txt" paths="./..." +goimports: +ifeq (, $(shell which goimports)) + @{ \ + echo "goimports not found!";\ + echo "installing goimports...";\ + go get golang.org/x/tools/cmd/goimports;\ + } +else +GO_IMPORTS=$(shell which goimports) +endif + # Run go fmt against code -fmt: - gofmt -s -w . +fmt: goimports + go fmt ./... && $(GO_IMPORTS) -w ./ vet: go vet ./... diff --git a/charts/kyverno-policies/templates/default/disallow-adding-capabilities.yaml b/charts/kyverno-policies/templates/default/disallow-adding-capabilities.yaml index c477ee0b5e..1405f91e68 100644 --- a/charts/kyverno-policies/templates/default/disallow-adding-capabilities.yaml +++ b/charts/kyverno-policies/templates/default/disallow-adding-capabilities.yaml @@ -26,7 +26,7 @@ spec: validate: message: >- Adding of additional capabilities beyond the default set is not allowed. - The fields spec.containers[*].securityContext.capabilities.add and + The fields spec.containers[*].securityContext.capabilities.add and spec.initContainers[*].securityContext.capabilities.add must be empty. pattern: spec: diff --git a/charts/kyverno-policies/templates/default/disallow-host-namespaces.yaml b/charts/kyverno-policies/templates/default/disallow-host-namespaces.yaml index 8adb1a5ff2..44af945405 100644 --- a/charts/kyverno-policies/templates/default/disallow-host-namespaces.yaml +++ b/charts/kyverno-policies/templates/default/disallow-host-namespaces.yaml @@ -9,7 +9,7 @@ metadata: {{- if .Values.podSecuritySeverity }} policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }} {{- end }} - policies.kyverno.io/description: >- + policies.kyverno.io/description: >- Host namespaces (Process ID namespace, Inter-Process Communication namespace, and network namespace) allow access to shared information and can be used to elevate privileges. Pods should not be allowed access to host namespaces. @@ -33,4 +33,4 @@ spec: =(hostPID): "false" =(hostIPC): "false" =(hostNetwork): "false" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/default/disallow-host-path.yaml b/charts/kyverno-policies/templates/default/disallow-host-path.yaml index 20728232c3..b09aa068d9 100644 --- a/charts/kyverno-policies/templates/default/disallow-host-path.yaml +++ b/charts/kyverno-policies/templates/default/disallow-host-path.yaml @@ -31,4 +31,4 @@ spec: spec: =(volumes): - X(hostPath): "null" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/default/disallow-host-ports.yaml b/charts/kyverno-policies/templates/default/disallow-host-ports.yaml index 990f3d63bd..3df228294b 100644 --- a/charts/kyverno-policies/templates/default/disallow-host-ports.yaml +++ b/charts/kyverno-policies/templates/default/disallow-host-ports.yaml @@ -35,4 +35,4 @@ spec: containers: - =(ports): - X(hostPort): 0 -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/default/disallow-privileged-containers.yaml b/charts/kyverno-policies/templates/default/disallow-privileged-containers.yaml index dd5eeceb6e..cd7de1016f 100644 --- a/charts/kyverno-policies/templates/default/disallow-privileged-containers.yaml +++ b/charts/kyverno-policies/templates/default/disallow-privileged-containers.yaml @@ -30,8 +30,8 @@ spec: spec: =(initContainers): - =(securityContext): - =(privileged): "false" + =(privileged): "false" containers: - =(securityContext): =(privileged): "false" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/default/disallow-proc-mount.yaml b/charts/kyverno-policies/templates/default/disallow-proc-mount.yaml index 3a7288d6dd..36dbc276e2 100644 --- a/charts/kyverno-policies/templates/default/disallow-proc-mount.yaml +++ b/charts/kyverno-policies/templates/default/disallow-proc-mount.yaml @@ -26,7 +26,7 @@ spec: message: >- Changing the proc mount from the default is not allowed. The fields spec.containers[*].securityContext.procMount and - spec.initContainers[*].securityContext.procMount must not be changed + spec.initContainers[*].securityContext.procMount must not be changed from `Default`. pattern: spec: @@ -36,4 +36,4 @@ spec: containers: - =(securityContext): =(procMount): "Default" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/default/disallow-selinux.yaml b/charts/kyverno-policies/templates/default/disallow-selinux.yaml index 952096ec11..6a20a7d283 100644 --- a/charts/kyverno-policies/templates/default/disallow-selinux.yaml +++ b/charts/kyverno-policies/templates/default/disallow-selinux.yaml @@ -38,4 +38,4 @@ spec: containers: - =(securityContext): X(seLinuxOptions): "null" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/default/restrict-apparmor-profiles.yaml b/charts/kyverno-policies/templates/default/restrict-apparmor-profiles.yaml index 441c2cd6f6..105f37d9de 100644 --- a/charts/kyverno-policies/templates/default/restrict-apparmor-profiles.yaml +++ b/charts/kyverno-policies/templates/default/restrict-apparmor-profiles.yaml @@ -11,8 +11,8 @@ metadata: policies.kyverno.io/severity: {{ .Values.podSecuritySeverity | quote }} {{- end }} policies.kyverno.io/description: >- - On supported hosts, the 'runtime/default' AppArmor profile is applied by default. - The default policy should prevent overriding or disabling the policy, or restrict + On supported hosts, the 'runtime/default' AppArmor profile is applied by default. + The default policy should prevent overriding or disabling the policy, or restrict overrides to an allowed set of profiles. labels: {{ include "kyverno-policies.labels" . | nindent 4 }} app: kyverno @@ -34,4 +34,4 @@ spec: metadata: =(annotations): =(container.apparmor.security.beta.kubernetes.io/*): "runtime/default" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/default/restrict-sysctls.yaml b/charts/kyverno-policies/templates/default/restrict-sysctls.yaml index 30e4a4b709..7988c76d8a 100644 --- a/charts/kyverno-policies/templates/default/restrict-sysctls.yaml +++ b/charts/kyverno-policies/templates/default/restrict-sysctls.yaml @@ -37,4 +37,4 @@ spec: =(sysctls): - name: "kernel.shm_rmid_forced | net.ipv4.ip_local_port_range | net.ipv4.tcp_syncookies | net.ipv4.ping_group_range" value: "?*" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/restricted/deny-privilege-escalation.yaml b/charts/kyverno-policies/templates/restricted/deny-privilege-escalation.yaml index ca14e6b926..ace894f3aa 100644 --- a/charts/kyverno-policies/templates/restricted/deny-privilege-escalation.yaml +++ b/charts/kyverno-policies/templates/restricted/deny-privilege-escalation.yaml @@ -36,4 +36,4 @@ spec: containers: - =(securityContext): =(allowPrivilegeEscalation): "false" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/restricted/require-non-root-groups.yaml b/charts/kyverno-policies/templates/restricted/require-non-root-groups.yaml index c8bb037dda..81958fe392 100644 --- a/charts/kyverno-policies/templates/restricted/require-non-root-groups.yaml +++ b/charts/kyverno-policies/templates/restricted/require-non-root-groups.yaml @@ -24,9 +24,9 @@ spec: - Pod validate: message: >- - Running with root group IDs is disallowed. The fields - spec.securityContext.runAsGroup, spec.containers[*].securityContext.runAsGroup, - and spec.initContainers[*].securityContext.runAsGroup must be empty + Running with root group IDs is disallowed. The fields + spec.securityContext.runAsGroup, spec.containers[*].securityContext.runAsGroup, + and spec.initContainers[*].securityContext.runAsGroup must be empty or greater than zero. pattern: spec: @@ -45,7 +45,7 @@ spec: - Pod validate: message: >- - Adding of supplemental group IDs is not allowed. The field + Adding of supplemental group IDs is not allowed. The field spec.securityContext.supplementalGroups must not be defined. pattern: spec: @@ -64,4 +64,4 @@ spec: spec: =(securityContext): =(fsGroup): ">0" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/restricted/require-run-as-nonroot.yaml b/charts/kyverno-policies/templates/restricted/require-run-as-nonroot.yaml index 25973be98b..8982e91df1 100644 --- a/charts/kyverno-policies/templates/restricted/require-run-as-nonroot.yaml +++ b/charts/kyverno-policies/templates/restricted/require-run-as-nonroot.yaml @@ -35,12 +35,12 @@ spec: =(runAsNonRoot): true =(initContainers): - =(securityContext): - =(runAsNonRoot): true + =(runAsNonRoot): true - spec: containers: - securityContext: runAsNonRoot: true =(initContainers): - securityContext: - runAsNonRoot: true -{{- end -}} \ No newline at end of file + runAsNonRoot: true +{{- end -}} diff --git a/charts/kyverno-policies/templates/restricted/restrict-seccomp.yaml b/charts/kyverno-policies/templates/restricted/restrict-seccomp.yaml index d0c1d6952c..bfe9085308 100644 --- a/charts/kyverno-policies/templates/restricted/restrict-seccomp.yaml +++ b/charts/kyverno-policies/templates/restricted/restrict-seccomp.yaml @@ -44,4 +44,4 @@ spec: - =(securityContext): =(seccompProfile): =(type): "runtime/default" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno-policies/templates/restricted/restrict-volume-types.yaml b/charts/kyverno-policies/templates/restricted/restrict-volume-types.yaml index 9ebca924bc..abb0c55a41 100644 --- a/charts/kyverno-policies/templates/restricted/restrict-volume-types.yaml +++ b/charts/kyverno-policies/templates/restricted/restrict-volume-types.yaml @@ -278,4 +278,4 @@ spec: spec: =(volumes): - X(csi): "null" -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/charts/kyverno/templates/clusterrole.yaml b/charts/kyverno/templates/clusterrole.yaml index 8c0c7ee7eb..ac849a985d 100644 --- a/charts/kyverno/templates/clusterrole.yaml +++ b/charts/kyverno/templates/clusterrole.yaml @@ -36,7 +36,7 @@ rules: verbs: - create - delete - - get + - get - list - patch - update @@ -52,7 +52,7 @@ rules: verbs: - create - delete - - get + - get - update - watch - apiGroups: @@ -62,7 +62,7 @@ rules: resourceNames: - kubernetes.io/legacy-unknown verbs: - - approve + - approve --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -125,7 +125,7 @@ rules: - customresourcedefinitions verbs: - delete ---- +--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -226,4 +226,4 @@ rules: - reportchangerequests - clusterreportchangerequests verbs: - - "*" \ No newline at end of file + - "*" diff --git a/charts/kyverno/templates/poddisruptionbudget.yaml b/charts/kyverno/templates/poddisruptionbudget.yaml index a21df84807..5ba0cd08ba 100644 --- a/charts/kyverno/templates/poddisruptionbudget.yaml +++ b/charts/kyverno/templates/poddisruptionbudget.yaml @@ -11,4 +11,4 @@ spec: selector: matchLabels: {{ include "kyverno.matchLabels" . | nindent 6 }} app: kyverno -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/kyverno/templates/servicemonitor.yaml b/charts/kyverno/templates/servicemonitor.yaml index 769c98b176..6c09faf85d 100644 --- a/charts/kyverno/templates/servicemonitor.yaml +++ b/charts/kyverno/templates/servicemonitor.yaml @@ -34,4 +34,4 @@ spec: tlsConfig: {{- toYaml .Values.serviceMonitor.tlsConfig | nindent 8 }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/cmd/cli/kubectl-kyverno/main.go b/cmd/cli/kubectl-kyverno/main.go index 3b85f44e94..3a5bf46832 100644 --- a/cmd/cli/kubectl-kyverno/main.go +++ b/cmd/cli/kubectl-kyverno/main.go @@ -1,8 +1,6 @@ package main -import ( - "github.com/kyverno/kyverno/pkg/kyverno" -) +import "github.com/kyverno/kyverno/pkg/kyverno" func main() { kyverno.CLI() diff --git a/go.mod b/go.mod index e52b2d8839..7ed90b39de 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/spf13/cobra v1.2.1 github.com/stretchr/testify v1.7.0 github.com/xanzy/ssh-agent v0.3.0 // indirect + golang.org/x/tools v0.1.7 // indirect gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gotest.tools v2.2.0+incompatible diff --git a/go.sum b/go.sum index d82b6e102d..e6db7f580d 100644 --- a/go.sum +++ b/go.sum @@ -1721,6 +1721,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= @@ -1990,6 +1991,7 @@ golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210505214959-0714010a04ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg= golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -2156,6 +2158,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b h1:3Dq0eVHn0uaQJmPO+/aYPI/fRMqdrVDbu7MQcku54gg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2278,6 +2281,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/api/kyverno/v1/generaterequest_types.go b/pkg/api/kyverno/v1/generaterequest_types.go index 8f1f53452f..af686d7e82 100644 --- a/pkg/api/kyverno/v1/generaterequest_types.go +++ b/pkg/api/kyverno/v1/generaterequest_types.go @@ -50,6 +50,7 @@ type GenerateRequestContext struct { AdmissionRequestInfo AdmissionRequestInfoObject `json:"admissionRequestInfo,omitempty" yaml:"admissionRequestInfo,omitempty"` } +// AdmissionRequestInfoObject stores the admission request and operation details type AdmissionRequestInfoObject struct { // +optional AdmissionRequest string `json:"admissionRequest,omitempty" yaml:"admissionRequest,omitempty"` diff --git a/pkg/api/kyverno/v1/policy_types.go b/pkg/api/kyverno/v1/policy_types.go index 86a22683db..9c6489b26c 100755 --- a/pkg/api/kyverno/v1/policy_types.go +++ b/pkg/api/kyverno/v1/policy_types.go @@ -136,7 +136,7 @@ const ( Fail FailurePolicyType = "Fail" ) -// AnyAllCondition consists of conditions wrapped denoting a logical criteria to be fulfilled. +// AnyAllConditions consists of conditions wrapped denoting a logical criteria to be fulfilled. // AnyConditions get fulfilled when at least one of its sub-conditions passes. // AllConditions get fulfilled only when all of its sub-conditions pass. type AnyAllConditions struct { @@ -311,9 +311,10 @@ type ExcludeResources struct { ResourceDescription `json:"resources,omitempty" yaml:"resources,omitempty"` } +// ResourceFilters is a slice of ResourceFilter type ResourceFilters []ResourceFilter -// ResourceFilters allow users to "AND" or "OR" between resources +// ResourceFilter allow users to "AND" or "OR" between resources type ResourceFilter struct { // UserInfo contains information about the user performing the operation. // +optional @@ -411,12 +412,12 @@ type Mutation struct { // +optional PatchesJSON6902 string `json:"patchesJson6902,omitempty" yaml:"patchesJson6902,omitempty"` - // ForEach applies policy rule changes to nested elements. + // ForEachMutation applies policy rule changes to nested elements. // +optional ForEachMutation []*ForEachMutation `json:"foreach,omitempty" yaml:"foreach,omitempty"` } -// ForEach applies policy rule changes to nested elements. +// ForEachMutation applies policy rule changes to nested elements. type ForEachMutation struct { // List specifies a JMESPath expression that results in one or more elements @@ -427,7 +428,7 @@ type ForEachMutation struct { // +optional Context []ContextEntry `json:"context,omitempty" yaml:"context,omitempty"` - // Preconditions are used to determine if a policy rule should be applied by evaluating a + // AnyAllConditions are used to determine if a policy rule should be applied by evaluating a // set of conditions. The declaration can contain nested `any` or `all` statements. // See: https://kyverno.io/docs/writing-policies/preconditions/ // +kubebuilder:validation:XPreserveUnknownFields @@ -498,7 +499,7 @@ type Deny struct { AnyAllConditions apiextensions.JSON `json:"conditions,omitempty" yaml:"conditions,omitempty"` } -// ForEach applies policy rule checks to nested elements. +// ForEachValidation applies policy rule checks to nested elements. type ForEachValidation struct { // List specifies a JMESPath expression that results in one or more elements @@ -509,7 +510,7 @@ type ForEachValidation struct { // +optional Context []ContextEntry `json:"context,omitempty" yaml:"context,omitempty"` - // Preconditions are used to determine if a policy rule should be applied by evaluating a + // AnyAllConditions are used to determine if a policy rule should be applied by evaluating a // set of conditions. The declaration can contain nested `any` or `all` statements. // See: https://kyverno.io/docs/writing-policies/preconditions/ // +kubebuilder:validation:XPreserveUnknownFields diff --git a/pkg/api/kyverno/v1/utils.go b/pkg/api/kyverno/v1/utils.go index ec6ae37ff2..161e8bd537 100755 --- a/pkg/api/kyverno/v1/utils.go +++ b/pkg/api/kyverno/v1/utils.go @@ -19,7 +19,7 @@ func (p *ClusterPolicy) HasAutoGenAnnotation() bool { return false } -//HasMutateOrValidateOrGenerate checks for rule types +// HasMutateOrValidateOrGenerate checks for rule types func (p *ClusterPolicy) HasMutateOrValidateOrGenerate() bool { for _, rule := range p.Spec.Rules { if rule.HasMutate() || rule.HasValidate() || rule.HasGenerate() { @@ -29,7 +29,7 @@ func (p *ClusterPolicy) HasMutateOrValidateOrGenerate() bool { return false } -//HasMutate checks for mutate rule types +// HasMutate checks for mutate rule types func (p *ClusterPolicy) HasMutate() bool { for _, rule := range p.Spec.Rules { if rule.HasMutate() { @@ -62,7 +62,7 @@ func (p *ClusterPolicy) HasGenerate() bool { return false } -//HasVerifyImages checks for image verification rule types +// HasVerifyImages checks for image verification rule types func (p *ClusterPolicy) HasVerifyImages() bool { for _, rule := range p.Spec.Rules { if rule.HasVerifyImages() { @@ -102,6 +102,7 @@ func (r Rule) HasGenerate() bool { return !reflect.DeepEqual(r.Generation, Generation{}) } +// MatchKinds returns a slice of all kinds to match func (r Rule) MatchKinds() []string { matchKinds := r.MatchResources.ResourceDescription.Kinds for _, value := range r.MatchResources.All { @@ -114,6 +115,7 @@ func (r Rule) MatchKinds() []string { return matchKinds } +// ExcludeKinds returns a slice of all kinds to exclude func (r Rule) ExcludeKinds() []string { excludeKinds := r.ExcludeResources.ResourceDescription.Kinds for _, value := range r.ExcludeResources.All { @@ -243,20 +245,20 @@ func (in *Rule) DeepCopyInto(out *Rule) { // } } -//ToKey generates the key string used for adding label to polivy violation +// ToKey generates the key string used for adding label to polivy violation func (rs ResourceSpec) ToKey() string { return rs.Kind + "." + rs.Name } // ViolatedRule stores the information regarding the rule. type ViolatedRule struct { - // Specifies violated rule name. + // Name specifies violated rule name. Name string `json:"name" yaml:"name"` - // Specifies violated rule type. + // Type specifies violated rule type. Type string `json:"type" yaml:"type"` - // Specifies violation message. + // Message specifies violation message. // +optional Message string `json:"message" yaml:"message"` diff --git a/pkg/common/common.go b/pkg/common/common.go index 011e79aa59..f7356bdec8 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -22,8 +22,10 @@ import ( // Policy Reporting Modes const ( - Enforce = "enforce" // blocks the request on failure - Audit = "audit" // dont block the request on failure, but report failiures as policy violations + // Enforce blocks the request on failure + Enforce = "enforce" + // Audit indicates not to block the request on failure, but report failiures as policy violations + Audit = "audit" ) // Policy Reporting Types @@ -118,6 +120,7 @@ func VariableToJSON(key, value string) []byte { return jsonData } +// RetryFunc allows retrying a function on error within a given timeout func RetryFunc(retryInterval, timeout time.Duration, run func() error, logger logr.Logger) func() error { return func() error { registerTimeout := time.After(timeout) diff --git a/pkg/config/dynamicconfig.go b/pkg/config/dynamicconfig.go index 197a606570..b39be2facc 100644 --- a/pkg/config/dynamicconfig.go +++ b/pkg/config/dynamicconfig.go @@ -104,12 +104,14 @@ func (cd *ConfigData) FilterNamespaces(namespaces []string) []string { return results } +// GetWebhooks returns the webhook configs func (cd *ConfigData) GetWebhooks() []WebhookConfig { cd.mux.RLock() defer cd.mux.RUnlock() return cd.webhooks } +// GetInitConfigMapName returns the init configmap name func (cd *ConfigData) GetInitConfigMapName() string { return cd.cmName } @@ -170,7 +172,7 @@ func NewConfigData(rclient kubernetes.Interface, cmInformer informers.ConfigMapI return &cd } -//Run checks syncing +// Run checks syncing func (cd *ConfigData) Run(stopCh <-chan struct{}) { logger := cd.log // wait for cache to populate first time diff --git a/pkg/config/metricsconfig.go b/pkg/config/metricsconfig.go index 65e3861d21..9af902a6f3 100644 --- a/pkg/config/metricsconfig.go +++ b/pkg/config/metricsconfig.go @@ -24,6 +24,7 @@ type MetricsConfigData struct { log logr.Logger } +// MetricsConfig stores the config for metrics type MetricsConfig struct { namespaces namespacesConfig metricsRefreshInterval time.Duration @@ -44,10 +45,12 @@ func (mcd *MetricsConfigData) GetIncludeNamespaces() []string { return mcd.metricsConfig.namespaces.IncludeNamespaces } +// GetMetricsRefreshInterval returns the refresh interval for the metrics func (mcd *MetricsConfigData) GetMetricsRefreshInterval() time.Duration { return mcd.metricsConfig.metricsRefreshInterval } +// GetMetricsConfigMapName returns the configmap name for the metric func (mcd *MetricsConfigData) GetMetricsConfigMapName() string { return mcd.cmName } diff --git a/pkg/cosign/client.go b/pkg/cosign/client.go index c9d2b07888..f48e580ba3 100644 --- a/pkg/cosign/client.go +++ b/pkg/cosign/client.go @@ -2,6 +2,7 @@ package cosign import ( "context" + "github.com/google/go-containerregistry/pkg/name" "github.com/sigstore/cosign/pkg/cosign" ) diff --git a/pkg/cosign/cosign.go b/pkg/cosign/cosign.go index b78e73ee66..c71938d7c7 100644 --- a/pkg/cosign/cosign.go +++ b/pkg/cosign/cosign.go @@ -49,6 +49,7 @@ func Initialize(client kubernetes.Interface, namespace, serviceAccount string, i return nil } +// VerifySignature verifies that the image has the expected key func VerifySignature(imageRef string, key []byte, repository string, log logr.Logger) (digest string, err error) { pubKey, err := decodePEM(key) if err != nil { diff --git a/pkg/cosign/cosign_test.go b/pkg/cosign/cosign_test.go index 7d4018d5da..c4a1273f36 100644 --- a/pkg/cosign/cosign_test.go +++ b/pkg/cosign/cosign_test.go @@ -1,10 +1,11 @@ package cosign import ( + "testing" + "github.com/go-logr/logr" "github.com/sigstore/cosign/pkg/cosign" "gotest.tools/assert" - "testing" ) const cosignPayload = `{ diff --git a/pkg/cosign/mock.go b/pkg/cosign/mock.go index 6cce307e7e..5c2cb185d1 100644 --- a/pkg/cosign/mock.go +++ b/pkg/cosign/mock.go @@ -3,6 +3,7 @@ package cosign import ( "context" "fmt" + "github.com/google/go-containerregistry/pkg/name" "github.com/sigstore/cosign/pkg/cosign" ) diff --git a/pkg/engine/anchor/anchor.go b/pkg/engine/anchor/anchor.go index 03fd3e5005..5cf9dad566 100644 --- a/pkg/engine/anchor/anchor.go +++ b/pkg/engine/anchor/anchor.go @@ -10,14 +10,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" ) -//ValidationHandler for element processes +// ValidationHandler for element processes type ValidationHandler interface { Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) } type resourceElementHandler = func(log logr.Logger, resourceElement, patternElement, originPattern interface{}, path string, ac *common.AnchorKey) (string, error) -//CreateElementHandler factory to process elements +// CreateElementHandler factory to process elements func CreateElementHandler(element string, pattern interface{}, path string) ValidationHandler { switch { case commonAnchors.IsConditionAnchor(element): @@ -35,7 +35,7 @@ func CreateElementHandler(element string, pattern interface{}, path string) Vali } } -//NewNegationHandler returns instance of negation handler +// NewNegationHandler returns instance of negation handler func NewNegationHandler(anchor string, pattern interface{}, path string) ValidationHandler { return NegationHandler{ anchor: anchor, @@ -44,14 +44,14 @@ func NewNegationHandler(anchor string, pattern interface{}, path string) Validat } } -//NegationHandler provides handler for check if the tag in anchor is not defined +// NegationHandler provides handler for check if the tag in anchor is not defined type NegationHandler struct { anchor string pattern interface{} path string } -//Handle process negation handler +// Handle process negation handler func (nh NegationHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) { anchorKey, _ := commonAnchors.RemoveAnchor(nh.anchor) currentPath := nh.path + anchorKey + "/" @@ -64,7 +64,7 @@ func (nh NegationHandler) Handle(handler resourceElementHandler, resourceMap map return "", nil } -//NewEqualityHandler returens instance of equality handler +// NewEqualityHandler returens instance of equality handler func NewEqualityHandler(anchor string, pattern interface{}, path string) ValidationHandler { return EqualityHandler{ anchor: anchor, @@ -73,14 +73,14 @@ func NewEqualityHandler(anchor string, pattern interface{}, path string) Validat } } -//EqualityHandler provides handler for non anchor element +// EqualityHandler provides handler for non anchor element type EqualityHandler struct { anchor string pattern interface{} path string } -//Handle processed condition anchor +// Handle processed condition anchor func (eh EqualityHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) { anchorKey, _ := commonAnchors.RemoveAnchor(eh.anchor) currentPath := eh.path + anchorKey + "/" @@ -96,7 +96,7 @@ func (eh EqualityHandler) Handle(handler resourceElementHandler, resourceMap map return "", nil } -//NewDefaultHandler returns handler for non anchor elements +// NewDefaultHandler returns handler for non anchor elements func NewDefaultHandler(element string, pattern interface{}, path string) ValidationHandler { return DefaultHandler{ element: element, @@ -105,14 +105,14 @@ func NewDefaultHandler(element string, pattern interface{}, path string) Validat } } -//DefaultHandler provides handler for non anchor element +// DefaultHandler provides handler for non anchor element type DefaultHandler struct { element string pattern interface{} path string } -//Handle process non anchor element +// Handle process non anchor element func (dh DefaultHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) { currentPath := dh.path + dh.element + "/" if dh.pattern == "*" && resourceMap[dh.element] != nil { @@ -128,7 +128,7 @@ func (dh DefaultHandler) Handle(handler resourceElementHandler, resourceMap map[ return "", nil } -//NewConditionAnchorHandler returns an instance of condition acnhor handler +// NewConditionAnchorHandler returns an instance of condition acnhor handler func NewConditionAnchorHandler(anchor string, pattern interface{}, path string) ValidationHandler { return ConditionAnchorHandler{ anchor: anchor, @@ -137,14 +137,14 @@ func NewConditionAnchorHandler(anchor string, pattern interface{}, path string) } } -//ConditionAnchorHandler provides handler for condition anchor +// ConditionAnchorHandler provides handler for condition anchor type ConditionAnchorHandler struct { anchor string pattern interface{} path string } -//Handle processed condition anchor +// Handle processed condition anchor func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) { anchorKey, _ := commonAnchors.RemoveAnchor(ch.anchor) currentPath := ch.path + anchorKey + "/" @@ -162,7 +162,7 @@ func (ch ConditionAnchorHandler) Handle(handler resourceElementHandler, resource return "", nil } -//NewGlobalAnchorHandler returns an instance of condition acnhor handler +// NewGlobalAnchorHandler returns an instance of condition acnhor handler func NewGlobalAnchorHandler(anchor string, pattern interface{}, path string) ValidationHandler { return GlobalAnchorHandler{ anchor: anchor, @@ -171,14 +171,14 @@ func NewGlobalAnchorHandler(anchor string, pattern interface{}, path string) Val } } -//GlobalAnchorHandler provides handler for global condition anchor +// GlobalAnchorHandler provides handler for global condition anchor type GlobalAnchorHandler struct { anchor string pattern interface{} path string } -//Handle processed global condition anchor +// Handle processed global condition anchor func (gh GlobalAnchorHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) { anchorKey, _ := commonAnchors.RemoveAnchor(gh.anchor) currentPath := gh.path + anchorKey + "/" @@ -195,7 +195,7 @@ func (gh GlobalAnchorHandler) Handle(handler resourceElementHandler, resourceMap return "", nil } -//NewExistenceHandler returns existence handler +// NewExistenceHandler returns existence handler func NewExistenceHandler(anchor string, pattern interface{}, path string) ValidationHandler { return ExistenceHandler{ anchor: anchor, @@ -204,14 +204,14 @@ func NewExistenceHandler(anchor string, pattern interface{}, path string) Valida } } -//ExistenceHandler provides handlers to process exitence anchor handler +// ExistenceHandler provides handlers to process exitence anchor handler type ExistenceHandler struct { anchor string pattern interface{} path string } -//Handle processes the existence anchor handler +// Handle processes the existence anchor handler func (eh ExistenceHandler) Handle(handler resourceElementHandler, resourceMap map[string]interface{}, originPattern interface{}, ac *common.AnchorKey) (string, error) { // skip is used by existence anchor to not process further if condition is not satisfied anchorKey, _ := commonAnchors.RemoveAnchor(eh.anchor) @@ -261,7 +261,7 @@ func validateExistenceListResource(handler resourceElementHandler, resourceList return path, fmt.Errorf("existence anchor validation failed at path %s", path) } -//GetAnchorsResourcesFromMap returns map of anchors +// GetAnchorsResourcesFromMap returns map of anchors func GetAnchorsResourcesFromMap(patternMap map[string]interface{}) (map[string]interface{}, map[string]interface{}) { anchors := map[string]interface{}{} resources := map[string]interface{}{} diff --git a/pkg/engine/common/anchorKey.go b/pkg/engine/common/anchorKey.go index 8b79e16319..a770ff5af4 100644 --- a/pkg/engine/common/anchorKey.go +++ b/pkg/engine/common/anchorKey.go @@ -26,7 +26,7 @@ func NewConditionalAnchorError(msg string) ValidateAnchorError { } } -// IsConditionAnchorError ... +// IsConditionAnchorError checks if the error is a conditional anchor error func (e ValidateAnchorError) IsConditionAnchorError() bool { return e.Err == ConditionalAnchorErr } @@ -39,16 +39,17 @@ func NewGlobalAnchorError(msg string) ValidateAnchorError { } } -// IsConditionAnchorError ... +// IsGlobalAnchorError checks if the error is a global anchor error func (e ValidateAnchorError) IsGlobalAnchorError() bool { return e.Err == GlobalAnchorErr } -// IsNil ... +// IsNil checks if the error isn't populated func (e ValidateAnchorError) IsNil() bool { return e == ValidateAnchorError{} } +// Error returns an error instance of the anchor error func (e ValidateAnchorError) Error() error { return errors.New(e.Message) } diff --git a/pkg/engine/context/context.go b/pkg/engine/context/context.go index a924a96c62..bf046199da 100644 --- a/pkg/engine/context/context.go +++ b/pkg/engine/context/context.go @@ -99,7 +99,7 @@ func (ctx *Context) AddJSON(dataRaw []byte) error { return nil } -// AddJSON merges json data +// AddJSONObject merges json data func (ctx *Context) AddJSONObject(jsonData interface{}) error { jsonBytes, err := json.Marshal(jsonData) if err != nil { diff --git a/pkg/engine/imageVerify_test.go b/pkg/engine/imageVerify_test.go index fea9f62929..6d1988724a 100644 --- a/pkg/engine/imageVerify_test.go +++ b/pkg/engine/imageVerify_test.go @@ -2,13 +2,14 @@ package engine import ( "encoding/json" + "testing" + kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/cosign" "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/utils" "gotest.tools/assert" - "testing" ) var test_policy_good = `{ diff --git a/pkg/engine/jmespath/functions.go b/pkg/engine/jmespath/functions.go index f3e12a208a..9799e80c51 100644 --- a/pkg/engine/jmespath/functions.go +++ b/pkg/engine/jmespath/functions.go @@ -336,7 +336,14 @@ func jpfSplit(arguments []interface{}) (interface{}, error) { return nil, err } - return strings.Split(str.String(), sep.String()), nil + split := strings.Split(str.String(), sep.String()) + arr := make([]interface{}, len(split)) + + for i, v := range split { + arr[i] = v + } + + return arr, nil } func jpRegexReplaceAll(arguments []interface{}) (interface{}, error) { diff --git a/pkg/engine/jmespath/functions_test.go b/pkg/engine/jmespath/functions_test.go index 427627419f..a2342bae01 100644 --- a/pkg/engine/jmespath/functions_test.go +++ b/pkg/engine/jmespath/functions_test.go @@ -128,7 +128,7 @@ func TestJMESPathFunctions_Split(t *testing.T) { result, err := jp.Search("") assert.NilError(t, err) - split, ok := result.([]string) + split, ok := result.([]interface{}) assert.Assert(t, ok) assert.Equal(t, split[0], "Hello") assert.Equal(t, split[1], "Gophers") diff --git a/pkg/engine/jsonContext_test.go b/pkg/engine/jsonContext_test.go index 950229cd59..69e92dddbf 100644 --- a/pkg/engine/jsonContext_test.go +++ b/pkg/engine/jsonContext_test.go @@ -3,8 +3,9 @@ package engine import ( "bytes" "encoding/json" - "gotest.tools/assert" "testing" + + "gotest.tools/assert" ) func Test_parseMultilineBlockBody(t *testing.T) { diff --git a/pkg/engine/json-utils/traverse.go b/pkg/engine/jsonutils/traverse.go similarity index 99% rename from pkg/engine/json-utils/traverse.go rename to pkg/engine/jsonutils/traverse.go index 0f06043a8d..624f1773c8 100644 --- a/pkg/engine/json-utils/traverse.go +++ b/pkg/engine/jsonutils/traverse.go @@ -1,4 +1,4 @@ -package json_utils +package jsonutils import ( "fmt" diff --git a/pkg/engine/json-utils/traverse_test.go b/pkg/engine/jsonutils/traverse_test.go similarity index 98% rename from pkg/engine/json-utils/traverse_test.go rename to pkg/engine/jsonutils/traverse_test.go index 1910656d26..e32c13a169 100644 --- a/pkg/engine/json-utils/traverse_test.go +++ b/pkg/engine/jsonutils/traverse_test.go @@ -1,4 +1,4 @@ -package json_utils +package jsonutils import ( "encoding/json" diff --git a/pkg/engine/mutate/patchJson6902_test.go b/pkg/engine/mutate/patchJson6902_test.go index 94baf483d7..f69283f399 100644 --- a/pkg/engine/mutate/patchJson6902_test.go +++ b/pkg/engine/mutate/patchJson6902_test.go @@ -2,9 +2,10 @@ package mutate import ( "fmt" - "github.com/kyverno/kyverno/pkg/engine/response" "testing" + "github.com/kyverno/kyverno/pkg/engine/response" + "github.com/ghodss/yaml" assert "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/pkg/engine/mutate/patches_test.go b/pkg/engine/mutate/patches_test.go index 76f73d7ab8..0ccd584900 100644 --- a/pkg/engine/mutate/patches_test.go +++ b/pkg/engine/mutate/patches_test.go @@ -1,9 +1,10 @@ package mutate import ( - "github.com/kyverno/kyverno/pkg/engine/response" "testing" + "github.com/kyverno/kyverno/pkg/engine/response" + "gotest.tools/assert" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/controller-runtime/pkg/log" diff --git a/pkg/engine/mutation.go b/pkg/engine/mutation.go index 76d2b23f9f..5351b0dcf6 100644 --- a/pkg/engine/mutation.go +++ b/pkg/engine/mutation.go @@ -99,7 +99,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) { if rule.Mutation.ForEachMutation != nil { ruleResp, patchedResource = mutateForEachResource(ruleCopy, policyContext, patchedResource, logger) } else { - err, mutateResp := mutateResource(ruleCopy, policyContext.JSONContext, patchedResource, logger, 0) + mutateResp, err := mutateResource(ruleCopy, policyContext.JSONContext, patchedResource, logger, 0) if err != nil { if mutateResp.skip { ruleResp = ruleResponse(&policy.Spec.Rules[i], utils.Mutation, err.Error(), response.RuleStatusSkip) @@ -174,7 +174,7 @@ func mutateForEachResource(rule *kyverno.Rule, ctx *PolicyContext, resource unst } var skip = false - err, mutateResp := mutateResource(rule, ctx.JSONContext, patchedResource, logger, foreachIndex) + mutateResp, err := mutateResource(rule, ctx.JSONContext, patchedResource, logger, foreachIndex) if err != nil && !skip { return ruleResponse(rule, utils.Mutation, err.Error(), response.RuleStatusError), resource } @@ -204,7 +204,7 @@ type mutateResponse struct { message string } -func mutateResource(rule *kyverno.Rule, ctx *context.Context, resource unstructured.Unstructured, logger logr.Logger, foreachIndex int) (error, *mutateResponse) { +func mutateResource(rule *kyverno.Rule, ctx *context.Context, resource unstructured.Unstructured, logger logr.Logger, foreachIndex int) (*mutateResponse, error) { mutateResp := &mutateResponse{false, unstructured.Unstructured{}, nil, ""} // Pre-conditions checks for the list of foreach rules should ideally be performed once. @@ -212,22 +212,22 @@ func mutateResource(rule *kyverno.Rule, ctx *context.Context, resource unstructu // Also, the foreach index parameter should be removed and a set of patches should be passed in. anyAllConditions, err := variables.SubstituteAllInPreconditions(logger, ctx, rule.AnyAllConditions) if err != nil { - return errors.Wrapf(err, "failed to substitute vars in preconditions"), mutateResp + return mutateResp, errors.Wrapf(err, "failed to substitute vars in preconditions") } copyConditions, err := transformConditions(anyAllConditions) if err != nil { - return errors.Wrapf(err, "failed to load context"), mutateResp + return mutateResp, errors.Wrapf(err, "failed to load context") } if !variables.EvaluateConditions(logger, ctx, copyConditions) { mutateResp.skip = true - return fmt.Errorf("preconditions mismatch"), mutateResp + return mutateResp, fmt.Errorf("preconditions mismatch") } updatedRule, err := variables.SubstituteAllInRule(logger, ctx, *rule) if err != nil { - return errors.Wrapf(err, "variable substitution failed"), mutateResp + return mutateResp, errors.Wrapf(err, "variable substitution failed") } mutation := updatedRule.Mutation.DeepCopy() @@ -238,7 +238,7 @@ func mutateResource(rule *kyverno.Rule, ctx *context.Context, resource unstructu // - overlay pattern does not match the resource conditions if resp.Patches == nil { mutateResp.skip = true - return fmt.Errorf("resource does not match pattern"), mutateResp + return mutateResp, fmt.Errorf("resource does not match pattern") } mutateResp.skip = false @@ -252,7 +252,7 @@ func mutateResource(rule *kyverno.Rule, ctx *context.Context, resource unstructu logger.Error(err, "failed to update resource in the JSON context") } - return nil, mutateResp + return mutateResp, nil } func startMutateResultResponse(resp *response.EngineResponse, policy kyverno.ClusterPolicy, resource unstructured.Unstructured) { diff --git a/pkg/engine/operator/operator.go b/pkg/engine/operator/operator.go index 2029bde0c9..60b3e999a3 100644 --- a/pkg/engine/operator/operator.go +++ b/pkg/engine/operator/operator.go @@ -1,5 +1,9 @@ package operator +import ( + "regexp" +) + // Operator is string alias that represents selection operators enum type Operator string @@ -16,6 +20,10 @@ const ( More Operator = ">" // Less stands for < Less Operator = "<" + // InRange stands for - + InRange Operator = "-" + // NotInRange stands for !- + NotInRange Operator = "!-" ) //ReferenceSign defines the operator for anchor reference @@ -47,5 +55,13 @@ func GetOperatorFromStringPattern(pattern string) Operator { return NotEqual } + if match, _ := regexp.Match(`^(\d+(\.\d+)?)([^-]*)!-(\d+(\.\d+)?)([^-]*)$`, []byte(pattern)); match { + return NotInRange + } + + if match, _ := regexp.Match(`^(\d+(\.\d+)?)([^-]*)-(\d+(\.\d+)?)([^-]*)$`, []byte(pattern)); match { + return InRange + } + return Equal } diff --git a/pkg/engine/operator/operator_test.go b/pkg/engine/operator/operator_test.go index 1ca89b47ee..2f67341d42 100644 --- a/pkg/engine/operator/operator_test.go +++ b/pkg/engine/operator/operator_test.go @@ -1,8 +1,9 @@ package operator import ( - "gotest.tools/assert" "testing" + + "gotest.tools/assert" ) func TestGetOperatorFromStringPattern_OneChar(t *testing.T) { @@ -16,3 +17,19 @@ func TestGetOperatorFromStringPattern_EmptyString(t *testing.T) { func TestGetOperatorFromStringPattern_OnlyOperator(t *testing.T) { assert.Equal(t, GetOperatorFromStringPattern(">="), MoreEqual) } + +func TestGetOperatorFromStringPattern_RangeOperator(t *testing.T) { + assert.Equal(t, GetOperatorFromStringPattern("0-1"), InRange) + assert.Equal(t, GetOperatorFromStringPattern("0Mi-1024Mi"), InRange) + + assert.Equal(t, GetOperatorFromStringPattern("0!-1"), NotInRange) + assert.Equal(t, GetOperatorFromStringPattern("0Mi!-1024Mi"), NotInRange) + + assert.Equal(t, GetOperatorFromStringPattern("text1024Mi-2048Mi"), Equal) + assert.Equal(t, GetOperatorFromStringPattern("test-value"), Equal) + assert.Equal(t, GetOperatorFromStringPattern("value-*"), Equal) + + assert.Equal(t, GetOperatorFromStringPattern("text1024Mi!-2048Mi"), Equal) + assert.Equal(t, GetOperatorFromStringPattern("test!-value"), Equal) + assert.Equal(t, GetOperatorFromStringPattern("value!-*"), Equal) +} diff --git a/pkg/engine/response/response_test.go b/pkg/engine/response/response_test.go index 31af153db0..0f3f89842a 100644 --- a/pkg/engine/response/response_test.go +++ b/pkg/engine/response/response_test.go @@ -1,9 +1,10 @@ package response import ( + "testing" + "gopkg.in/yaml.v2" "gotest.tools/assert" - "testing" ) var sourceYAML = ` diff --git a/pkg/engine/response/status.go b/pkg/engine/response/status.go index d5f050cb86..ebcaced17b 100644 --- a/pkg/engine/response/status.go +++ b/pkg/engine/response/status.go @@ -81,17 +81,17 @@ func getRuleStatus(s string) (*RuleStatus, error) { return nil, fmt.Errorf("invalid status: %s", s) } -func (v *RuleStatus) UnmarshalYAML(unmarshal func(interface{}) error) error { - var s string - if err := unmarshal(&s); err != nil { +func (s *RuleStatus) UnmarshalYAML(unmarshal func(interface{}) error) error { + var str string + if err := unmarshal(&str); err != nil { return err } - statusVal, err := getRuleStatus(s) + statusVal, err := getRuleStatus(str) if err != nil { return err } - *v = *statusVal + *s = *statusVal return nil } diff --git a/pkg/engine/utils/utils.go b/pkg/engine/utils/utils.go index 4c01a85ba8..7e584eb623 100644 --- a/pkg/engine/utils/utils.go +++ b/pkg/engine/utils/utils.go @@ -2,12 +2,13 @@ package utils import ( "fmt" + "strconv" + "strings" + jsonpatch "github.com/evanphx/json-patch/v5" commonAnchor "github.com/kyverno/kyverno/pkg/engine/anchor/common" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/controller-runtime/pkg/log" - "strconv" - "strings" ) //RuleType defines the type for rule diff --git a/pkg/engine/validate/pattern.go b/pkg/engine/validate/pattern.go index cde899ff3e..40bed7980b 100644 --- a/pkg/engine/validate/pattern.go +++ b/pkg/engine/validate/pattern.go @@ -177,17 +177,45 @@ func checkForAndConditionsAndValidate(log logr.Logger, value interface{}, patter // Handler for single pattern value during validation process // Detects if pattern has a number func validateValueWithStringPattern(log logr.Logger, value interface{}, pattern string) bool { + operatorVariable := operator.GetOperatorFromStringPattern(pattern) - operator := operator.GetOperatorFromStringPattern(pattern) - pattern = pattern[len(operator):] + // Upon encountering InRange operator split the string by `-` and basically + // verify the result of (x >= leftEndpoint & x <= rightEndpoint) + if operatorVariable == operator.InRange { + endpoints := strings.Split(pattern, "-") + leftEndpoint, rightEndpoint := endpoints[0], endpoints[1] + + gt := validateValueWithStringPattern(log, value, fmt.Sprintf(">=%s", leftEndpoint)) + if !gt { + return false + } + pattern = fmt.Sprintf("<=%s", rightEndpoint) + operatorVariable = operator.LessEqual + } + + // Upon encountering NotInRange operator split the string by `!-` and basically + // verify the result of (x < leftEndpoint | x > rightEndpoint) + if operatorVariable == operator.NotInRange { + endpoints := strings.Split(pattern, "!-") + leftEndpoint, rightEndpoint := endpoints[0], endpoints[1] + + lt := validateValueWithStringPattern(log, value, fmt.Sprintf("<%s", leftEndpoint)) + if lt { + return true + } + pattern = fmt.Sprintf(">%s", rightEndpoint) + operatorVariable = operator.More + } + + pattern = pattern[len(operatorVariable):] pattern = strings.TrimSpace(pattern) number, str := getNumberAndStringPartsFromPattern(pattern) if number == "" { - return validateString(log, value, str, operator) + return validateString(log, value, str, operatorVariable) } - return validateNumberWithStr(log, value, pattern, operator) + return validateNumberWithStr(log, value, pattern, operatorVariable) } // Handler for string values diff --git a/pkg/engine/validate/pattern_test.go b/pkg/engine/validate/pattern_test.go index cef6b81e99..200afd7984 100644 --- a/pkg/engine/validate/pattern_test.go +++ b/pkg/engine/validate/pattern_test.go @@ -310,6 +310,42 @@ func TestValidateValueWithStringPattern_WithSpace(t *testing.T) { assert.Assert(t, validateValueWithStringPattern(log.Log, 4, ">= 3")) } +func TestValidateValueWithStringPattern_Ranges(t *testing.T) { + assert.Assert(t, validateValueWithStringPattern(log.Log, 0, "0-2")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 1, "0-2")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 2, "0-2")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, 3, "0-2")) + + assert.Assert(t, validateValueWithStringPattern(log.Log, 0, "10!-20")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, 15, "10!-20")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 25, "10!-20")) + + assert.Assert(t, !validateValueWithStringPattern(log.Log, 0, "0.00001-2.00001")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 1, "0.00001-2.00001")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 2, "0.00001-2.00001")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, 2.0001, "0.00001-2.00001")) + + assert.Assert(t, validateValueWithStringPattern(log.Log, 0, "0.00001!-2.00001")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, 1, "0.00001!-2.00001")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, 2, "0.00001!-2.00001")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 2.0001, "0.00001!-2.00001")) + + assert.Assert(t, validateValueWithStringPattern(log.Log, 2, "2-2")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, 2, "2!-2")) + + assert.Assert(t, validateValueWithStringPattern(log.Log, 2.99999, "2.99998-3")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 2.99997, "2.99998!-3")) + assert.Assert(t, validateValueWithStringPattern(log.Log, 3.00001, "2.99998!-3")) + + assert.Assert(t, validateValueWithStringPattern(log.Log, "256Mi", "128Mi-512Mi")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, "1024Mi", "128Mi-512Mi")) + assert.Assert(t, !validateValueWithStringPattern(log.Log, "64Mi", "128Mi-512Mi")) + + assert.Assert(t, !validateValueWithStringPattern(log.Log, "256Mi", "128Mi!-512Mi")) + assert.Assert(t, validateValueWithStringPattern(log.Log, "1024Mi", "128Mi!-512Mi")) + assert.Assert(t, validateValueWithStringPattern(log.Log, "64Mi", "128Mi!-512Mi")) +} + func TestValidateNumberWithStr_LessFloatAndInt(t *testing.T) { assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7.000001", operator.More)) assert.Assert(t, validateNumberWithStr(log.Log, 7.00001, "7", operator.NotEqual)) diff --git a/pkg/engine/validation.go b/pkg/engine/validation.go index 3671b4c0b3..c6d927b002 100644 --- a/pkg/engine/validation.go +++ b/pkg/engine/validation.go @@ -425,7 +425,8 @@ func isSameRuleResponse(r1 *response.RuleResponse, r2 *response.RuleResponse) bo func (v *validator) validatePatterns(resource unstructured.Unstructured) *response.RuleResponse { if v.pattern != nil { if err := validate.MatchPattern(v.log, resource.Object, v.pattern); err != nil { - if pe, ok := err.(*validate.PatternError); ok { + pe, ok := err.(*validate.PatternError) + if ok { v.log.V(3).Info("validation error", "path", pe.Path, "error", err.Error()) if pe.Skip { @@ -437,9 +438,9 @@ func (v *validator) validatePatterns(resource unstructured.Unstructured) *respon } return ruleResponse(v.rule, utils.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusFail) - } else { - return ruleResponse(v.rule, utils.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusError) } + + return ruleResponse(v.rule, utils.Validation, v.buildErrorMessage(err, pe.Path), response.RuleStatusError) } v.log.V(4).Info("successfully processed rule") diff --git a/pkg/engine/variables/evaluate_test.go b/pkg/engine/variables/evaluate_test.go index 4549bd3e95..074b977989 100644 --- a/pkg/engine/variables/evaluate_test.go +++ b/pkg/engine/variables/evaluate_test.go @@ -10,1676 +10,304 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" ) -// STRINGS -func Test_Eval_Equal_Const_String_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: "name", - Operator: kyverno.Equal, - Value: "name", - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_Equal_Const_String_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: "name", - Operator: kyverno.Equal, - Value: "name1", - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_NoEqual_Const_String_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: "name", - Operator: kyverno.NotEqual, - Value: "name1", - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_NoEqual_Const_String_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: "name", - Operator: kyverno.NotEqual, - Value: "name", - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_string_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1", - Operator: kyverno.GreaterThanOrEquals, - Value: 1.0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_string_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1", - Operator: kyverno.GreaterThanOrEquals, - Value: 0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1.1", - Operator: kyverno.GreaterThanOrEquals, - Value: "2", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_quantity_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "10Gi", - Operator: kyverno.GreaterThanOrEquals, - Value: "1Gi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_quantity_equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.GreaterThanOrEquals, - Value: "1Gi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_quantity_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.GreaterThanOrEquals, - Value: "15Gi", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_quantity_different_units(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.GreaterThanOrEquals, - Value: "10Mi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThan_Const_string_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1", - Operator: kyverno.GreaterThan, - Value: 1.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThan_Const_string_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1", - Operator: kyverno.GreaterThan, - Value: 0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThan_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1.1", - Operator: kyverno.GreaterThan, - Value: "2", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThan_Const_quantity_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "10Gi", - Operator: kyverno.GreaterThan, - Value: "1Gi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThan_Const_quantity_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.GreaterThan, - Value: "1Gi", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThanOrEquals_Const_string_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1", - Operator: kyverno.LessThanOrEquals, - Value: 1.0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_string_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "0", - Operator: kyverno.LessThanOrEquals, - Value: 1, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2.0", - Operator: kyverno.LessThanOrEquals, - Value: "1.1", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThanOrEquals_Const_quantity_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.LessThanOrEquals, - Value: "10Gi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_quantity_equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.LessThanOrEquals, - Value: "1Gi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_quantity_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "15Gi", - Operator: kyverno.LessThanOrEquals, - Value: "1Gi", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThanOrEquals_Const_quantity_different_units(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Mi", - Operator: kyverno.LessThanOrEquals, - Value: "1Gi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThan_Const_string_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1", - Operator: kyverno.LessThan, - Value: 1.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThan_Const_string_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "0", - Operator: kyverno.LessThan, - Value: 1, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThan_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2.0", - Operator: kyverno.LessThan, - Value: "1.1", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThan_Const_quantity_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.LessThan, - Value: "10Gi", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThan_Const_quantity_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1Gi", - Operator: kyverno.LessThan, - Value: "1Gi", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_string_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.GreaterThanOrEquals, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_DifferentUnits_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.GreaterThanOrEquals, - Value: "60m", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_DifferentUnits_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.GreaterThanOrEquals, - Value: "60m", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_string_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.GreaterThanOrEquals, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.GreaterThanOrEquals, - Value: "2h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThan_Const_string_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.GreaterThan, - Value: "2h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThan_Const_string_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.GreaterThan, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThan_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.GreaterThan, - Value: "2h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_string_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.LessThanOrEquals, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_string_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.LessThanOrEquals, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.LessThanOrEquals, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_string_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.LessThan, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_string_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.LessThan, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThan_Const_string_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.LessThan, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -//Bool - -func Test_Eval_Equal_Const_Bool_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: true, - Operator: kyverno.Equal, - Value: true, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_Equal_Const_Bool_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: true, - Operator: kyverno.Equal, - Value: false, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_NoEqual_Const_Bool_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: true, - Operator: kyverno.NotEqual, - Value: false, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_NoEqual_Const_Bool_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: true, - Operator: kyverno.NotEqual, - Value: true, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -// int -func Test_Eval_Equal_Const_int_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.Equal, - Value: 1, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_Equal_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.Equal, - Value: 2, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_NoEqual_Const_int_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.NotEqual, - Value: 2, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_NoEqual_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.NotEqual, - Value: 1, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_int_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.GreaterThanOrEquals, - Value: 1.0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_int_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.GreaterThanOrEquals, - Value: 0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.GreaterThanOrEquals, - Value: "2", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThan_Const_int_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.GreaterThan, - Value: 1.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThan_Const_int_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.GreaterThan, - Value: 0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThan_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.GreaterThan, - Value: "2", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThanOrEquals_Const_int_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.LessThanOrEquals, - Value: 1.0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_int_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 0, - Operator: kyverno.LessThanOrEquals, - Value: 1, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 2, - Operator: kyverno.LessThanOrEquals, - Value: "1", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThan_Const_int_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1, - Operator: kyverno.LessThan, - Value: 1.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThan_Const_int_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 0, - Operator: kyverno.LessThan, - Value: 1, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThan_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 2, - Operator: kyverno.LessThan, - Value: "1", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_int_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.GreaterThanOrEquals, - Value: 3600, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_int_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.GreaterThanOrEquals, - Value: 3600, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.GreaterThanOrEquals, - Value: 7200, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_int_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200, - Operator: kyverno.GreaterThanOrEquals, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThan_Const_int_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.GreaterThan, - Value: 3600, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_int_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "2h", - Operator: kyverno.LessThanOrEquals, - Value: 7200, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_int_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.LessThanOrEquals, - Value: 7200, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200, - Operator: kyverno.LessThanOrEquals, - Value: 3600, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_int_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600, - Operator: kyverno.DurationLessThan, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_int_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600, - Operator: kyverno.DurationLessThan, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThan_Const_int_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200, - Operator: kyverno.DurationLessThan, - Value: 3600, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -// int64 -func Test_Eval_Equal_Const_int64_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: int64(1), - Operator: kyverno.Equal, - Value: int64(1), - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_Equal_Const_int64_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: int64(1), - Operator: kyverno.Equal, - Value: int64(2), - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_NoEqual_Const_int64_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: int64(1), - Operator: kyverno.NotEqual, - Value: int64(2), - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_NoEqual_Const_int64_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: int64(1), - Operator: kyverno.NotEqual, - Value: int64(1), - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_int64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(3600), - Operator: kyverno.DurationGreaterThanOrEquals, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_int64_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(7200), - Operator: kyverno.DurationGreaterThanOrEquals, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_int64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(3600), - Operator: kyverno.DurationGreaterThanOrEquals, - Value: int64(7200), - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThan_Const_int64_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(3600), - Operator: kyverno.DurationGreaterThan, - Value: int64(7200), - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThan_Const_int64_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(7200), - Operator: kyverno.DurationGreaterThan, - Value: int64(3600), - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThan_Const_int64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(3600), - Operator: kyverno.DurationGreaterThan, - Value: int64(7200), - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_int64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(7200), - Operator: kyverno.DurationLessThanOrEquals, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_int64_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(3600), - Operator: kyverno.DurationLessThanOrEquals, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_int64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(7200), - Operator: kyverno.LessThanOrEquals, - Value: int64(3600), - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_int64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(3600), - Operator: kyverno.DurationLessThan, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_int64_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(3600), - Operator: kyverno.DurationLessThan, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThan_Const_int64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: int64(7200), - Operator: kyverno.DurationLessThan, - Value: int64(3600), - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -//float64 - -func Test_Eval_Equal_Const_float64_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1.5, - Operator: kyverno.Equal, - Value: 1.5, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_Equal_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1.5, - Operator: kyverno.Equal, - Value: 1.6, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_NoEqual_Const_float64_Pass(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1.5, - Operator: kyverno.NotEqual, - Value: 1.6, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_NoEqual_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - // no variables - condition := kyverno.Condition{ - Key: 1.5, - Operator: kyverno.NotEqual, - Value: 1.5, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_float64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.0, - Operator: kyverno.GreaterThanOrEquals, - Value: 1.0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_float64_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.5, - Operator: kyverno.GreaterThanOrEquals, - Value: 0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThanOrEquals_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.95, - Operator: kyverno.GreaterThanOrEquals, - Value: "2", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThan_Const_float64_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.0, - Operator: kyverno.GreaterThan, - Value: 1.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_GreaterThan_Const_float64_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.5, - Operator: kyverno.GreaterThan, - Value: "0", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_GreaterThan_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.95, - Operator: kyverno.GreaterThan, - Value: "2.5", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThanOrEquals_Const_float64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.0, - Operator: kyverno.LessThanOrEquals, - Value: 1.0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_float64_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 0.5, - Operator: kyverno.LessThanOrEquals, - Value: 1, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThanOrEquals_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 2.0, - Operator: kyverno.LessThanOrEquals, - Value: "1.95", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThan_Const_float64_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 1.0, - Operator: kyverno.LessThan, - Value: 1.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_LessThan_Const_float64_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 0.5, - Operator: kyverno.LessThan, - Value: "1.5", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_LessThan_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 2.5, - Operator: kyverno.LessThan, - Value: 1.95, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_float64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600.0, - Operator: kyverno.DurationGreaterThanOrEquals, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_float64_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200.0, - Operator: kyverno.DurationGreaterThanOrEquals, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThanOrEquals_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600.0, - Operator: kyverno.DurationGreaterThanOrEquals, - Value: 7200.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThan_Const_float64_Equal_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600.0, - Operator: kyverno.DurationGreaterThan, - Value: 7200.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationGreaterThan_Const_float64_Greater_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200.0, - Operator: kyverno.DurationGreaterThan, - Value: "1h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationGreaterThan_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600.0, - Operator: kyverno.DurationGreaterThan, - Value: 7200.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_float64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200.0, - Operator: kyverno.DurationLessThanOrEquals, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_float64_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600.0, - Operator: kyverno.DurationLessThanOrEquals, - Value: "2h", - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThanOrEquals_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200.0, - Operator: kyverno.LessThanOrEquals, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_float64_Equal_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 3600.0, - Operator: kyverno.DurationLessThan, - Value: "1h", - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_DurationLessThan_Const_float64_Less_Pass(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: "1h", - Operator: kyverno.DurationLessThan, - Value: 7200.0, - } - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_DurationLessThan_Const_float64_Fail(t *testing.T) { - ctx := context.NewContext() - condition := kyverno.Condition{ - Key: 7200.0, - Operator: kyverno.DurationLessThan, - Value: 3600.0, - } - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -//object/map[string]interface - -func Test_Eval_Equal_Const_object_Pass(t *testing.T) { - ctx := context.NewContext() - var err error - - obj1Raw := []byte(`{ "dir": { "file1": "a" } }`) - obj2Raw := []byte(`{ "dir": { "file1": "a" } }`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.Equal, - Value: obj2, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_Equal_Const_object_Fail(t *testing.T) { - ctx := context.NewContext() - var err error - obj1Raw := []byte(`{ "dir": { "file1": "a" } }`) - obj2Raw := []byte(`{ "dir": { "file1": "b" } }`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.Equal, - Value: obj2, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_NotEqual_Const_object_Pass(t *testing.T) { - ctx := context.NewContext() - var err error - obj1Raw := []byte(`{ "dir": { "file1": "a" } }`) - obj2Raw := []byte(`{ "dir": { "file1": "b" } }`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.NotEqual, - Value: obj2, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_NotEqual_Const_object_Fail(t *testing.T) { - ctx := context.NewContext() - var err error - obj1Raw := []byte(`{ "dir": { "file1": "a" } }`) - obj2Raw := []byte(`{ "dir": { "file1": "a" } }`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.NotEqual, - Value: obj2, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -// list/ []interface{} - -func Test_Eval_Equal_Const_list_Pass(t *testing.T) { - ctx := context.NewContext() - var err error - obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`) - obj2Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.Equal, - Value: obj2, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_Equal_Const_list_Fail(t *testing.T) { - ctx := context.NewContext() - var err error - obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`) - obj2Raw := []byte(`[ { "name": "b", "file": "a" }, { "name": "b", "file": "b" } ]`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.Equal, - Value: obj2, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_NotEqual_Const_list_Pass(t *testing.T) { - ctx := context.NewContext() - var err error - obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`) - obj2Raw := []byte(`[ { "name": "b", "file": "a" }, { "name": "b", "file": "b" } ]`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.NotEqual, - Value: obj2, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_NotEqual_Const_list_Fail(t *testing.T) { - ctx := context.NewContext() - var err error - obj1Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`) - obj2Raw := []byte(`[ { "name": "a", "file": "a" }, { "name": "b", "file": "b" } ]`) - var obj1, obj2 interface{} - err = json.Unmarshal(obj1Raw, &obj1) - if err != nil { - t.Error(err) - } - err = json.Unmarshal(obj2Raw, &obj2) - if err != nil { - t.Error(err) - } - // no variables - condition := kyverno.Condition{ - Key: obj1, - Operator: kyverno.NotEqual, - Value: obj2, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") +func TestEvaluate(t *testing.T) { + testCases := []struct { + Condition kyverno.Condition + Result bool + }{ + // Equals + {kyverno.Condition{Key: "string", Operator: kyverno.Equals, Value: "string"}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.Equals, Value: 1}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.Equals, Value: int64(1)}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.Equals, Value: 1}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.Equals, Value: 1.0}, true}, + {kyverno.Condition{Key: true, Operator: kyverno.Equals, Value: true}, true}, + {kyverno.Condition{Key: false, Operator: kyverno.Equals, Value: false}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.Equals, Value: "1Gi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.Equals, Value: "1024Mi"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.Equals, Value: "1h"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.Equals, Value: "60m"}, true}, + {kyverno.Condition{Key: map[string]interface{}{"foo": "bar"}, Operator: kyverno.Equals, Value: map[string]interface{}{"foo": "bar"}}, true}, + {kyverno.Condition{Key: []interface{}{"foo", "bar"}, Operator: kyverno.Equals, Value: []interface{}{"foo", "bar"}}, true}, + {kyverno.Condition{Key: []interface{}{map[string]string{"foo": "bar"}}, Operator: kyverno.Equals, Value: []interface{}{map[string]string{"foo": "bar"}}}, true}, + {kyverno.Condition{Key: "string", Operator: kyverno.Equals, Value: "not string"}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.Equals, Value: 2}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.Equals, Value: int64(2)}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.Equals, Value: 2}, false}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.Equals, Value: 2.0}, false}, + {kyverno.Condition{Key: true, Operator: kyverno.Equals, Value: false}, false}, + {kyverno.Condition{Key: false, Operator: kyverno.Equals, Value: true}, false}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.Equals, Value: "10Gi"}, false}, + {kyverno.Condition{Key: "10Gi", Operator: kyverno.Equals, Value: "1024Mi"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.Equals, Value: "5h"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.Equals, Value: "30m"}, false}, + {kyverno.Condition{Key: "string", Operator: kyverno.Equals, Value: 1}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.Equals, Value: "2"}, false}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.Equals, Value: "2.0"}, false}, + {kyverno.Condition{Key: true, Operator: kyverno.Equals, Value: "false"}, false}, + {kyverno.Condition{Key: false, Operator: kyverno.Equals, Value: "true"}, false}, + {kyverno.Condition{Key: map[string]interface{}{"foo": "bar"}, Operator: kyverno.Equals, Value: map[string]interface{}{"bar": "foo"}}, false}, + {kyverno.Condition{Key: []interface{}{"foo", "bar"}, Operator: kyverno.Equals, Value: []interface{}{"bar", "foo"}}, false}, + {kyverno.Condition{Key: []interface{}{map[string]string{"foo": "bar"}}, Operator: kyverno.Equals, Value: []interface{}{map[string]string{"bar": "foo"}}}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.Equals, Value: 3600}, true}, + {kyverno.Condition{Key: "2h", Operator: kyverno.Equals, Value: 3600}, false}, + + // Not Equals + {kyverno.Condition{Key: "string", Operator: kyverno.NotEquals, Value: "string"}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.NotEquals, Value: 1}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.NotEquals, Value: int64(1)}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.NotEquals, Value: 1}, false}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.NotEquals, Value: 1.0}, false}, + {kyverno.Condition{Key: true, Operator: kyverno.NotEquals, Value: false}, true}, + {kyverno.Condition{Key: false, Operator: kyverno.NotEquals, Value: false}, false}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.NotEquals, Value: "1Gi"}, false}, + {kyverno.Condition{Key: "10Gi", Operator: kyverno.NotEquals, Value: "1024Mi"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.NotEquals, Value: "1h"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.NotEquals, Value: "60m"}, false}, + {kyverno.Condition{Key: map[string]interface{}{"foo": "bar"}, Operator: kyverno.NotEquals, Value: map[string]interface{}{"foo": "bar"}}, false}, + {kyverno.Condition{Key: []interface{}{"foo", "bar"}, Operator: kyverno.NotEquals, Value: []interface{}{"foo", "bar"}}, false}, + {kyverno.Condition{Key: []interface{}{map[string]string{"foo": "bar"}}, Operator: kyverno.NotEquals, Value: []interface{}{map[string]string{"foo": "bar"}}}, false}, + {kyverno.Condition{Key: "string", Operator: kyverno.NotEquals, Value: "not string"}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.NotEquals, Value: 2}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.NotEquals, Value: int64(2)}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.NotEquals, Value: 2}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.NotEquals, Value: 2.0}, true}, + {kyverno.Condition{Key: true, Operator: kyverno.NotEquals, Value: true}, false}, + {kyverno.Condition{Key: false, Operator: kyverno.NotEquals, Value: true}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.NotEquals, Value: "10Gi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.NotEquals, Value: "1024Mi"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.NotEquals, Value: "5h"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.NotEquals, Value: "30m"}, true}, + {kyverno.Condition{Key: "string", Operator: kyverno.NotEquals, Value: 1}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.NotEquals, Value: "2"}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.NotEquals, Value: "2.0"}, true}, + {kyverno.Condition{Key: true, Operator: kyverno.NotEquals, Value: "false"}, true}, + {kyverno.Condition{Key: false, Operator: kyverno.NotEquals, Value: "true"}, true}, + {kyverno.Condition{Key: map[string]interface{}{"foo": "bar"}, Operator: kyverno.NotEquals, Value: map[string]interface{}{"bar": "foo"}}, true}, + {kyverno.Condition{Key: []interface{}{"foo", "bar"}, Operator: kyverno.NotEquals, Value: []interface{}{"bar", "foo"}}, true}, + {kyverno.Condition{Key: []interface{}{map[string]string{"foo": "bar"}}, Operator: kyverno.NotEquals, Value: []interface{}{map[string]string{"bar": "foo"}}}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.NotEquals, Value: 3600}, false}, + {kyverno.Condition{Key: "2h", Operator: kyverno.NotEquals, Value: 3600}, true}, + + // Greater Than + {kyverno.Condition{Key: 10, Operator: kyverno.GreaterThan, Value: 1}, true}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.GreaterThan, Value: 1.0}, true}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.GreaterThan, Value: 1}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThan, Value: 10}, false}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.GreaterThan, Value: 1.5}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThan, Value: 1.5}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThan, Value: 1}, false}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.GreaterThan, Value: 1.0}, false}, + {kyverno.Condition{Key: "10Gi", Operator: kyverno.GreaterThan, Value: "1Gi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.GreaterThan, Value: "1Mi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.GreaterThan, Value: "10Gi"}, false}, + {kyverno.Condition{Key: "10Mi", Operator: kyverno.GreaterThan, Value: "10Mi"}, false}, + {kyverno.Condition{Key: "10h", Operator: kyverno.GreaterThan, Value: "1h"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.GreaterThan, Value: "30m"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.GreaterThan, Value: "1h"}, false}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.GreaterThan, Value: "1Gi"}, false}, + {kyverno.Condition{Key: "10", Operator: kyverno.GreaterThan, Value: 1}, true}, + {kyverno.Condition{Key: 100, Operator: kyverno.GreaterThan, Value: "10"}, true}, + {kyverno.Condition{Key: "100", Operator: kyverno.GreaterThan, Value: "10"}, true}, + {kyverno.Condition{Key: "10", Operator: kyverno.GreaterThan, Value: "10"}, false}, + {kyverno.Condition{Key: "1", Operator: kyverno.GreaterThan, Value: "10"}, false}, + {kyverno.Condition{Key: "1", Operator: kyverno.GreaterThan, Value: 10}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThan, Value: "10"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.GreaterThan, Value: 3600}, false}, + {kyverno.Condition{Key: "2h", Operator: kyverno.GreaterThan, Value: 3600}, true}, + {kyverno.Condition{Key: 3600, Operator: kyverno.GreaterThan, Value: "1h"}, false}, + {kyverno.Condition{Key: 3600, Operator: kyverno.GreaterThan, Value: "30m"}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThan, Value: int64(1)}, false}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.GreaterThan, Value: int64(1)}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThan, Value: int64(10)}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThan, Value: 1}, false}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.GreaterThan, Value: 1}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThan, Value: 10}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThan, Value: int64(1)}, false}, + {kyverno.Condition{Key: 10, Operator: kyverno.GreaterThan, Value: int64(1)}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThan, Value: int64(10)}, false}, + {kyverno.Condition{Key: -5, Operator: kyverno.GreaterThan, Value: 1}, false}, + {kyverno.Condition{Key: -5, Operator: kyverno.GreaterThan, Value: -10}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThan, Value: -10}, true}, + + // Less Than + {kyverno.Condition{Key: 10, Operator: kyverno.LessThan, Value: 1}, false}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.LessThan, Value: 1.0}, false}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.LessThan, Value: 1}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThan, Value: 10}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.LessThan, Value: 1.5}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThan, Value: 1.5}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThan, Value: 1}, false}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.LessThan, Value: 1.0}, false}, + {kyverno.Condition{Key: "10Gi", Operator: kyverno.LessThan, Value: "1Gi"}, false}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.LessThan, Value: "10Gi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.LessThan, Value: "1Mi"}, false}, + {kyverno.Condition{Key: "1Mi", Operator: kyverno.LessThan, Value: "1Gi"}, true}, + {kyverno.Condition{Key: "10h", Operator: kyverno.LessThan, Value: "1h"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.LessThan, Value: "30m"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.LessThan, Value: "1h"}, false}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.LessThan, Value: "1Gi"}, false}, + {kyverno.Condition{Key: "10", Operator: kyverno.LessThan, Value: 1}, false}, + {kyverno.Condition{Key: 100, Operator: kyverno.LessThan, Value: "10"}, false}, + {kyverno.Condition{Key: "100", Operator: kyverno.LessThan, Value: "10"}, false}, + {kyverno.Condition{Key: "10", Operator: kyverno.LessThan, Value: "10"}, false}, + {kyverno.Condition{Key: "1", Operator: kyverno.LessThan, Value: "10"}, true}, + {kyverno.Condition{Key: "1", Operator: kyverno.LessThan, Value: 10}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThan, Value: "10"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.LessThan, Value: 3600}, false}, + {kyverno.Condition{Key: "30m", Operator: kyverno.LessThan, Value: 3600}, true}, + {kyverno.Condition{Key: 3600, Operator: kyverno.LessThan, Value: "1h"}, false}, + {kyverno.Condition{Key: 3600, Operator: kyverno.LessThan, Value: "30m"}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThan, Value: int64(1)}, false}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.LessThan, Value: int64(1)}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThan, Value: int64(10)}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThan, Value: 1}, false}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.LessThan, Value: 1}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThan, Value: 10}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThan, Value: int64(1)}, false}, + {kyverno.Condition{Key: 10, Operator: kyverno.LessThan, Value: int64(1)}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThan, Value: int64(10)}, true}, + {kyverno.Condition{Key: -5, Operator: kyverno.LessThan, Value: 1}, true}, + {kyverno.Condition{Key: -5, Operator: kyverno.LessThan, Value: -10}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThan, Value: -10}, false}, + + // Greater Than or Equal + {kyverno.Condition{Key: 10, Operator: kyverno.GreaterThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.GreaterThanOrEquals, Value: 1.0}, true}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.GreaterThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThanOrEquals, Value: 10}, false}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.GreaterThanOrEquals, Value: 1.5}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThanOrEquals, Value: 1.5}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.GreaterThanOrEquals, Value: 1.0}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.GreaterThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: "10Gi", Operator: kyverno.GreaterThanOrEquals, Value: "1Gi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.GreaterThanOrEquals, Value: "1Mi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.GreaterThanOrEquals, Value: "10Gi"}, false}, + {kyverno.Condition{Key: "10h", Operator: kyverno.GreaterThanOrEquals, Value: "1h"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.GreaterThanOrEquals, Value: "30m"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.GreaterThanOrEquals, Value: "1h"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.GreaterThanOrEquals, Value: "1Gi"}, true}, + {kyverno.Condition{Key: "10", Operator: kyverno.GreaterThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: 100, Operator: kyverno.GreaterThanOrEquals, Value: "10"}, true}, + {kyverno.Condition{Key: "100", Operator: kyverno.GreaterThanOrEquals, Value: "10"}, true}, + {kyverno.Condition{Key: "10", Operator: kyverno.GreaterThanOrEquals, Value: "10"}, true}, + {kyverno.Condition{Key: "1", Operator: kyverno.GreaterThanOrEquals, Value: "10"}, false}, + {kyverno.Condition{Key: "1", Operator: kyverno.GreaterThanOrEquals, Value: 10}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThanOrEquals, Value: "10"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.GreaterThanOrEquals, Value: 3600}, true}, + {kyverno.Condition{Key: "2h", Operator: kyverno.GreaterThanOrEquals, Value: 3600}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThanOrEquals, Value: int64(1)}, true}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.GreaterThanOrEquals, Value: int64(1)}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThanOrEquals, Value: int64(10)}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.GreaterThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.GreaterThanOrEquals, Value: 10}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThanOrEquals, Value: int64(1)}, true}, + {kyverno.Condition{Key: 10, Operator: kyverno.GreaterThanOrEquals, Value: int64(1)}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.GreaterThanOrEquals, Value: int64(10)}, false}, + + // Less Than or Equal + {kyverno.Condition{Key: 10, Operator: kyverno.LessThanOrEquals, Value: 1}, false}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.LessThanOrEquals, Value: 1.0}, false}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.LessThanOrEquals, Value: 1}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThanOrEquals, Value: 10}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.LessThanOrEquals, Value: 1.5}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThanOrEquals, Value: 1.5}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: 1.0, Operator: kyverno.LessThanOrEquals, Value: 1.0}, true}, + {kyverno.Condition{Key: "10Gi", Operator: kyverno.LessThanOrEquals, Value: "1Gi"}, false}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.LessThanOrEquals, Value: "10Gi"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.LessThanOrEquals, Value: "1Mi"}, false}, + {kyverno.Condition{Key: "1Mi", Operator: kyverno.LessThanOrEquals, Value: "1Gi"}, true}, + {kyverno.Condition{Key: "10h", Operator: kyverno.LessThanOrEquals, Value: "1h"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.LessThanOrEquals, Value: "30m"}, false}, + {kyverno.Condition{Key: "1h", Operator: kyverno.LessThanOrEquals, Value: "1h"}, true}, + {kyverno.Condition{Key: "1Gi", Operator: kyverno.LessThanOrEquals, Value: "1Gi"}, true}, + {kyverno.Condition{Key: "10", Operator: kyverno.LessThanOrEquals, Value: 1}, false}, + {kyverno.Condition{Key: 100, Operator: kyverno.LessThanOrEquals, Value: "10"}, false}, + {kyverno.Condition{Key: "100", Operator: kyverno.LessThanOrEquals, Value: "10"}, false}, + {kyverno.Condition{Key: "10", Operator: kyverno.LessThanOrEquals, Value: "10"}, true}, + {kyverno.Condition{Key: "1", Operator: kyverno.LessThanOrEquals, Value: "10"}, true}, + {kyverno.Condition{Key: "1", Operator: kyverno.LessThanOrEquals, Value: 10}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThanOrEquals, Value: "10"}, true}, + {kyverno.Condition{Key: "1h", Operator: kyverno.LessThanOrEquals, Value: 3600}, true}, + {kyverno.Condition{Key: "2h", Operator: kyverno.LessThanOrEquals, Value: 3600}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThanOrEquals, Value: int64(1)}, true}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.LessThanOrEquals, Value: int64(1)}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThanOrEquals, Value: int64(10)}, true}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThanOrEquals, Value: 1}, true}, + {kyverno.Condition{Key: int64(10), Operator: kyverno.LessThanOrEquals, Value: 1}, false}, + {kyverno.Condition{Key: int64(1), Operator: kyverno.LessThanOrEquals, Value: 10}, true}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThanOrEquals, Value: int64(1)}, true}, + {kyverno.Condition{Key: 10, Operator: kyverno.LessThanOrEquals, Value: int64(1)}, false}, + {kyverno.Condition{Key: 1, Operator: kyverno.LessThanOrEquals, Value: int64(10)}, true}, + + // In + {kyverno.Condition{Key: 1, Operator: kyverno.In, Value: []interface{}{1, 2, 3}}, true}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.In, Value: []interface{}{1, 1.5, 2, 3}}, true}, + {kyverno.Condition{Key: "1", Operator: kyverno.In, Value: []interface{}{"1", "2", "3"}}, true}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "2.2.2.2"}, Operator: kyverno.In, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, true}, + {kyverno.Condition{Key: 5, Operator: kyverno.In, Value: []interface{}{1, 2, 3}}, false}, + {kyverno.Condition{Key: 5.5, Operator: kyverno.In, Value: []interface{}{1, 1.5, 2, 3}}, false}, + {kyverno.Condition{Key: "5", Operator: kyverno.In, Value: []interface{}{"1", "2", "3"}}, false}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "4.4.4.4"}, Operator: kyverno.In, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + + // Not In + {kyverno.Condition{Key: 1, Operator: kyverno.NotIn, Value: []interface{}{1, 2, 3}}, false}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.NotIn, Value: []interface{}{1, 1.5, 2, 3}}, false}, + {kyverno.Condition{Key: "1", Operator: kyverno.NotIn, Value: []interface{}{"1", "2", "3"}}, false}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "2.2.2.2"}, Operator: kyverno.NotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + {kyverno.Condition{Key: 5, Operator: kyverno.NotIn, Value: []interface{}{1, 2, 3}}, true}, + {kyverno.Condition{Key: 5.5, Operator: kyverno.NotIn, Value: []interface{}{1, 1.5, 2, 3}}, true}, + {kyverno.Condition{Key: "5", Operator: kyverno.NotIn, Value: []interface{}{"1", "2", "3"}}, true}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "4.4.4.4"}, Operator: kyverno.NotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, true}, + + // Any In + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "5.5.5.5"}, Operator: kyverno.AnyIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, true}, + {kyverno.Condition{Key: []interface{}{"4.4.4.4", "5.5.5.5"}, Operator: kyverno.AnyIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "5.5.5.5"}, Operator: kyverno.AnyIn, Value: []interface{}{"1.1.1.1"}}, true}, + {kyverno.Condition{Key: []interface{}{1, 2}, Operator: kyverno.AnyIn, Value: []interface{}{1, 2, 3, 4}}, true}, + {kyverno.Condition{Key: []interface{}{1, 5}, Operator: kyverno.AnyIn, Value: []interface{}{1, 2, 3, 4}}, true}, + {kyverno.Condition{Key: []interface{}{5}, Operator: kyverno.AnyIn, Value: []interface{}{1, 2, 3, 4}}, false}, + + // All In + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "2.2.2.2"}, Operator: kyverno.AllIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, true}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "5.5.5.5"}, Operator: kyverno.AllIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + {kyverno.Condition{Key: []interface{}{"4.4.4.4", "5.5.5.5"}, Operator: kyverno.AllIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "5.5.5.5"}, Operator: kyverno.AllIn, Value: []interface{}{"1.1.1.1"}}, false}, + {kyverno.Condition{Key: []interface{}{1, 2}, Operator: kyverno.AllIn, Value: []interface{}{1, 2, 3, 4}}, true}, + {kyverno.Condition{Key: []interface{}{1, 5}, Operator: kyverno.AllIn, Value: []interface{}{1, 2, 3, 4}}, false}, + {kyverno.Condition{Key: []interface{}{5}, Operator: kyverno.AllIn, Value: []interface{}{1, 2, 3, 4}}, false}, + + // All Not In + {kyverno.Condition{Key: 1, Operator: kyverno.AllNotIn, Value: []interface{}{1, 2, 3}}, false}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.AllNotIn, Value: []interface{}{1, 1.5, 2, 3}}, false}, + {kyverno.Condition{Key: "1", Operator: kyverno.AllNotIn, Value: []interface{}{"1", "2", "3"}}, false}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "2.2.2.2"}, Operator: kyverno.AllNotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + {kyverno.Condition{Key: 5, Operator: kyverno.AllNotIn, Value: []interface{}{1, 2, 3}}, true}, + {kyverno.Condition{Key: 5.5, Operator: kyverno.AllNotIn, Value: []interface{}{1, 1.5, 2, 3}}, true}, + {kyverno.Condition{Key: "5", Operator: kyverno.AllNotIn, Value: []interface{}{"1", "2", "3"}}, true}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "4.4.4.4"}, Operator: kyverno.AllNotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + {kyverno.Condition{Key: []interface{}{"5.5.5.5", "4.4.4.4"}, Operator: kyverno.AllNotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, true}, + + // Any Not In + {kyverno.Condition{Key: 1, Operator: kyverno.AnyNotIn, Value: []interface{}{1, 2, 3}}, false}, + {kyverno.Condition{Key: 1.5, Operator: kyverno.AnyNotIn, Value: []interface{}{1, 1.5, 2, 3}}, false}, + {kyverno.Condition{Key: "1", Operator: kyverno.AnyNotIn, Value: []interface{}{"1", "2", "3"}}, false}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "2.2.2.2"}, Operator: kyverno.AnyNotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, false}, + {kyverno.Condition{Key: 5, Operator: kyverno.AnyNotIn, Value: []interface{}{1, 2, 3}}, true}, + {kyverno.Condition{Key: 5.5, Operator: kyverno.AnyNotIn, Value: []interface{}{1, 1.5, 2, 3}}, true}, + {kyverno.Condition{Key: "5", Operator: kyverno.AnyNotIn, Value: []interface{}{"1", "2", "3"}}, true}, + {kyverno.Condition{Key: []interface{}{"1.1.1.1", "4.4.4.4"}, Operator: kyverno.AnyNotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, true}, + {kyverno.Condition{Key: []interface{}{"5.5.5.5", "4.4.4.4"}, Operator: kyverno.AnyNotIn, Value: []interface{}{"1.1.1.1", "2.2.2.2", "3.3.3.3"}}, true}, + } + + ctx := context.NewContext() + for _, tc := range testCases { + if Evaluate(log.Log, ctx, tc.Condition) != tc.Result { + t.Errorf("%v - expected result to be %v", tc.Condition, tc.Result) + } } } @@ -1757,543 +385,3 @@ func Test_Eval_Equal_Var_Fail(t *testing.T) { t.Error("expected to fail") } } - -// subset test - -// test passes if ALL values in "key" are in "value" ("key" is a subset of "value") -func Test_Eval_In_String_Set_Pass(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "2.2.2.2"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.In, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -// test passes if NOT ALL values in "key" are in "value" ("key" is not a subset of "value") -func Test_Eval_In_String_Set_Fail(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "4.4.4.4"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.In, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_AnyIn_String_Set_Pass1(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "5.5.5.5"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AnyIn_String_Set_Pass2(t *testing.T) { - ctx := context.NewContext() - key := [3]string{"1.1.1.1", "5.5.5.5", "2.2.2.2"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - - value := [2]string{"2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AnyIn_String_Set_Pass3(t *testing.T) { - ctx := context.NewContext() - key := [1]string{"1.1.1.1"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AnyIn_String_Set_Fail1(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"5.5.5.5", "4.4.4.4"} - keyInterface := make([]interface{}, len(key), len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_AnyIn_String_Set_Fail2(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"5.5.5.5"} - keyInterface := make([]interface{}, len(key), len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} -func Test_Eval_AllIn_String_Set_Pass1(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "3.3.3.3"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AllIn_String_Set_Pass2(t *testing.T) { - ctx := context.NewContext() - key := [1]string{"1.1.1.1"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AllIn_String_Set_Fail1(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"5.5.5.5", "4.4.4.4"} - keyInterface := make([]interface{}, len(key), len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_AllIn_String_Set_Fail2(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"5.5.5.5"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} -func Test_Eval_AllIn_String_Set_Fail3(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "4.4.4.4"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -// test passes if ONE of the values in "key" is NOT in "value" ("key" is not a subset of "value") -func Test_Eval_NotIn_String_Set_Pass(t *testing.T) { - ctx := context.NewContext() - key := [3]string{"1.1.1.1", "4.4.4.4", "5.5.5.5"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.NotIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -// test passes if ALL of the values in "key" are in "value" ("key" is a subset of "value") -func Test_Eval_NotIn_String_Set_Fail(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "2.2.2.2"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.NotIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_AnyNotIn_String_Set_Pass1(t *testing.T) { - ctx := context.NewContext() - key := [3]string{"1.1.1.1", "4.4.4.4", "5.5.5.5"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyNotIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AnyNotIn_String_Set_Pass2(t *testing.T) { - ctx := context.NewContext() - key := [1]string{"4.4.4.4"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyNotIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AnyNotIn_String_Set_Pass3(t *testing.T) { - ctx := context.NewContext() - key := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [1]string{"1.1.1.1"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyNotIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -// test passes if ALL of the values in "key" are in "value" ("key" is a subset of "value") -func Test_Eval_AnyNotIn_String_Set_Fail1(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "2.2.2.2"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AnyNotIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_AllNotIn_String_Set_Pass1(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"4.4.4.4", "5.5.5.5"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllNotIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -func Test_Eval_AllNotIn_String_Set_Pass2(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"4.4.4.4", "5.5.5.5"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [1]string{"1.1.1.1"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllNotIn, - Value: valueInterface, - } - - if !Evaluate(log.Log, ctx, condition) { - t.Error("expected to pass") - } -} - -// test passes if ALL of the values in "key" are in "value" ("key" is a subset of "value") -func Test_Eval_AllNotIn_String_Set_Fail1(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "2.2.2.2"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllNotIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} - -func Test_Eval_AllNotIn_String_Set_Fail2(t *testing.T) { - ctx := context.NewContext() - key := [2]string{"1.1.1.1", "5.5.5.5"} - keyInterface := make([]interface{}, len(key)) - for i := range key { - keyInterface[i] = key[i] - } - value := [3]string{"1.1.1.1", "2.2.2.2", "3.3.3.3"} - valueInterface := make([]interface{}, len(value)) - for i := range value { - valueInterface[i] = value[i] - } - - condition := kyverno.Condition{ - Key: keyInterface, - Operator: kyverno.AllNotIn, - Value: valueInterface, - } - - if Evaluate(log.Log, ctx, condition) { - t.Error("expected to fail") - } -} diff --git a/pkg/engine/variables/operator/allin.go b/pkg/engine/variables/operator/allin.go index 4101ababba..e6713db1fb 100644 --- a/pkg/engine/variables/operator/allin.go +++ b/pkg/engine/variables/operator/allin.go @@ -31,7 +31,7 @@ func (allin AllInHandler) Evaluate(key, value interface{}) bool { case []interface{}: var stringSlice []string for _, v := range typedKey { - stringSlice = append(stringSlice, v.(string)) + stringSlice = append(stringSlice, fmt.Sprint(v)) } return allin.validateValueWithStringSetPattern(stringSlice, value) default: @@ -70,11 +70,7 @@ func allSetExistsInArray(key []string, value interface{}, log logr.Logger, allNo case []interface{}: var valueSlice []string for _, val := range valuesAvailable { - v, ok := val.(string) - if !ok { - return true, false - } - valueSlice = append(valueSlice, v) + valueSlice = append(valueSlice, fmt.Sprint(val)) } if allNotIn { return false, isAllNotIn(key, valueSlice) @@ -114,12 +110,7 @@ func isAllIn(key []string, value []string) bool { } } } - if found == len(key) { - return true - } else { - return false - } - + return found == len(key) } // isAllNotIn checks if all the values in S1 are not in S2 diff --git a/pkg/engine/variables/operator/allnotin.go b/pkg/engine/variables/operator/allnotin.go index f163f371e6..ab5f8e1523 100644 --- a/pkg/engine/variables/operator/allnotin.go +++ b/pkg/engine/variables/operator/allnotin.go @@ -26,10 +26,12 @@ func (allnin AllNotInHandler) Evaluate(key, value interface{}) bool { switch typedKey := key.(type) { case string: return allnin.validateValueWithStringPattern(typedKey, value) + case int, int32, int64, float32, float64: + return allnin.validateValueWithStringPattern(fmt.Sprint(typedKey), value) case []interface{}: var stringSlice []string for _, v := range typedKey { - stringSlice = append(stringSlice, v.(string)) + stringSlice = append(stringSlice, fmt.Sprint(v)) } return allnin.validateValueWithStringSetPattern(stringSlice, value) default: diff --git a/pkg/engine/variables/operator/anyin.go b/pkg/engine/variables/operator/anyin.go index 41bbd0108e..da99ee2515 100644 --- a/pkg/engine/variables/operator/anyin.go +++ b/pkg/engine/variables/operator/anyin.go @@ -28,10 +28,12 @@ func (anyin AnyInHandler) Evaluate(key, value interface{}) bool { switch typedKey := key.(type) { case string: return anyin.validateValueWithStringPattern(typedKey, value) + case int, int32, int64, float32, float64: + return anyin.validateValueWithStringPattern(fmt.Sprint(typedKey), value) case []interface{}: var stringSlice []string for _, v := range typedKey { - stringSlice = append(stringSlice, v.(string)) + stringSlice = append(stringSlice, fmt.Sprint(v)) } return anyin.validateValueWithStringSetPattern(stringSlice, value) default: @@ -70,11 +72,7 @@ func anySetExistsInArray(key []string, value interface{}, log logr.Logger, anyNo case []interface{}: var valueSlice []string for _, val := range valuesAvailable { - v, ok := val.(string) - if !ok { - return true, false - } - valueSlice = append(valueSlice, v) + valueSlice = append(valueSlice, fmt.Sprint(val)) } if anyNotIn { return false, isAnyNotIn(key, valueSlice) @@ -126,11 +124,7 @@ func isAnyNotIn(key []string, value []string) bool { } } } - if found < len(key) { - return true - } else { - return false - } + return found < len(key) } func (anyin AnyInHandler) validateValueWithBoolPattern(_ bool, _ interface{}) bool { diff --git a/pkg/engine/variables/operator/anynotin.go b/pkg/engine/variables/operator/anynotin.go index fba7ce1bc2..52e598fd81 100644 --- a/pkg/engine/variables/operator/anynotin.go +++ b/pkg/engine/variables/operator/anynotin.go @@ -26,10 +26,12 @@ func (anynin AnyNotInHandler) Evaluate(key, value interface{}) bool { switch typedKey := key.(type) { case string: return anynin.validateValueWithStringPattern(typedKey, value) + case int, int32, int64, float32, float64: + return anynin.validateValueWithStringPattern(fmt.Sprint(typedKey), value) case []interface{}: var stringSlice []string for _, v := range typedKey { - stringSlice = append(stringSlice, v.(string)) + stringSlice = append(stringSlice, fmt.Sprint(v)) } return anynin.validateValueWithStringSetPattern(stringSlice, value) default: diff --git a/pkg/engine/variables/operator/equal.go b/pkg/engine/variables/operator/equal.go index 4f226cd5c5..9772235e12 100644 --- a/pkg/engine/variables/operator/equal.go +++ b/pkg/engine/variables/operator/equal.go @@ -7,6 +7,7 @@ import ( "strconv" "github.com/minio/pkg/wildcard" + "k8s.io/apimachinery/pkg/api/resource" "github.com/go-logr/logr" "github.com/kyverno/kyverno/pkg/engine/context" @@ -67,6 +68,26 @@ func (eh EqualHandler) validateValueWithMapPattern(key map[string]interface{}, v } func (eh EqualHandler) validateValueWithStringPattern(key string, value interface{}) bool { + // We need to check duration first as it's the only type that can be compared to a different type. + durationKey, durationValue, err := parseDuration(key, value) + if err == nil { + return durationKey.Seconds() == durationValue.Seconds() + } + + // Attempt to extract resource quantity from string. + resourceKey, err := resource.ParseQuantity(key) + if err == nil { + switch typedValue := value.(type) { + case string: + resourceValue, err := resource.ParseQuantity(typedValue) + if err != nil { + eh.log.Error(fmt.Errorf("parse error: "), "Failed to parse value type doesn't match key type") + return false + } + return resourceKey.Equal(resourceValue) + } + } + if val, ok := value.(string); ok { return wildcard.Match(val, key) } diff --git a/pkg/engine/variables/operator/in.go b/pkg/engine/variables/operator/in.go index e55807f66a..5350738675 100644 --- a/pkg/engine/variables/operator/in.go +++ b/pkg/engine/variables/operator/in.go @@ -10,8 +10,9 @@ import ( "github.com/kyverno/kyverno/pkg/engine/context" ) -// deprecated -//NewInHandler returns handler to manage In operations +// NewInHandler returns handler to manage In operations +// +// Deprecated: Use `NewAllInHandler` or `NewAnyInHandler` instead func NewInHandler(log logr.Logger, ctx context.EvalInterface) OperatorHandler { return InHandler{ ctx: ctx, @@ -19,17 +20,19 @@ func NewInHandler(log logr.Logger, ctx context.EvalInterface) OperatorHandler { } } -//InHandler provides implementation to handle In Operator +// InHandler provides implementation to handle In Operator type InHandler struct { ctx context.EvalInterface log logr.Logger } -//Evaluate evaluates expression with In Operator +// Evaluate evaluates expression with In Operator func (in InHandler) Evaluate(key, value interface{}) bool { switch typedKey := key.(type) { case string: return in.validateValueWithStringPattern(typedKey, value) + case int, int32, int64, float32, float64: + return in.validateValueWithStringPattern(fmt.Sprint(typedKey), value) case []interface{}: var stringSlice []string for _, v := range typedKey { @@ -60,18 +63,12 @@ func keyExistsInArray(key string, value interface{}, log logr.Logger) (invalidTy case []interface{}: for _, val := range valuesAvailable { - v, ok := val.(string) - if !ok { - return true, false - } - - if ok && wildcard.Match(key, v) { + if wildcard.Match(key, fmt.Sprint(val)) { return false, true } } case string: - if wildcard.Match(valuesAvailable, key) { return false, true } diff --git a/pkg/engine/variables/operator/notequal.go b/pkg/engine/variables/operator/notequal.go index f2e4f72885..def87995dc 100644 --- a/pkg/engine/variables/operator/notequal.go +++ b/pkg/engine/variables/operator/notequal.go @@ -7,6 +7,7 @@ import ( "strconv" "github.com/minio/pkg/wildcard" + "k8s.io/apimachinery/pkg/api/resource" "github.com/go-logr/logr" "github.com/kyverno/kyverno/pkg/engine/context" @@ -55,7 +56,7 @@ func (neh NotEqualHandler) validateValueWithSlicePattern(key []interface{}, valu return !reflect.DeepEqual(key, val) } neh.log.Info("Expected type []interface{}", "value", value, "type", fmt.Sprintf("%T", value)) - return false + return true } func (neh NotEqualHandler) validateValueWithMapPattern(key map[string]interface{}, value interface{}) bool { @@ -63,16 +64,36 @@ func (neh NotEqualHandler) validateValueWithMapPattern(key map[string]interface{ return !reflect.DeepEqual(key, val) } neh.log.Info("Expected type map[string]interface{}", "value", value, "type", fmt.Sprintf("%T", value)) - return false + return true } func (neh NotEqualHandler) validateValueWithStringPattern(key string, value interface{}) bool { + // We need to check duration first as it's the only type that can be compared to a different type. + durationKey, durationValue, err := parseDuration(key, value) + if err == nil { + return durationKey.Seconds() != durationValue.Seconds() + } + + // Attempt to extract resource quantity from string. + resourceKey, err := resource.ParseQuantity(key) + if err == nil { + switch typedValue := value.(type) { + case string: + resourceValue, err := resource.ParseQuantity(typedValue) + if err != nil { + neh.log.Error(fmt.Errorf("parse error: "), "Failed to parse value type doesn't match key type") + return false + } + return !resourceKey.Equal(resourceValue) + } + } + if val, ok := value.(string); ok { return !wildcard.Match(val, key) } neh.log.Info("Expected type string", "value", value, "type", fmt.Sprintf("%T", value)) - return false + return true } func (neh NotEqualHandler) validateValueWithFloatPattern(key float64, value interface{}) bool { @@ -96,21 +117,21 @@ func (neh NotEqualHandler) validateValueWithFloatPattern(key float64, value inte float64Num, err := strconv.ParseFloat(typedValue, 64) if err != nil { neh.log.Error(err, "Failed to parse float64 from string") - return false + return true } return float64Num != key default: neh.log.Info("Expected type float", "value", value, "type", fmt.Sprintf("%T", value)) - return false + return true } - return false + return true } func (neh NotEqualHandler) validateValueWithBoolPattern(key bool, value interface{}) bool { typedValue, ok := value.(bool) if !ok { neh.log.Info("Expected type bool", "value", value, "type", fmt.Sprintf("%T", value)) - return false + return true } return key != typedValue } @@ -133,11 +154,11 @@ func (neh NotEqualHandler) validateValueWithIntPattern(key int64, value interfac int64Num, err := strconv.ParseInt(typedValue, 10, 64) if err != nil { neh.log.Error(err, "Failed to parse int64 from string") - return false + return true } return int64Num != key default: neh.log.Info("Expected type int", "value", value, "type", fmt.Sprintf("%T", value)) - return false + return true } } diff --git a/pkg/engine/variables/operator/notin.go b/pkg/engine/variables/operator/notin.go index 7ce0a44ee6..1396377477 100644 --- a/pkg/engine/variables/operator/notin.go +++ b/pkg/engine/variables/operator/notin.go @@ -7,8 +7,9 @@ import ( "github.com/kyverno/kyverno/pkg/engine/context" ) -// deprecated //NewNotInHandler returns handler to manage NotIn operations +// +// Deprecated: Use `NewAllNotInHandler` or `NewAnyNotInHandler` instead func NewNotInHandler(log logr.Logger, ctx context.EvalInterface) OperatorHandler { return NotInHandler{ ctx: ctx, @@ -16,17 +17,19 @@ func NewNotInHandler(log logr.Logger, ctx context.EvalInterface) OperatorHandler } } -//NotInHandler provides implementation to handle NotIn Operator +// NotInHandler provides implementation to handle NotIn Operator type NotInHandler struct { ctx context.EvalInterface log logr.Logger } -//Evaluate evaluates expression with NotIn Operator +// Evaluate evaluates expression with NotIn Operator func (nin NotInHandler) Evaluate(key, value interface{}) bool { switch typedKey := key.(type) { case string: return nin.validateValueWithStringPattern(typedKey, value) + case int, int32, int64, float32, float64: + return nin.validateValueWithStringPattern(fmt.Sprint(typedKey), value) case []interface{}: var stringSlice []string for _, v := range typedKey { diff --git a/pkg/engine/variables/operator/numeric.go b/pkg/engine/variables/operator/numeric.go index 16745dfbb5..3e98c8eb23 100644 --- a/pkg/engine/variables/operator/numeric.go +++ b/pkg/engine/variables/operator/numeric.go @@ -3,7 +3,6 @@ package operator import ( "fmt" "strconv" - "time" "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" @@ -38,8 +37,16 @@ func compareByCondition(key float64, value float64, op kyverno.ConditionOperator return key <= value case kyverno.LessThan: return key < value + case kyverno.Equals: + return key == value + case kyverno.Equal: + return key == value + case kyverno.NotEquals: + return key != value + case kyverno.NotEqual: + return key != value default: - (*log).Info(fmt.Sprintf("Expected operator, one of [GreaterThanOrEquals, GreaterThan, LessThanOrEquals, LessThan], found %s", op)) + (*log).Info(fmt.Sprintf("Expected operator, one of [GreaterThanOrEquals, GreaterThan, LessThanOrEquals, LessThan, Equals, NotEquals], found %s", op)) return false } } @@ -69,6 +76,10 @@ func (noh NumericOperatorHandler) validateValueWithIntPattern(key int64, value i case float64: return compareByCondition(float64(key), typedValue, noh.condition, &noh.log) case string: + durationKey, durationValue, err := parseDuration(key, value) + if err == nil { + return compareByCondition(float64(durationKey.Seconds()), float64(durationValue.Seconds()), noh.condition, &noh.log) + } // extract float64 and (if that fails) then, int64 from the string float64val, err := strconv.ParseFloat(typedValue, 64) if err == nil { @@ -95,6 +106,10 @@ func (noh NumericOperatorHandler) validateValueWithFloatPattern(key float64, val case float64: return compareByCondition(key, typedValue, noh.condition, &noh.log) case string: + durationKey, durationValue, err := parseDuration(key, value) + if err == nil { + return compareByCondition(float64(durationKey.Seconds()), float64(durationValue.Seconds()), noh.condition, &noh.log) + } float64val, err := strconv.ParseFloat(typedValue, 64) if err == nil { return compareByCondition(key, float64val, noh.condition, &noh.log) @@ -128,7 +143,7 @@ func (noh NumericOperatorHandler) validateValueWithResourcePattern(key resource. func (noh NumericOperatorHandler) validateValueWithStringPattern(key string, value interface{}) bool { // We need to check duration first as it's the only type that can be compared to a different type - durationKey, durationValue, err := noh.parseDuration(key, value) + durationKey, durationValue, err := parseDuration(key, value) if err == nil { return compareByCondition(float64(durationKey.Seconds()), float64(durationValue.Seconds()), noh.condition, &noh.log) } @@ -152,67 +167,6 @@ func (noh NumericOperatorHandler) validateValueWithStringPattern(key string, val return false } -func (noh NumericOperatorHandler) parseDuration(key, value interface{}) (*time.Duration, *time.Duration, error) { - var keyDuration *time.Duration - var valueDuration *time.Duration - var err error - - // We need to first ensure at least one of the values is actually a duration string - switch typedKey := key.(type) { - case string: - duration, err := time.ParseDuration(typedKey) - if err == nil && key != "0" { - keyDuration = &duration - } - } - switch typedValue := value.(type) { - case string: - duration, err := time.ParseDuration(typedValue) - if err == nil && value != "0" { - valueDuration = &duration - } - } - if keyDuration == nil && valueDuration == nil { - return keyDuration, valueDuration, fmt.Errorf("neither value is a duration") - } - - if keyDuration == nil { - var duration time.Duration - - switch typedKey := key.(type) { - case int: - duration = time.Duration(typedKey) * time.Second - case int64: - duration = time.Duration(typedKey) * time.Second - case float64: - duration = time.Duration(typedKey) * time.Second - default: - return keyDuration, valueDuration, fmt.Errorf("no valid duration value") - } - - keyDuration = &duration - } - - if valueDuration == nil { - var duration time.Duration - - switch typedValue := value.(type) { - case int: - duration = time.Duration(typedValue) * time.Second - case int64: - duration = time.Duration(typedValue) * time.Second - case float64: - duration = time.Duration(typedValue) * time.Second - default: - return keyDuration, valueDuration, fmt.Errorf("no valid duration value") - } - - valueDuration = &duration - } - - return keyDuration, valueDuration, err -} - // the following functions are unreachable because the key is strictly supposed to be numeric // still the following functions are just created to make NumericOperatorHandler struct implement OperatorHandler interface func (noh NumericOperatorHandler) validateValueWithBoolPattern(key bool, value interface{}) bool { diff --git a/pkg/engine/variables/operator/operator.go b/pkg/engine/variables/operator/operator.go index 5da56999d1..8145778984 100644 --- a/pkg/engine/variables/operator/operator.go +++ b/pkg/engine/variables/operator/operator.go @@ -1,7 +1,9 @@ package operator import ( + "fmt" "strings" + "time" "github.com/go-logr/logr" kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" @@ -74,3 +76,64 @@ func CreateOperatorHandler(log logr.Logger, ctx context.EvalInterface, op kyvern return nil } + +func parseDuration(key, value interface{}) (*time.Duration, *time.Duration, error) { + var keyDuration *time.Duration + var valueDuration *time.Duration + var err error + + // We need to first ensure at least one of the values is actually a duration string. + switch typedKey := key.(type) { + case string: + duration, err := time.ParseDuration(typedKey) + if err == nil && key != "0" { + keyDuration = &duration + } + } + switch typedValue := value.(type) { + case string: + duration, err := time.ParseDuration(typedValue) + if err == nil && value != "0" { + valueDuration = &duration + } + } + if keyDuration == nil && valueDuration == nil { + return keyDuration, valueDuration, fmt.Errorf("neither value is a duration") + } + + if keyDuration == nil { + var duration time.Duration + + switch typedKey := key.(type) { + case int: + duration = time.Duration(typedKey) * time.Second + case int64: + duration = time.Duration(typedKey) * time.Second + case float64: + duration = time.Duration(typedKey) * time.Second + default: + return keyDuration, valueDuration, fmt.Errorf("no valid duration value") + } + + keyDuration = &duration + } + + if valueDuration == nil { + var duration time.Duration + + switch typedValue := value.(type) { + case int: + duration = time.Duration(typedValue) * time.Second + case int64: + duration = time.Duration(typedValue) * time.Second + case float64: + duration = time.Duration(typedValue) * time.Second + default: + return keyDuration, valueDuration, fmt.Errorf("no valid duration value") + } + + valueDuration = &duration + } + + return keyDuration, valueDuration, err +} diff --git a/pkg/engine/variables/vars.go b/pkg/engine/variables/vars.go index bbcc585b49..6f7361fc1d 100644 --- a/pkg/engine/variables/vars.go +++ b/pkg/engine/variables/vars.go @@ -13,7 +13,7 @@ import ( kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/engine/anchor/common" "github.com/kyverno/kyverno/pkg/engine/context" - jsonUtils "github.com/kyverno/kyverno/pkg/engine/json-utils" + jsonUtils "github.com/kyverno/kyverno/pkg/engine/jsonutils" "github.com/kyverno/kyverno/pkg/engine/operator" ) @@ -21,10 +21,10 @@ var RegexVariables = regexp.MustCompile(`^\{\{[^{}]*\}\}|[^\\]\{\{[^{}]*\}\}`) var RegexEscpVariables = regexp.MustCompile(`\\\{\{[^{}]*\}\}`) -// Regex for '$(...)' at the beginning of the string, and 'x$(...)' where 'x' is not '\' +// RegexReferences is the Regex for '$(...)' at the beginning of the string, and 'x$(...)' where 'x' is not '\' var RegexReferences = regexp.MustCompile(`^\$\(.[^\ ]*\)|[^\\]\$\(.[^\ ]*\)`) -// Regex for '\$(...)' +// RegexEscpReferences is the Regex for '\$(...)' var RegexEscpReferences = regexp.MustCompile(`\\\$\(.[^\ ]*\)`) var regexVariableInit = regexp.MustCompile(`^\{\{[^{}]*\}\}`) @@ -298,7 +298,7 @@ func substituteReferencesIfAny(log logr.Logger) jsonUtils.Action { for _, v := range RegexReferences.FindAllString(value, -1) { initial := v[:2] == `$(` - v_old := v + old := v if !initial { v = v[1:] @@ -321,15 +321,15 @@ func substituteReferencesIfAny(log logr.Logger) jsonUtils.Action { log.V(3).Info("reference resolved", "reference", v, "value", resolvedReference, "path", data.Path) if val, ok := resolvedReference.(string); ok { - replace_with := "" + replacement := "" if !initial { - replace_with = string(v_old[0]) + replacement = string(old[0]) } - replace_with += val + replacement += val - value = strings.Replace(value, v_old, replace_with, 1) + value = strings.Replace(value, old, replacement, 1) continue } @@ -370,7 +370,7 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface, vr Var for _, v := range vars { initial := len(regexVariableInit.FindAllString(v, -1)) > 0 - v_old := v + old := v if !initial { v = v[1:] @@ -406,7 +406,7 @@ func substituteVariablesIfAny(log logr.Logger, ctx context.EvalInterface, vr Var prefix := "" if !initial { - prefix = string(v_old[0]) + prefix = string(old[0]) } if value, err = substituteVarInPattern(prefix, originalPattern, v, substitutedVar); err != nil { @@ -524,7 +524,7 @@ func valFromReferenceToString(value interface{}, operator string) (string, error func FindAndShiftReferences(log logr.Logger, value, shift, pivot string) string { for _, reference := range RegexReferences.FindAllString(value, -1) { initial := reference[:2] == `$(` - reference_old := reference + oldReference := reference if !initial { reference = reference[1:] @@ -542,15 +542,15 @@ func FindAndShiftReferences(log logr.Logger, value, shift, pivot string) string } shiftedReference := strings.Replace(reference, pivot, pivot+"/"+shift, -1) - replace_with := "" + replacement := "" if !initial { - replace_with = string(reference_old[0]) + replacement = string(oldReference[0]) } - replace_with += shiftedReference + replacement += shiftedReference - value = strings.Replace(value, reference_old, replace_with, 1) + value = strings.Replace(value, oldReference, replacement, 1) } return value diff --git a/pkg/engine/variables/vars_test.go b/pkg/engine/variables/vars_test.go index c9d29474c3..da0e5433a4 100644 --- a/pkg/engine/variables/vars_test.go +++ b/pkg/engine/variables/vars_test.go @@ -9,7 +9,7 @@ import ( v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/engine/context" - ju "github.com/kyverno/kyverno/pkg/engine/json-utils" + ju "github.com/kyverno/kyverno/pkg/engine/jsonutils" "gotest.tools/assert" "sigs.k8s.io/controller-runtime/pkg/log" ) diff --git a/pkg/generate/generate.go b/pkg/generate/generate.go index da4f005926..011dfa1490 100644 --- a/pkg/generate/generate.go +++ b/pkg/generate/generate.go @@ -435,7 +435,15 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou label["policy.kyverno.io/synchronize"] = "enable" newResource.SetLabels(label) - if _, err := ValidateResourceWithPattern(logger, generatedObj.Object, rdata); err != nil { + if genAPIVersion == "" { + generatedResourceAPIVersion := generatedObj.GetAPIVersion() + newResource.SetAPIVersion(generatedResourceAPIVersion) + } + if genNamespace == "" { + newResource.SetNamespace("default") + } + + if _, err := ValidateResourceWithPattern(logger, generatedObj.Object, newResource.Object); err != nil { _, err = client.UpdateResource(genAPIVersion, genKind, genNamespace, newResource, false) if err != nil { logger.Error(err, "failed to update resource") diff --git a/pkg/kyverno/apply/apply_command.go b/pkg/kyverno/apply/apply_command.go index 66fa6c5dca..02015bf31c 100644 --- a/pkg/kyverno/apply/apply_command.go +++ b/pkg/kyverno/apply/apply_command.go @@ -336,30 +336,37 @@ func checkMutateLogPath(mutateLogPath string) (mutateLogPathIsDir bool, err erro // printReportOrViolation - printing policy report/violations func printReportOrViolation(policyReport bool, rc *common.ResultCounts, resourcePaths []string, resourcesLen int, skipInvalidPolicies SkippedInvalidPolicies, stdin bool, pvInfos []policyreport.Info) { + divider := "----------------------------------------------------------------------" + if len(skipInvalidPolicies.skipped) > 0 { - fmt.Println("----------------------------------------------------------------------\nPolicies Skipped(as required variables are not provided by the users):") + fmt.Println(divider) + fmt.Println("Policies Skipped (as required variables are not provided by the user):") for i, policyName := range skipInvalidPolicies.skipped { - fmt.Println(i+1, ". ", policyName) + fmt.Printf("%d. %s\n", i+1, policyName) } - fmt.Println("----------------------------------------------------------------------") + fmt.Println(divider) } if len(skipInvalidPolicies.invalid) > 0 { - fmt.Println("----------------------------------------------------------------------\nInvalid Policies:") + fmt.Println(divider) + fmt.Println("Invalid Policies:") for i, policyName := range skipInvalidPolicies.invalid { - fmt.Println(i+1, ". ", policyName) + fmt.Printf("%d. %s\n", i+1, policyName) } - fmt.Println("----------------------------------------------------------------------") + fmt.Println(divider) } if policyReport { resps := buildPolicyReports(pvInfos) if len(resps) > 0 || resourcesLen == 0 { - fmt.Println("\n----------------------------------------------------------------------\nPOLICY REPORT:\n----------------------------------------------------------------------") + fmt.Println(divider) + fmt.Println("POLICY REPORT:") + fmt.Println(divider) report, _ := generateCLIRaw(resps) yamlReport, _ := yaml1.Marshal(report) fmt.Println(string(yamlReport)) } else { - fmt.Println("----------------------------------------------------------------------\nPOLICY REPORT: skip generating policy report (no validate policy found/resource skipped)") + fmt.Println(divider) + fmt.Println("POLICY REPORT: skip generating policy report (no validate policy found/resource skipped)") } } else { if !stdin { diff --git a/pkg/kyverno/common/common.go b/pkg/kyverno/common/common.go index def5a92238..6bed706ebd 100644 --- a/pkg/kyverno/common/common.go +++ b/pkg/kyverno/common/common.go @@ -81,10 +81,10 @@ func GetPolicies(paths []string) (policies []*v1.ClusterPolicy, errors []error) err error ) - isHttpPath := IsHttpRegex.MatchString(path) + isHTTPPath := IsHTTPRegex.MatchString(path) // path clean and retrieving file info can be possible if it's not an HTTP URL - if !isHttpPath { + if !isHTTPPath { path = filepath.Clean(path) fileDesc, err = os.Stat(path) if err != nil { @@ -95,7 +95,7 @@ func GetPolicies(paths []string) (policies []*v1.ClusterPolicy, errors []error) } // apply file from a directory is possible only if the path is not HTTP URL - if !isHttpPath && fileDesc.IsDir() { + if !isHTTPPath && fileDesc.IsDir() { files, err := ioutil.ReadDir(path) if err != nil { err := fmt.Errorf("failed to process %v: %v", path, err.Error()) @@ -117,7 +117,7 @@ func GetPolicies(paths []string) (policies []*v1.ClusterPolicy, errors []error) } else { var fileBytes []byte - if isHttpPath { + if isHTTPPath { // We accept here that a random URL might be called based on user provided input. resp, err := http.Get(path) // #nosec if err != nil { @@ -258,7 +258,7 @@ func PolicyHasNonAllowedVariables(policy v1.ClusterPolicy) error { matchesAll := RegexVariables.FindAllStringSubmatch(string(ruleJSON), -1) matchesAllowed := AllowedVariables.FindAllStringSubmatch(string(ruleJSON), -1) if (len(matchesAll) > len(matchesAllowed)) && len(rule.Context) == 0 { - allowed := "{{request.*}}, {{element.*}}, {{serviceAccountName}}, {{serviceAccountNamespace}}, {{@}}, and context variables" + allowed := "{{request.*}}, {{element.*}}, {{serviceAccountName}}, {{serviceAccountNamespace}}, {{@}}, {{images.*}} and context variables" return fmt.Errorf("rule \"%s\" has forbidden variables. Allowed variables are: %s", rule.Name, allowed) } } diff --git a/pkg/kyverno/common/fetch.go b/pkg/kyverno/common/fetch.go index 1da5973c65..327eff22c8 100644 --- a/pkg/kyverno/common/fetch.go +++ b/pkg/kyverno/common/fetch.go @@ -220,7 +220,7 @@ func getFileBytes(path string) ([]byte, error) { err error ) - if IsHttpRegex.MatchString(path) { + if IsHTTPRegex.MatchString(path) { // We accept here that a random URL might be called based on user provided input. resp, err := http.Get(path) // #nosec if err != nil { diff --git a/pkg/kyverno/common/regex.go b/pkg/kyverno/common/regex.go index ad2a4bd5f0..60c803e8a6 100644 --- a/pkg/kyverno/common/regex.go +++ b/pkg/kyverno/common/regex.go @@ -7,11 +7,11 @@ import ( // RegexVariables represents regex for '{{}}' var RegexVariables = regexp.MustCompile(`\{\{[^{}]*\}\}`) -// AllowedVariables represents regex for {{request.}}, {{serviceAccountName}}, {{serviceAccountNamespace}}, {{@}} and functions e.g. {{divide(,))}} -var AllowedVariables = regexp.MustCompile(`\{\{\s*(request\.|serviceAccountName|serviceAccountNamespace|element\.|@|([a-z_0-9]+\())[^{}]*\}\}`) +// AllowedVariables represents regex for {{request.}}, {{serviceAccountName}}, {{serviceAccountNamespace}}, {{@}}, {{element.}}, {{images.}} +var AllowedVariables = regexp.MustCompile(`\{\{\s*(request\.|serviceAccountName|serviceAccountNamespace|element\.|@|images\.|([a-z_0-9]+\())[^{}]*\}\}`) -// AllowedVariables represents regex for {{request.}}, {{serviceAccountName}}, {{serviceAccountNamespace}} +// WildCardAllowedVariables represents regex for the allowed fields in wildcards var WildCardAllowedVariables = regexp.MustCompile(`\{\{\s*(request\.|serviceAccountName|serviceAccountNamespace)[^{}]*\}\}`) -// IsHttpRegex represents regex for starts with http:// or https:// -var IsHttpRegex = regexp.MustCompile("^(http|https)://") +// IsHTTPRegex represents regex for starts with http:// or https:// +var IsHTTPRegex = regexp.MustCompile("^(http|https)://") diff --git a/pkg/kyverno/test/test_command.go b/pkg/kyverno/test/test_command.go index 03f83e1eb8..b72d8ad5db 100644 --- a/pkg/kyverno/test/test_command.go +++ b/pkg/kyverno/test/test_command.go @@ -81,7 +81,7 @@ For validate policies rule: resource: namespace: (OPTIONAL) - kind: + kind: result: @@ -101,7 +101,7 @@ Policy (Namespaced) rule: resource: namespace: (OPTIONAL) - kind: + kind: patchedResource: result: @@ -126,7 +126,7 @@ ClusterPolicy (Cluster-wide) Result descriptions: pass --> The patched resource generated by Kyverno equals the patched resource provided by the user. -fail --> The patched resource generated by Kyverno is not equal to the patched resource provided by the user. +fail --> The patched resource generated by Kyverno is not equal to the patched resource provided by the user. skip --> The rule is not applied. For more information visit https://kyverno.io/docs/kyverno-cli/#test @@ -521,9 +521,9 @@ func isNamespacedPolicy(policyNames string) (bool, error) { func getUserDefinedPolicyNameAndNamespace(policyName string) (string, string) { if strings.Contains(policyName, "/") { - policy_n_ns := strings.Split(policyName, "/") - namespace := policy_n_ns[0] - policy := policy_n_ns[1] + parts := strings.Split(policyName, "/") + namespace := parts[0] + policy := parts[1] return namespace, policy } return "", policyName diff --git a/pkg/policycache/cache.go b/pkg/policycache/cache.go index afc69920ee..dbdb571ca1 100644 --- a/pkg/policycache/cache.go +++ b/pkg/policycache/cache.go @@ -197,11 +197,11 @@ func addCacheHelper(rmr kyverno.ResourceFilter, m *pMap, rule kyverno.Rule, muta } } -func (pc *pMap) get(key PolicyType, gvk, namespace string) (names []string) { - pc.RLock() - defer pc.RUnlock() +func (m *pMap) get(key PolicyType, gvk, namespace string) (names []string) { + m.RLock() + defer m.RUnlock() _, kind := common.GetKindFromGVK(gvk) - for _, policyName := range pc.kindDataMap[kind][key] { + for _, policyName := range m.kindDataMap[kind][key] { ns, key, isNamespacedPolicy := policy2.ParseNamespacedPolicy(policyName) if !isNamespacedPolicy && namespace == "" { names = append(names, key) @@ -262,19 +262,19 @@ func removeCacheHelper(rmr kyverno.ResourceFilter, m *pMap, pName string) { } } -func (m *policyCache) getPolicyObject(key PolicyType, gvk string, nspace string) (policyObject []*kyverno.ClusterPolicy) { +func (pc *policyCache) getPolicyObject(key PolicyType, gvk string, nspace string) (policyObject []*kyverno.ClusterPolicy) { _, kind := common.GetKindFromGVK(gvk) - policyNames := m.pMap.get(key, kind, nspace) - wildcardPolicies := m.pMap.get(key, "*", nspace) + policyNames := pc.pMap.get(key, kind, nspace) + wildcardPolicies := pc.pMap.get(key, "*", nspace) policyNames = append(policyNames, wildcardPolicies...) for _, policyName := range policyNames { var policy *kyverno.ClusterPolicy ns, key, isNamespacedPolicy := policy2.ParseNamespacedPolicy(policyName) if !isNamespacedPolicy { - policy, _ = m.pLister.Get(key) + policy, _ = pc.pLister.Get(key) } else { if ns == nspace { - nspolicy, _ := m.npLister.Policies(ns).Get(key) + nspolicy, _ := pc.npLister.Policies(ns).Get(key) policy = policy2.ConvertPolicyToClusterPolicy(nspolicy) } } diff --git a/pkg/policyreport/builder.go b/pkg/policyreport/builder.go index 102a310bff..5ca961d37d 100755 --- a/pkg/policyreport/builder.go +++ b/pkg/policyreport/builder.go @@ -35,7 +35,7 @@ const ( deletedAnnotationResourceName string = "kyverno.io/delete.resource.name" deletedAnnotationResourceKind string = "kyverno.io/delete.resource.kind" - // static value for PolicyReportResult.Source + // SourceValue is the static value for PolicyReportResult.Source SourceValue = "Kyverno" ) diff --git a/pkg/testrunner/scenario.go b/pkg/testrunner/scenario.go index 9bb7424cd4..8974264eae 100644 --- a/pkg/testrunner/scenario.go +++ b/pkg/testrunner/scenario.go @@ -32,13 +32,13 @@ type Scenario struct { TestCases []TestCase } -//CaseT defines input and output for a case +// TestCase defines input and output for a case type TestCase struct { Input Input `yaml:"input"` Expected Expected `yaml:"expected"` } -//Input defines input for a test scenario +// Input defines input for a test scenario type Input struct { Policy string `yaml:"policy"` Resource string `yaml:"resource"` diff --git a/pkg/testrunner/scenario_test.go b/pkg/testrunner/scenario_test.go index 541b14b475..55d67d14bb 100644 --- a/pkg/testrunner/scenario_test.go +++ b/pkg/testrunner/scenario_test.go @@ -1,11 +1,12 @@ package testrunner import ( + "io/ioutil" + "testing" + "github.com/kyverno/kyverno/pkg/engine/response" "gopkg.in/yaml.v3" "gotest.tools/assert" - "io/ioutil" - "testing" ) var sourceYAML = ` diff --git a/pkg/utils/util.go b/pkg/utils/util.go index b38c4b7e95..feebe4bf80 100644 --- a/pkg/utils/util.go +++ b/pkg/utils/util.go @@ -24,7 +24,7 @@ import ( var regexVersion = regexp.MustCompile(`v(\d+).(\d+).(\d+)\.*`) -//Contains Check if strint is contained in a list of string +// Contains checks if a string is contained in a list of string func contains(list []string, element string, fn func(string, string) bool) bool { for _, e := range list { if fn(e, element) { @@ -44,12 +44,12 @@ func ContainsPod(list []string, element string) bool { return false } -//ContainsNamepace check if namespace satisfies any list of pattern(regex) +// ContainsNamepace check if namespace satisfies any list of pattern(regex) func ContainsNamepace(patterns []string, ns string) bool { return contains(patterns, ns, compareNamespaces) } -//ContainsString check if the string is contains in a list +// ContainsString checks if the string is contained in the list func ContainsString(list []string, element string) bool { return contains(list, element, compareString) } @@ -62,7 +62,7 @@ func compareString(str, name string) bool { return str == name } -//NewKubeClient returns a new kubernetes client +// NewKubeClient returns a new kubernetes client func NewKubeClient(config *rest.Config) (kubernetes.Interface, error) { kclient, err := kubernetes.NewForConfig(config) if err != nil { @@ -160,7 +160,7 @@ func HigherThanKubernetesVersion(client *client.Client, log logr.Logger, major, b, err := isVersionHigher(serverVersion.String(), major, minor, patch) if err != nil { - logger.Error(err, "serverVersion", serverVersion) + logger.Error(err, "serverVersion", serverVersion.String()) return false } @@ -168,27 +168,29 @@ func HigherThanKubernetesVersion(client *client.Client, log logr.Logger, major, } func isVersionHigher(version string, major int, minor int, patch int) (bool, error) { - groups := regexVersion.FindAllStringSubmatch(version, -1) - if len(groups) != 1 || len(groups[0]) != 4 { + groups := regexVersion.FindStringSubmatch(version) + if len(groups) != 4 { return false, fmt.Errorf("invalid version %s. Expected {major}.{minor}.{patch}", version) } - currentMajor, err := strconv.Atoi(groups[0][1]) + currentMajor, err := strconv.Atoi(groups[1]) if err != nil { return false, fmt.Errorf("failed to extract major version from %s", version) } - currentMinor, err := strconv.Atoi(groups[0][2]) + currentMinor, err := strconv.Atoi(groups[2]) if err != nil { return false, fmt.Errorf("failed to extract minor version from %s", version) } - currentPatch, err := strconv.Atoi(groups[0][3]) + currentPatch, err := strconv.Atoi(groups[3]) if err != nil { return false, fmt.Errorf("failed to extract minor version from %s", version) } - if currentMajor <= major && currentMinor <= minor && currentPatch <= patch { + if currentMajor < major || + (currentMajor == major && currentMinor < minor) || + (currentMajor == major && currentMinor == minor && currentPatch <= patch) { return false, nil } @@ -212,7 +214,7 @@ func SliceContains(slice []string, values ...string) bool { return false } -// ApiextensionsJsonTOKyvernoConditions takes in user-provided conditions in abstract apiextensions.JSON form +// ApiextensionsJsonToKyvernoConditions takes in user-provided conditions in abstract apiextensions.JSON form // and converts it into []kyverno.Condition or kyverno.AnyAllConditions according to its content. // it also helps in validating the condtions as it returns an error when the conditions are provided wrongfully by the user. func ApiextensionsJsonToKyvernoConditions(original apiextensions.JSON) (interface{}, error) { diff --git a/pkg/utils/util_test.go b/pkg/utils/util_test.go index 928bc50b79..8198b0d9d3 100644 --- a/pkg/utils/util_test.go +++ b/pkg/utils/util_test.go @@ -91,6 +91,15 @@ func Test_higherVersion(t *testing.T) { v, err = isVersionHigher("v1.5.9-rc2", 1, 5, 9) assert.Assert(t, v == false && err == nil) + + v, err = isVersionHigher("v1.5.9", 2, 1, 0) + assert.Assert(t, v == false && err == nil) + + v, err = isVersionHigher("v2.1.0", 1, 5, 9) + assert.Assert(t, v == true && err == nil) + + v, err = isVersionHigher("v1.5.9-x-v1.5.9.x", 1, 5, 8) + assert.Assert(t, v == true && err == nil) } func Test_ConvertResource(t *testing.T) { diff --git a/pkg/webhookconfig/registration.go b/pkg/webhookconfig/registration.go index be1c94a23d..4dabdeb0e1 100644 --- a/pkg/webhookconfig/registration.go +++ b/pkg/webhookconfig/registration.go @@ -175,11 +175,11 @@ func (wrc *Register) Remove(cleanUp chan<- struct{}) { } -// +deprecated // UpdateWebhookConfigurations updates resource webhook configurations dynamically // base on the UPDATEs of Kyverno init-config ConfigMap // // it currently updates namespaceSelector only, can be extend to update other fields +// +deprecated func (wrc *Register) UpdateWebhookConfigurations(configHandler config.Interface) { logger := wrc.log.WithName("UpdateWebhookConfigurations") for { @@ -622,12 +622,12 @@ func (wrc *Register) checkEndpoint() error { } kyverno := pods.Items[0] - podIp, _, err := unstructured.NestedString(kyverno.UnstructuredContent(), "status", "podIP") + podIP, _, err := unstructured.NestedString(kyverno.UnstructuredContent(), "status", "podIP") if err != nil { return fmt.Errorf("failed to extract pod IP: %v", err) } - if podIp == "" { + if podIP == "" { return fmt.Errorf("pod is not assigned to any node yet") } @@ -637,7 +637,7 @@ func (wrc *Register) checkEndpoint() error { } for _, addr := range subset.Addresses { - if addr.IP == podIp { + if addr.IP == podIP { wrc.log.Info("Endpoint ready", "ns", config.KyvernoNamespace, "name", config.KyvernoServiceName) return nil } diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index bb86b0cc80..6082a8adbb 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -300,20 +300,14 @@ func (ws *WebhookServer) resourceMutation(request *v1beta1.AdmissionRequest) *v1 requestTime := time.Now().Unix() kind := request.Kind.Kind mutatePolicies := ws.pCache.GetPolicies(policycache.Mutate, kind, request.Namespace) - generatePolicies := ws.pCache.GetPolicies(policycache.Generate, kind, request.Namespace) verifyImagesPolicies := ws.pCache.GetPolicies(policycache.VerifyImages, kind, request.Namespace) - if len(mutatePolicies) == 0 && len(generatePolicies) == 0 && len(verifyImagesPolicies) == 0 { + if len(mutatePolicies) == 0 && len(verifyImagesPolicies) == 0 { logger.V(4).Info("no policies matched admission request") - if request.Operation == v1beta1.Update { - // handle generate source resource updates - go ws.handleUpdatesForGenerateRules(request, []*v1.ClusterPolicy{}) - } - return successResponse(nil) } - addRoles := containsRBACInfo(mutatePolicies, generatePolicies) + addRoles := containsRBACInfo(mutatePolicies) policyContext, err := ws.buildPolicyContext(request, addRoles) if err != nil { logger.Error(err, "failed to build policy context") @@ -334,9 +328,6 @@ func (ws *WebhookServer) resourceMutation(request *v1beta1.AdmissionRequest) *v1 return failureResponse(err.Error()) } - newRequest = patchRequest(imagePatches, newRequest, logger) - ws.applyGeneratePolicies(newRequest, policyContext, generatePolicies, requestTime, logger) - var patches = append(mutatePatches, imagePatches...) return successResponse(patches) } @@ -355,11 +346,10 @@ func (ws *WebhookServer) buildPolicyContext(request *v1beta1.AdmissionRequest, a } if addRoles { - if roles, clusterRoles, err := userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request, ws.configHandler); err != nil { + var err error + userRequestInfo.Roles, userRequestInfo.ClusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request, ws.configHandler) + if err != nil { return nil, errors.Wrap(err, "failed to fetch RBAC information for request") - } else { - userRequestInfo.Roles = roles - userRequestInfo.ClusterRoles = clusterRoles } } @@ -488,6 +478,7 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) * if request.Operation == v1beta1.Delete { ws.handleDelete(request) } + if excludeKyvernoResources(request.Kind.Kind) { return successResponse(nil) } @@ -500,9 +491,15 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) * // Get namespace policies from the cache for the requested resource namespace nsPolicies := ws.pCache.GetPolicies(policycache.ValidateEnforce, kind, request.Namespace) policies = append(policies, nsPolicies...) + generatePolicies := ws.pCache.GetPolicies(policycache.Generate, kind, request.Namespace) + + if len(generatePolicies) == 0 && request.Operation == v1beta1.Update { + // handle generate source resource updates + go ws.handleUpdatesForGenerateRules(request, []*v1.ClusterPolicy{}) + } var roles, clusterRoles []string - if containsRBACInfo(policies) { + if containsRBACInfo(policies, generatePolicies) { var err error roles, clusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request, ws.configHandler) if err != nil { @@ -561,6 +558,9 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) * // push admission request to audit handler, this won't block the admission request ws.auditHandler.Add(request.DeepCopy()) + // process generate policies + ws.applyGeneratePolicies(request, policyContext, generatePolicies, admissionRequestTimestamp, logger) + return successResponse(nil) } diff --git a/pkg/webhooks/validate_audit.go b/pkg/webhooks/validate_audit.go index c43a58f16f..5c2ee4790f 100644 --- a/pkg/webhooks/validate_audit.go +++ b/pkg/webhooks/validate_audit.go @@ -1,11 +1,12 @@ package webhooks import ( - "github.com/kyverno/kyverno/pkg/engine" - "github.com/kyverno/kyverno/pkg/utils" "strings" "time" + "github.com/kyverno/kyverno/pkg/engine" + "github.com/kyverno/kyverno/pkg/utils" + "github.com/pkg/errors" "github.com/kyverno/kyverno/pkg/common" diff --git a/pkg/webhooks/verify_images.go b/pkg/webhooks/verify_images.go index aca1b05e1f..b3e0282602 100644 --- a/pkg/webhooks/verify_images.go +++ b/pkg/webhooks/verify_images.go @@ -2,6 +2,7 @@ package webhooks import ( "errors" + "github.com/go-logr/logr" v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/engine"