From c8edf1ab324a96cec8e719f76120b721a6651199 Mon Sep 17 00:00:00 2001
From: shuting <shuting@nirmata.com>
Date: Thu, 2 Feb 2023 22:46:53 +0800
Subject: [PATCH] fix: admission review variables for DELETE operations (#6197)

* build trigger from the stored admission request payload

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add a kuttl test

Signed-off-by: ShutingZhao <shuting@nirmata.com>

---------

Signed-off-by: ShutingZhao <shuting@nirmata.com>
---
 pkg/background/common/resource.go             | 13 ++++-
 pkg/webhooks/resource/utils.go                |  4 +-
 .../existing/basic-delete/01-assert.yaml      |  9 +++
 .../existing/basic-delete/01-manifests.yaml   | 58 +++++++++++++++++++
 .../existing/basic-delete/02-delete-cm.yaml   |  7 +++
 .../existing/basic-delete/03-assert.yaml      |  7 +++
 .../standard/existing/basic-delete/README.md  | 11 ++++
 .../existing/basic-delete/cleanup.yaml        |  4 ++
 8 files changed, 110 insertions(+), 3 deletions(-)
 create mode 100644 test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-assert.yaml
 create mode 100644 test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-manifests.yaml
 create mode 100644 test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/02-delete-cm.yaml
 create mode 100644 test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/03-assert.yaml
 create mode 100644 test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/README.md
 create mode 100644 test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/cleanup.yaml

diff --git a/pkg/background/common/resource.go b/pkg/background/common/resource.go
index 0ead37cb48..1220fa24f1 100644
--- a/pkg/background/common/resource.go
+++ b/pkg/background/common/resource.go
@@ -8,6 +8,7 @@ import (
 	"github.com/go-logr/logr"
 	kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
 	"github.com/kyverno/kyverno/pkg/clients/dclient"
+	kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
 	retryutils "github.com/kyverno/kyverno/pkg/utils/retry"
 	admissionv1 "k8s.io/api/admission/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
@@ -51,6 +52,16 @@ func GetResource(client dclient.Interface, urSpec kyvernov1beta1.UpdateRequestSp
 		return nil, err
 	}
 
-	log.V(2).Info("fetched trigger resource", "resourceSpec", resourceSpec)
+	if resource == nil && urSpec.Context.AdmissionRequestInfo.AdmissionRequest != nil {
+		request := urSpec.Context.AdmissionRequestInfo.AdmissionRequest
+		raw := request.Object.Raw
+		if request.Operation == admissionv1.Delete {
+			raw = request.OldObject.Raw
+		}
+
+		resource, err = kubeutils.BytesToUnstructured(raw)
+	}
+
+	log.V(3).Info("fetched trigger resource", "resourceSpec", resourceSpec)
 	return resource, err
 }
diff --git a/pkg/webhooks/resource/utils.go b/pkg/webhooks/resource/utils.go
index 5e156d60de..f7ddc15dc6 100644
--- a/pkg/webhooks/resource/utils.go
+++ b/pkg/webhooks/resource/utils.go
@@ -49,7 +49,7 @@ func applyUpdateRequest(
 	ctx context.Context,
 	request *admissionv1.AdmissionRequest,
 	ruleType kyvernov1beta1.RequestType,
-	grGenerator updaterequest.Generator,
+	urGenerator updaterequest.Generator,
 	userRequestInfo kyvernov1beta1.RequestInfo,
 	action admissionv1.Operation,
 	engineResponses ...*engineapi.EngineResponse,
@@ -61,7 +61,7 @@ func applyUpdateRequest(
 
 	for _, er := range engineResponses {
 		ur := transform(admissionRequestInfo, userRequestInfo, er, ruleType)
-		if err := grGenerator.Apply(ctx, ur, action); err != nil {
+		if err := urGenerator.Apply(ctx, ur, action); err != nil {
 			failedUpdateRequest = append(failedUpdateRequest, updateRequestResponse{ur: ur, err: err})
 		}
 	}
diff --git a/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-assert.yaml b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-assert.yaml
new file mode 100644
index 0000000000..0ac1ea7dcc
--- /dev/null
+++ b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: test-post-mutation-delete-trigger
+status:
+  conditions:
+  - reason: Succeeded
+    status: "True"
+    type: Ready
diff --git a/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-manifests.yaml b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-manifests.yaml
new file mode 100644
index 0000000000..706fb39f53
--- /dev/null
+++ b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/01-manifests.yaml
@@ -0,0 +1,58 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: staging-2
+  labels:
+    app-type: corp
+  annotations:
+    cloud.platformzero.com/serviceClass: "xl2"
+---
+apiVersion: v1
+data:
+  foo: bar
+kind: ConfigMap
+metadata:
+  name: dictionary-2
+  namespace: staging-2
+---
+apiVersion: v1
+data:
+  foo: YmFy
+kind: Secret
+metadata:
+  name: test-secret-2
+  namespace: staging-2
+type: Opaque
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+  name: test-post-mutation-delete-trigger
+spec:
+  mutateExistingOnPolicyUpdate: false
+  rules:
+    - name: mutate-secret-on-configmap-delete
+      match:
+        any:
+        - resources:
+            kinds:
+            - ConfigMap
+            names:
+            - dictionary-2
+            namespaces:
+            - staging-2
+      preconditions:
+        any:
+        - key: "{{ request.operation }}"
+          operator: Equals
+          value: DELETE
+      mutate:
+        targets:
+        - apiVersion: v1
+          kind: Secret
+          name: test-secret-2
+          namespace: "{{ request.object.metadata.namespace }}"
+        patchStrategicMerge:
+          metadata:
+            labels:
+              foo: "{{ request.object.metadata.name }}"
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/02-delete-cm.yaml b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/02-delete-cm.yaml
new file mode 100644
index 0000000000..82f33a28bc
--- /dev/null
+++ b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/02-delete-cm.yaml
@@ -0,0 +1,7 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+delete:
+- apiVersion: v1
+  kind: ConfigMap
+  name: dictionary-2
+  namespace: staging-2
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/03-assert.yaml b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/03-assert.yaml
new file mode 100644
index 0000000000..fc44140bd6
--- /dev/null
+++ b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/03-assert.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: test-secret-2
+  namespace: staging-2
+  labels:
+    foo: dictionary-2
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/README.md b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/README.md
new file mode 100644
index 0000000000..9abd9c3007
--- /dev/null
+++ b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This is a basic test for the mutate existing capability which ensures that specifically deleting a triggering resource, via a precondition, results in the correct mutation of a different resource.
+
+## Expected Behavior
+
+When the `dictionary-2` ConfigMap is deleted, this should result in the mutation of the Secret named `test-secret-2` within the same Namespace to add the label `foo` with value set to the name or `dictionary-2` in this case. If the Secret is mutated so that the label `foo: dictionary-2` is present, the test passes. If not, the test fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/cleanup.yaml b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/cleanup.yaml
new file mode 100644
index 0000000000..15c3c49051
--- /dev/null
+++ b/test/conformance/kuttl/mutate/clusterpolicy/standard/existing/basic-delete/cleanup.yaml
@@ -0,0 +1,4 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+commands:
+  - command: kubectl delete -f 01-manifests.yaml --force --wait=true --ignore-not-found=true
\ No newline at end of file