1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/webhooks/resource/validation_test.go

1161 lines
23 KiB
Go
Raw Normal View History

package resource
import (
"context"
"encoding/json"
"fmt"
"testing"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
log "github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/registryclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
webhookutils "github.com/kyverno/kyverno/pkg/webhooks/utils"
"gotest.tools/assert"
)
func TestValidate_failure_action_overrides(t *testing.T) {
testcases := []struct {
rawPolicy []byte
rawResource []byte
blocked bool
messages map[string]string
rawResourceNamespaceLabels map[string]string
}{
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"default"
]
},
{
"action": "audit",
"namespaces": [
"test"
]
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "default"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"default"
]
},
{
"action": "audit",
"namespaces": [
"test"
]
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"labels": {
"app": "my-app"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: false,
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"default"
]
},
{
"action": "audit",
"namespaces": [
"test"
]
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "test"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: false,
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"default"
]
},
{
"action": "audit",
"namespaces": [
"test"
]
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "default"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"default"
]
},
{
"action": "audit",
"namespaces": [
"test"
]
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"labels": {
"app": "my-app"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: false,
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"default"
]
},
{
"action": "audit",
"namespaces": [
"test"
]
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "test"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: false,
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"default"
]
},
{
"action": "audit",
"namespaces": [
"test"
]
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": ""
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
messages: map[string]string{
"check-label-app": "validation error: The label 'app' is required. rule check-label-app failed at path /metadata/labels/",
},
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "audit",
"namespaces": [
"dev"
],
"namespaceSelector": {
"matchExpressions": [{
"key" : "kubernetes.io/metadata.name",
"operator": "In",
"values": [
"prod"
]
}]
}
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "default"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
messages: map[string]string{
"check-label-app": "validation error: The label 'app' is required. rule check-label-app failed at path /metadata/labels/",
},
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "audit",
"namespaceSelector": {
"matchExpressions": [{
"key" : "kubernetes.io/metadata.name",
"operator": "In",
"values": [
"prod"
]
}]
}
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "prod"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: false,
rawResourceNamespaceLabels: map[string]string{
"kubernetes.io/metadata.name": "prod",
},
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "audit",
"namespaceSelector": {
"matchExpressions": [{
"key" : "kubernetes.io/metadata.name",
"operator": "In",
"values": [
"prod"
]
}]
}
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "default"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
messages: map[string]string{
"check-label-app": "validation error: The label 'app' is required. rule check-label-app failed at path /metadata/labels/",
},
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "audit",
"namespaces": [
"dev"
],
"namespaceSelector": {
"matchExpressions": [{
"key" : "kubernetes.io/metadata.name",
"operator": "In",
"values": [
"prod"
]
}]
}
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "dev"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
rawResourceNamespaceLabels: map[string]string{
"kubernetes.io/metadata.name": "dev",
},
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "enforce",
"validationFailureActionOverrides":
[
{
"action": "audit",
"namespaces": [
"dev"
],
"namespaceSelector": {
"matchExpressions": [{
"key" : "kubernetes.io/metadata.name",
"operator": "In",
"values": [
"prod"
]
}]
}
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "prod"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
rawResourceNamespaceLabels: map[string]string{
"kubernetes.io/metadata.name": "prod",
},
},
{
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"dev"
],
"namespaceSelector": {
"matchExpressions": [{
"key" : "kubernetes.io/metadata.name",
"operator": "In",
"values": [
"prod"
]
}]
}
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "dev"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: false,
rawResourceNamespaceLabels: map[string]string{
"kubernetes.io/metadata.name": "dev",
},
}, {
rawPolicy: []byte(`
{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {
"name": "check-label-app"
},
"spec": {
"validationFailureAction": "audit",
"validationFailureActionOverrides":
[
{
"action": "enforce",
"namespaces": [
"dev"
],
"namespaceSelector": {
"matchExpressions": [{
"key" : "kubernetes.io/metadata.name",
"operator": "In",
"values": [
"dev"
]
}]
}
}
],
"rules": [
{
"name": "check-label-app",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"message": "The label 'app' is required.",
"pattern": {
"metadata": {
"labels": {
"app": "?*"
}
}
}
}
}
]
}
}
`),
rawResource: []byte(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "test-pod",
"namespace": "dev"
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "nginx:latest"
}
]
}
}
`),
blocked: true,
rawResourceNamespaceLabels: map[string]string{
"kubernetes.io/metadata.name": "dev",
},
},
}
eng := engine.NewEngine(
config.NewDefaultConfiguration(),
nil,
registryclient.NewOrDie(),
engineapi.DefaultContextLoaderFactory(nil),
nil,
)
for i, tc := range testcases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
var policy kyvernov1.ClusterPolicy
err := json.Unmarshal(tc.rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := kubeutils.BytesToUnstructured(tc.rawResource)
assert.NilError(t, err)
ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured).WithNamespaceLabels(tc.rawResourceNamespaceLabels)
er := eng.Validate(
context.TODO(),
ctx,
)
if tc.blocked && tc.messages != nil {
for _, r := range er.PolicyResponse.Rules {
msg := tc.messages[r.Name]
assert.Equal(t, r.Message, msg)
}
}
failurePolicy := kyvernov1.Fail
blocked := webhookutils.BlockRequest([]*engineapi.EngineResponse{&er}, failurePolicy, log.WithName("WebhookServer"))
assert.Assert(t, tc.blocked == blocked)
})
}
}
func Test_RuleSelector(t *testing.T) {
var rawPolicy = []byte(`{
"apiVersion": "kyverno.io/v1",
"kind": "ClusterPolicy",
"metadata": {"name": "check-label-app"},
"spec": {
"validationFailureAction": "enforce",
"rules": [
{
"name": "check-label-test",
"match": {"name": "test-*", "resources": {"kinds": ["Pod"]}},
"validate": {
"message": "The label 'app' is required.",
"pattern": { "metadata": { "labels": { "app": "?*" } } }
}
},
{
"name": "check-labels",
"match": {"name": "*", "resources": {"kinds": ["Pod"]}},
"validate": {
"message": "The label 'app' is required.",
"pattern": { "metadata": { "labels": { "app": "?*", "test" : "?*" } } }
}
}
]
}
}`)
var rawResource = []byte(`{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {"name": "test-pod", "namespace": "", "labels": { "app" : "test-pod" }},
"spec": {"containers": [{"name": "nginx", "image": "nginx:latest"}]}
}`)
var policy kyvernov1.ClusterPolicy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
assert.NilError(t, err)
assert.Assert(t, resourceUnstructured != nil)
ctx := engine.NewPolicyContext().WithPolicy(&policy).WithNewResource(*resourceUnstructured)
eng := engine.NewEngine(
config.NewDefaultConfiguration(),
nil,
registryclient.NewOrDie(),
engineapi.DefaultContextLoaderFactory(nil),
nil,
)
resp := eng.Validate(
context.TODO(),
ctx,
)
assert.Assert(t, resp.PolicyResponse.Stats.RulesAppliedCount == 2)
assert.Assert(t, resp.PolicyResponse.Stats.RulesErrorCount == 0)
log := log.WithName("Test_RuleSelector")
blocked := webhookutils.BlockRequest([]*engineapi.EngineResponse{&resp}, kyvernov1.Fail, log)
assert.Assert(t, blocked == true)
applyOne := kyvernov1.ApplyOne
policy.Spec.ApplyRules = &applyOne
resp = eng.Validate(
context.TODO(),
ctx,
)
assert.Assert(t, resp.PolicyResponse.Stats.RulesAppliedCount == 1)
assert.Assert(t, resp.PolicyResponse.Stats.RulesErrorCount == 0)
blocked = webhookutils.BlockRequest([]*engineapi.EngineResponse{&resp}, kyvernov1.Fail, log)
assert.Assert(t, blocked == false)
}