2019-12-31 01:08:50 +00:00
|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
2022-11-29 13:59:40 +00:00
|
|
|
"context"
|
2019-12-31 01:08:50 +00:00
|
|
|
"encoding/json"
|
2021-03-23 17:34:03 +00:00
|
|
|
"reflect"
|
2022-01-05 01:36:33 +00:00
|
|
|
"strings"
|
2021-03-23 17:34:03 +00:00
|
|
|
"testing"
|
2019-12-31 01:08:50 +00:00
|
|
|
|
2021-10-29 16:13:20 +00:00
|
|
|
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
|
2022-04-14 12:20:18 +00:00
|
|
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
|
2022-08-31 06:03:47 +00:00
|
|
|
client "github.com/kyverno/kyverno/pkg/clients/dclient"
|
2023-01-30 11:41:09 +00:00
|
|
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
2022-11-29 13:59:40 +00:00
|
|
|
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
2022-12-07 15:08:37 +00:00
|
|
|
"github.com/kyverno/kyverno/pkg/registryclient"
|
2023-01-03 12:02:15 +00:00
|
|
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
2019-12-31 01:08:50 +00:00
|
|
|
"gotest.tools/assert"
|
2021-07-22 21:23:03 +00:00
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
2022-04-25 12:20:40 +00:00
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2019-12-31 01:08:50 +00:00
|
|
|
)
|
|
|
|
|
2022-01-05 01:36:33 +00:00
|
|
|
func Test_VariableSubstitutionPatchStrategicMerge(t *testing.T) {
|
2021-08-31 19:44:36 +00:00
|
|
|
policyRaw := []byte(`{
|
2022-07-29 07:02:26 +00:00
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "add-label"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "add-name-label",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"appname": "{{request.object.metadata.name}}"
|
|
|
|
}
|
2021-08-31 19:44:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-29 07:02:26 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
|
2021-08-31 19:44:36 +00:00
|
|
|
resourceRaw := []byte(`{
|
2022-07-29 07:02:26 +00:00
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-root-user"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "check-root-user",
|
|
|
|
"image": "nginxinc/nginx-unprivileged",
|
|
|
|
"securityContext": {
|
|
|
|
"runAsNonRoot": true
|
|
|
|
}
|
2021-08-31 19:44:36 +00:00
|
|
|
}
|
2022-07-29 07:02:26 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
2020-09-22 23:19:09 +00:00
|
|
|
expectedPatch := []byte(`{"op":"add","path":"/metadata/labels","value":{"appname":"check-root-user"}}`)
|
2019-12-31 01:08:50 +00:00
|
|
|
|
|
|
|
var policy kyverno.ClusterPolicy
|
2021-08-31 19:44:36 +00:00
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
2020-03-23 19:05:05 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
2023-01-03 12:02:15 +00:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2019-12-31 01:08:50 +00:00
|
|
|
assert.NilError(t, err)
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
|
|
|
err = enginecontext.AddResource(ctx, resourceRaw)
|
2020-03-23 19:05:05 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
2019-12-31 01:08:50 +00:00
|
|
|
value, err := ctx.Query("request.object.metadata.name")
|
2020-08-08 00:09:24 +00:00
|
|
|
|
2019-12-31 01:08:50 +00:00
|
|
|
t.Log(value)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
2020-12-23 23:10:07 +00:00
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
2022-12-12 15:20:20 +00:00
|
|
|
newResource: *resourceUnstructured,
|
|
|
|
}
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2019-12-31 01:08:50 +00:00
|
|
|
t.Log(string(expectedPatch))
|
2021-10-07 01:31:20 +00:00
|
|
|
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
2019-12-31 01:08:50 +00:00
|
|
|
t.Log(string(er.PolicyResponse.Rules[0].Patches[0]))
|
|
|
|
if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) {
|
|
|
|
t.Error("patches dont match")
|
|
|
|
}
|
|
|
|
}
|
2020-01-09 20:24:37 +00:00
|
|
|
|
|
|
|
func Test_variableSubstitutionPathNotExist(t *testing.T) {
|
|
|
|
resourceRaw := []byte(`{
|
2021-08-31 19:44:36 +00:00
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-root-user"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "check-root-user",
|
|
|
|
"image": "nginxinc/nginx-unprivileged",
|
|
|
|
"securityContext": {
|
|
|
|
"runAsNonRoot": true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "substitute-variable"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "test-path-not-exist",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
2022-01-05 01:36:33 +00:00
|
|
|
"patchStrategicMerge": {
|
2021-08-31 19:44:36 +00:00
|
|
|
"spec": {
|
|
|
|
"name": "{{request.object.metadata.name1}}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
2020-01-09 20:24:37 +00:00
|
|
|
|
|
|
|
var policy kyverno.ClusterPolicy
|
2021-08-31 19:44:36 +00:00
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
2020-03-23 19:05:05 +00:00
|
|
|
assert.NilError(t, err)
|
2023-01-03 12:02:15 +00:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2020-01-09 20:24:37 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
|
|
|
err = enginecontext.AddResource(ctx, resourceRaw)
|
2020-03-23 19:05:05 +00:00
|
|
|
assert.NilError(t, err)
|
2020-01-09 20:24:37 +00:00
|
|
|
|
2020-12-23 23:10:07 +00:00
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
2022-12-12 15:20:20 +00:00
|
|
|
newResource: *resourceUnstructured,
|
|
|
|
}
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2022-01-05 01:36:33 +00:00
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
|
|
|
assert.Assert(t, strings.Contains(er.PolicyResponse.Rules[0].Message, "Unknown key \"name1\" in path"))
|
2020-01-11 01:15:44 +00:00
|
|
|
}
|
2021-04-29 17:09:44 +00:00
|
|
|
|
|
|
|
func Test_variableSubstitutionCLI(t *testing.T) {
|
|
|
|
resourceRaw := []byte(`{
|
2021-08-31 19:44:36 +00:00
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "nginx-config-test"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"image": "nginx:latest",
|
|
|
|
"name": "test-nginx"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "cm-variable-example"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "example-configmap-lookup",
|
|
|
|
"context": [
|
|
|
|
{
|
|
|
|
"name": "dictionary",
|
|
|
|
"configMap": {
|
|
|
|
"name": "mycmap",
|
|
|
|
"namespace": "default"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"my-environment-name": "{{dictionary.data.env}}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
2021-04-29 17:09:44 +00:00
|
|
|
|
|
|
|
configMapVariableContext := store.Context{
|
|
|
|
Policies: []store.Policy{
|
|
|
|
{
|
|
|
|
Name: "cm-variable-example",
|
|
|
|
Rules: []store.Rule{
|
|
|
|
{
|
|
|
|
Name: "example-configmap-lookup",
|
2022-05-07 20:30:11 +00:00
|
|
|
Values: map[string]interface{}{
|
2021-04-29 17:09:44 +00:00
|
|
|
"dictionary.data.env": "dev1",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedPatch := []byte(`{"op":"add","path":"/metadata/labels","value":{"my-environment-name":"dev1"}}`)
|
|
|
|
|
|
|
|
store.SetContext(configMapVariableContext)
|
|
|
|
store.SetMock(true)
|
|
|
|
var policy kyverno.ClusterPolicy
|
2021-08-31 19:44:36 +00:00
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
2021-04-29 17:09:44 +00:00
|
|
|
assert.NilError(t, err)
|
2023-01-03 12:02:15 +00:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2021-04-29 17:09:44 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
|
|
|
err = enginecontext.AddResource(ctx, resourceRaw)
|
2021-04-29 17:09:44 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resourceUnstructured,
|
2021-04-29 17:09:44 +00:00
|
|
|
}
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2021-10-07 01:31:20 +00:00
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
2021-04-29 17:09:44 +00:00
|
|
|
t.Log(string(expectedPatch))
|
|
|
|
t.Log(string(er.PolicyResponse.Rules[0].Patches[0]))
|
|
|
|
if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) {
|
2021-07-22 21:23:03 +00:00
|
|
|
t.Error("patches don't match")
|
2021-04-29 17:09:44 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-22 21:23:03 +00:00
|
|
|
|
|
|
|
// https://github.com/kyverno/kyverno/issues/2022
|
|
|
|
func Test_chained_rules(t *testing.T) {
|
2021-08-31 19:44:36 +00:00
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "replace-image-registry",
|
|
|
|
"annotations": {
|
|
|
|
"policies.kyverno.io/minversion": "1.4.2"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "replace-image-registry",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"(name)": "*",
|
|
|
|
"image": "{{regex_replace_all('^[^/]+','{{@}}','myregistry.corp.com')}}"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "replace-image-registry-chained",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"(name)": "*",
|
|
|
|
"image": "{{regex_replace_all('\\b(myregistry.corp.com)\\b','{{@}}','otherregistry.corp.com')}}"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "test",
|
|
|
|
"image": "foo/bash:5.0"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
2021-07-22 21:23:03 +00:00
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-01-03 12:02:15 +00:00
|
|
|
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2021-07-22 21:23:03 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
2022-04-09 11:52:50 +00:00
|
|
|
err = ctx.AddResource(resource.Object)
|
2021-07-22 21:23:03 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resource,
|
2021-07-22 21:23:03 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 17:14:40 +00:00
|
|
|
err = ctx.AddImageInfos(resource, cfg)
|
2021-07-22 21:23:03 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
2021-07-22 21:23:03 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2021-07-22 21:23:03 +00:00
|
|
|
containers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "containers")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Equal(t, containers[0].(map[string]interface{})["image"], "otherregistry.corp.com/foo/bash:5.0")
|
|
|
|
|
2021-10-07 01:31:20 +00:00
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 2)
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[1].Patches), 1)
|
|
|
|
|
2021-07-22 21:23:03 +00:00
|
|
|
assert.Equal(t, string(er.PolicyResponse.Rules[0].Patches[0]), `{"op":"replace","path":"/spec/containers/0/image","value":"myregistry.corp.com/foo/bash:5.0"}`)
|
|
|
|
assert.Equal(t, string(er.PolicyResponse.Rules[1].Patches[0]), `{"op":"replace","path":"/spec/containers/0/image","value":"otherregistry.corp.com/foo/bash:5.0"}`)
|
|
|
|
}
|
2021-08-17 21:43:21 +00:00
|
|
|
|
|
|
|
func Test_precondition(t *testing.T) {
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "nginx-config-test",
|
|
|
|
"labels": {
|
|
|
|
"app.kubernetes.io/managed-by": "Helm"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"image": "nginx:latest",
|
|
|
|
"name": "test-nginx"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
2021-08-31 19:44:36 +00:00
|
|
|
policyRaw := []byte(`{
|
2021-08-17 21:43:21 +00:00
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "cm-variable-example"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "example-configmap-lookup",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"preconditions": [
|
|
|
|
{
|
|
|
|
"key": "{{ request.object.metadata.labels.\"app.kubernetes.io/managed-by\"}}",
|
|
|
|
"operator": "Equals",
|
|
|
|
"value": "Helm"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"my-added-label": "test"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
expectedPatch := []byte(`{"op":"add","path":"/metadata/labels/my-added-label","value":"test"}`)
|
|
|
|
|
|
|
|
store.SetMock(true)
|
|
|
|
var policy kyverno.ClusterPolicy
|
2021-08-31 19:44:36 +00:00
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
2021-08-17 21:43:21 +00:00
|
|
|
assert.NilError(t, err)
|
2023-01-03 12:02:15 +00:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2021-08-17 21:43:21 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
|
|
|
err = enginecontext.AddResource(ctx, resourceRaw)
|
2021-08-17 21:43:21 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resourceUnstructured,
|
2021-08-17 21:43:21 +00:00
|
|
|
}
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2021-08-17 21:43:21 +00:00
|
|
|
t.Log(string(expectedPatch))
|
|
|
|
t.Log(string(er.PolicyResponse.Rules[0].Patches[0]))
|
|
|
|
if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) {
|
|
|
|
t.Error("patches don't match")
|
|
|
|
}
|
|
|
|
}
|
2021-09-02 00:50:37 +00:00
|
|
|
|
|
|
|
func Test_nonZeroIndexNumberPatchesJson6902(t *testing.T) {
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Endpoints",
|
|
|
|
"metadata": {
|
|
|
|
"name": "my-service"
|
|
|
|
},
|
|
|
|
"subsets": [
|
|
|
|
{
|
|
|
|
"addresses": [
|
|
|
|
{
|
|
|
|
"ip": "127.0.0.1"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}`)
|
|
|
|
|
|
|
|
policyraw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "policy-endpoints"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "Add IP to subset",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Endpoints"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"preconditions": [
|
|
|
|
{
|
|
|
|
"key": "{{ request.object.subsets[] | length(@) }}",
|
|
|
|
"operator": "Equals",
|
|
|
|
"value": "1"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"mutate": {
|
|
|
|
"patchesJson6902": "- path: \"/subsets/0/addresses/-\"\n op: add\n value: {\"ip\":\"192.168.42.172\"}"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "Add IP to subsets",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Endpoints"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"preconditions": [
|
|
|
|
{
|
|
|
|
"key": "{{ request.object.subsets[] | length(@) }}",
|
|
|
|
"operator": "Equals",
|
|
|
|
"value": "2"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"mutate": {
|
|
|
|
"patchesJson6902": "- path: \"/subsets/0/addresses/-\"\n op: add\n value: {\"ip\":\"192.168.42.172\"}\n- path: \"/subsets/1/addresses/-\"\n op: add\n value: {\"ip\":\"192.168.42.173\"}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
|
|
|
|
expectedPatch := []byte(`{"op":"add","path":"/subsets/0/addresses/1","value":{"ip":"192.168.42.172"}}`)
|
|
|
|
|
|
|
|
store.SetMock(true)
|
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(policyraw, &policy)
|
|
|
|
assert.NilError(t, err)
|
2023-01-03 12:02:15 +00:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2021-09-02 00:50:37 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
|
|
|
err = enginecontext.AddResource(ctx, resourceRaw)
|
2021-09-02 00:50:37 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resourceUnstructured,
|
2021-09-02 00:50:37 +00:00
|
|
|
}
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2021-09-02 00:50:37 +00:00
|
|
|
t.Log(string(expectedPatch))
|
|
|
|
t.Log(string(er.PolicyResponse.Rules[0].Patches[0]))
|
|
|
|
if !reflect.DeepEqual(expectedPatch, er.PolicyResponse.Rules[0].Patches[0]) {
|
|
|
|
t.Error("patches don't match")
|
|
|
|
}
|
|
|
|
}
|
2021-10-07 01:31:20 +00:00
|
|
|
|
|
|
|
func Test_foreach(t *testing.T) {
|
|
|
|
policyRaw := []byte(`{
|
2021-10-14 07:20:52 +00:00
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "replace-image-registry"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "replace-image-registry",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"foreach": [
|
|
|
|
{
|
|
|
|
"list": "request.object.spec.containers",
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "{{ element.name }}",
|
|
|
|
"image": "registry.io/{{images.containers.{{element.name}}.path}}:{{images.containers.{{element.name}}.tag}}"
|
|
|
|
}
|
|
|
|
]
|
2021-10-07 01:31:20 +00:00
|
|
|
}
|
2021-10-14 07:20:52 +00:00
|
|
|
}
|
2021-10-07 01:31:20 +00:00
|
|
|
}
|
2021-10-14 07:20:52 +00:00
|
|
|
]
|
2021-10-07 01:31:20 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-14 07:20:52 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
2021-10-07 01:31:20 +00:00
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "test1",
|
|
|
|
"image": "foo1/bash1:5.0"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "test2",
|
|
|
|
"image": "foo2/bash2:5.0"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "test3",
|
|
|
|
"image": "foo3/bash3:5.0"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-01-03 12:02:15 +00:00
|
|
|
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2021-10-07 01:31:20 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
2022-04-09 11:52:50 +00:00
|
|
|
err = ctx.AddResource(resource.Object)
|
2021-10-07 01:31:20 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resource,
|
2021-10-07 01:31:20 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 17:14:40 +00:00
|
|
|
err = ctx.AddImageInfos(resource, cfg)
|
2021-10-07 01:31:20 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
2021-10-07 01:31:20 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2021-10-07 01:31:20 +00:00
|
|
|
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
2023-01-30 11:41:09 +00:00
|
|
|
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
2021-10-07 01:31:20 +00:00
|
|
|
|
|
|
|
containers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "containers")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
for _, c := range containers {
|
|
|
|
ctnr := c.(map[string]interface{})
|
|
|
|
switch ctnr["name"] {
|
|
|
|
case "test1":
|
|
|
|
assert.Equal(t, ctnr["image"], "registry.io/foo1/bash1:5.0")
|
|
|
|
case "test2":
|
|
|
|
assert.Equal(t, ctnr["image"], "registry.io/foo2/bash2:5.0")
|
|
|
|
case "test3":
|
|
|
|
assert.Equal(t, ctnr["image"], "registry.io/foo3/bash3:5.0")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-14 17:14:11 +00:00
|
|
|
|
|
|
|
func Test_foreach_element_mutation(t *testing.T) {
|
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "mutate-privileged"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "audit",
|
|
|
|
"background": false,
|
|
|
|
"webhookTimeoutSeconds": 10,
|
|
|
|
"failurePolicy": "Fail",
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "set-privileged",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"foreach": [
|
|
|
|
{
|
|
|
|
"list": "request.object.spec.containers",
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"(name)": "{{ element.name }}",
|
|
|
|
"securityContext": {
|
|
|
|
"privileged": false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "nginx"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx1",
|
|
|
|
"image": "nginx"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "nginx2",
|
|
|
|
"image": "nginx"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-01-03 12:02:15 +00:00
|
|
|
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2021-10-14 17:14:11 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
2022-04-09 11:52:50 +00:00
|
|
|
err = ctx.AddResource(resource.Object)
|
2021-10-14 17:14:11 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resource,
|
2021-10-14 17:14:11 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 17:14:40 +00:00
|
|
|
err = ctx.AddImageInfos(resource, cfg)
|
2021-10-14 17:14:11 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
2021-10-14 17:14:11 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2021-10-14 17:14:11 +00:00
|
|
|
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
2023-01-30 11:41:09 +00:00
|
|
|
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
2021-10-14 17:14:11 +00:00
|
|
|
|
|
|
|
containers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "containers")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
for _, c := range containers {
|
|
|
|
ctnr := c.(map[string]interface{})
|
|
|
|
_securityContext, ok := ctnr["securityContext"]
|
|
|
|
assert.Assert(t, ok)
|
|
|
|
|
|
|
|
securityContext := _securityContext.(map[string]interface{})
|
|
|
|
assert.Equal(t, securityContext["privileged"], false)
|
|
|
|
}
|
|
|
|
}
|
2022-01-18 23:38:49 +00:00
|
|
|
|
|
|
|
func Test_Container_InitContainer_foreach(t *testing.T) {
|
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "prepend-registry",
|
|
|
|
"annotations": {
|
|
|
|
"pod-policies.kyverno.io/autogen-controllers": "none"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "prepend-registry-containers",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"foreach": [
|
|
|
|
{
|
|
|
|
"list": "request.object.spec.containers",
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "{{ element.name }}",
|
|
|
|
"image": "registry.io/{{ images.containers.\"{{element.name}}\".path}}:{{images.containers.\"{{element.name}}\".tag}}"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"list": "request.object.spec.initContainers",
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"spec": {
|
|
|
|
"initContainers": [
|
|
|
|
{
|
|
|
|
"name": "{{ element.name }}",
|
|
|
|
"image": "registry.io/{{ images.initContainers.\"{{element.name}}\".name}}:{{images.initContainers.\"{{element.name}}\".tag}}"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "mypod"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"automountServiceAccountToken": false,
|
|
|
|
"initContainers": [
|
|
|
|
{
|
|
|
|
"name": "alpine",
|
|
|
|
"image": "alpine:latest"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "busybox",
|
|
|
|
"image": "busybox:1.28"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:1.2.3"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "redis",
|
|
|
|
"image": "redis:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-01-03 12:02:15 +00:00
|
|
|
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2022-01-18 23:38:49 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
2022-04-09 11:52:50 +00:00
|
|
|
err = ctx.AddResource(resource.Object)
|
2022-01-18 23:38:49 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resource,
|
2022-01-18 23:38:49 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 17:14:40 +00:00
|
|
|
err = ctx.AddImageInfos(resource, cfg)
|
2022-01-18 23:38:49 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
2022-01-18 23:38:49 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2022-01-18 23:38:49 +00:00
|
|
|
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
2023-01-30 11:41:09 +00:00
|
|
|
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
2022-01-18 23:38:49 +00:00
|
|
|
|
|
|
|
containers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "containers")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
for _, c := range containers {
|
|
|
|
ctnr := c.(map[string]interface{})
|
|
|
|
switch ctnr["name"] {
|
|
|
|
case "alpine":
|
|
|
|
assert.Equal(t, ctnr["image"], "registry.io/alpine:latest")
|
|
|
|
case "busybox":
|
|
|
|
assert.Equal(t, ctnr["image"], "registry.io/busybox:1.28")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
initContainers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "initContainers")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
for _, c := range initContainers {
|
|
|
|
ctnr := c.(map[string]interface{})
|
|
|
|
switch ctnr["name"] {
|
|
|
|
case "nginx":
|
|
|
|
assert.Equal(t, ctnr["image"], "registry.io/nginx:1.2.3")
|
|
|
|
case "redis":
|
|
|
|
assert.Equal(t, ctnr["image"], "registry.io/redis:latest")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-25 15:15:31 +00:00
|
|
|
|
|
|
|
func Test_foreach_order_mutation_(t *testing.T) {
|
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "replace-image"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "replace-image",
|
|
|
|
"match": {
|
|
|
|
"all": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"foreach": [
|
|
|
|
{
|
|
|
|
"list": "request.object.spec.containers",
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"(name)": "{{ element.name }}",
|
|
|
|
"image": "replaced"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "mongodb",
|
|
|
|
"labels": {
|
|
|
|
"app": "mongodb"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"image": "docker.io/mongo:5.0.3",
|
|
|
|
"name": "mongod"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"image": "nginx",
|
|
|
|
"name": "nginx"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"image": "nginx",
|
|
|
|
"name": "nginx3"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"image": "quay.io/mongodb/mongodb-agent:11.0.5.6963-1",
|
|
|
|
"name": "mongodb-agent"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
2022-12-12 15:20:20 +00:00
|
|
|
|
|
|
|
er := testApplyPolicyToResource(t, policyRaw, resourceRaw)
|
|
|
|
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
2023-01-30 11:41:09 +00:00
|
|
|
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
2022-12-12 15:20:20 +00:00
|
|
|
|
|
|
|
containers, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "containers")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
for i, c := range containers {
|
|
|
|
ctnr := c.(map[string]interface{})
|
|
|
|
switch i {
|
|
|
|
case 0:
|
|
|
|
assert.Equal(t, ctnr["name"], "mongod")
|
|
|
|
case 1:
|
|
|
|
assert.Equal(t, ctnr["name"], "nginx")
|
|
|
|
case 3:
|
|
|
|
assert.Equal(t, ctnr["name"], "mongodb-agent")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-30 11:41:09 +00:00
|
|
|
func testApplyPolicyToResource(t *testing.T, policyRaw, resourceRaw []byte) *engineapi.EngineResponse {
|
2022-03-25 15:15:31 +00:00
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-01-03 12:02:15 +00:00
|
|
|
resource, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2022-03-25 15:15:31 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
2022-04-09 11:52:50 +00:00
|
|
|
err = ctx.AddResource(resource.Object)
|
2022-03-25 15:15:31 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resource,
|
2022-03-25 15:15:31 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 17:14:40 +00:00
|
|
|
err = ctx.AddImageInfos(resource, cfg)
|
2022-03-25 15:15:31 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
err = enginecontext.MutateResourceWithImageInfo(resourceRaw, ctx)
|
2022-03-25 15:15:31 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2022-12-12 15:20:20 +00:00
|
|
|
return er
|
|
|
|
}
|
2022-03-25 15:15:31 +00:00
|
|
|
|
2022-12-12 15:20:20 +00:00
|
|
|
func Test_mutate_nested_foreach(t *testing.T) {
|
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "replace-image-registry"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "replace-dns-suffix",
|
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Ingress"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"foreach": [
|
|
|
|
{
|
|
|
|
"list": "request.object.spec.tls",
|
|
|
|
"foreach": [
|
|
|
|
{
|
|
|
|
"list": "element.hosts",
|
|
|
|
"patchesJson6902": "- path: /spec/tls/{{elementIndex0}}/hosts/{{elementIndex1}}\n op: replace\n value: {{replace_all('{{element}}', '.foo.com', '.newfoo.com')}}"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "networking.k8s.io/v1",
|
|
|
|
"kind": "Ingress",
|
|
|
|
"metadata": {
|
|
|
|
"name": "tls-example-ingress"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"tls": [
|
|
|
|
{
|
|
|
|
"hosts": [
|
|
|
|
"https-example.foo.com"
|
|
|
|
],
|
|
|
|
"secretName": "testsecret-tls"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"hosts": [
|
|
|
|
"https-example2.foo.com"
|
|
|
|
],
|
|
|
|
"secretName": "testsecret-tls-2"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"host": "https-example.foo.com",
|
|
|
|
"http": {
|
|
|
|
"paths": [
|
|
|
|
{
|
|
|
|
"path": "/",
|
|
|
|
"pathType": "Prefix",
|
|
|
|
"backend": {
|
|
|
|
"service": {
|
|
|
|
"name": "service1",
|
|
|
|
"port": {
|
|
|
|
"number": 80
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"host": "https-example2.foo.com",
|
|
|
|
"http": {
|
|
|
|
"paths": [
|
|
|
|
{
|
|
|
|
"path": "/",
|
|
|
|
"pathType": "Prefix",
|
|
|
|
"backend": {
|
|
|
|
"service": {
|
|
|
|
"name": "service2",
|
|
|
|
"port": {
|
|
|
|
"number": 80
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
|
|
|
|
er := testApplyPolicyToResource(t, policyRaw, resourceRaw)
|
2022-03-25 15:15:31 +00:00
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
2023-01-30 11:41:09 +00:00
|
|
|
assert.Equal(t, er.PolicyResponse.Rules[0].Status, engineapi.RuleStatusPass)
|
2022-12-12 15:20:20 +00:00
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 2)
|
2022-03-25 15:15:31 +00:00
|
|
|
|
2022-12-12 15:20:20 +00:00
|
|
|
tlsArr, _, err := unstructured.NestedSlice(er.PatchedResource.Object, "spec", "tls")
|
2022-03-25 15:15:31 +00:00
|
|
|
assert.NilError(t, err)
|
2022-12-12 15:20:20 +00:00
|
|
|
for _, e := range tlsArr {
|
|
|
|
tls := e.(map[string]interface{})
|
|
|
|
hosts := tls["hosts"].([]interface{})
|
|
|
|
for _, h := range hosts {
|
|
|
|
s := h.(string)
|
|
|
|
assert.Assert(t, strings.HasSuffix(s, ".newfoo.com"))
|
2022-03-25 15:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-25 12:20:40 +00:00
|
|
|
|
|
|
|
func Test_mutate_existing_resources(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
policy []byte
|
|
|
|
trigger []byte
|
2022-05-24 12:19:36 +00:00
|
|
|
targets [][]byte
|
2022-04-25 12:20:40 +00:00
|
|
|
targetList string
|
|
|
|
patches []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "test-different-trigger-target",
|
|
|
|
policy: []byte(`{
|
2022-05-24 12:19:36 +00:00
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-post-mutation"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "mutate-deploy-on-configmap-update",
|
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"ConfigMap"
|
|
|
|
],
|
|
|
|
"names": [
|
|
|
|
"dictionary"
|
|
|
|
],
|
|
|
|
"namespaces": [
|
|
|
|
"staging"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"preconditions": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"key": "{{ request.object.data.foo }}",
|
|
|
|
"operator": "Equals",
|
|
|
|
"value": "bar"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"targets": [
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Deployment",
|
|
|
|
"name": "example-A",
|
|
|
|
"namespace": "staging"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"foo": "bar"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
trigger: []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"foo": "bar"
|
|
|
|
},
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "dictionary",
|
|
|
|
"namespace": "staging"
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
targets: [][]byte{[]byte(`{
|
|
|
|
"apiVersion": "apps/v1",
|
|
|
|
"kind": "Deployment",
|
|
|
|
"metadata": {
|
|
|
|
"name": "example-A",
|
|
|
|
"namespace": "staging",
|
|
|
|
"labels": {
|
|
|
|
"app": "nginx"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"replicas": 1,
|
|
|
|
"selector": {
|
|
|
|
"matchLabels": {
|
|
|
|
"app": "nginx"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"template": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "nginx"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:1.14.2",
|
|
|
|
"ports": [
|
|
|
|
{
|
|
|
|
"containerPort": 80
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`)},
|
|
|
|
targetList: "DeploymentList",
|
|
|
|
patches: []string{`{"op":"add","path":"/metadata/labels/foo","value":"bar"}`},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "test-same-trigger-target",
|
|
|
|
policy: []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-post-mutation"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "mutate-deploy-on-configmap-update",
|
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"ConfigMap"
|
|
|
|
],
|
|
|
|
"names": [
|
|
|
|
"dictionary"
|
|
|
|
],
|
|
|
|
"namespaces": [
|
|
|
|
"staging"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"preconditions": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"key": "{{ request.object.data.foo }}",
|
|
|
|
"operator": "Equals",
|
|
|
|
"value": "bar"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"targets": [
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"name": "dictionary",
|
|
|
|
"namespace": "staging"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"foo": "bar"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
trigger: []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"foo": "bar"
|
|
|
|
},
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "dictionary",
|
|
|
|
"namespace": "staging"
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
targets: [][]byte{[]byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"foo": "bar"
|
|
|
|
},
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "dictionary",
|
|
|
|
"namespace": "staging"
|
|
|
|
}
|
|
|
|
}`)},
|
|
|
|
targetList: "ComfigMapList",
|
|
|
|
patches: []string{`{"op":"add","path":"/metadata/labels","value":{"foo":"bar"}}`},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "test-in-place-variable",
|
|
|
|
policy: []byte(`
|
|
|
|
{
|
2022-04-25 12:20:40 +00:00
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
2022-05-24 12:19:36 +00:00
|
|
|
"name": "sync-cms"
|
2022-04-25 12:20:40 +00:00
|
|
|
},
|
|
|
|
"spec": {
|
2022-05-24 12:19:36 +00:00
|
|
|
"mutateExistingOnPolicyUpdate": false,
|
2022-04-25 12:20:40 +00:00
|
|
|
"rules": [
|
|
|
|
{
|
2022-05-24 12:19:36 +00:00
|
|
|
"name": "concat-cm",
|
2022-04-25 12:20:40 +00:00
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"ConfigMap"
|
|
|
|
],
|
|
|
|
"names": [
|
2022-05-24 12:19:36 +00:00
|
|
|
"cmone"
|
2022-04-25 12:20:40 +00:00
|
|
|
],
|
|
|
|
"namespaces": [
|
2022-05-24 12:19:36 +00:00
|
|
|
"foo"
|
2022-04-25 12:20:40 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"targets": [
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
2022-05-24 12:19:36 +00:00
|
|
|
"kind": "ConfigMap",
|
|
|
|
"name": "cmtwo",
|
|
|
|
"namespace": "bar"
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
|
|
|
],
|
|
|
|
"patchStrategicMerge": {
|
2022-05-24 12:19:36 +00:00
|
|
|
"data": {
|
|
|
|
"keytwo": "{{@}}-{{request.object.data.keyone}}"
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
2022-05-24 12:19:36 +00:00
|
|
|
`),
|
|
|
|
trigger: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"keyone": "valueone"
|
|
|
|
},
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "cmone",
|
|
|
|
"namespace": "foo"
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
2022-05-24 12:19:36 +00:00
|
|
|
}
|
|
|
|
`),
|
|
|
|
targets: [][]byte{[]byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"keytwo": "valuetwo"
|
2022-04-25 12:20:40 +00:00
|
|
|
},
|
2022-05-24 12:19:36 +00:00
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "cmtwo",
|
|
|
|
"namespace": "bar"
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-24 12:19:36 +00:00
|
|
|
`)},
|
|
|
|
targetList: "ComfigMapList",
|
|
|
|
patches: []string{`{"op":"replace","path":"/data/keytwo","value":"valuetwo-valueone"}`},
|
2022-04-25 12:20:40 +00:00
|
|
|
},
|
|
|
|
{
|
2022-05-24 12:19:36 +00:00
|
|
|
name: "test-in-place-variable",
|
|
|
|
policy: []byte(`
|
|
|
|
{
|
2022-04-25 12:20:40 +00:00
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
2022-05-24 12:19:36 +00:00
|
|
|
"name": "sync-cms"
|
2022-04-25 12:20:40 +00:00
|
|
|
},
|
|
|
|
"spec": {
|
2022-05-24 12:19:36 +00:00
|
|
|
"mutateExistingOnPolicyUpdate": false,
|
2022-04-25 12:20:40 +00:00
|
|
|
"rules": [
|
|
|
|
{
|
2022-05-24 12:19:36 +00:00
|
|
|
"name": "concat-cm",
|
2022-04-25 12:20:40 +00:00
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"ConfigMap"
|
|
|
|
],
|
|
|
|
"names": [
|
2022-05-24 12:19:36 +00:00
|
|
|
"cmone"
|
2022-04-25 12:20:40 +00:00
|
|
|
],
|
|
|
|
"namespaces": [
|
2022-05-24 12:19:36 +00:00
|
|
|
"foo"
|
2022-04-25 12:20:40 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"targets": [
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "ConfigMap",
|
2022-05-24 12:19:36 +00:00
|
|
|
"name": "cmtwo",
|
|
|
|
"namespace": "bar"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"name": "cmthree",
|
|
|
|
"namespace": "bar"
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
|
|
|
],
|
|
|
|
"patchStrategicMerge": {
|
2022-05-24 12:19:36 +00:00
|
|
|
"data": {
|
|
|
|
"key": "{{@}}-{{request.object.data.keyone}}"
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
2022-05-24 12:19:36 +00:00
|
|
|
`),
|
|
|
|
trigger: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"keyone": "valueone"
|
|
|
|
},
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "cmone",
|
|
|
|
"namespace": "foo"
|
|
|
|
}
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
2022-05-24 12:19:36 +00:00
|
|
|
`),
|
|
|
|
targets: [][]byte{
|
|
|
|
[]byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"key": "valuetwo"
|
|
|
|
},
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "cmtwo",
|
|
|
|
"namespace": "bar"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
[]byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"data": {
|
|
|
|
"key": "valuethree"
|
|
|
|
},
|
|
|
|
"kind": "ConfigMap",
|
|
|
|
"metadata": {
|
|
|
|
"name": "cmthree",
|
|
|
|
"namespace": "bar"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
},
|
2022-04-25 12:20:40 +00:00
|
|
|
targetList: "ComfigMapList",
|
2022-05-24 12:19:36 +00:00
|
|
|
patches: []string{`{"op":"replace","path":"/data/key","value":"valuetwo-valueone"}`, `{"op":"replace","path":"/data/key","value":"valuethree-valueone"}`},
|
2022-04-25 12:20:40 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-05-24 12:19:36 +00:00
|
|
|
var policyContext *PolicyContext
|
2022-04-25 12:20:40 +00:00
|
|
|
for _, test := range tests {
|
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(test.policy, &policy)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-01-03 12:02:15 +00:00
|
|
|
trigger, err := kubeutils.BytesToUnstructured(test.trigger)
|
2022-04-25 12:20:40 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-05-24 12:19:36 +00:00
|
|
|
for _, target := range test.targets {
|
2023-01-03 12:02:15 +00:00
|
|
|
target, err := kubeutils.BytesToUnstructured(target)
|
2022-05-24 12:19:36 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
2022-05-24 12:19:36 +00:00
|
|
|
err = ctx.AddResource(trigger.Object)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
gvrToListKind := map[schema.GroupVersionResource]string{
|
|
|
|
{Group: target.GroupVersionKind().Group, Version: target.GroupVersionKind().Version, Resource: target.GroupVersionKind().Kind}: test.targetList,
|
|
|
|
}
|
|
|
|
|
|
|
|
objects := []runtime.Object{target}
|
|
|
|
scheme := runtime.NewScheme()
|
2022-08-02 14:54:02 +00:00
|
|
|
dclient, err := client.NewFakeClient(scheme, gvrToListKind, objects...)
|
2022-05-24 12:19:36 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
dclient.SetDiscovery(client.NewFakeDiscoveryClient(nil))
|
|
|
|
|
2022-11-29 13:59:40 +00:00
|
|
|
_, err = dclient.GetResource(context.TODO(), target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName())
|
2022-05-24 12:19:36 +00:00
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext = &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
client: dclient,
|
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *trigger,
|
2022-05-24 12:19:36 +00:00
|
|
|
}
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2022-04-25 12:20:40 +00:00
|
|
|
|
|
|
|
for _, rr := range er.PolicyResponse.Rules {
|
2022-05-24 12:19:36 +00:00
|
|
|
for i, p := range rr.Patches {
|
|
|
|
assert.Equal(t, test.patches[i], string(p), "test %s failed:\nGot %s\nExpected: %s", test.name, rr.Patches[i], test.patches[i])
|
2023-01-30 11:41:09 +00:00
|
|
|
assert.Equal(t, rr.Status, engineapi.RuleStatusPass, rr.Status)
|
2022-05-24 12:19:36 +00:00
|
|
|
}
|
2022-04-25 12:20:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-29 07:02:26 +00:00
|
|
|
|
|
|
|
func Test_RuleSelectorMutate(t *testing.T) {
|
|
|
|
policyRaw := []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "add-label"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "add-app-label",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"name": "check-root-user",
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "root"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "add-appname-label",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"appname": "{{request.object.metadata.name}}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-02 17:14:40 +00:00
|
|
|
}
|
2022-07-29 07:02:26 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
|
|
|
|
resourceRaw := []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-root-user"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "check-root-user",
|
|
|
|
"image": "nginxinc/nginx-unprivileged",
|
|
|
|
"securityContext": {
|
|
|
|
"runAsNonRoot": true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
|
|
|
|
expectedPatch1 := []byte(`{"op":"add","path":"/metadata/labels","value":{"app":"root"}}`)
|
|
|
|
expectedPatch2 := []byte(`{"op":"add","path":"/metadata/labels/appname","value":"check-root-user"}`)
|
|
|
|
|
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
err := json.Unmarshal(policyRaw, &policy)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
2023-01-03 12:02:15 +00:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(resourceRaw)
|
2022-07-29 07:02:26 +00:00
|
|
|
assert.NilError(t, err)
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
|
|
|
err = enginecontext.AddResource(ctx, resourceRaw)
|
2022-07-29 07:02:26 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = ctx.Query("request.object.metadata.name")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resourceUnstructured,
|
2022-07-29 07:02:26 +00:00
|
|
|
}
|
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2022-07-29 07:02:26 +00:00
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 2)
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[1].Patches), 1)
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(expectedPatch1, er.PolicyResponse.Rules[0].Patches[0]) {
|
|
|
|
t.Error("rule 1 patches dont match")
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(expectedPatch2, er.PolicyResponse.Rules[1].Patches[0]) {
|
|
|
|
t.Errorf("rule 2 patches dont match")
|
|
|
|
}
|
|
|
|
|
|
|
|
applyOne := kyverno.ApplyOne
|
2022-12-02 08:14:23 +00:00
|
|
|
policyContext.policy.GetSpec().ApplyRules = &applyOne
|
2022-07-29 07:02:26 +00:00
|
|
|
|
2022-12-09 13:45:11 +00:00
|
|
|
er = Mutate(context.TODO(), registryclient.NewOrDie(), policyContext)
|
2022-07-29 07:02:26 +00:00
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules), 1)
|
|
|
|
assert.Equal(t, len(er.PolicyResponse.Rules[0].Patches), 1)
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(expectedPatch1, er.PolicyResponse.Rules[0].Patches[0]) {
|
|
|
|
t.Error("rule 1 patches dont match")
|
|
|
|
}
|
|
|
|
}
|
2022-11-10 16:03:45 +00:00
|
|
|
|
|
|
|
func Test_SpecialCharacters(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
policyRaw []byte
|
|
|
|
documentRaw []byte
|
|
|
|
want [][]byte
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "regex_replace",
|
|
|
|
policyRaw: []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "regex-replace-all-demo"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "retention-adjust",
|
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Deployment"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"retention": "{{ regex_replace_all('([0-9])([0-9])', '{{ @ }}', '${1}0') }}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
documentRaw: []byte(`{
|
|
|
|
"apiVersion": "apps/v1",
|
|
|
|
"kind": "Deployment",
|
|
|
|
"metadata": {
|
|
|
|
"name": "busybox",
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox",
|
|
|
|
"retention": "days_37"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"replicas": 3,
|
|
|
|
"selector": {
|
|
|
|
"matchLabels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"template": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"image": "busybox:1.28",
|
|
|
|
"name": "busybox",
|
|
|
|
"command": [
|
|
|
|
"sleep",
|
|
|
|
"9999"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
want: [][]byte{
|
|
|
|
[]byte(`{"op":"replace","path":"/metadata/labels/retention","value":"days_30"}`),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "regex_replace_with_slash",
|
|
|
|
policyRaw: []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "regex-replace-all-demo"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "retention-adjust",
|
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Deployment"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"corp.com/retention": "{{ regex_replace_all('([0-9])([0-9])', '{{ @ }}', '${1}0') }}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
documentRaw: []byte(`{
|
|
|
|
"apiVersion": "apps/v1",
|
|
|
|
"kind": "Deployment",
|
|
|
|
"metadata": {
|
|
|
|
"name": "busybox",
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox",
|
|
|
|
"corp.com/retention": "days_37"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"replicas": 3,
|
|
|
|
"selector": {
|
|
|
|
"matchLabels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"template": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"image": "busybox:1.28",
|
|
|
|
"name": "busybox",
|
|
|
|
"command": [
|
|
|
|
"sleep",
|
|
|
|
"9999"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
want: [][]byte{
|
|
|
|
[]byte(`{"op":"replace","path":"/metadata/labels/corp.com~1retention","value":"days_30"}`),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "regex_replace_with_hyphen",
|
|
|
|
policyRaw: []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "regex-replace-all-demo"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"background": false,
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "retention-adjust",
|
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Deployment"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"corp-retention": "{{ regex_replace_all('([0-9])([0-9])', '{{ @ }}', '${1}0') }}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
documentRaw: []byte(`{
|
|
|
|
"apiVersion": "apps/v1",
|
|
|
|
"kind": "Deployment",
|
|
|
|
"metadata": {
|
|
|
|
"name": "busybox",
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox",
|
|
|
|
"corp-retention": "days_37"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"replicas": 3,
|
|
|
|
"selector": {
|
|
|
|
"matchLabels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"template": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"image": "busybox:1.28",
|
|
|
|
"name": "busybox",
|
|
|
|
"command": [
|
|
|
|
"sleep",
|
|
|
|
"9999"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
want: [][]byte{
|
|
|
|
[]byte(`{"op":"replace","path":"/metadata/labels/corp-retention","value":"days_30"}`),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "to_upper_with_hyphen",
|
|
|
|
policyRaw: []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "to-upper-demo"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "format-deploy-zone",
|
|
|
|
"match": {
|
|
|
|
"any": [
|
|
|
|
{
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Deployment"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"mutate": {
|
|
|
|
"patchStrategicMerge": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"deploy-zone": "{{ to_upper('{{@}}') }}"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
documentRaw: []byte(`{
|
|
|
|
"apiVersion": "apps/v1",
|
|
|
|
"kind": "Deployment",
|
|
|
|
"metadata": {
|
|
|
|
"name": "busybox",
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox",
|
|
|
|
"deploy-zone": "eu-central-1"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"replicas": 3,
|
|
|
|
"selector": {
|
|
|
|
"matchLabels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"template": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "busybox"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"image": "busybox:1.28",
|
|
|
|
"name": "busybox",
|
|
|
|
"command": [
|
|
|
|
"sleep",
|
|
|
|
"9999"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`),
|
|
|
|
want: [][]byte{
|
|
|
|
[]byte(`{"op":"replace","path":"/metadata/labels/deploy-zone","value":"EU-CENTRAL-1"}`),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// Parse policy document.
|
|
|
|
var policy kyverno.ClusterPolicy
|
|
|
|
if err := json.Unmarshal(tt.policyRaw, &policy); err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse resource document.
|
2023-01-03 12:02:15 +00:00
|
|
|
resource, err := kubeutils.BytesToUnstructured(tt.documentRaw)
|
2022-11-10 16:03:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("ConvertToUnstructured() error = %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create JSON context and add the resource.
|
2022-11-29 13:59:40 +00:00
|
|
|
ctx := enginecontext.NewContext()
|
2022-11-10 16:03:45 +00:00
|
|
|
err = ctx.AddResource(resource.Object)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("ctx.AddResource() error = %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create policy context.
|
|
|
|
policyContext := &PolicyContext{
|
2022-12-02 08:14:23 +00:00
|
|
|
policy: &policy,
|
|
|
|
jsonContext: ctx,
|
|
|
|
newResource: *resource,
|
2022-11-10 16:03:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Mutate and make sure that we got the expected amount of rules.
|
2022-12-09 13:45:11 +00:00
|
|
|
patches := Mutate(context.TODO(), registryclient.NewOrDie(), policyContext).GetPatches()
|
2022-11-10 16:03:45 +00:00
|
|
|
if !reflect.DeepEqual(patches, tt.want) {
|
|
|
|
t.Errorf("Mutate() got patches %s, expected %s", patches, tt.want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|