From 1c3bddf8ca599452362dbbd902f6179b57936512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Edouard=20Br=C3=A9t=C3=A9ch=C3=A9?= Date: Mon, 10 Mar 2025 14:28:44 +0100 Subject: [PATCH] feat: support mock in CLI for VPs (#12344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: support mock in CLI for VPs Signed-off-by: Charles-Edouard Brétéché * implement get cm mock Signed-off-by: Charles-Edouard Brétéché * move into cel package Signed-off-by: Charles-Edouard Brétéché --------- Signed-off-by: Charles-Edouard Brétéché --- .../kubectl-kyverno/apis/v1alpha1/context.go | 22 ++ .../kubectl-kyverno/commands/apply/command.go | 23 +- .../commands/apply/command_test.go | 34 +++ .../config/crds/cli.kyverno.io_contexts.yaml | 50 +++++ cmd/cli/kubectl-kyverno/context/load.go | 34 +++ cmd/cli/kubectl-kyverno/context/load_test.go | 149 +++++++++++++ .../data/crds/cli.kyverno.io_contexts.yaml | 50 +++++ docs/user/cli/commands/kyverno_apply.md | 1 + docs/user/cli/crd/index.html | 108 +++++++++ .../cli/crd/kyverno_kubectl.v1alpha1.html | 208 ++++++++++++++++++ pkg/cel/policy/fake_context.go | 84 +++++++ .../policy-with-cm/context.yaml | 14 ++ .../policy-with-cm/pod1.yaml | 14 ++ .../policy-with-cm/pod2.yaml | 15 ++ .../policy-with-cm/policy.yaml | 18 ++ 15 files changed, 823 insertions(+), 1 deletion(-) create mode 100644 cmd/cli/kubectl-kyverno/apis/v1alpha1/context.go create mode 100644 cmd/cli/kubectl-kyverno/config/crds/cli.kyverno.io_contexts.yaml create mode 100644 cmd/cli/kubectl-kyverno/context/load.go create mode 100644 cmd/cli/kubectl-kyverno/context/load_test.go create mode 100644 cmd/cli/kubectl-kyverno/data/crds/cli.kyverno.io_contexts.yaml create mode 100644 pkg/cel/policy/fake_context.go create mode 100644 test/cli/test-validating-policy/policy-with-cm/context.yaml create mode 100644 test/cli/test-validating-policy/policy-with-cm/pod1.yaml create mode 100644 test/cli/test-validating-policy/policy-with-cm/pod2.yaml create mode 100644 test/cli/test-validating-policy/policy-with-cm/policy.yaml diff --git a/cmd/cli/kubectl-kyverno/apis/v1alpha1/context.go b/cmd/cli/kubectl-kyverno/apis/v1alpha1/context.go new file mode 100644 index 0000000000..59af21eb27 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/apis/v1alpha1/context.go @@ -0,0 +1,22 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope="Cluster" + +// Values declares values to be loaded by the Kyverno CLI +type Context struct { + metav1.TypeMeta `json:",inline,omitempty"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + ContextSpec `json:"spec"` +} + +type ContextSpec struct { + Resources []unstructured.Unstructured `json:"resources,omitempty"` +} diff --git a/cmd/cli/kubectl-kyverno/commands/apply/command.go b/cmd/cli/kubectl-kyverno/commands/apply/command.go index 4ede72c356..3590398c1b 100644 --- a/cmd/cli/kubectl-kyverno/commands/apply/command.go +++ b/cmd/cli/kubectl-kyverno/commands/apply/command.go @@ -16,6 +16,7 @@ import ( kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2" policiesv1alpha1 "github.com/kyverno/kyverno/api/policies.kyverno.io/v1alpha1" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command" + clicontext "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/context" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/data" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/deprecations" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/exception" @@ -65,6 +66,7 @@ type ApplyCommandConfig struct { Variables []string ValuesFile string UserInfoPath string + ContextPath string Cluster bool PolicyReport bool OutputFormat string @@ -162,6 +164,7 @@ func Command() *cobra.Command { cmd.Flags().StringVarP(&applyCommandConfig.UserInfoPath, "userinfo", "u", "", "Admission Info including Roles, Cluster Roles and Subjects") cmd.Flags().StringSliceVarP(&applyCommandConfig.Variables, "set", "s", nil, "Variables that are required") cmd.Flags().StringVarP(&applyCommandConfig.ValuesFile, "values-file", "f", "", "File containing values for policy variables") + cmd.Flags().StringVarP(&applyCommandConfig.ContextPath, "context-file", "", "", "File containing context data for CEL policies") cmd.Flags().BoolVarP(&applyCommandConfig.PolicyReport, "policy-report", "p", false, "Generates policy report when passed (default policyviolation)") cmd.Flags().StringVarP(&applyCommandConfig.OutputFormat, "output-format", "", "yaml", "Specifies the policy report format (json or yaml). Default: yaml.") cmd.Flags().StringVarP(&applyCommandConfig.Namespace, "namespace", "n", "", "Optional Policy parameter passed with cluster flag") @@ -373,6 +376,24 @@ func (c *ApplyCommandConfig) applyValidatingPolicies( return nil, err } restMapper = restmapper.NewDiscoveryRESTMapper(apiGroupResources) + fakeContextProvider := celpolicy.NewFakeContextProvider() + if c.ContextPath != "" { + ctx, err := clicontext.Load(nil, c.ContextPath) + if err != nil { + return nil, err + } + for _, resource := range ctx.ContextSpec.Resources { + gvk := resource.GroupVersionKind() + mapping, err := restMapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + if err := fakeContextProvider.AddResource(mapping.Resource, &resource); err != nil { + return nil, err + } + } + } + contextProvider = fakeContextProvider } responses := make([]engineapi.EngineResponse, 0) responsesTemp := make([]engine.EngineResponse, 0) @@ -398,7 +419,7 @@ func (c *ApplyCommandConfig) applyValidatingPolicies( "", resource.GetName(), resource.GetNamespace(), - // TODO + // TODO: how to manage other operations ? admissionv1.Create, resource, nil, diff --git a/cmd/cli/kubectl-kyverno/commands/apply/command_test.go b/cmd/cli/kubectl-kyverno/commands/apply/command_test.go index 9be483d858..a3adc1c4ed 100644 --- a/cmd/cli/kubectl-kyverno/commands/apply/command_test.go +++ b/cmd/cli/kubectl-kyverno/commands/apply/command_test.go @@ -586,6 +586,40 @@ func Test_Apply_ValidatingPolicies(t *testing.T) { }, }}, }, + { + config: ApplyCommandConfig{ + PolicyPaths: []string{"../../../../../test/cli/test-validating-policy/policy-with-cm/policy.yaml"}, + ResourcePaths: []string{"../../../../../test/cli/test-validating-policy/policy-with-cm/pod1.yaml"}, + ContextPath: "../../../../../test/cli/test-validating-policy/policy-with-cm/context.yaml", + PolicyReport: true, + }, + expectedPolicyReports: []policyreportv1alpha2.PolicyReport{{ + Summary: policyreportv1alpha2.PolicyReportSummary{ + Pass: 1, + Fail: 0, + Skip: 0, + Error: 0, + Warn: 0, + }, + }}, + }, + { + config: ApplyCommandConfig{ + PolicyPaths: []string{"../../../../../test/cli/test-validating-policy/policy-with-cm/policy.yaml"}, + ResourcePaths: []string{"../../../../../test/cli/test-validating-policy/policy-with-cm/pod2.yaml"}, + ContextPath: "../../../../../test/cli/test-validating-policy/policy-with-cm/context.yaml", + PolicyReport: true, + }, + expectedPolicyReports: []policyreportv1alpha2.PolicyReport{{ + Summary: policyreportv1alpha2.PolicyReportSummary{ + Pass: 0, + Fail: 1, + Skip: 0, + Error: 0, + Warn: 0, + }, + }}, + }, } compareSummary := func(expected policyreportv1alpha2.PolicyReportSummary, actual policyreportv1alpha2.PolicyReportSummary, desc string) { diff --git a/cmd/cli/kubectl-kyverno/config/crds/cli.kyverno.io_contexts.yaml b/cmd/cli/kubectl-kyverno/config/crds/cli.kyverno.io_contexts.yaml new file mode 100644 index 0000000000..3695c6d08f --- /dev/null +++ b/cmd/cli/kubectl-kyverno/config/crds/cli.kyverno.io_contexts.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + name: contexts.cli.kyverno.io +spec: + group: cli.kyverno.io + names: + kind: Context + listKind: ContextList + plural: contexts + singular: context + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Values declares values to be loaded by the Kyverno CLI + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + resources: + items: + type: object + type: array + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/cmd/cli/kubectl-kyverno/context/load.go b/cmd/cli/kubectl-kyverno/context/load.go new file mode 100644 index 0000000000..fbab0828a4 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/context/load.go @@ -0,0 +1,34 @@ +package context + +import ( + "io" + "os" + + "github.com/go-git/go-billy/v5" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/apis/v1alpha1" + "k8s.io/apimachinery/pkg/util/yaml" +) + +func Load(f billy.Filesystem, filepath string) (*v1alpha1.Context, error) { + yamlBytes, err := readFile(f, filepath) + if err != nil { + return nil, err + } + vals := &v1alpha1.Context{} + if err := yaml.UnmarshalStrict(yamlBytes, vals); err != nil { + return nil, err + } + return vals, nil +} + +func readFile(f billy.Filesystem, filepath string) ([]byte, error) { + if f != nil { + file, err := f.Open(filepath) + if err != nil { + return nil, err + } + defer file.Close() + return io.ReadAll(file) + } + return os.ReadFile(filepath) +} diff --git a/cmd/cli/kubectl-kyverno/context/load_test.go b/cmd/cli/kubectl-kyverno/context/load_test.go new file mode 100644 index 0000000000..4bd2fc39d2 --- /dev/null +++ b/cmd/cli/kubectl-kyverno/context/load_test.go @@ -0,0 +1,149 @@ +package context + +// import ( +// "os" +// "reflect" +// "testing" + +// "github.com/go-git/go-billy/v5" +// "github.com/go-git/go-billy/v5/memfs" +// "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/apis/v1alpha1" +// ) + +// func Test_readFile(t *testing.T) { +// mustReadFile := func(path string) []byte { +// t.Helper() +// data, err := os.ReadFile(path) +// if err != nil { +// t.Fatal(err) +// } +// return data +// } +// tests := []struct { +// name string +// f billy.Filesystem +// filepath string +// want []byte +// wantErr bool +// }{{ +// name: "empty", +// filepath: "", +// want: nil, +// wantErr: true, +// }, { +// name: "does not exist", +// filepath: "../_testdata/values/doesnotexist", +// want: nil, +// wantErr: true, +// }, { +// name: "bad format", +// filepath: "../_testdata/values/bad-format.yaml", +// want: mustReadFile("../_testdata/values/bad-format.yaml"), +// wantErr: false, +// }, { +// name: "valid", +// filepath: "../_testdata/values/limit-configmap-for-sa.yaml", +// want: mustReadFile("../_testdata/values/limit-configmap-for-sa.yaml"), +// wantErr: false, +// }, { +// name: "empty (billy)", +// f: memfs.New(), +// filepath: "", +// want: nil, +// wantErr: true, +// }, { +// name: "valid (billy)", +// f: func() billy.Filesystem { +// f := memfs.New() +// file, err := f.Create("valid.yaml") +// if err != nil { +// t.Fatal(err) +// } +// defer file.Close() +// if _, err := file.Write([]byte("foo: bar")); err != nil { +// t.Fatal(err) +// } +// return f +// }(), +// filepath: "valid.yaml", +// want: []byte("foo: bar"), +// wantErr: false, +// }} +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// got, err := readFile(tt.f, tt.filepath) +// if (err != nil) != tt.wantErr { +// t.Errorf("readFile() error = %v, wantErr %v", err, tt.wantErr) +// return +// } +// if !reflect.DeepEqual(got, tt.want) { +// t.Errorf("readFile() = %v, want %v", got, tt.want) +// } +// }) +// } +// } + +// func TestLoad(t *testing.T) { +// tests := []struct { +// name string +// f billy.Filesystem +// filepath string +// want *v1alpha1.Values +// wantErr bool +// }{{ +// name: "empty", +// filepath: "", +// want: nil, +// wantErr: true, +// }, { +// name: "does not exist", +// filepath: "../_testdata/values/doesnotexist", +// want: nil, +// wantErr: true, +// }, { +// name: "bad format", +// filepath: "../_testdata/values/bad-format.yaml", +// want: nil, +// wantErr: true, +// }, { +// name: "valid", +// filepath: "../_testdata/values/limit-configmap-for-sa.yaml", +// want: &v1alpha1.Values{ +// ValuesSpec: v1alpha1.ValuesSpec{ +// NamespaceSelectors: []v1alpha1.NamespaceSelector{{ +// Name: "test1", +// Labels: map[string]string{ +// "foo.com/managed-state": "managed", +// }, +// }}, +// Policies: []v1alpha1.Policy{{ +// Name: "limit-configmap-for-sa", +// Resources: []v1alpha1.Resource{{ +// Name: "any-configmap-name-good", +// Values: map[string]interface{}{ +// "request.operation": "UPDATE", +// }, +// }, { +// Name: "any-configmap-name-bad", +// Values: map[string]interface{}{ +// "request.operation": "UPDATE", +// }, +// }}, +// }}, +// }, +// }, +// wantErr: false, +// }} +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// got, err := Load(tt.f, tt.filepath) +// if (err != nil) != tt.wantErr { +// t.Errorf("Load() error = %v, wantErr %v", err, tt.wantErr) +// return +// } +// if !reflect.DeepEqual(got, tt.want) { +// t.Errorf("Load() = %v, want %v", got, tt.want) +// } +// }) +// } +// } diff --git a/cmd/cli/kubectl-kyverno/data/crds/cli.kyverno.io_contexts.yaml b/cmd/cli/kubectl-kyverno/data/crds/cli.kyverno.io_contexts.yaml new file mode 100644 index 0000000000..3695c6d08f --- /dev/null +++ b/cmd/cli/kubectl-kyverno/data/crds/cli.kyverno.io_contexts.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + name: contexts.cli.kyverno.io +spec: + group: cli.kyverno.io + names: + kind: Context + listKind: ContextList + plural: contexts + singular: context + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Values declares values to be loaded by the Kyverno CLI + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + resources: + items: + type: object + type: array + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/docs/user/cli/commands/kyverno_apply.md b/docs/user/cli/commands/kyverno_apply.md index 0cca1507dc..48369fe910 100644 --- a/docs/user/cli/commands/kyverno_apply.md +++ b/docs/user/cli/commands/kyverno_apply.md @@ -40,6 +40,7 @@ kyverno apply [flags] --audit-warn If set to true, will flag audit policies as warnings instead of failures -c, --cluster Checks if policies should be applied to cluster in the current context --context string The name of the kubeconfig context to use + --context-file string File containing context data for CEL policies --continue-on-fail If set to true, will continue to apply policies on the next resource upon failure to apply to the current resource instead of exiting out --detailed-results If set to true, display detailed results -e, --exception strings Policy exception to be considered when evaluating policies against resources diff --git a/docs/user/cli/crd/index.html b/docs/user/cli/crd/index.html index bdf69d3a59..a8d60a307d 100644 --- a/docs/user/cli/crd/index.html +++ b/docs/user/cli/crd/index.html @@ -25,6 +25,8 @@ background-color: #1589dd;

cli.kyverno.io/v1alpha1

Resource Types:
+

Context +

+

+

Values declares values to be loaded by the Kyverno CLI

+

+ + + + + + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+apiVersion
+string
+ +cli.kyverno.io/v1alpha1 + +
+kind
+string +
Context
+metadata
+ + +Kubernetes meta/v1.ObjectMeta + + +
+Refer to the Kubernetes API documentation for the fields of the +metadata field. +
+spec
+ + +ContextSpec + + +
+
+
+ + + + + +
+resources
+ + +[]Kubernetes meta/v1/unstructured.Unstructured + + +
+
+
+

Test

@@ -426,6 +503,37 @@ github.com/kyverno/kyverno-json/pkg/apis/policy/v1alpha1.Any


+

ContextSpec +

+

+(Appears on: +Context) +

+

+

+ + + + + + + + + + + + + +
FieldDescription
+resources
+ + +[]Kubernetes meta/v1/unstructured.Unstructured + + +
+
+

NamespaceSelector

diff --git a/docs/user/cli/crd/kyverno_kubectl.v1alpha1.html b/docs/user/cli/crd/kyverno_kubectl.v1alpha1.html index da72cfd14a..71513918fa 100644 --- a/docs/user/cli/crd/kyverno_kubectl.v1alpha1.html +++ b/docs/user/cli/crd/kyverno_kubectl.v1alpha1.html @@ -25,6 +25,8 @@

Resource Types:

  • + Context +
  • Test
  • UserInfo @@ -34,6 +36,149 @@ +

    Context +

    + + + +

    Values declares values to be loaded by the Kyverno CLI

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    apiVersion
    string
    cli.kyverno.io/v1alpha1
    kind
    string
    Context
    metadata + + * + +
    + + + + + meta/v1.ObjectMeta + + +
    + + + + + + Refer to the Kubernetes API documentation for the fields of the + metadata field. + + + +
    spec + + * + +
    + + + + + + ContextSpec + + + +
    + + + + + + + +
    +
    + + + + + + + + + + + + + + +
    resources + + * + +
    + + + + + []meta/v1/unstructured.Unstructured + + +
    + + + + + + + +
    + +
    + +

    Test

    @@ -856,6 +1001,69 @@ This field is deprecated, use metadata.name instead

    + + + + + + + + + + +

    ContextSpec +

    + + +

    + (Appears in: + Context) +

    + + +

    + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/cel/policy/fake_context.go b/pkg/cel/policy/fake_context.go new file mode 100644 index 0000000000..cda5946666 --- /dev/null +++ b/pkg/cel/policy/fake_context.go @@ -0,0 +1,84 @@ +package policy + +import ( + "github.com/kyverno/kyverno/pkg/imageverification/imagedataloader" + kerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type FakeContextProvider struct { + resources map[string]map[string]map[string]*unstructured.Unstructured +} + +func NewFakeContextProvider() *FakeContextProvider { + return &FakeContextProvider{ + resources: map[string]map[string]map[string]*unstructured.Unstructured{}, + } +} + +func (cp *FakeContextProvider) AddResource(gvr schema.GroupVersionResource, obj runtime.Object) error { + object, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return err + } + resource := &unstructured.Unstructured{Object: object} + resources := cp.resources[gvr.String()] + if resources == nil { + resources = map[string]map[string]*unstructured.Unstructured{} + cp.resources[gvr.String()] = resources + } + namespace := resources[resource.GetNamespace()] + if namespace == nil { + namespace = map[string]*unstructured.Unstructured{} + resources[resource.GetNamespace()] = namespace + } + namespace[resource.GetName()] = resource + return nil +} + +func (cp *FakeContextProvider) GetConfigMap(ns, n string) (unstructured.Unstructured, error) { + cm, err := cp.GetResource("v1", "configmaps", ns, n) + if err != nil { + return unstructured.Unstructured{}, err + } + return *cm, nil +} + +func (cp *FakeContextProvider) GetGlobalReference(string, string) (any, error) { + panic("not implemented") +} + +func (cp *FakeContextProvider) GetImageData(string) (*imagedataloader.ImageData, error) { + panic("not implemented") +} + +func (cp *FakeContextProvider) ParseImageReference(string) (imagedataloader.ImageReference, error) { + panic("not implemented") +} + +func (cp *FakeContextProvider) ListResources(apiVersion, resource, namespace string) (*unstructured.UnstructuredList, error) { + panic("not implemented") +} + +func (cp *FakeContextProvider) GetResource(apiVersion, resource, namespace, name string) (*unstructured.Unstructured, error) { + gv, err := schema.ParseGroupVersion(apiVersion) + if err != nil { + return nil, err + } + gvr := gv.WithResource(resource) + resources := cp.resources[gvr.String()] + if resources == nil { + return nil, kerrors.NewNotFound(gvr.GroupResource(), name) + } + namespaced := resources[namespace] + if namespaced == nil { + return nil, kerrors.NewNotFound(gvr.GroupResource(), name) + } + resourced := namespaced[name] + if resourced == nil { + return nil, kerrors.NewNotFound(gvr.GroupResource(), name) + } + return resourced, nil +} diff --git a/test/cli/test-validating-policy/policy-with-cm/context.yaml b/test/cli/test-validating-policy/policy-with-cm/context.yaml new file mode 100644 index 0000000000..c455aa8624 --- /dev/null +++ b/test/cli/test-validating-policy/policy-with-cm/context.yaml @@ -0,0 +1,14 @@ +apiVersion: cli.kyverno.io/v1alpha1 +kind: Context +metadata: + name: kyverno-test.yaml +spec: + resources: + - apiVersion: v1 + kind: ConfigMap + metadata: + namespace: default + name: policy-cm + data: + name: good-pod + diff --git a/test/cli/test-validating-policy/policy-with-cm/pod1.yaml b/test/cli/test-validating-policy/policy-with-cm/pod1.yaml new file mode 100644 index 0000000000..194c86cead --- /dev/null +++ b/test/cli/test-validating-policy/policy-with-cm/pod1.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: good-pod +spec: + containers: + - name: + image: nginx + volumeMounts: + - name: udev + mountPath: /data + volumes: + - name: udev + emptyDir: {} diff --git a/test/cli/test-validating-policy/policy-with-cm/pod2.yaml b/test/cli/test-validating-policy/policy-with-cm/pod2.yaml new file mode 100644 index 0000000000..a4c4d770fd --- /dev/null +++ b/test/cli/test-validating-policy/policy-with-cm/pod2.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: bad-pod +spec: + containers: + - name: + image: nginx + volumeMounts: + - name: udev + mountPath: /data + volumes: + - name: udev + hostPath: + path: /etc/udev diff --git a/test/cli/test-validating-policy/policy-with-cm/policy.yaml b/test/cli/test-validating-policy/policy-with-cm/policy.yaml new file mode 100644 index 0000000000..14bbfb1a5f --- /dev/null +++ b/test/cli/test-validating-policy/policy-with-cm/policy.yaml @@ -0,0 +1,18 @@ +apiVersion: policies.kyverno.io/v1alpha1 +kind: ValidatingPolicy +metadata: + name: disallow-host-path +spec: + matchConstraints: + resourceRules: + - apiGroups: [""] + apiVersions: ["v1"] + operations: ["CREATE", "UPDATE"] + resources: ["pods"] + variables: + - name: cm + expression: >- + context.GetConfigMap(object.metadata.namespace, "policy-cm") + validations: + - expression: >- + object.metadata.name == variables.cm.data.name
    FieldDescription
    resources + + * + +
    + + + + + []meta/v1/unstructured.Unstructured + + +
    + + + + + + +