@@ -1594,6 +1609,15 @@ Kubernetes apiextensions/v1.JSON
+ForeachOrder
+(string
alias)
+
+(Appears on:
+ForEachMutation)
+
+
+
ForeachOrder specifies the iteration order in foreach statements.
+
GenerateType
(string
alias)
diff --git a/pkg/engine/handlers/mutation/common.go b/pkg/engine/handlers/mutation/common.go
index ab41825b77..f88a2772ac 100644
--- a/pkg/engine/handlers/mutation/common.go
+++ b/pkg/engine/handlers/mutation/common.go
@@ -69,15 +69,22 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
patchedResource := f.resource
var allPatches []jsonpatch.JsonPatchOperation
+ reverse := false
if foreach.RawPatchStrategicMerge != nil {
+ reverse = true
+ } else if foreach.Order != nil && *foreach.Order == kyvernov1.Descending {
+ reverse = true
+ }
+ if reverse {
engineutils.InvertedElement(elements)
}
-
for index, element := range elements {
if element == nil {
continue
}
-
+ if reverse {
+ index = len(elements) - 1 - index
+ }
f.policyContext.JSONContext().Reset()
policyContext := f.policyContext.Copy()
@@ -131,8 +138,7 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
allPatches = append(allPatches, mutateResp.Patches...)
}
}
- sortedPatches := patch.FilterAndSortPatches(allPatches)
- return mutate.NewResponse(engineapi.RuleStatusPass, patchedResource.unstructured, sortedPatches, "")
+ return mutate.NewResponse(engineapi.RuleStatusPass, patchedResource.unstructured, allPatches, "")
}
func buildRuleResponse(rule *kyvernov1.Rule, mutateResp *mutate.Response, info resourceInfo) *engineapi.RuleResponse {
diff --git a/pkg/engine/mutate/patch/patchesUtils.go b/pkg/engine/mutate/patch/patchesUtils.go
index 6e574e5a2c..cccdfde723 100644
--- a/pkg/engine/mutate/patch/patchesUtils.go
+++ b/pkg/engine/mutate/patch/patchesUtils.go
@@ -23,17 +23,17 @@ func generatePatches(src, dst []byte) ([]jsonpatch.JsonPatchOperation, error) {
if pp, err := jsonpatch.CreatePatch(src, dst); err != nil {
return nil, err
} else {
- return FilterAndSortPatches(pp), err
+ return filterAndSortPatches(pp), err
}
}
-// FilterAndSortPatches
+// filterAndSortPatches
// 1. filters out patches with the certain paths
// 2. sorts the removal patches(with same path) by the key of index
// in descending order. The sort is required as when removing multiple
// elements from an array, the elements must be removed in descending
// order to preserve each index value.
-func FilterAndSortPatches(originalPatches []jsonpatch.JsonPatchOperation) []jsonpatch.JsonPatchOperation {
+func filterAndSortPatches(originalPatches []jsonpatch.JsonPatchOperation) []jsonpatch.JsonPatchOperation {
patches := filterInvalidPatches(originalPatches)
result := make([]jsonpatch.JsonPatchOperation, len(patches))
diff --git a/pkg/engine/mutate/patch/patchesUtils_test.go b/pkg/engine/mutate/patch/patchesUtils_test.go
index 249426e9cf..17103e6c67 100644
--- a/pkg/engine/mutate/patch/patchesUtils_test.go
+++ b/pkg/engine/mutate/patch/patchesUtils_test.go
@@ -320,7 +320,7 @@ func Test_sortRemovalPatches(t *testing.T) {
}
for i, test := range tests {
- sortedPatches := FilterAndSortPatches(test.patches)
+ sortedPatches := filterAndSortPatches(test.patches)
assertnew.Equal(t, test.expected, sortedPatches, fmt.Sprintf("%dth test fails", i))
}
}
diff --git a/test/conformance/kuttl/mutate/policy/cornercases/foreach-remove-elements/policy.yaml b/test/conformance/kuttl/mutate/policy/cornercases/foreach-remove-elements/policy.yaml
index f244db6de6..a2d91a776c 100644
--- a/test/conformance/kuttl/mutate/policy/cornercases/foreach-remove-elements/policy.yaml
+++ b/test/conformance/kuttl/mutate/policy/cornercases/foreach-remove-elements/policy.yaml
@@ -15,6 +15,7 @@ spec:
mutate:
foreach:
- list: request.object.spec.volumes[]
+ order: Descending
preconditions:
all:
- key: hostPath
diff --git a/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/README.md b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/README.md
new file mode 100644
index 0000000000..4763840548
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/README.md
@@ -0,0 +1,13 @@
+## Description
+
+This is a test of the policy in this folder.
+
+Note: In order for this test to work on Pods emitted from Pod controllers, the Kyverno ConfigMap excludeGroups value may need to be modified to remove the entry for system:serviceaccounts:kube-system or else mutation may not occur.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resources. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/policy-ready.yaml
new file mode 100644
index 0000000000..6696bb1d2d
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-emptydir-sizelimit
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/policy.yaml b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/policy.yaml
new file mode 100644
index 0000000000..2a7cf157b3
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/policy.yaml
@@ -0,0 +1,46 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: add-emptydir-sizelimit
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-emptydir-sizelimit
+ annotations:
+ pod-policies.kyverno.io/autogen-controllers: none
+ policies.kyverno.io/title: Add emptyDir sizeLimit
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/subject: Pod
+ policies.kyverno.io/minversion: 1.6.0
+ kyverno.io/kyverno-version: 1.7.3,1.8.0-rc2
+ kyverno.io/kubernetes-version: "1.24"
+ policies.kyverno.io/description: >-
+ When a Pod requests an emptyDir, by default it does not have a size limit which
+ may allow it to consume excess or all of the space in the medium backing the volume.
+ This can quickly overrun a Node and may result in a denial of service for other
+ workloads. This policy adds a sizeLimit field to all Pods mounting emptyDir
+ volumes, if not present, and sets it to 100Mi.
+spec:
+ rules:
+ - name: mutate-emptydir
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: "request.object.spec.volumes[]"
+ preconditions:
+ all:
+ - key: "{{element.keys(@)}}"
+ operator: AnyIn
+ value: emptyDir
+ - key: "{{element.emptyDir.sizeLimit || ''}}"
+ operator: Equals
+ value: ''
+ patchesJson6902: |-
+ - path: "/spec/volumes/{{elementIndex}}/emptyDir/sizeLimit"
+ op: add
+ value: 100Mi
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/resource-mutated.yaml
new file mode 100644
index 0000000000..f1080792f5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/resource-mutated.yaml
@@ -0,0 +1,86 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod01
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - image: aiboelckajdow:1.35
+ name: busybox
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ volumes:
+ - emptyDir:
+ sizeLimit: 100Mi
+ name: foo
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod02
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: busybox
+ image: iopybmeyffhjq:1.35
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ volumes:
+ - name: foo
+ emptyDir:
+ sizeLimit: 50Mi
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod03
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: busybox
+ image: flfmfioapzhdts:1.35
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ - mountPath: /bar
+ name: bar
+ volumes:
+ - name: foo
+ emptyDir:
+ sizeLimit: 50Mi
+ - name: bar
+ emptyDir:
+ sizeLimit: 100Mi
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod04
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - image: imvplaiskduqnf:1.35
+ name: busybox
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ - mountPath: /bar
+ name: bar
+ - mountPath: /baz
+ name: baz
+ volumes:
+ - emptyDir:
+ sizeLimit: 50Mi
+ name: foo
+ - hostPath:
+ path: /opt/baz
+ name: baz
+ - emptyDir:
+ sizeLimit: 100Mi
+ name: bar
diff --git a/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/resource.yaml b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/resource.yaml
new file mode 100644
index 0000000000..878ced1811
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-emptydirsizelimit/resource.yaml
@@ -0,0 +1,83 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod01
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: busybox
+ image: aiboelckajdow:1.35
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ volumes:
+ - name: foo
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod02
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: busybox
+ image: iopybmeyffhjq:1.35
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ volumes:
+ - name: foo
+ emptyDir:
+ sizeLimit: 50Mi
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod03
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: busybox
+ image: flfmfioapzhdts:1.35
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ - mountPath: /bar
+ name: bar
+ volumes:
+ - name: foo
+ emptyDir:
+ sizeLimit: 50Mi
+ - name: bar
+ emptyDir: {}
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod04
+ namespace: add-emptydir-sizelimit
+spec:
+ automountServiceAccountToken: false
+ containers:
+ - name: busybox
+ image: imvplaiskduqnf:1.35
+ volumeMounts:
+ - mountPath: /foo
+ name: foo
+ - mountPath: /bar
+ name: bar
+ - mountPath: /baz
+ name: baz
+ volumes:
+ - name: foo
+ emptyDir:
+ sizeLimit: 50Mi
+ - name: baz
+ hostPath:
+ path: /opt/baz
+ - name: bar
+ emptyDir: {}
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/01-crd.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/01-crd.yaml
new file mode 100644
index 0000000000..6db5372cb0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/01-crd.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- crd.yaml
+assert:
+- crd-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/02-policy.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/02-policy.yaml
new file mode 100644
index 0000000000..57ffd5631d
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/02-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/03-resource.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/03-resource.yaml
new file mode 100644
index 0000000000..de14ac5c9c
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/03-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/README.md b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/README.md
new file mode 100644
index 0000000000..6ec7030d63
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/README.md
@@ -0,0 +1,12 @@
+## Description
+
+This is a description of what my test does and why it needs to do it.
+
+## Expected Behavior
+
+This is the expected behavior of my test. Although it's assumed the test, overall, should pass/succeed, be specific about what the internal behavior is which leads to that result.
+
+## Reference Issue(s)
+
+1234
+test
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/crd-assert.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/crd-assert.yaml
new file mode 100644
index 0000000000..a7aee3c477
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/crd-assert.yaml
@@ -0,0 +1,13 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: externalsecrets.external-secrets.io
+spec: {}
+status:
+ acceptedNames:
+ kind: ExternalSecret
+ listKind: ExternalSecretList
+ plural: externalsecrets
+ singular: externalsecret
+ storedVersions:
+ - v1beta1
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/crd.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/crd.yaml
new file mode 100644
index 0000000000..8cf533cc60
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/crd.yaml
@@ -0,0 +1,694 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.11.3
+ name: externalsecrets.external-secrets.io
+spec:
+ group: external-secrets.io
+ names:
+ categories:
+ - externalsecrets
+ kind: ExternalSecret
+ listKind: ExternalSecretList
+ plural: externalsecrets
+ shortNames:
+ - es
+ singular: externalsecret
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .spec.secretStoreRef.name
+ name: Store
+ type: string
+ - jsonPath: .spec.refreshInterval
+ name: Refresh Interval
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+ name: Status
+ type: string
+ deprecated: true
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: ExternalSecret is the Schema for the external-secrets API.
+ 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:
+ description: ExternalSecretSpec defines the desired state of ExternalSecret.
+ properties:
+ data:
+ description: Data defines the connection between the Kubernetes Secret
+ keys and the Provider data
+ items:
+ description: ExternalSecretData defines the connection between the
+ Kubernetes Secret key (spec.data.) and the Provider data.
+ properties:
+ remoteRef:
+ description: ExternalSecretDataRemoteRef defines Provider data
+ location.
+ properties:
+ conversionStrategy:
+ default: Default
+ description: Used to define a conversion Strategy
+ type: string
+ key:
+ description: Key is the key used in the Provider, mandatory
+ type: string
+ property:
+ description: Used to select a specific property of the Provider
+ value (if a map), if supported
+ type: string
+ version:
+ description: Used to select a specific version of the Provider
+ value, if supported
+ type: string
+ required:
+ - key
+ type: object
+ secretKey:
+ type: string
+ required:
+ - remoteRef
+ - secretKey
+ type: object
+ type: array
+ dataFrom:
+ description: DataFrom is used to fetch all properties from a specific
+ Provider data If multiple entries are specified, the Secret keys
+ are merged in the specified order
+ items:
+ description: ExternalSecretDataRemoteRef defines Provider data location.
+ properties:
+ conversionStrategy:
+ default: Default
+ description: Used to define a conversion Strategy
+ type: string
+ key:
+ description: Key is the key used in the Provider, mandatory
+ type: string
+ property:
+ description: Used to select a specific property of the Provider
+ value (if a map), if supported
+ type: string
+ version:
+ description: Used to select a specific version of the Provider
+ value, if supported
+ type: string
+ required:
+ - key
+ type: object
+ type: array
+ refreshInterval:
+ default: 1h
+ description: RefreshInterval is the amount of time before the values
+ are read again from the SecretStore provider Valid time units are
+ "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to
+ fetch and create it once. Defaults to 1h.
+ type: string
+ secretStoreRef:
+ description: SecretStoreRef defines which SecretStore to fetch the
+ ExternalSecret data.
+ properties:
+ kind:
+ description: Kind of the SecretStore resource (SecretStore or
+ ClusterSecretStore) Defaults to `SecretStore`
+ type: string
+ name:
+ description: Name of the SecretStore resource
+ type: string
+ required:
+ - name
+ type: object
+ target:
+ description: ExternalSecretTarget defines the Kubernetes Secret to
+ be created There can be only one target per ExternalSecret.
+ properties:
+ creationPolicy:
+ default: Owner
+ description: CreationPolicy defines rules on how to create the
+ resulting Secret Defaults to 'Owner'
+ type: string
+ immutable:
+ description: Immutable defines if the final secret will be immutable
+ type: boolean
+ name:
+ description: Name defines the name of the Secret resource to be
+ managed This field is immutable Defaults to the .metadata.name
+ of the ExternalSecret resource
+ type: string
+ template:
+ description: Template defines a blueprint for the created Secret
+ resource.
+ properties:
+ data:
+ additionalProperties:
+ type: string
+ type: object
+ engineVersion:
+ default: v1
+ description: EngineVersion specifies the template engine version
+ that should be used to compile/execute the template specified
+ in .data and .templateFrom[].
+ type: string
+ metadata:
+ description: ExternalSecretTemplateMetadata defines metadata
+ fields for the Secret blueprint.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ templateFrom:
+ items:
+ maxProperties: 1
+ minProperties: 1
+ properties:
+ configMap:
+ properties:
+ items:
+ items:
+ properties:
+ key:
+ type: string
+ required:
+ - key
+ type: object
+ type: array
+ name:
+ type: string
+ required:
+ - items
+ - name
+ type: object
+ secret:
+ properties:
+ items:
+ items:
+ properties:
+ key:
+ type: string
+ required:
+ - key
+ type: object
+ type: array
+ name:
+ type: string
+ required:
+ - items
+ - name
+ type: object
+ type: object
+ type: array
+ type:
+ type: string
+ type: object
+ type: object
+ required:
+ - secretStoreRef
+ - target
+ type: object
+ status:
+ properties:
+ conditions:
+ items:
+ properties:
+ lastTransitionTime:
+ format: date-time
+ type: string
+ message:
+ type: string
+ reason:
+ type: string
+ status:
+ type: string
+ type:
+ type: string
+ required:
+ - status
+ - type
+ type: object
+ type: array
+ refreshTime:
+ description: refreshTime is the time and date the external secret
+ was fetched and the target secret updated
+ format: date-time
+ nullable: true
+ type: string
+ syncedResourceVersion:
+ description: SyncedResourceVersion keeps track of the last synced
+ version
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: false
+ subresources:
+ status: {}
+ - additionalPrinterColumns:
+ - jsonPath: .spec.secretStoreRef.name
+ name: Store
+ type: string
+ - jsonPath: .spec.refreshInterval
+ name: Refresh Interval
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Ready")].reason
+ name: Status
+ type: string
+ - jsonPath: .status.conditions[?(@.type=="Ready")].status
+ name: Ready
+ type: string
+ name: v1beta1
+ schema:
+ openAPIV3Schema:
+ description: ExternalSecret is the Schema for the external-secrets API.
+ 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:
+ description: ExternalSecretSpec defines the desired state of ExternalSecret.
+ properties:
+ data:
+ description: Data defines the connection between the Kubernetes Secret
+ keys and the Provider data
+ items:
+ description: ExternalSecretData defines the connection between the
+ Kubernetes Secret key (spec.data.) and the Provider data.
+ properties:
+ remoteRef:
+ description: RemoteRef points to the remote secret and defines
+ which secret (version/property/..) to fetch.
+ properties:
+ conversionStrategy:
+ default: Default
+ description: Used to define a conversion Strategy
+ type: string
+ decodingStrategy:
+ default: None
+ description: Used to define a decoding Strategy
+ type: string
+ key:
+ description: Key is the key used in the Provider, mandatory
+ type: string
+ metadataPolicy:
+ description: Policy for fetching tags/labels from provider
+ secrets, possible options are Fetch, None. Defaults to
+ None
+ type: string
+ property:
+ description: Used to select a specific property of the Provider
+ value (if a map), if supported
+ type: string
+ version:
+ description: Used to select a specific version of the Provider
+ value, if supported
+ type: string
+ required:
+ - key
+ type: object
+ secretKey:
+ description: SecretKey defines the key in which the controller
+ stores the value. This is the key in the Kind=Secret
+ type: string
+ sourceRef:
+ description: SourceRef allows you to override the source from
+ which the value will pulled from.
+ maxProperties: 1
+ properties:
+ generatorRef:
+ description: GeneratorRef points to a generator custom resource
+ in
+ properties:
+ apiVersion:
+ default: generators.external-secrets.io/v1alpha1
+ description: Specify the apiVersion of the generator
+ resource
+ type: string
+ kind:
+ description: Specify the Kind of the resource, e.g.
+ Password, ACRAccessToken etc.
+ type: string
+ name:
+ description: Specify the name of the generator resource
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ storeRef:
+ description: SecretStoreRef defines which SecretStore to
+ fetch the ExternalSecret data.
+ properties:
+ kind:
+ description: Kind of the SecretStore resource (SecretStore
+ or ClusterSecretStore) Defaults to `SecretStore`
+ type: string
+ name:
+ description: Name of the SecretStore resource
+ type: string
+ required:
+ - name
+ type: object
+ type: object
+ required:
+ - remoteRef
+ - secretKey
+ type: object
+ type: array
+ dataFrom:
+ description: DataFrom is used to fetch all properties from a specific
+ Provider data If multiple entries are specified, the Secret keys
+ are merged in the specified order
+ items:
+ properties:
+ extract:
+ description: 'Used to extract multiple key/value pairs from
+ one secret Note: Extract does not support sourceRef.Generator
+ or sourceRef.GeneratorRef.'
+ properties:
+ conversionStrategy:
+ default: Default
+ description: Used to define a conversion Strategy
+ type: string
+ decodingStrategy:
+ default: None
+ description: Used to define a decoding Strategy
+ type: string
+ key:
+ description: Key is the key used in the Provider, mandatory
+ type: string
+ metadataPolicy:
+ description: Policy for fetching tags/labels from provider
+ secrets, possible options are Fetch, None. Defaults to
+ None
+ type: string
+ property:
+ description: Used to select a specific property of the Provider
+ value (if a map), if supported
+ type: string
+ version:
+ description: Used to select a specific version of the Provider
+ value, if supported
+ type: string
+ required:
+ - key
+ type: object
+ find:
+ description: 'Used to find secrets based on tags or regular
+ expressions Note: Find does not support sourceRef.Generator
+ or sourceRef.GeneratorRef.'
+ properties:
+ conversionStrategy:
+ default: Default
+ description: Used to define a conversion Strategy
+ type: string
+ decodingStrategy:
+ default: None
+ description: Used to define a decoding Strategy
+ type: string
+ name:
+ description: Finds secrets based on the name.
+ properties:
+ regexp:
+ description: Finds secrets base
+ type: string
+ type: object
+ path:
+ description: A root path to start the find operations.
+ type: string
+ tags:
+ additionalProperties:
+ type: string
+ description: Find secrets based on tags.
+ type: object
+ type: object
+ rewrite:
+ description: Used to rewrite secret Keys after getting them
+ from the secret Provider Multiple Rewrite operations can be
+ provided. They are applied in a layered order (first to last)
+ items:
+ properties:
+ regexp:
+ description: Used to rewrite with regular expressions.
+ The resulting key will be the output of a regexp.ReplaceAll
+ operation.
+ properties:
+ source:
+ description: Used to define the regular expression
+ of a re.Compiler.
+ type: string
+ target:
+ description: Used to define the target pattern of
+ a ReplaceAll operation.
+ type: string
+ required:
+ - source
+ - target
+ type: object
+ type: object
+ type: array
+ sourceRef:
+ description: SourceRef points to a store or generator which
+ contains secret values ready to use. Use this in combination
+ with Extract or Find pull values out of a specific SecretStore.
+ When sourceRef points to a generator Extract or Find is not
+ supported. The generator returns a static map of values
+ maxProperties: 1
+ properties:
+ generatorRef:
+ description: GeneratorRef points to a generator custom resource
+ in
+ properties:
+ apiVersion:
+ default: generators.external-secrets.io/v1alpha1
+ description: Specify the apiVersion of the generator
+ resource
+ type: string
+ kind:
+ description: Specify the Kind of the resource, e.g.
+ Password, ACRAccessToken etc.
+ type: string
+ name:
+ description: Specify the name of the generator resource
+ type: string
+ required:
+ - kind
+ - name
+ type: object
+ storeRef:
+ description: SecretStoreRef defines which SecretStore to
+ fetch the ExternalSecret data.
+ properties:
+ kind:
+ description: Kind of the SecretStore resource (SecretStore
+ or ClusterSecretStore) Defaults to `SecretStore`
+ type: string
+ name:
+ description: Name of the SecretStore resource
+ type: string
+ required:
+ - name
+ type: object
+ type: object
+ type: object
+ type: array
+ refreshInterval:
+ default: 1h
+ description: RefreshInterval is the amount of time before the values
+ are read again from the SecretStore provider Valid time units are
+ "ns", "us" (or "µs"), "ms", "s", "m", "h" May be set to zero to
+ fetch and create it once. Defaults to 1h.
+ type: string
+ secretStoreRef:
+ description: SecretStoreRef defines which SecretStore to fetch the
+ ExternalSecret data.
+ properties:
+ kind:
+ description: Kind of the SecretStore resource (SecretStore or
+ ClusterSecretStore) Defaults to `SecretStore`
+ type: string
+ name:
+ description: Name of the SecretStore resource
+ type: string
+ required:
+ - name
+ type: object
+ target:
+ default:
+ creationPolicy: Owner
+ deletionPolicy: Retain
+ description: ExternalSecretTarget defines the Kubernetes Secret to
+ be created There can be only one target per ExternalSecret.
+ properties:
+ creationPolicy:
+ default: Owner
+ description: CreationPolicy defines rules on how to create the
+ resulting Secret Defaults to 'Owner'
+ enum:
+ - Owner
+ - Orphan
+ - Merge
+ - None
+ type: string
+ deletionPolicy:
+ default: Retain
+ description: DeletionPolicy defines rules on how to delete the
+ resulting Secret Defaults to 'Retain'
+ enum:
+ - Delete
+ - Merge
+ - Retain
+ type: string
+ immutable:
+ description: Immutable defines if the final secret will be immutable
+ type: boolean
+ name:
+ description: Name defines the name of the Secret resource to be
+ managed This field is immutable Defaults to the .metadata.name
+ of the ExternalSecret resource
+ type: string
+ template:
+ description: Template defines a blueprint for the created Secret
+ resource.
+ properties:
+ data:
+ additionalProperties:
+ type: string
+ type: object
+ engineVersion:
+ default: v2
+ type: string
+ mergePolicy:
+ default: Replace
+ type: string
+ metadata:
+ description: ExternalSecretTemplateMetadata defines metadata
+ fields for the Secret blueprint.
+ properties:
+ annotations:
+ additionalProperties:
+ type: string
+ type: object
+ labels:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ templateFrom:
+ items:
+ properties:
+ configMap:
+ properties:
+ items:
+ items:
+ properties:
+ key:
+ type: string
+ templateAs:
+ default: Values
+ type: string
+ required:
+ - key
+ type: object
+ type: array
+ name:
+ type: string
+ required:
+ - items
+ - name
+ type: object
+ literal:
+ type: string
+ secret:
+ properties:
+ items:
+ items:
+ properties:
+ key:
+ type: string
+ templateAs:
+ default: Values
+ type: string
+ required:
+ - key
+ type: object
+ type: array
+ name:
+ type: string
+ required:
+ - items
+ - name
+ type: object
+ target:
+ default: Data
+ type: string
+ type: object
+ type: array
+ type:
+ type: string
+ type: object
+ type: object
+ type: object
+ status:
+ properties:
+ conditions:
+ items:
+ properties:
+ lastTransitionTime:
+ format: date-time
+ type: string
+ message:
+ type: string
+ reason:
+ type: string
+ status:
+ type: string
+ type:
+ type: string
+ required:
+ - status
+ - type
+ type: object
+ type: array
+ refreshTime:
+ description: refreshTime is the time and date the external secret
+ was fetched and the target secret updated
+ format: date-time
+ nullable: true
+ type: string
+ syncedResourceVersion:
+ description: SyncedResourceVersion keeps track of the last synced
+ version
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources:
+ status: {}
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/policy-ready.yaml
new file mode 100644
index 0000000000..51234b6594
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-external-secret-prefix
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/policy.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/policy.yaml
new file mode 100644
index 0000000000..ae3d6a0ecf
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/policy.yaml
@@ -0,0 +1,44 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: add-external-secret-prefix
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-external-secret-prefix
+ annotations:
+ policies.kyverno.io/title: Add prefix to external secret
+ policies.kyverno.io/category: ExternalSecretOperator
+ policies.kyverno.io/severity: medium
+ policies.kyverno.io/subject: ExternalSecret
+ kyverno.io/kyverno-version: 1.7.1
+ policies.kyverno.io/minversion: 1.6.0
+ kyverno.io/kubernetes-version: "1.23"
+ policies.kyverno.io/description: >-
+ This Policy mutates secretRef key to add a prefix.
+ External Secret Operator proposes to use kyverno to force ExternalSecrets
+ to have namespace prefix so that kubernetes administrators do not need to
+ define permissions and users per namespace.
+ Doing this developers are abstracted by administrators naming convention and will not
+ be able to access secrets from other namespaces.
+ In this example, in the JSON patch change "prefix-" to your preferred prefix. For example: {{ request.namespace }}
+spec:
+ rules:
+ - name: add-external-secret-prefix
+ match:
+ any:
+ - resources:
+ kinds:
+ - ExternalSecret
+ mutate:
+ foreach:
+ - list: "request.object.spec.data"
+ patchesJson6902: |-
+ - path: /spec/data/{{elementIndex}}/remoteRef
+ op: add
+ value:
+ key: "prefix-{{element.remoteRef.key}}"
+ property: "{{element.remoteRef.property}}"
+ conversionStrategy: "{{element.remoteRef.conversionStrategy}}"
+ decodingStrategy: "{{element.remoteRef.decodingStrategy}}"
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/resource-mutated.yaml
new file mode 100644
index 0000000000..03eab8636c
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/resource-mutated.yaml
@@ -0,0 +1,27 @@
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+ name: example
+ namespace: add-external-secret-prefix
+spec:
+ data:
+ - remoteRef:
+ conversionStrategy: Default
+ decodingStrategy: None
+ key: prefix-remote-secret
+ property: name.first
+ secretKey: firstname
+ - remoteRef:
+ conversionStrategy: Default
+ decodingStrategy: None
+ key: prefix-friend-secret
+ property: friends.1.first
+ secretKey: first_friend
+ refreshInterval: 1m
+ secretStoreRef:
+ kind: SecretStore
+ name: aws
+ target:
+ creationPolicy: Owner
+ deletionPolicy: Retain
+ name: secret-to-be-created
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/resource.yaml b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/resource.yaml
new file mode 100644
index 0000000000..e89a9db993
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-external-secret-prefix/resource.yaml
@@ -0,0 +1,26 @@
+apiVersion: external-secrets.io/v1beta1
+kind: ExternalSecret
+metadata:
+ name: example
+ namespace: add-external-secret-prefix
+spec:
+ refreshInterval: 1m
+ secretStoreRef:
+ name: aws
+ kind: SecretStore
+ target:
+ name: secret-to-be-created
+ creationPolicy: Owner
+ data:
+ - secretKey: firstname
+ remoteRef:
+ key: remote-secret
+ property: "name.first"
+ conversionStrategy: Default
+ decodingStrategy: None
+ - secretKey: first_friend
+ remoteRef:
+ key: friend-secret
+ property: "friends.1.first"
+ conversionStrategy: Default
+ decodingStrategy: None
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/README.md b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/README.md
new file mode 100644
index 0000000000..4763840548
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/README.md
@@ -0,0 +1,13 @@
+## Description
+
+This is a test of the policy in this folder.
+
+Note: In order for this test to work on Pods emitted from Pod controllers, the Kyverno ConfigMap excludeGroups value may need to be modified to remove the entry for system:serviceaccounts:kube-system or else mutation may not occur.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resources. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/policy-ready.yaml
new file mode 100644
index 0000000000..da767ab21e
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-image-as-env-var
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/policy.yaml b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/policy.yaml
new file mode 100644
index 0000000000..fe52715a16
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/policy.yaml
@@ -0,0 +1,40 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: add-image-as-env-var
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-image-as-env-var
+ annotations:
+ pod-policies.kyverno.io/autogen-controllers: none
+ policies.kyverno.io/title: Add Image as Environment Variable
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/severity: medium
+ kyverno.io/kyverno-version: 1.10.0-alpha.2
+ kyverno.io/kubernetes-version: "1.26"
+ policies.kyverno.io/subject: Pod
+ policies.kyverno.io/description: >-
+ The Kubernetes downward API only has the ability to express so many
+ options as environment variables. The image consumed in a Pod is commonly
+ needed to make the application aware of some logic it must take. This policy
+ takes the value of the `image` field and adds it as an environment variable
+ to Pods.
+spec:
+ rules:
+ - name: pod-containers-inject-image
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers[]
+ patchesJson6902: |-
+ - op: add
+ path: /spec/containers/{{elementIndex}}/env/-
+ value:
+ name: K8S_IMAGE
+ value: "{{ element.image }}"
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/resource-mutated.yaml
new file mode 100644
index 0000000000..02d10206c8
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/resource-mutated.yaml
@@ -0,0 +1,47 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod01
+ namespace: add-image-as-env-var
+spec:
+ containers:
+ - env:
+ - name: FOO
+ value: bar
+ - name: K8S_IMAGE
+ value: aiboelckajdow:1.35
+ image: aiboelckajdow:1.35
+ name: busybox
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod02
+ namespace: add-image-as-env-var
+spec:
+ containers:
+ - env:
+ - name: K8S_IMAGE
+ value: bicoapeibsjasjdhb:1.35
+ image: bicoapeibsjasjdhb:1.35
+ name: busybox
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod03
+ namespace: add-image-as-env-var
+spec:
+ containers:
+ - env:
+ - name: COLOR
+ value: red
+ - name: K8S_IMAGE
+ value: pqmbjduzivyyaiv:1.35
+ image: pqmbjduzivyyaiv:1.35
+ name: busybox
+ - env:
+ - name: K8S_IMAGE
+ value: yqkbmzydleyds:1.1.0
+ image: yqkbmzydleyds:1.1.0
+ name: nginx
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/resource.yaml b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/resource.yaml
new file mode 100644
index 0000000000..9f670115a5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-image-as-env-var/resource.yaml
@@ -0,0 +1,37 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod01
+ namespace: add-image-as-env-var
+spec:
+ containers:
+ - name: busybox
+ image: aiboelckajdow:1.35
+ env:
+ - name: FOO
+ value: bar
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod02
+ namespace: add-image-as-env-var
+spec:
+ containers:
+ - name: busybox
+ image: bicoapeibsjasjdhb:1.35
+---
+apiVersion: v1
+kind: Pod
+metadata:
+ name: pod03
+ namespace: add-image-as-env-var
+spec:
+ containers:
+ - name: busybox
+ image: pqmbjduzivyyaiv:1.35
+ env:
+ - name: COLOR
+ value: red
+ - name: nginx
+ image: yqkbmzydleyds:1.1.0
diff --git a/test/conformance/kuttl/mutate/refactor/add-node-affinity/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/add-node-affinity/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-node-affinity/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-node-affinity/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/add-node-affinity/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-node-affinity/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-node-affinity/README.md b/test/conformance/kuttl/mutate/refactor/add-node-affinity/README.md
new file mode 100644
index 0000000000..04644f67f5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-node-affinity/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This is a test of the policy in this folder.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resources. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-node-affinity/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/add-node-affinity/policy-ready.yaml
new file mode 100644
index 0000000000..ba706ce75a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-node-affinity/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-node-affinity
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-node-affinity/policy.yaml b/test/conformance/kuttl/mutate/refactor/add-node-affinity/policy.yaml
new file mode 100644
index 0000000000..315e4c5770
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-node-affinity/policy.yaml
@@ -0,0 +1,38 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: add-node-affinity
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-node-affinity
+ annotations:
+ policies.kyverno.io/title: Add Node Affinity
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/severity: medium
+ policies.kyverno.io/subject: Deployment
+ kyverno.io/kyverno-version: 1.6.0
+ kyverno.io/kubernetes-version: "1.21"
+ policies.kyverno.io/description: >-
+ Node affinity, similar to node selection, is a way to specify which node(s) on which Pods will be scheduled
+ but based on more complex conditions. This policy will add node affinity to a Deployment and if one already
+ exists an expression will be added to it.
+spec:
+ background: false
+ rules:
+ - name: add-node-affinity-deployment
+ match:
+ any:
+ - resources:
+ kinds:
+ - Deployment
+ mutate:
+ patchesJson6902: |-
+ - path: "/spec/template/spec/affinity/nodeAffinity/requiredDuringSchedulingIgnoredDuringExecution/nodeSelectorTerms/-1/matchExpressions/-1"
+ op: add
+ value:
+ key: zone_weight
+ operator: Lt
+ values:
+ - "400"
diff --git a/test/conformance/kuttl/mutate/refactor/add-node-affinity/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-node-affinity/resource-mutated.yaml
new file mode 100644
index 0000000000..a7d826b9fa
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-node-affinity/resource-mutated.yaml
@@ -0,0 +1,107 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: tomcat
+ name: tomcat-deployment
+ namespace: add-node-affinity
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tomcat
+ template:
+ metadata:
+ labels:
+ app: tomcat
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: zone_weight
+ operator: Lt
+ values:
+ - "400"
+ containers:
+ - image: thisisdefinitelynottomcat:9.0
+ name: tomcat
+ ports:
+ - containerPort: 80
+ protocol: TCP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: nginx
+ name: nginx-deployment
+ namespace: add-node-affinity
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: fookey
+ operator: In
+ values:
+ - bar
+ - key: zone_weight
+ operator: Lt
+ values:
+ - "400"
+ containers:
+ - image: thisisdefinitelynotnginx:1.0.1
+ name: nginx
+ ports:
+ - containerPort: 80
+ protocol: TCP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: redis
+ name: redis-deployment
+ namespace: add-node-affinity
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: redis
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: zone_weight
+ operator: Lt
+ values:
+ - "400"
+ matchFields:
+ - key: metadata.name
+ operator: In
+ values:
+ - red
+ containers:
+ - image: thisisdefinitelynotredis:latest
+ name: redis
+ ports:
+ - containerPort: 80
+ protocol: TCP
diff --git a/test/conformance/kuttl/mutate/refactor/add-node-affinity/resource.yaml b/test/conformance/kuttl/mutate/refactor/add-node-affinity/resource.yaml
new file mode 100644
index 0000000000..ea470494af
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-node-affinity/resource.yaml
@@ -0,0 +1,86 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: tomcat-deployment
+ namespace: add-node-affinity
+ labels:
+ app: tomcat
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: tomcat
+ template:
+ metadata:
+ labels:
+ app: tomcat
+ spec:
+ containers:
+ - name: tomcat
+ image: thisisdefinitelynottomcat:9.0
+ ports:
+ - containerPort: 80
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: nginx-deployment
+ namespace: add-node-affinity
+ labels:
+ app: nginx
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: nginx
+ template:
+ metadata:
+ labels:
+ app: nginx
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: fookey
+ operator: In
+ values:
+ - bar
+ containers:
+ - name: nginx
+ image: thisisdefinitelynotnginx:1.0.1
+ ports:
+ - containerPort: 80
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis-deployment
+ namespace: add-node-affinity
+ labels:
+ app: redis
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: redis
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchFields:
+ - key: metadata.name
+ operator: In
+ values:
+ - red
+ containers:
+ - name: redis
+ image: thisisdefinitelynotredis:latest
+ ports:
+ - containerPort: 80
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/02-pod.yaml
new file mode 100644
index 0000000000..79800b2516
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/02-pod.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- pod.yaml
+assert:
+- pod-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/03-deployment.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/03-deployment.yaml
new file mode 100644
index 0000000000..61dea991e2
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/03-deployment.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- deployment.yaml
+assert:
+- deployment-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/04-cronjob.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/04-cronjob.yaml
new file mode 100644
index 0000000000..d84c0963be
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/04-cronjob.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- cronjob.yaml
+assert:
+- cronjob-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/README.md b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/README.md
new file mode 100644
index 0000000000..04644f67f5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This is a test of the policy in this folder.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resources. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/cronjob-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/cronjob-mutated.yaml
new file mode 100644
index 0000000000..f2c62f44dc
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/cronjob-mutated.yaml
@@ -0,0 +1,20 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: hello
+ namespace: add-pod-priorityclassname
+spec:
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - args:
+ - /bin/sh
+ - -c
+ - date; echo Hello from the Kubernetes cluster
+ image: somejunkimagegoeshere
+ name: hello
+ priorityClassName: non-production
+ restartPolicy: OnFailure
+ schedule: '*/1 * * * *'
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/cronjob.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/cronjob.yaml
new file mode 100644
index 0000000000..830a04e39f
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/cronjob.yaml
@@ -0,0 +1,19 @@
+apiVersion: batch/v1
+kind: CronJob
+metadata:
+ name: hello
+ namespace: add-pod-priorityclassname
+spec:
+ schedule: "*/1 * * * *"
+ jobTemplate:
+ spec:
+ template:
+ spec:
+ containers:
+ - name: hello
+ image: somejunkimagegoeshere
+ args:
+ - /bin/sh
+ - -c
+ - date; echo Hello from the Kubernetes cluster
+ restartPolicy: OnFailure
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/deployment-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/deployment-mutated.yaml
new file mode 100644
index 0000000000..d005a048f5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/deployment-mutated.yaml
@@ -0,0 +1,24 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: busybox
+ name: busybox
+ namespace: add-pod-priorityclassname
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: busybox
+ template:
+ metadata:
+ labels:
+ app: busybox
+ spec:
+ containers:
+ - command:
+ - sleep
+ - "9999"
+ image: somejunkbusyboximage:1.28
+ name: busybox
+ priorityClassName: non-production
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/deployment.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/deployment.yaml
new file mode 100644
index 0000000000..516f8074cf
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/deployment.yaml
@@ -0,0 +1,21 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: busybox
+ namespace: add-pod-priorityclassname
+ labels:
+ app: busybox
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: busybox
+ template:
+ metadata:
+ labels:
+ app: busybox
+ spec:
+ containers:
+ - image: somejunkbusyboximage:1.28
+ name: busybox
+ command: ["sleep", "9999"]
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/pod-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/pod-mutated.yaml
new file mode 100644
index 0000000000..b9c25ea733
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/pod-mutated.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: blank
+ namespace: add-pod-priorityclassname
+spec:
+ containers:
+ - image: sfsdafasdfsadfsadf
+ name: busybox
+ priorityClassName: non-production
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/pod.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/pod.yaml
new file mode 100644
index 0000000000..b5db2b7c27
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/pod.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: blank
+ namespace: add-pod-priorityclassname
+spec:
+ containers:
+ - name: busybox
+ image: sfsdafasdfsadfsadf
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/policy-ready.yaml
new file mode 100644
index 0000000000..c95f7c6422
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-pod-priorityclassname
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/policy.yaml b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/policy.yaml
new file mode 100644
index 0000000000..0a1dc98679
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-pod-priorityclassname/policy.yaml
@@ -0,0 +1,93 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: add-pod-priorityclassname
+---
+apiVersion: scheduling.k8s.io/v1
+kind: PriorityClass
+metadata:
+ name: non-production
+value: 1234
+globalDefault: false
+description: "This priority class should be used for XYZ service pods only."
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-pod-priorityclassname
+ annotations:
+ policies.kyverno.io/title: Add Pod priorityClassName
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/severity: medium
+ policies.kyverno.io/subject: Pod
+ pod-policies.kyverno.io/autogen-controllers: none
+ kyverno.io/kyverno-version: 1.7.1
+ policies.kyverno.io/minversion: 1.6.0
+ kyverno.io/kubernetes-version: "1.23"
+ policies.kyverno.io/description: >-
+ A Pod PriorityClass is used to provide a guarantee on the scheduling of a Pod relative to others.
+ This policy adds the priorityClassName of `non-production` to any Pod deployed
+ into a Namespace that does not have the label env=production.
+spec:
+ background: false
+ rules:
+ - name: add-priorityclass-pods
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ namespaceSelector:
+ matchExpressions:
+ - key: env
+ operator: NotIn
+ values:
+ - production
+ mutate:
+ patchesJson6902: |-
+ - op: remove
+ path: '/spec/priority'
+ - op: add
+ path: /spec/priorityClassName
+ value: 'non-production'
+ - name: add-priorityclass-controllers
+ match:
+ any:
+ - resources:
+ kinds:
+ - Deployment
+ - DaemonSet
+ - StatefulSet
+ - Job
+ namespaceSelector:
+ matchExpressions:
+ - key: env
+ operator: NotIn
+ values:
+ - production
+ mutate:
+ patchesJson6902: |-
+ - op: remove
+ path: '/spec/template/spec/priority'
+ - op: add
+ path: /spec/template/spec/priorityClassName
+ value: 'non-production'
+ - name: add-priorityclass-cronjobs
+ match:
+ any:
+ - resources:
+ kinds:
+ - CronJob
+ namespaceSelector:
+ matchExpressions:
+ - key: env
+ operator: NotIn
+ values:
+ - production
+ mutate:
+ patchesJson6902: |-
+ - op: remove
+ path: '/spec/jobTemplate/spec/template/spec/priority'
+ - op: add
+ path: /spec/jobTemplate/spec/template/spec/priorityClassName
+ value: 'non-production'
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-tolerations/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/add-tolerations/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-tolerations/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-tolerations/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/add-tolerations/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-tolerations/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-tolerations/README.md b/test/conformance/kuttl/mutate/refactor/add-tolerations/README.md
new file mode 100644
index 0000000000..1e9be3bf91
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-tolerations/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This is a test of the policy in this folder.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resource. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-tolerations/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/add-tolerations/policy-ready.yaml
new file mode 100644
index 0000000000..f3ea2605c3
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-tolerations/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-tolerations
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-tolerations/policy.yaml b/test/conformance/kuttl/mutate/refactor/add-tolerations/policy.yaml
new file mode 100644
index 0000000000..640622b412
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-tolerations/policy.yaml
@@ -0,0 +1,43 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: add-tolerations
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-tolerations
+ annotations:
+ policies.kyverno.io/title: Add Tolerations
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/severity: medium
+ policies.kyverno.io/subject: Pod
+ kyverno.io/kyverno-version: 1.7.1
+ policies.kyverno.io/minversion: 1.6.0
+ kyverno.io/kubernetes-version: "1.23"
+ policies.kyverno.io/description: >-
+ Pod tolerations are used to schedule on Nodes which have
+ a matching taint. This policy adds the toleration `org.com/role=service:NoSchedule`
+ if existing tolerations do not contain the key `org.com/role`.
+spec:
+ rules:
+ - name: service-toleration
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ preconditions:
+ any:
+ - key: "org.com/role"
+ operator: AnyNotIn
+ value: "{{ request.object.spec.tolerations[].key || `[]` }}"
+ mutate:
+ patchesJson6902: |-
+ - op: add
+ path: "/spec/tolerations/-"
+ value:
+ key: org.com/role
+ operator: Equal
+ value: service
+ effect: NoSchedule
diff --git a/test/conformance/kuttl/mutate/refactor/add-tolerations/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-tolerations/resource-mutated.yaml
new file mode 100644
index 0000000000..7f209bdd3c
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-tolerations/resource-mutated.yaml
@@ -0,0 +1,25 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: addpod02
+ namespace: add-tolerations
+spec:
+ containers:
+ - image: containerimage01
+ name: container01
+ tolerations:
+ - effect: NoSchedule
+ key: org.com/test
+ operator: Exists
+ - effect: NoExecute
+ key: node.kubernetes.io/not-ready
+ operator: Exists
+ tolerationSeconds: 300
+ - effect: NoExecute
+ key: node.kubernetes.io/unreachable
+ operator: Exists
+ tolerationSeconds: 300
+ - effect: NoSchedule
+ key: org.com/role
+ operator: Equal
+ value: service
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-tolerations/resource.yaml b/test/conformance/kuttl/mutate/refactor/add-tolerations/resource.yaml
new file mode 100644
index 0000000000..ff625d5ef0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-tolerations/resource.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: addpod02
+ namespace: add-tolerations
+spec:
+ containers:
+ - name: container01
+ image: containerimage01
+ tolerations:
+ - key: org.com/test
+ operator: Exists
+ effect: NoSchedule
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/03-sleep.yaml b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/03-sleep.yaml
new file mode 100644
index 0000000000..b2822f5976
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/03-sleep.yaml
@@ -0,0 +1,4 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+commands:
+ - command: sleep 10
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/README.md b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/README.md
new file mode 100644
index 0000000000..1e9be3bf91
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This is a test of the policy in this folder.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resource. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/policy-ready.yaml
new file mode 100644
index 0000000000..d2a163ed95
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-volume
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/policy.yaml b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/policy.yaml
new file mode 100644
index 0000000000..3fa6a6903f
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/policy.yaml
@@ -0,0 +1,41 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: add-volume
+ annotations:
+ policies.kyverno.io/title: Add Volume to Deployment
+ policies.kyverno.io/category: Sample
+ policies.kyverno.io/subject: Deployment, Volume
+ policies.kyverno.io/minversion: 1.6.0
+ policies.kyverno.io/description: >-
+ Some Kubernetes applications like HashiCorp Vault must perform some modifications
+ to resources in order to invoke their specific functionality. Often times, that functionality
+ is controlled by the presence of a label or specific annotation. This policy, based on HashiCorp
+ Vault, adds a volume and volumeMount to a Deployment if there is an annotation called
+ "vault.k8s.corp.net/inject=enabled" present.
+spec:
+ rules:
+ - name: add-volume
+ match:
+ any:
+ - resources:
+ kinds:
+ - Deployment
+ preconditions:
+ any:
+ - key: "{{request.object.spec.template.metadata.annotations.\"vault.k8s.corp.net/inject\"}}"
+ operator: Equals
+ value: enabled
+ mutate:
+ patchesJson6902: |-
+ - op: add
+ path: /spec/template/spec/volumes/-
+ value:
+ name: vault-secret
+ emptyDir:
+ medium: Memory
+ - op: add
+ path: /spec/template/spec/containers/0/volumeMounts/-
+ value:
+ mountPath: /secret
+ name: vault-secret
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/resource-mutated.yaml
new file mode 100644
index 0000000000..0884c306f2
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/resource-mutated.yaml
@@ -0,0 +1,37 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: myapp
+ name: mydeploy
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: myapp
+ template:
+ metadata:
+ annotations:
+ vault.k8s.corp.net/inject: enabled
+ labels:
+ app: myapp
+ spec:
+ containers:
+ - image: somedummyimagehere:latest
+ name: container01
+ volumeMounts:
+ - mountPath: /secret
+ name: vault-secret
+ - image: anotherdummyimagehere:1.2.3
+ name: container02
+ volumeMounts:
+ - mountPath: /extra
+ name: foobar
+ volumes:
+ - hostPath:
+ path: /foo/bar
+ type: ""
+ name: foobar
+ - emptyDir:
+ medium: Memory
+ name: vault-secret
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/add-volume-deployment/resource.yaml b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/resource.yaml
new file mode 100644
index 0000000000..3cd01a542e
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/add-volume-deployment/resource.yaml
@@ -0,0 +1,30 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: myapp
+ name: mydeploy
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: myapp
+ template:
+ metadata:
+ labels:
+ app: myapp
+ annotations:
+ vault.k8s.corp.net/inject: enabled
+ spec:
+ containers:
+ - image: somedummyimagehere:latest
+ name: container01
+ - image: anotherdummyimagehere:1.2.3
+ name: container02
+ volumeMounts:
+ - mountPath: /extra
+ name: foobar
+ volumes:
+ - hostPath:
+ path: /foo/bar
+ name: foobar
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/annotate-base-images/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/annotate-base-images/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/annotate-base-images/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/annotate-base-images/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/annotate-base-images/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/annotate-base-images/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/annotate-base-images/README.md b/test/conformance/kuttl/mutate/refactor/annotate-base-images/README.md
new file mode 100644
index 0000000000..4760c95418
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/annotate-base-images/README.md
@@ -0,0 +1,13 @@
+## Description
+
+This is a test of the policy in this folder.
+
+Note: In order for this test to work on Pods emitted from Pod controllers, the Kyverno ConfigMap excludeGroups value may need to be modified to remove the entry for system:serviceaccounts:kube-system or else mutation may not occur.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resource. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/annotate-base-images/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/annotate-base-images/policy-ready.yaml
new file mode 100644
index 0000000000..cbdcf062cd
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/annotate-base-images/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: annotate-base-images
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/annotate-base-images/policy.yaml b/test/conformance/kuttl/mutate/refactor/annotate-base-images/policy.yaml
new file mode 100644
index 0000000000..f1034b75a5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/annotate-base-images/policy.yaml
@@ -0,0 +1,53 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: annotate-base-images
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: annotate-base-images
+ annotations:
+ policies.kyverno.io/title: Annotate Base Images
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/severity: medium
+ pod-policies.kyverno.io/autogen-controllers: none
+ kyverno.io/kyverno-version: 1.7.0
+ policies.kyverno.io/minversion: 1.7.0
+ kyverno.io/kubernetes-version: "1.23"
+ policies.kyverno.io/subject: Pod
+ policies.kyverno.io/description: >-
+ A base image used to construct a container image is not accessible
+ by any Kubernetes component and not a field in a Pod spec as it must
+ be fetched from a registry. Having this information available in the resource
+ referencing the containers helps to provide a clearer understanding of
+ its contents. This policy adds an annotation to a Pod or its controllers
+ with the base image used for each container if present in an OCI annotation.
+spec:
+ rules:
+ - name: mutate-base-image
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ preconditions:
+ all:
+ - key: "{{request.operation || 'BACKGROUND'}}"
+ operator: NotEquals
+ value: DELETE
+ mutate:
+ foreach:
+ - list: "request.object.spec.containers"
+ context:
+ - name: imageData
+ imageRegistry:
+ reference: "{{ element.image }}"
+ - name: basename
+ variable:
+ jmesPath: imageData.manifest.annotations."org.opencontainers.image.base.name"
+ default: ''
+ patchesJson6902: |-
+ - path: "/metadata/annotations/kyverno.io~1baseimages{{elementIndex}}"
+ op: add
+ value: "{{basename}}"
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/annotate-base-images/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/annotate-base-images/resource-mutated.yaml
new file mode 100644
index 0000000000..3342035fd5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/annotate-base-images/resource-mutated.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ annotations:
+ kyverno.io/baseimages0: distroless.dev/static:latest
+ kyverno.io/baseimages1: cgr.dev/chainguard/static:latest
+ name: testpodannotate
+ namespace: annotate-base-images
+spec:
+ containers:
+ - image: ghcr.io/kyverno/kyverno:v1.8.0
+ name: kyverno180
+ - image: ghcr.io/kyverno/kyverno:v1.9.0
+ name: kyverno190
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/annotate-base-images/resource.yaml b/test/conformance/kuttl/mutate/refactor/annotate-base-images/resource.yaml
new file mode 100644
index 0000000000..c9b9b12b38
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/annotate-base-images/resource.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: testpodannotate
+ namespace: annotate-base-images
+spec:
+ containers:
+ - name: kyverno180
+ image: ghcr.io/kyverno/kyverno:v1.8.0
+ - name: kyverno190
+ image: ghcr.io/kyverno/kyverno:v1.9.0
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/01-policy.yaml
new file mode 100644
index 0000000000..404ce85387
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - policy.yaml
+assert:
+ - policy-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/02-pod.yaml
new file mode 100644
index 0000000000..1c30edc8b6
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/02-pod.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - pod.yaml
+assert:
+ - pod-assert.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/README.md b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/README.md
new file mode 100644
index 0000000000..d4ce0de70e
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This test adds an element to an array and removes it.
+
+## Expected Behavior
+
+After mutation, the array is expected to be the same as the original array.
+
+## Reference Issue(s)
+
+5661
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/pod-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/pod-assert.yaml
new file mode 100644
index 0000000000..13e4c5e395
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/pod-assert.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env:
+ - name: ENV_ONE
+ value: "one"
+ - name: ENV_TWO
+ value: "two"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/pod.yaml
new file mode 100644
index 0000000000..13e4c5e395
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/pod.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env:
+ - name: ENV_ONE
+ value: "one"
+ - name: ENV_TWO
+ value: "two"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/policy-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/policy-assert.yaml
new file mode 100644
index 0000000000..368e9a1688
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/policy-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/policy.yaml
new file mode 100644
index 0000000000..b19e5cbe41
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/add-and-remove/policy.yaml
@@ -0,0 +1,44 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+spec:
+ background: false
+ schemaValidation: false
+ rules:
+ - name: dummy-1
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers[0].env
+ order: Ascending
+ patchesJson6902: |-
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: add
+ value:
+ name: DUMMY
+ value: "dummy"
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: remove
+ - name: dummy-2
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers[0].env
+ order: Descending
+ patchesJson6902: |-
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: add
+ value:
+ name: DUMMY
+ value: "dummy"
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: remove
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/01-policy.yaml
new file mode 100644
index 0000000000..404ce85387
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - policy.yaml
+assert:
+ - policy-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/02-pod.yaml
new file mode 100644
index 0000000000..1c30edc8b6
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/02-pod.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - pod.yaml
+assert:
+ - pod-assert.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/README.md b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/README.md
new file mode 100644
index 0000000000..660299b665
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This test removes an element from an array and adds one, effectively replacing it.
+
+## Expected Behavior
+
+After mutation, the array is expected to contained only replaced elements.
+
+## Reference Issue(s)
+
+5661
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/pod-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/pod-assert.yaml
new file mode 100644
index 0000000000..e512796fdd
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/pod-assert.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env:
+ - name: DUMMY_2
+ value: "dummy-2"
+ - name: DUMMY_2
+ value: "dummy-2"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/pod.yaml
new file mode 100644
index 0000000000..13e4c5e395
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/pod.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env:
+ - name: ENV_ONE
+ value: "one"
+ - name: ENV_TWO
+ value: "two"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/policy-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/policy-assert.yaml
new file mode 100644
index 0000000000..368e9a1688
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/policy-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/policy.yaml
new file mode 100644
index 0000000000..04fe979c0d
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-and-add/policy.yaml
@@ -0,0 +1,44 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+spec:
+ background: false
+ schemaValidation: false
+ rules:
+ - name: dummy-1
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers[0].env
+ order: Ascending
+ patchesJson6902: |-
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: remove
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: add
+ value:
+ name: DUMMY
+ value: "dummy"
+ - name: dummy-2
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers[0].env
+ order: Descending
+ patchesJson6902: |-
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: remove
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: add
+ value:
+ name: DUMMY_2
+ value: "dummy-2"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/01-policy.yaml
new file mode 100644
index 0000000000..404ce85387
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - policy.yaml
+assert:
+ - policy-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/02-pod.yaml
new file mode 100644
index 0000000000..1c30edc8b6
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/02-pod.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - pod.yaml
+assert:
+ - pod-assert.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/README.md b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/README.md
new file mode 100644
index 0000000000..cf047935e8
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This test removes multiple elements from an array iterating in ascending order.
+
+## Expected Behavior
+
+Element at index 0 is removed but element at index 1 is not (because when we removed element at index 0, the element at index 1 moved to index 0 and there's nothing to remove at index 1 anymore).
+
+## Reference Issue(s)
+
+5661
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/pod-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/pod-assert.yaml
new file mode 100644
index 0000000000..fe00900f58
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/pod-assert.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env:
+ # first element was removed, second env var became index 0
+ # next patch is supposed to remove element at index 1 but it doesn't exist anymore
+ - name: ENV_TWO
+ value: "two"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/pod.yaml
new file mode 100644
index 0000000000..13e4c5e395
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/pod.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env:
+ - name: ENV_ONE
+ value: "one"
+ - name: ENV_TWO
+ value: "two"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/policy-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/policy-assert.yaml
new file mode 100644
index 0000000000..368e9a1688
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/policy-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/policy.yaml
new file mode 100644
index 0000000000..022c29828c
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-ascending-order/policy.yaml
@@ -0,0 +1,20 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+spec:
+ background: false
+ schemaValidation: false
+ rules:
+ - name: remove-elements
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers[0].env
+ patchesJson6902: |-
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: remove
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/01-policy.yaml
new file mode 100644
index 0000000000..404ce85387
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - policy.yaml
+assert:
+ - policy-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/02-pod.yaml
new file mode 100644
index 0000000000..d522d8a59d
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/02-pod.yaml
@@ -0,0 +1,8 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - pod.yaml
+assert:
+ - pod-assert.yaml
+error:
+ - pod-error.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/README.md b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/README.md
new file mode 100644
index 0000000000..197be5bbd8
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This test removes multiple elements from an array iterating in descending order.
+
+## Expected Behavior
+
+Element at index 1 is removed then element at index 0 is removed, the array becomes empty.
+
+## Reference Issue(s)
+
+5661
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod-assert.yaml
new file mode 100644
index 0000000000..655c6a39d8
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod-assert.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod-error.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod-error.yaml
new file mode 100644
index 0000000000..07c7eaf5cc
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod-error.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env: null
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod.yaml
new file mode 100644
index 0000000000..13e4c5e395
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/pod.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ env:
+ - name: ENV_ONE
+ value: "one"
+ - name: ENV_TWO
+ value: "two"
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/policy-assert.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/policy-assert.yaml
new file mode 100644
index 0000000000..368e9a1688
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/policy-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
diff --git a/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/policy.yaml b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/policy.yaml
new file mode 100644
index 0000000000..0f926b313c
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/foreach/remove-multiple-elements-in-descending-order/policy.yaml
@@ -0,0 +1,21 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+spec:
+ background: false
+ schemaValidation: false
+ rules:
+ - name: remove-elements
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers[0].env
+ order: Descending
+ patchesJson6902: |-
+ - path: /spec/containers/0/env/{{elementIndex}}
+ op: remove
diff --git a/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/README.md b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/README.md
new file mode 100644
index 0000000000..4760c95418
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/README.md
@@ -0,0 +1,13 @@
+## Description
+
+This is a test of the policy in this folder.
+
+Note: In order for this test to work on Pods emitted from Pod controllers, the Kyverno ConfigMap excludeGroups value may need to be modified to remove the entry for system:serviceaccounts:kube-system or else mutation may not occur.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resource. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/policy-ready.yaml
new file mode 100644
index 0000000000..875489a78b
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: inject-env-var-from-image-label
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/policy.yaml b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/policy.yaml
new file mode 100644
index 0000000000..109b28368a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/policy.yaml
@@ -0,0 +1,56 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: inject-env-var-from-image-label
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: inject-env-var-from-image-label
+ annotations:
+ policies.kyverno.io/title: Inject Env Var from Image Label
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/severity: medium
+ pod-policies.kyverno.io/autogen-controllers: none
+ kyverno.io/kyverno-version: 1.6.0
+ policies.kyverno.io/minversion: 1.7.0
+ kyverno.io/kubernetes-version: "1.23"
+ policies.kyverno.io/subject: Pod
+ policies.kyverno.io/description: >-
+ Container images which use metadata such as the LABEL directive in a Dockerfile
+ do not surface this information to apps running within. In some cases, running the image
+ as a container may need access to this information. This policy injects the value of a label
+ set in a Dockerfile named `maintainer` as an environment variable to the corresponding container
+ in the Pod.
+spec:
+ rules:
+ - name: add-env-maintainer
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ preconditions:
+ all:
+ - key: "{{request.operation || 'BACKGROUND'}}"
+ operator: NotEquals
+ value: DELETE
+ mutate:
+ foreach:
+ - list: "request.object.spec.containers"
+ context:
+ - name: maintainer
+ imageRegistry:
+ reference: "{{ element.image }}"
+ jmesPath: "configData.config.Labels.maintainer || ''"
+ preconditions:
+ all:
+ - key: "{{maintainer}}"
+ operator: NotEquals
+ value: ""
+ patchesJson6902: |-
+ - op: add
+ path: "/spec/containers/{{elementIndex}}/env/-"
+ value:
+ name: MAINTAINER
+ value: "{{maintainer}}"
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/resource-mutated.yaml
new file mode 100644
index 0000000000..20e4404966
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/resource-mutated.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: testpodlabel
+ namespace: inject-env-var-from-image-label
+spec:
+ containers:
+ - env:
+ - name: MAINTAINER
+ value: NGINX Docker Maintainers
+ image: docker.io/nginx@sha256:63b44e8ddb83d5dd8020327c1f40436e37a6fffd3ef2498a6204df23be6e7e94
+ name: nginx
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/resource.yaml b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/resource.yaml
new file mode 100644
index 0000000000..5fa437cba0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/inject-env-var-from-image-label/resource.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: testpodlabel
+ namespace: inject-env-var-from-image-label
+spec:
+ containers:
+ - name: nginx
+ image: docker.io/nginx@sha256:63b44e8ddb83d5dd8020327c1f40436e37a6fffd3ef2498a6204df23be6e7e94
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/01-crd.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/01-crd.yaml
new file mode 100644
index 0000000000..6db5372cb0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/01-crd.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- crd.yaml
+assert:
+- crd-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/02-policy.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/02-policy.yaml
new file mode 100644
index 0000000000..57ffd5631d
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/02-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/03-resource.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/03-resource.yaml
new file mode 100644
index 0000000000..de14ac5c9c
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/03-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/README.md b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/README.md
new file mode 100644
index 0000000000..1e9be3bf91
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This is a test of the policy in this folder.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resource. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/crd-assert.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/crd-assert.yaml
new file mode 100644
index 0000000000..7c5977cd96
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/crd-assert.yaml
@@ -0,0 +1,12 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ name: policies.config.kio.kasten.io
+status:
+ acceptedNames:
+ kind: Policy
+ listKind: PolicyList
+ plural: policies
+ singular: policy
+ storedVersions:
+ - v1alpha1
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/crd.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/crd.yaml
new file mode 100644
index 0000000000..8d66ccb902
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/crd.yaml
@@ -0,0 +1,70 @@
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.8.0
+ generation: 1
+ name: policies.config.kio.kasten.io
+spec:
+ conversion:
+ strategy: None
+ group: config.kio.kasten.io
+ names:
+ kind: Policy
+ listKind: PolicyList
+ plural: policies
+ singular: policy
+ scope: Namespaced
+ versions:
+ - additionalPrinterColumns:
+ - jsonPath: .status.validation
+ name: Status
+ type: string
+ - jsonPath: .metadata.creationTimestamp
+ name: Age
+ type: date
+ name: v1alpha1
+ schema:
+ openAPIV3Schema:
+ description: Policy is the Schema for the policies API
+ 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:
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ status:
+ description: PolicyStatus defines the observed state of Policy
+ properties:
+ error:
+ description: List of errors with the policy (for example, due to validation
+ failures)
+ items:
+ type: string
+ type: array
+ hash:
+ description: Hash of Spec
+ format: int32
+ type: integer
+ specModifiedTime:
+ description: Timestamp when spec last changed
+ format: date-time
+ type: string
+ validation:
+ description: Validation status
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: true
+ subresources: {}
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/policy-ready.yaml
new file mode 100644
index 0000000000..99fd5a77ed
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: k10-minimum-retention
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/policy.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/policy.yaml
new file mode 100644
index 0000000000..296f683049
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/policy.yaml
@@ -0,0 +1,78 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: k10-minimum-retention
+---
+apiVersion: kyverno.io/v1
+kind: ClusterPolicy
+metadata:
+ name: k10-minimum-retention
+ annotations:
+ policies.kyverno.io/title: Minimum Backup Retention
+ policies.kyverno.io/category: Kasten K10 by Veeam
+ kyverno.io/kyverno-version: 1.6.2
+ policies.kyverno.io/minversion: 1.6.2
+ kyverno.io/kubernetes-version: "1.21-1.22"
+ policies.kyverno.io/subject: Policy
+ policies.kyverno.io/description: >-
+ K10 Policy resources can be validated to adhere to common compliance retention standards.
+ Uncomment the regulation/compliance standards you want to enforce for according to GFS retention.
+ This policy deletes the retention value in the backup operation and replaces it with the specified retention.
+ Note: K10 Policy uses the GFS retention scheme and export operations default to use the retention of the backup operation.
+ To use different
+ This policy can also be used go reduce retentions lengths to enforce cost optimization.
+spec:
+ schemaValidation: false
+ rules:
+ - name: k10-minimum-retention
+ match:
+ any:
+ - resources:
+ kinds:
+ - config.kio.kasten.io/v1alpha1/Policy
+ mutate:
+ # Federal Information Security Management Act (FISMA): 3 Years
+ #patchesJson6902: |-
+ # - path: "/spec/retention"
+ # op: replace
+ # value: {"hourly":24,"daily":30,"weekly":4,"monthly":12,"yearly":3}
+
+ # Health Insurance Portability and Accountability Act (HIPAA): 6 Years
+ #patchesJson6902: |-
+ # - path: "/spec/retention"
+ # op: replace
+ # value: {"hourly":24,"daily":30,"weekly":4,"monthly":12,"yearly":6}
+
+ # National Energy Commission (NERC): 3 to 6 Years
+ #patchesJson6902: |-
+ # - path: "/spec/retention"
+ # op: replace
+ # value: {"hourly":24,"daily":30,"weekly":4,"monthly":12,"yearly":3}
+
+ # Basel II Capital Accord: 3 to 7 Years
+ #patchesJson6902: |-
+ # - path: "/spec/retention"
+ # op: replace
+ # value: {"hourly":24,"daily":30,"weekly":4,"monthly":12,"yearly":3}
+
+ # Sarbanes-Oxley Act of 2002 (SOX): 7 Years
+ #patchesJson6902: |-
+ # - path: "/spec/retention"
+ # op: replace
+ # value: {"hourly":24,"daily":30,"weekly":4,"monthly":12,"yearly":7}
+
+ # National Industrial Security Program Operating Manual (NISPOM): 6 to 12 Months
+ #patchesJson6902: |-
+ # - path: "/spec/retention"
+ # op: replace
+ # value: {"hourly":24,"daily":30,"weekly":4,"monthly":6}
+
+ # Cost Optimization (Maximum Retention: 3 Months)
+ patchesJson6902: |-
+ - path: "/spec/retention"
+ op: replace
+ value:
+ hourly: 24
+ daily: 30
+ weekly: 4
+ monthly: 3
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/resource-mutated.yaml
new file mode 100644
index 0000000000..1717549537
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/resource-mutated.yaml
@@ -0,0 +1,42 @@
+apiVersion: config.kio.kasten.io/v1alpha1
+kind: Policy
+metadata:
+ generation: 1
+ labels:
+ appPriority: Mission-Critical
+ name: hourly-policy
+ namespace: k10-minimum-retention
+spec:
+ actions:
+ - action: backup
+ - action: export
+ exportParameters:
+ exportData:
+ enabled: true
+ frequency: '@monthly'
+ profile:
+ name: my-profile
+ namespace: kasten-io
+ retention:
+ monthly: 12
+ yearly: 5
+ comment: My sample custom backup policy
+ frequency: '@hourly'
+ retention:
+ daily: 30
+ hourly: 24
+ monthly: 3
+ weekly: 4
+ selector:
+ matchLabels:
+ k10.kasten.io/appNamespace: sampleApp
+ subFrequency:
+ days:
+ - 15
+ hours:
+ - 22
+ - 7
+ minutes:
+ - 30
+ weekdays:
+ - 5
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/resource.yaml b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/resource.yaml
new file mode 100644
index 0000000000..9f139aaba1
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/k10-minimum-retention/resource.yaml
@@ -0,0 +1,35 @@
+apiVersion: config.kio.kasten.io/v1alpha1
+kind: Policy
+metadata:
+ name: hourly-policy
+ namespace: k10-minimum-retention
+ labels:
+ appPriority: Mission-Critical
+spec:
+ comment: My sample custom backup policy
+ frequency: '@hourly' # change this to @daily to test the 'audit_mission_critical_RPO' policy
+ subFrequency:
+ minutes: [30]
+ hours: [22,7]
+ weekdays: [5]
+ days: [15]
+ retention:
+ daily: 14
+ weekly: 4
+ monthly: 6
+ actions:
+ - action: backup
+ - action: export # comment this line out to test 'enforce_3-2-1' policy
+ exportParameters:
+ frequency: '@monthly'
+ profile:
+ name: my-profile
+ namespace: kasten-io
+ exportData:
+ enabled: true
+ retention:
+ monthly: 12
+ yearly: 5
+ selector:
+ matchLabels:
+ k10.kasten.io/appNamespace: sampleApp
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/01-policy.yaml
new file mode 100644
index 0000000000..404ce85387
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - policy.yaml
+assert:
+ - policy-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/02-pod.yaml
new file mode 100644
index 0000000000..d522d8a59d
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/02-pod.yaml
@@ -0,0 +1,8 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - pod.yaml
+assert:
+ - pod-assert.yaml
+error:
+ - pod-error.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/README.md b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/README.md
new file mode 100644
index 0000000000..ecdbc082d3
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This test uses a nested foreach to remove all env variables from all containers.
+
+## Expected Behavior
+
+The created pod contains the same containers as the original pod but all env variables in all containers have been removed.
+
+## Reference Issue(s)
+
+5661
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod-assert.yaml b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod-assert.yaml
new file mode 100644
index 0000000000..de5a1bd6fb
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod-assert.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox-1
+ image: busybox:1.35
+ - name: busybox-2
+ image: busybox:1.35
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod-error.yaml b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod-error.yaml
new file mode 100644
index 0000000000..24bc3167b7
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod-error.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox-1
+ image: busybox:1.35
+ env: null
+ - name: busybox-2
+ image: busybox:1.35
+ env: null
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod.yaml b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod.yaml
new file mode 100644
index 0000000000..c3575184d9
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/pod.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox-1
+ image: busybox:1.35
+ env:
+ - name: ONE
+ value: "one"
+ - name: TWO
+ value: "two"
+ - name: busybox-2
+ image: busybox:1.35
+ env:
+ - name: THREE
+ value: "three"
+ - name: FOUR
+ value: "four"
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/policy-assert.yaml b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/policy-assert.yaml
new file mode 100644
index 0000000000..368e9a1688
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/policy-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
diff --git a/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/policy.yaml b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/policy.yaml
new file mode 100644
index 0000000000..bfad47fdaa
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/nested-foreach/remove-all-env-vars/policy.yaml
@@ -0,0 +1,23 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+spec:
+ background: false
+ schemaValidation: false
+ rules:
+ - name: dummy-1
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ foreach:
+ - list: request.object.spec.containers
+ foreach:
+ - list: element0.env
+ order: Descending
+ patchesJson6902: |-
+ - path: /spec/containers/{{elementIndex0}}/env/{{elementIndex1}}
+ op: remove
diff --git a/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/01-policy.yaml
new file mode 100644
index 0000000000..f3857739b0
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- policy.yaml
+assert:
+- policy-ready.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/02-resource.yaml b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/02-resource.yaml
new file mode 100644
index 0000000000..7e08de156a
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/02-resource.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+- resource.yaml
+assert:
+- resource-mutated.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/README.md b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/README.md
new file mode 100644
index 0000000000..1e9be3bf91
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/README.md
@@ -0,0 +1,11 @@
+## Description
+
+This is a test of the policy in this folder.
+
+## Expected Behavior
+
+The resource is expected to be mutated so it resembles the specified asserted resource. If it does, the test passes. If it does not, it fails.
+
+## Reference Issue(s)
+
+N/A
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/policy-ready.yaml b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/policy-ready.yaml
new file mode 100644
index 0000000000..cffd63c835
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/policy-ready.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v2beta1
+kind: ClusterPolicy
+metadata:
+ name: replace-ingress-hosts
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/policy.yaml b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/policy.yaml
new file mode 100644
index 0000000000..929ecfb0c5
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/policy.yaml
@@ -0,0 +1,51 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: replace-ingress-hosts
+---
+apiVersion: kyverno.io/v2beta1
+kind: ClusterPolicy
+metadata:
+ name: replace-ingress-hosts
+ annotations:
+ policies.kyverno.io/title: Replace Ingress Hosts
+ policies.kyverno.io/category: Other
+ policies.kyverno.io/severity: medium
+ kyverno.io/kyverno-version: 1.9.0
+ policies.kyverno.io/minversion: 1.9.0
+ kyverno.io/kubernetes-version: "1.24"
+ policies.kyverno.io/subject: Ingress
+ policies.kyverno.io/description: >-
+ An Ingress may specify host names at a variety of locations in the same resource.
+ In some cases, those host names should be modified to, for example, update domain names
+ silently. The replacement must be done in all the fields where a host name can be specified.
+ This policy, illustrating the use of nested foreach loops and operable in Kyverno 1.9+, replaces
+ host names that end with `old.com` with `new.com`.
+spec:
+ background: false
+ rules:
+ - name: replace-old-with-new
+ match:
+ any:
+ - resources:
+ kinds:
+ - Ingress
+ mutate:
+ foreach:
+ - list: request.object.spec.rules
+ patchesJson6902: |-
+ - path: /spec/rules/{{elementIndex}}/host
+ op: replace
+ value: {{replace_all('{{element.host}}', '.old.com', '.new.com')}}
+ - list: request.object.spec.tls[]
+ foreach:
+ - list: "element.hosts"
+ patchesJson6902: |-
+ - path: /spec/tls/{{elementIndex0}}/hosts/{{elementIndex1}}
+ op: replace
+ value: "{{ replace_all('{{element}}', '.old.com', '.new.com') }}"
+ - list: request.object.spec.tls[]
+ patchesJson6902: |-
+ - path: /spec/tls/{{elementIndex}}/secretName
+ op: replace
+ value: "{{ replace_all('{{element.secretName}}', '.old.com', '.new.com') }}"
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/resource-mutated.yaml b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/resource-mutated.yaml
new file mode 100644
index 0000000000..7127f77a0b
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/resource-mutated.yaml
@@ -0,0 +1,37 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ labels:
+ app: kuard
+ name: kuard
+ namespace: replace-ingress-hosts
+spec:
+ rules:
+ - host: kuard.new.com
+ http:
+ paths:
+ - backend:
+ service:
+ name: kuard
+ port:
+ number: 8080
+ path: /
+ pathType: ImplementationSpecific
+ - host: hr.new.com
+ http:
+ paths:
+ - backend:
+ service:
+ name: kuard
+ port:
+ number: 8090
+ path: /myhr
+ pathType: ImplementationSpecific
+ tls:
+ - hosts:
+ - kuard.new.com
+ - kuard-foo.new.com
+ secretName: foosecret.new.com
+ - hosts:
+ - hr.new.com
+ secretName: hr.new.com
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/resource.yaml b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/resource.yaml
new file mode 100644
index 0000000000..59f2ecb383
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/replace-ingress-hosts/resource.yaml
@@ -0,0 +1,37 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: kuard
+ namespace: replace-ingress-hosts
+ labels:
+ app: kuard
+spec:
+ rules:
+ - host: kuard.old.com
+ http:
+ paths:
+ - backend:
+ service:
+ name: kuard
+ port:
+ number: 8080
+ path: /
+ pathType: ImplementationSpecific
+ - host: hr.old.com
+ http:
+ paths:
+ - backend:
+ service:
+ name: kuard
+ port:
+ number: 8090
+ path: /myhr
+ pathType: ImplementationSpecific
+ tls:
+ - hosts:
+ - kuard.old.com
+ - kuard-foo.old.com
+ secretName: foosecret.old.com
+ - hosts:
+ - hr.old.com
+ secretName: hr.old.com
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/01-policy.yaml
new file mode 100644
index 0000000000..404ce85387
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - policy.yaml
+assert:
+ - policy-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/02-pod.yaml
new file mode 100644
index 0000000000..1c30edc8b6
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/02-pod.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - pod.yaml
+assert:
+ - pod-assert.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/README.md b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/README.md
new file mode 100644
index 0000000000..633844c464
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/README.md
@@ -0,0 +1,13 @@
+## Description
+
+This test removes multiple elements from an array iterating in ascending order.
+
+## Expected Behavior
+
+Removing in ascending order is usually not giving the expected result as removing one element will modify the index on the following elements.
+Hence the path to remove following elements are going to point to the wrong index, removing should be done in descending order.
+In this case, the we expect volumes at index 0 and 1 to be removed but as we remove volume at index 0 first, removing the volume at index 1 actually removes the volume at index 2 in the original array.
+
+## Reference Issue(s)
+
+5661
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/pod-assert.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/pod-assert.yaml
new file mode 100644
index 0000000000..67a5cc838b
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/pod-assert.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ volumes:
+ - name: volume-2
+ hostPath:
+ path: "/var/run/foo-2"
+ - projected: {}
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/pod.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/pod.yaml
new file mode 100644
index 0000000000..64fa05c327
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/pod.yaml
@@ -0,0 +1,18 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ volumes:
+ - name: volume-1
+ hostPath:
+ path: "/var/run/foo-1"
+ - name: volume-2
+ hostPath:
+ path: "/var/run/foo-2"
+ - name: volume-3
+ hostPath:
+ path: "/var/run/foo-3"
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/policy-assert.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/policy-assert.yaml
new file mode 100644
index 0000000000..368e9a1688
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/policy-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/policy.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/policy.yaml
new file mode 100644
index 0000000000..b10c8aa91f
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-ascending-order/policy.yaml
@@ -0,0 +1,20 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+spec:
+ background: false
+ schemaValidation: false
+ rules:
+ - name: remove-elements
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ patchesJson6902: |-
+ - path: /spec/volumes/0
+ op: remove
+ - path: /spec/volumes/1
+ op: remove
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/01-policy.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/01-policy.yaml
new file mode 100644
index 0000000000..404ce85387
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/01-policy.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - policy.yaml
+assert:
+ - policy-assert.yaml
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/02-pod.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/02-pod.yaml
new file mode 100644
index 0000000000..1c30edc8b6
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/02-pod.yaml
@@ -0,0 +1,6 @@
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+apply:
+ - pod.yaml
+assert:
+ - pod-assert.yaml
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/README.md b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/README.md
new file mode 100644
index 0000000000..849197fc3e
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/README.md
@@ -0,0 +1,12 @@
+## Description
+
+This test removes multiple elements from an array iterating in descending order.
+
+## Expected Behavior
+
+The two first volumes in the pod are removed.
+Removing in descending order is usually prefered as it preserves the index of array elements while iterating.
+
+## Reference Issue(s)
+
+5661
\ No newline at end of file
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/pod-assert.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/pod-assert.yaml
new file mode 100644
index 0000000000..47818ade76
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/pod-assert.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ volumes:
+ - name: volume-3
+ hostPath:
+ path: /var/run/foo-3
+ - projected: {}
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/pod.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/pod.yaml
new file mode 100644
index 0000000000..a89a2e0c36
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/pod.yaml
@@ -0,0 +1,18 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: busybox
+spec:
+ containers:
+ - name: busybox
+ image: busybox:1.35
+ volumes:
+ - name: volume-1
+ hostPath:
+ path: /var/run/foo-1
+ - name: volume-2
+ hostPath:
+ path: /var/run/foo-2
+ - name: volume-3
+ hostPath:
+ path: /var/run/foo-3
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/policy-assert.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/policy-assert.yaml
new file mode 100644
index 0000000000..368e9a1688
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/policy-assert.yaml
@@ -0,0 +1,9 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+status:
+ conditions:
+ - reason: Succeeded
+ status: "True"
+ type: Ready
diff --git a/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/policy.yaml b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/policy.yaml
new file mode 100644
index 0000000000..710234098e
--- /dev/null
+++ b/test/conformance/kuttl/mutate/refactor/simple/remove-multiple-elements-in-descending-order/policy.yaml
@@ -0,0 +1,20 @@
+apiVersion: kyverno.io/v1
+kind: Policy
+metadata:
+ name: foreach-remove-elements
+spec:
+ background: false
+ schemaValidation: false
+ rules:
+ - name: remove-elements
+ match:
+ any:
+ - resources:
+ kinds:
+ - Pod
+ mutate:
+ patchesJson6902: |-
+ - path: /spec/volumes/1
+ op: remove
+ - path: /spec/volumes/0
+ op: remove