Repository: kubernetes-sigs/security-profiles-operator
Pull request #1288 (2022-11-10 08:56:23)

Remove crossplane-runtime dependency
#### What type of PR is this?


/kind cleanup


#### What this PR does / why we need it:
This allows us to maintain our own status types and be faster on upgrades.
#### Which issue(s) this PR fixes:

<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.

Fixes #

or

None
-->
None
#### Does this PR have test?
None
<!--
If tests aren't applicable just write N/A.
-->

#### Special notes for your reviewer:
~~This seems to be a breaking API change.~~
#### Does this PR introduce a user-facing change?

<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->

```release-note
None
```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/1288#" title="Author self-approved">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
codecov-commenter: # [Codecov](https://codecov.io/gh/kubernetes-sigs/security-profiles-operator/pull/1288?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#1288](https://codecov.io/gh/kubernetes-sigs/security-profiles-operator/pull/1288?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (f9371df) into [main](https://codecov.io/gh/kubernetes-sigs/security-profiles-operator/commit/e3af68082e340e9d1a866c24423964410f8975ed?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (e3af680) will **decrease** coverage by `0.87%`.
> The diff coverage is `0.00%`.

> :exclamation: Current head f9371df differs from pull request most recent head 6133cd7. Consider uploading reports for the commit 6133cd7 to get more accurate results

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1288      +/-   ##
==========================================
- Coverage   44.76%   43.88%   -0.88%     
==========================================
  Files          48       49       +1     
  Lines        5402     5510     +108     
==========================================
  Hits         2418     2418              
- Misses       2864     2972     +108     
  Partials      120      120              
```

</details>
saschagrunert: @jhrozek @JAORMX @Vincent056 @ccojocar @pjbgf PTAL
k8s-ci-robot: @saschagrunert: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 6133cd7123b38f263edc96336c93afdcbc55cd3f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1288/pull-security-profiles-operator-test-e2e/1590630406598692864) | true | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=1288). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Asaschagrunert). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
saschagrunert: /test pull-security-profiles-operator-test-e2e
saschagrunert: Trying to keep the API for backwards compatibility. 

Patch:
diff --git a/.golangci.yml b/.golangci.yml
index f05688522..a5daca68c 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -48,7 +48,7 @@ linters:
     - goheader
     - goimports
     - gomnd
-    # - gomoddirectives
+    - gomoddirectives
     - gomodguard
     - goprintffuncname
     - gosec
diff --git a/Dockerfile.build-image b/Dockerfile.build-image
index 5c7ac3f04..507742957 100644
--- a/Dockerfile.build-image
+++ b/Dockerfile.build-image
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # hash below relates to tag: bullseye-v1.4.0
-FROM k8s.gcr.io/build-image/debian-base@sha256:e6e8c911b1566556ae105d3600df04c600241f43b06d22c73592ebb446d60c49
+FROM registry.k8s.io/build-image/debian-base@sha256:e6e8c911b1566556ae105d3600df04c600241f43b06d22c73592ebb446d60c49
 WORKDIR /work
 
 RUN apt-get update && apt-get install -y wget xz-utils libapparmor-dev
diff --git a/api/profilebase/v1alpha1/profilebase.go b/api/profilebase/v1alpha1/profilebase.go
index 8477a0fb3..e025b169b 100644
--- a/api/profilebase/v1alpha1/profilebase.go
+++ b/api/profilebase/v1alpha1/profilebase.go
@@ -20,7 +20,6 @@ import (
 	"context"
 	"fmt"
 
-	rcommonv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
 	"k8s.io/apimachinery/pkg/api/meta"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -28,6 +27,7 @@ import (
 
 	"sigs.k8s.io/security-profiles-operator/api/profilerecording/v1alpha1"
 	secprofnodestatusv1alpha1 "sigs.k8s.io/security-profiles-operator/api/secprofnodestatus/v1alpha1"
+	spodv1alpha1 "sigs.k8s.io/security-profiles-operator/api/spod/v1alpha1"
 )
 
 const ProfilePartialLabel = "spo.x-k8s.io/partial"
@@ -75,8 +75,8 @@ func ListProfilesByRecording(
 
 // StatusBase contains common attributes for a profile's status.
 type StatusBase struct {
-	rcommonv1.ConditionedStatus `json:",inline"`
-	Status                      secprofnodestatusv1alpha1.ProfileState `json:"status,omitempty"`
+	spodv1alpha1.ConditionedStatus `json:",inline"`
+	Status                         secprofnodestatusv1alpha1.ProfileState `json:"status,omitempty"`
 }
 
 type StatusBaseUser interface {
diff --git a/api/selinuxprofile/v1alpha2/selinuxprofile_types.go b/api/selinuxprofile/v1alpha2/selinuxprofile_types.go
index 2ca1be67a..a93f0a7e7 100644
--- a/api/selinuxprofile/v1alpha2/selinuxprofile_types.go
+++ b/api/selinuxprofile/v1alpha2/selinuxprofile_types.go
@@ -57,6 +57,11 @@ type SelinuxProfileSpec struct {
 	// +optional
 	// +kubebuilder:default={{kind:"System",name:"container"}}
 	Inherit []PolicyRef `json:"inherit,omitempty"`
+	// Permissive, when true will cause the SELinux profile to only
+	// log violations instead of enforcing them.
+	// +optional
+	// +kubebuilder:default=false
+	Permissive bool `json:"permissive,omitempty"`
 	// Defines the allow policy for the profile
 	Allow Allow `json:"allow,omitempty"`
 }
diff --git a/api/spod/v1alpha1/spod_types.go b/api/spod/v1alpha1/spod_types.go
index c818fbd18..9fdc5c40b 100644
--- a/api/spod/v1alpha1/spod_types.go
+++ b/api/spod/v1alpha1/spod_types.go
@@ -17,13 +17,215 @@ limitations under the License.
 package v1alpha1
 
 import (
+	"sort"
+
 	"github.com/containers/common/pkg/seccomp"
-	rcommonv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
 	admissionregv1 "k8s.io/api/admissionregistration/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// A ConditionType represents a condition a resource could be in.
+type ConditionType string
+
+// Condition types.
+const (
+	// TypeReady resources are believed to be ready to handle work.
+	TypeReady ConditionType = "Ready"
+)
+
+// A ConditionReason represents the reason a resource is in a condition.
+type ConditionReason string
+
+// Reasons a resource is or is not ready.
+const (
+	ReasonAvailable   ConditionReason = "Available"
+	ReasonUnavailable ConditionReason = "Unavailable"
+	ReasonCreating    ConditionReason = "Creating"
+	ReasonDeleting    ConditionReason = "Deleting"
+	ReasonPending     ConditionReason = "Pending"
+	ReasonUpdating    ConditionReason = "Updating"
+)
+
+// A Condition that may apply to a resource.
+type Condition struct {
+	// Type of this condition. At most one of each condition type may apply to
+	// a resource at any point in time.
+	Type ConditionType `json:"type"`
+
+	// Status of this condition; is it currently True, False, or Unknown?
+	Status corev1.ConditionStatus `json:"status"`
+
+	// LastTransitionTime is the last time this condition transitioned from one
+	// status to another.
+	LastTransitionTime metav1.Time `json:"lastTransitionTime"`
+
+	// A Reason for this condition's last transition from one status to another.
+	Reason ConditionReason `json:"reason"`
+
+	// A Message containing details about this condition's last transition from
+	// one status to another, if any.
+	// +optional
+	Message string `json:"message,omitempty"`
+}
+
+// Equal returns true if the condition is identical to the supplied condition,
+// ignoring the LastTransitionTime.
+//
+//nolint:gocritic // just a few bytes too heavy
+func (c Condition) Equal(other Condition) bool {
+	return c.Type == other.Type &&
+		c.Status == other.Status &&
+		c.Reason == other.Reason &&
+		c.Message == other.Message
+}
+
+// A ConditionedStatus reflects the observed status of a resource. Only one
+// condition of each type may exist.
+type ConditionedStatus struct {
+	// Conditions of the resource.
+	// +optional
+	Conditions []Condition `json:"conditions,omitempty"`
+}
+
+// GetCondition returns the condition for the given ConditionType if exists,
+// otherwise returns an unknown condition.
+func (s *ConditionedStatus) GetReadyCondition() Condition {
+	for _, c := range s.Conditions {
+		if c.Type == TypeReady {
+			return c
+		}
+	}
+
+	return Condition{
+		Type:   TypeReady,
+		Status: corev1.ConditionUnknown,
+	}
+}
+
+// SetConditions sets the supplied conditions, replacing any existing conditions
+// of the same type. This is a no-op if all supplied conditions are identical,
+// ignoring the last transition time, to those already set.
+func (s *ConditionedStatus) SetConditions(c ...Condition) {
+	for _, new := range c {
+		exists := false
+		for i, existing := range s.Conditions {
+			if existing.Type != new.Type {
+				continue
+			}
+
+			if existing.Equal(new) {
+				exists = true
+				continue
+			}
+
+			s.Conditions[i] = new
+			exists = true
+		}
+		if !exists {
+			s.Conditions = append(s.Conditions, new)
+		}
+	}
+}
+
+// Equal returns true if the status is identical to the supplied status,
+// ignoring the LastTransitionTimes and order of statuses.
+func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool {
+	if s == nil || other == nil {
+		return s == nil && other == nil
+	}
+
+	if len(other.Conditions) != len(s.Conditions) {
+		return false
+	}
+
+	sc := make([]Condition, len(s.Conditions))
+	copy(sc, s.Conditions)
+
+	oc := make([]Condition, len(other.Conditions))
+	copy(oc, other.Conditions)
+
+	// We should not have more than one condition of each type.
+	sort.Slice(sc, func(i, j int) bool { return sc[i].Type < sc[j].Type })
+	sort.Slice(oc, func(i, j int) bool { return oc[i].Type < oc[j].Type })
+
+	for i := range sc {
+		if !sc[i].Equal(oc[i]) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Creating returns a condition that indicates the resource is currently
+// being created.
+func Creating() Condition {
+	return Condition{
+		Type:               TypeReady,
+		Status:             corev1.ConditionFalse,
+		LastTransitionTime: metav1.Now(),
+		Reason:             ReasonCreating,
+	}
+}
+
+// Deleting returns a condition that indicates the resource is currently
+// being deleted.
+func Deleting() Condition {
+	return Condition{
+		Type:               TypeReady,
+		Status:             corev1.ConditionFalse,
+		LastTransitionTime: metav1.Now(),
+		Reason:             ReasonDeleting,
+	}
+}
+
+// Available returns a condition that indicates the resource is
+// currently observed to be available for use.
+func Available() Condition {
+	return Condition{
+		Type:               TypeReady,
+		Status:             corev1.ConditionTrue,
+		LastTransitionTime: metav1.Now(),
+		Reason:             ReasonAvailable,
+	}
+}
+
+// Unavailable returns a condition that indicates the resource is not
+// currently available for use. Unavailable should be set only when Crossplane
+// expects the resource to be available but knows it is not, for example
+// because its API reports it is unhealthy.
+func Unavailable() Condition {
+	return Condition{
+		Type:               TypeReady,
+		Status:             corev1.ConditionFalse,
+		LastTransitionTime: metav1.Now(),
+		Reason:             ReasonUnavailable,
+	}
+}
+
+// Pending returns a condition that indicates the resource is currently
+// observed to be waiting for creating.
+func Pending() Condition {
+	return Condition{
+		Type:               TypeReady,
+		Status:             corev1.ConditionFalse,
+		LastTransitionTime: metav1.Now(),
+		Reason:             ReasonPending,
+	}
+}
+
+// Updating returns a condition that indicates the resource is currently
+// observed to be updating.
+func Updating() Condition {
+	return Condition{
+		Type:               TypeReady,
+		Status:             corev1.ConditionFalse,
+		LastTransitionTime: metav1.Now(),
+		Reason:             ReasonUpdating,
+	}
+}
+
 // SelinuxOptions defines options specific to the SELinux
 // functionality of the SecurityProfilesOperator.
 type SelinuxOptions struct {
@@ -126,7 +328,7 @@ const (
 
 // SPODStatus defines the observed state of SPOD.
 type SPODStatus struct {
-	rcommonv1.ConditionedStatus `json:",inline"`
+	ConditionedStatus `json:",inline"`
 	// Represents the state that the policy is in. Can be:
 	// PENDING, IN-PROGRESS, RUNNING or ERROR
 	State SPODState `json:"state,omitempty"`
@@ -157,32 +359,22 @@ type SecurityProfilesOperatorDaemonList struct {
 
 func (s *SPODStatus) StatePending() {
 	s.State = SPODStatePending
-	s.ConditionedStatus.SetConditions(rcommonv1.Condition{
-		Type:               rcommonv1.TypeReady,
-		Status:             corev1.ConditionFalse,
-		LastTransitionTime: metav1.Now(),
-		Reason:             "Pending",
-	})
+	s.ConditionedStatus.SetConditions(Pending())
 }
 
 func (s *SPODStatus) StateCreating() {
 	s.State = SPODStateCreating
-	s.ConditionedStatus.SetConditions(rcommonv1.Creating())
+	s.ConditionedStatus.SetConditions(Creating())
 }
 
 func (s *SPODStatus) StateUpdating() {
 	s.State = SPODStateUpdating
-	s.ConditionedStatus.SetConditions(rcommonv1.Condition{
-		Type:               rcommonv1.TypeReady,
-		Status:             corev1.ConditionFalse,
-		LastTransitionTime: metav1.Now(),
-		Reason:             "Updating",
-	})
+	s.ConditionedStatus.SetConditions(Updating())
 }
 
 func (s *SPODStatus) StateRunning() {
 	s.State = SPODStateRunning
-	s.ConditionedStatus.SetConditions(rcommonv1.Available())
+	s.ConditionedStatus.SetConditions(Available())
 }
 
 func init() { //nolint:gochecknoinits // required to init the scheme
diff --git a/api/spod/v1alpha1/zz_generated.deepcopy.go b/api/spod/v1alpha1/zz_generated.deepcopy.go
index 8bb885a3e..d3a3f94fc 100644
--- a/api/spod/v1alpha1/zz_generated.deepcopy.go
+++ b/api/spod/v1alpha1/zz_generated.deepcopy.go
@@ -29,6 +29,44 @@ import (
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Condition) DeepCopyInto(out *Condition) {
+	*out = *in
+	in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
+func (in *Condition) DeepCopy() *Condition {
+	if in == nil {
+		return nil
+	}
+	out := new(Condition)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ConditionedStatus) DeepCopyInto(out *ConditionedStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]Condition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionedStatus.
+func (in *ConditionedStatus) DeepCopy() *ConditionedStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(ConditionedStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *SPODSpec) DeepCopyInto(out *SPODSpec) {
 	*out = *in
diff --git a/bundle/manifests/security-profiles-operator.x-k8s.io_selinuxprofiles.yaml b/bundle/manifests/security-profiles-operator.x-k8s.io_selinuxprofiles.yaml
index ed4be7730..28ba6c057 100644
--- a/bundle/manifests/security-profiles-operator.x-k8s.io_selinuxprofiles.yaml
+++ b/bundle/manifests/security-profiles-operator.x-k8s.io_selinuxprofiles.yaml
@@ -77,6 +77,11 @@ spec:
                   - name
                   type: object
                 type: array
+              permissive:
+                default: false
+                description: Permissive, when true will cause the SELinux profile
+                  to only log violations instead of enforcing them.
+                type: boolean
             type: object
           status:
             description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
diff --git a/dependencies.yaml b/dependencies.yaml
index 94b90e88f..5163738ae 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -101,7 +101,7 @@ dependencies:
     version: sha256:e6e8c911b1566556ae105d3600df04c600241f43b06d22c73592ebb446d60c49
     refPaths:
     - path: Dockerfile.build-image
-      match: k8s.gcr.io/build-image/debian-base
+      match: registry.k8s.io/build-image/debian-base
 
   - name: nix
     version: 2.9.2
diff --git a/deploy/base-crds/crds/selinuxpolicy.yaml b/deploy/base-crds/crds/selinuxpolicy.yaml
index 2a2efe56b..cab8efeeb 100644
--- a/deploy/base-crds/crds/selinuxpolicy.yaml
+++ b/deploy/base-crds/crds/selinuxpolicy.yaml
@@ -178,6 +178,11 @@ spec:
                   - name
                   type: object
                 type: array
+              permissive:
+                default: false
+                description: Permissive, when true will cause the SELinux profile
+                  to only log violations instead of enforcing them.
+                type: boolean
             type: object
           status:
             description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
diff --git a/deploy/helm/crds/crds.yaml b/deploy/helm/crds/crds.yaml
index 342539858..b1a7fd0ea 100644
--- a/deploy/helm/crds/crds.yaml
+++ b/deploy/helm/crds/crds.yaml
@@ -1854,6 +1854,11 @@ spec:
                   - name
                   type: object
                 type: array
+              permissive:
+                default: false
+                description: Permissive, when true will cause the SELinux profile
+                  to only log violations instead of enforcing them.
+                type: boolean
             type: object
           status:
             description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
diff --git a/deploy/kustomize-deployment/kustomization.yaml b/deploy/kustomize-deployment/kustomization.yaml
index 23cf10f7f..addd40545 100644
--- a/deploy/kustomize-deployment/kustomization.yaml
+++ b/deploy/kustomize-deployment/kustomization.yaml
@@ -7,7 +7,7 @@ images:
     newName: gcr.io/k8s-staging-sp-operator/security-profiles-operator
     newTag: latest
     # For images to be released:
-    # newName: k8s.gcr.io/security-profiles-operator/security-profiles-operator
+    # newName: registry.k8s.io/security-profiles-operator/security-profiles-operator
     # newTag: v0.5.1
 
 commonLabels:
diff --git a/deploy/namespace-operator.yaml b/deploy/namespace-operator.yaml
index ff31ccc43..74e5589d3 100644
--- a/deploy/namespace-operator.yaml
+++ b/deploy/namespace-operator.yaml
@@ -1854,6 +1854,11 @@ spec:
                   - name
                   type: object
                 type: array
+              permissive:
+                default: false
+                description: Permissive, when true will cause the SELinux profile
+                  to only log violations instead of enforcing them.
+                type: boolean
             type: object
           status:
             description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
diff --git a/deploy/openshift-dev.yaml b/deploy/openshift-dev.yaml
index 9c8ff07ef..a686ff515 100644
--- a/deploy/openshift-dev.yaml
+++ b/deploy/openshift-dev.yaml
@@ -1854,6 +1854,11 @@ spec:
                   - name
                   type: object
                 type: array
+              permissive:
+                default: false
+                description: Permissive, when true will cause the SELinux profile
+                  to only log violations instead of enforcing them.
+                type: boolean
             type: object
           status:
             description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
diff --git a/deploy/operator.yaml b/deploy/operator.yaml
index fd76d6817..2759b30fc 100644
--- a/deploy/operator.yaml
+++ b/deploy/operator.yaml
@@ -1854,6 +1854,11 @@ spec:
                   - name
                   type: object
                 type: array
+              permissive:
+                default: false
+                description: Permissive, when true will cause the SELinux profile
+                  to only log violations instead of enforcing them.
+                type: boolean
             type: object
           status:
             description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
diff --git a/deploy/webhook-operator.yaml b/deploy/webhook-operator.yaml
index adef0f16e..8d8904f3b 100644
--- a/deploy/webhook-operator.yaml
+++ b/deploy/webhook-operator.yaml
@@ -1925,6 +1925,11 @@ spec:
                   - name
                   type: object
                 type: array
+              permissive:
+                default: false
+                description: Permissive, when true will cause the SELinux profile
+                  to only log violations instead of enforcing them.
+                type: boolean
             type: object
           status:
             description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
diff --git a/go.mod b/go.mod
index 90864a6d5..9a3fc4a22 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,6 @@ require (
 	github.com/blang/semver/v4 v4.0.0
 	github.com/cert-manager/cert-manager v1.10.0
 	github.com/containers/common v0.48.1-0.20220510094751-400832f41771
-	github.com/crossplane/crossplane-runtime v0.18.0
 	github.com/go-logr/logr v1.2.3
 	github.com/jellydator/ttlcache/v3 v3.0.0
 	github.com/maxbrunsfeld/counterfeiter/v6 v6.5.0
@@ -28,7 +27,7 @@ require (
 	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0
 	google.golang.org/protobuf v1.28.1
 	k8s.io/api v0.25.3
-	k8s.io/apimachinery v0.25.3
+	k8s.io/apimachinery v0.25.4
 	k8s.io/client-go v0.25.3
 	k8s.io/klog/v2 v2.80.1
 	sigs.k8s.io/controller-runtime v0.13.0
@@ -39,8 +38,6 @@ require (
 	sigs.k8s.io/zeitgeist v0.3.5
 )
 
-replace sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.12.3
-
 require (
 	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
 	github.com/BurntSushi/toml v1.2.1 // indirect
@@ -66,6 +63,7 @@ require (
 	github.com/emicklei/go-restful/v3 v3.8.0 // indirect
 	github.com/emirpasic/gods v1.12.0 // indirect
 	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
+	github.com/evanphx/json-patch/v5 v5.6.0 // indirect
 	github.com/fatih/color v1.13.0 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
 	github.com/go-errors/errors v1.0.1 // indirect
diff --git a/go.sum b/go.sum
index b9290a97d..936b53708 100644
--- a/go.sum
+++ b/go.sum
@@ -382,8 +382,6 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
 github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/crossplane/crossplane-runtime v0.18.0 h1:j1VxhKWp3iQKr1XNiMoBKmEvN2Z98E7rR0tyimu7dj4=
-github.com/crossplane/crossplane-runtime v0.18.0/go.mod h1:o9ExoilV6k2M3qzSFoRVX4phuww0mLmjs1WrDTvsR4s=
 github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
 github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
 github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
@@ -467,6 +465,8 @@ github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL
 github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
 github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
+github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
 github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
@@ -2144,8 +2144,8 @@ k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MA
 k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
 k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U=
 k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
-k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc=
-k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
+k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc=
+k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
 k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
 k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
 k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
@@ -2208,8 +2208,8 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
-sigs.k8s.io/controller-runtime v0.12.3 h1:FCM8xeY/FI8hoAfh/V4XbbYMY20gElh9yh+A98usMio=
-sigs.k8s.io/controller-runtime v0.12.3/go.mod h1:qKsk4WE6zW2Hfj0G4v10EnNB2jMG1C+NTb8h+DwCoU0=
+sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ=
+sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI=
 sigs.k8s.io/controller-tools v0.10.0 h1:0L5DTDTFB67jm9DkfrONgTGmfc/zYow0ZaHyppizU2U=
 sigs.k8s.io/controller-tools v0.10.0/go.mod h1:uvr0EW6IsprfB0jpQq6evtKy+hHyHCXNfdWI5ONPx94=
 sigs.k8s.io/gateway-api v0.5.0 h1:ze+k9fJqvmL8s1t3e4q1ST8RnN+f09dEv+gfacahlAE=
diff --git a/installation-usage.md b/installation-usage.md
index 226859468..767667302 100644
--- a/installation-usage.md
+++ b/installation-usage.md
@@ -26,6 +26,7 @@
     - [Merging per-container profile instances](#merging-per-container-profile-instances)
 - [Create a SELinux Profile](#create-a-selinux-profile)
   - [Apply a SELinux profile to a pod](#apply-a-selinux-profile-to-a-pod)
+  - [Make a SELinux profile permissive](#make-a-selinux-profile-permissive)
   - [Record a SELinux profile](#record-a-selinux-profile)
 - [Restricting to a Single Namespace](#restricting-to-a-single-namespace)
   - [Restricting to a Single Namespace with upstream deployment manifests](#restricting-to-a-single-namespace-with-upstream-deployment-manifests)
@@ -850,6 +851,15 @@ spec:
 
 Note that the SELinux type must exist before creating the workload.
 
+### Make a SELinux profile permissive
+
+Similarly to how a `SeccompProfile` might have a default action `SCMP_ACT_LOG`
+which would merely log violations of the policy, but not actually block the
+container from executing, a `SelinuxProfile` can be marked as "permissive"
+by setting `.spec.permissive` to `true`. This mode might be useful e.g. when
+the policy is known or suspected to be incomplete and you'd prefer to just
+watch for subsequent AVC denials after deploying the policy.
+
 ### Record a SELinux profile
 
 Please refer to the seccomp recording documentation, recording a SELinux
diff --git a/internal/pkg/manager/nodestatus/nodestatus.go b/internal/pkg/manager/nodestatus/nodestatus.go
index 860259429..cfec10fc8 100644
--- a/internal/pkg/manager/nodestatus/nodestatus.go
+++ b/internal/pkg/manager/nodestatus/nodestatus.go
@@ -23,7 +23,6 @@ import (
 	"net/http"
 	"time"
 
-	rcommonv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
 	"github.com/go-logr/logr"
 	appsv1 "k8s.io/api/apps/v1"
 	v1 "k8s.io/api/core/v1"
@@ -40,6 +39,7 @@ import (
 	seccompprofileapi "sigs.k8s.io/security-profiles-operator/api/seccompprofile/v1beta1"
 	statusv1alpha1 "sigs.k8s.io/security-profiles-operator/api/secprofnodestatus/v1alpha1"
 	selxv1alpha2 "sigs.k8s.io/security-profiles-operator/api/selinuxprofile/v1alpha2"
+	spodv1alpha1 "sigs.k8s.io/security-profiles-operator/api/spod/v1alpha1"
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/controller"
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/util"
@@ -290,22 +290,22 @@ func (r *StatusReconciler) reconcileStatus(
 	switch state {
 	case statusv1alpha1.ProfileStatePending, "":
 		outStatus.Status = statusv1alpha1.ProfileStatePending
-		outStatus.SetConditions(rcommonv1.Creating())
+		outStatus.SetConditions(spodv1alpha1.Creating())
 	case statusv1alpha1.ProfileStateInProgress:
-		outStatus.SetConditions(rcommonv1.Creating())
+		outStatus.SetConditions(spodv1alpha1.Creating())
 		outStatus.Status = statusv1alpha1.ProfileStateInProgress
 	case statusv1alpha1.ProfileStateInstalled:
 		outStatus.Status = statusv1alpha1.ProfileStateInstalled
-		outStatus.SetConditions(rcommonv1.Available())
+		outStatus.SetConditions(spodv1alpha1.Available())
 	case statusv1alpha1.ProfileStateTerminating:
 		outStatus.Status = statusv1alpha1.ProfileStateTerminating
-		outStatus.SetConditions(rcommonv1.Deleting())
+		outStatus.SetConditions(spodv1alpha1.Deleting())
 	case statusv1alpha1.ProfileStateError:
 		outStatus.Status = statusv1alpha1.ProfileStateError
-		outStatus.SetConditions(rcommonv1.Unavailable())
+		outStatus.SetConditions(spodv1alpha1.Unavailable())
 	case statusv1alpha1.ProfileStatePartial:
 		outStatus.Status = statusv1alpha1.ProfileStatePartial
-		outStatus.SetConditions(rcommonv1.Unavailable())
+		outStatus.SetConditions(spodv1alpha1.Unavailable())
 	}
 
 	l.V(config.VerboseLevel).Info("Updating status")
diff --git a/internal/pkg/manager/spod/spod_controller.go b/internal/pkg/manager/spod/spod_controller.go
index c69fe8f47..e06e42eb1 100644
--- a/internal/pkg/manager/spod/spod_controller.go
+++ b/internal/pkg/manager/spod/spod_controller.go
@@ -210,7 +210,7 @@ func (r *ReconcileSPOd) Reconcile(_ context.Context, req reconcile.Request) (rec
 	}
 
 	if foundSPOd.Status.NumberReady == foundSPOd.Status.DesiredNumberScheduled {
-		condready := spod.Status.GetCondition("Ready")
+		condready := spod.Status.GetReadyCondition()
 		// Don't pollute the logs. Let's only update when needed.
 		if condready.Status != corev1.ConditionTrue {
 			return r.handleRunningStatus(ctx, spod, logger)
diff --git a/internal/pkg/translator/obj2cil.go b/internal/pkg/translator/obj2cil.go
index 374e1af4e..0dea33b54 100644
--- a/internal/pkg/translator/obj2cil.go
+++ b/internal/pkg/translator/obj2cil.go
@@ -26,6 +26,10 @@ import (
 	selxv1alpha2 "sigs.k8s.io/security-profiles-operator/api/selinuxprofile/v1alpha2"
 )
 
+const (
+	typePermissive = "(typepermissive process)"
+)
+
 func Object2CIL(
 	systemInherits []string,
 	objInherits []selxv1alpha2.SelinuxProfileObject,
@@ -39,6 +43,10 @@ func Object2CIL(
 	for _, inherit := range objInherits {
 		cilbuilder.WriteString(getCILInheritline(inherit.GetPolicyUsage()))
 	}
+	if sp.Spec.Permissive {
+		cilbuilder.WriteString(typePermissive)
+		cilbuilder.WriteString("\n")
+	}
 	for ttype, tclassMap := range sp.Spec.Allow {
 		for tclass, perms := range tclassMap {
 			cilbuilder.WriteString(getCILAllowLine(sp, ttype, tclass, perms))
diff --git a/release.md b/release.md
index c45542bed..c3e32ae93 100644
--- a/release.md
+++ b/release.md
@@ -15,13 +15,13 @@ The first PR targets this repository and:
 - changes the `images` `newName`/`newTag` fields of
   [./deploy/kustomize-deployment/kustomization.yaml](deploy/kustomize-deployment/kustomization.yaml)
   from `gcr.io/k8s-staging-sp-operator/security-profiles-operator` to
-  `k8s.gcr.io/security-profiles-operator/security-profiles-operator` (`newName`) and the
+  `registry.k8s.io/security-profiles-operator/security-profiles-operator` (`newName`) and the
   corresponding tag (`newTag`). After that the make target `make bundle`
   has to be run and the changes have to be committed.
 - changes the `image` in the `CatalogSource` in the same way at
   [./examples/olm/install-resources.yaml](/examples/olm/install-resources.yaml)
 - changes [`hack/ci/e2e-olm.sh`](/hack/ci/e2e-olm.sh) to sed
-  `"s#k8s.gcr.io/security-profiles-operator/security-profiles-operator-catalog:v0.0.0#${CATALOG_IMG}#g"`
+  `"s#registry.k8s.io/security-profiles-operator/security-profiles-operator-catalog:v0.0.0#${CATALOG_IMG}#g"`
   instead of
   `"s#gcr.io/k8s-staging-sp-operator/security-profiles-operator-catalog:latest#${CATALOG_IMG}#g"`
   (please note to change the version `v0.0.0` to the upcoming release)
diff --git a/vendor/github.com/crossplane/crossplane-runtime/LICENSE b/vendor/github.com/crossplane/crossplane-runtime/LICENSE
deleted file mode 100644
index ef10385cc..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "{}"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright 2016 The Crossplane Authors. All rights reserved.
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/condition.go b/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/condition.go
deleted file mode 100644
index b49a74e03..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/condition.go
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1
-
-import (
-	"sort"
-
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-// A ConditionType represents a condition a resource could be in.
-type ConditionType string
-
-// Condition types.
-const (
-	// TypeReady resources are believed to be ready to handle work.
-	TypeReady ConditionType = "Ready"
-
-	// TypeSynced resources are believed to be in sync with the
-	// Kubernetes resources that manage their lifecycle.
-	TypeSynced ConditionType = "Synced"
-)
-
-// A ConditionReason represents the reason a resource is in a condition.
-type ConditionReason string
-
-// Reasons a resource is or is not ready.
-const (
-	ReasonAvailable   ConditionReason = "Available"
-	ReasonUnavailable ConditionReason = "Unavailable"
-	ReasonCreating    ConditionReason = "Creating"
-	ReasonDeleting    ConditionReason = "Deleting"
-)
-
-// Reasons a resource is or is not synced.
-const (
-	ReasonReconcileSuccess ConditionReason = "ReconcileSuccess"
-	ReasonReconcileError   ConditionReason = "ReconcileError"
-)
-
-// A Condition that may apply to a resource.
-type Condition struct {
-	// Type of this condition. At most one of each condition type may apply to
-	// a resource at any point in time.
-	Type ConditionType `json:"type"`
-
-	// Status of this condition; is it currently True, False, or Unknown?
-	Status corev1.ConditionStatus `json:"status"`
-
-	// LastTransitionTime is the last time this condition transitioned from one
-	// status to another.
-	LastTransitionTime metav1.Time `json:"lastTransitionTime"`
-
-	// A Reason for this condition's last transition from one status to another.
-	Reason ConditionReason `json:"reason"`
-
-	// A Message containing details about this condition's last transition from
-	// one status to another, if any.
-	// +optional
-	Message string `json:"message,omitempty"`
-}
-
-// Equal returns true if the condition is identical to the supplied condition,
-// ignoring the LastTransitionTime.
-func (c Condition) Equal(other Condition) bool {
-	return c.Type == other.Type &&
-		c.Status == other.Status &&
-		c.Reason == other.Reason &&
-		c.Message == other.Message
-}
-
-// WithMessage returns a condition by adding the provided message to existing
-// condition.
-func (c Condition) WithMessage(msg string) Condition {
-	c.Message = msg
-	return c
-}
-
-// NOTE(negz): Conditions are implemented as a slice rather than a map to comply
-// with Kubernetes API conventions. Ideally we'd comply by using a map that
-// marshalled to a JSON array, but doing so confuses the CRD schema generator.
-// https://github.com/kubernetes/community/blob/9bf8cd/contributors/devel/sig-architecture/api-conventions.md#lists-of-named-subobjects-preferred-over-maps
-
-// NOTE(negz): Do not manipulate Conditions directly. Use the Set method.
-
-// A ConditionedStatus reflects the observed status of a resource. Only
-// one condition of each type may exist.
-type ConditionedStatus struct {
-	// Conditions of the resource.
-	// +optional
-	Conditions []Condition `json:"conditions,omitempty"`
-}
-
-// NewConditionedStatus returns a stat with the supplied conditions set.
-func NewConditionedStatus(c ...Condition) *ConditionedStatus {
-	s := &ConditionedStatus{}
-	s.SetConditions(c...)
-	return s
-}
-
-// GetCondition returns the condition for the given ConditionType if exists,
-// otherwise returns nil
-func (s *ConditionedStatus) GetCondition(ct ConditionType) Condition {
-	for _, c := range s.Conditions {
-		if c.Type == ct {
-			return c
-		}
-	}
-
-	return Condition{Type: ct, Status: corev1.ConditionUnknown}
-}
-
-// SetConditions sets the supplied conditions, replacing any existing conditions
-// of the same type. This is a no-op if all supplied conditions are identical,
-// ignoring the last transition time, to those already set.
-func (s *ConditionedStatus) SetConditions(c ...Condition) {
-	for _, new := range c {
-		exists := false
-		for i, existing := range s.Conditions {
-			if existing.Type != new.Type {
-				continue
-			}
-
-			if existing.Equal(new) {
-				exists = true
-				continue
-			}
-
-			s.Conditions[i] = new
-			exists = true
-		}
-		if !exists {
-			s.Conditions = append(s.Conditions, new)
-		}
-	}
-}
-
-// Equal returns true if the status is identical to the supplied status,
-// ignoring the LastTransitionTimes and order of statuses.
-func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool {
-	if s == nil || other == nil {
-		return s == nil && other == nil
-	}
-
-	if len(other.Conditions) != len(s.Conditions) {
-		return false
-	}
-
-	sc := make([]Condition, len(s.Conditions))
-	copy(sc, s.Conditions)
-
-	oc := make([]Condition, len(other.Conditions))
-	copy(oc, other.Conditions)
-
-	// We should not have more than one condition of each type.
-	sort.Slice(sc, func(i, j int) bool { return sc[i].Type < sc[j].Type })
-	sort.Slice(oc, func(i, j int) bool { return oc[i].Type < oc[j].Type })
-
-	for i := range sc {
-		if !sc[i].Equal(oc[i]) {
-			return false
-		}
-	}
-
-	return true
-}
-
-// Creating returns a condition that indicates the resource is currently
-// being created.
-func Creating() Condition {
-	return Condition{
-		Type:               TypeReady,
-		Status:             corev1.ConditionFalse,
-		LastTransitionTime: metav1.Now(),
-		Reason:             ReasonCreating,
-	}
-}
-
-// Deleting returns a condition that indicates the resource is currently
-// being deleted.
-func Deleting() Condition {
-	return Condition{
-		Type:               TypeReady,
-		Status:             corev1.ConditionFalse,
-		LastTransitionTime: metav1.Now(),
-		Reason:             ReasonDeleting,
-	}
-}
-
-// Available returns a condition that indicates the resource is
-// currently observed to be available for use.
-func Available() Condition {
-	return Condition{
-		Type:               TypeReady,
-		Status:             corev1.ConditionTrue,
-		LastTransitionTime: metav1.Now(),
-		Reason:             ReasonAvailable,
-	}
-}
-
-// Unavailable returns a condition that indicates the resource is not
-// currently available for use. Unavailable should be set only when Crossplane
-// expects the resource to be available but knows it is not, for example
-// because its API reports it is unhealthy.
-func Unavailable() Condition {
-	return Condition{
-		Type:               TypeReady,
-		Status:             corev1.ConditionFalse,
-		LastTransitionTime: metav1.Now(),
-		Reason:             ReasonUnavailable,
-	}
-}
-
-// ReconcileSuccess returns a condition indicating that Crossplane successfully
-// completed the most recent reconciliation of the resource.
-func ReconcileSuccess() Condition {
-	return Condition{
-		Type:               TypeSynced,
-		Status:             corev1.ConditionTrue,
-		LastTransitionTime: metav1.Now(),
-		Reason:             ReasonReconcileSuccess,
-	}
-}
-
-// ReconcileError returns a condition indicating that Crossplane encountered an
-// error while reconciling the resource. This could mean Crossplane was
-// unable to update the resource to reflect its desired state, or that
-// Crossplane was unable to determine the current actual state of the resource.
-func ReconcileError(err error) Condition {
-	return Condition{
-		Type:               TypeSynced,
-		Status:             corev1.ConditionFalse,
-		LastTransitionTime: metav1.Now(),
-		Reason:             ReasonReconcileError,
-		Message:            err.Error(),
-	}
-}
diff --git a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/connection_details.go b/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/connection_details.go
deleted file mode 100644
index 9b5e871fe..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/connection_details.go
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1
-
-import (
-	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/types"
-)
-
-const (
-	// LabelKeyOwnerUID is the UID of the owner resource of a connection secret.
-	// Kubernetes provides owner/controller references to track ownership of
-	// resources including secrets, however, this would only work for in cluster
-	// k8s secrets. We opted to use a label for this purpose to be consistent
-	// across Secret Store implementations and expect all to support
-	// setting/getting labels.
-	LabelKeyOwnerUID = "secret.crossplane.io/owner-uid"
-)
-
-// PublishConnectionDetailsTo represents configuration of a connection secret.
-type PublishConnectionDetailsTo struct {
-	// Name is the name of the connection secret.
-	Name string `json:"name"`
-
-	// Metadata is the metadata for connection secret.
-	// +optional
-	Metadata *ConnectionSecretMetadata `json:"metadata,omitempty"`
-
-	// SecretStoreConfigRef specifies which secret store config should be used
-	// for this ConnectionSecret.
-	// +optional
-	// +kubebuilder:default={"name": "default"}
-	SecretStoreConfigRef *Reference `json:"configRef,omitempty"`
-}
-
-// ConnectionSecretMetadata represents metadata of a connection secret.
-// Labels are used to track ownership of connection secrets and has to be
-// supported for any secret store implementation.
-type ConnectionSecretMetadata struct {
-	// Labels are the labels/tags to be added to connection secret.
-	// - For Kubernetes secrets, this will be used as "metadata.labels".
-	// - It is up to Secret Store implementation for others store types.
-	// +optional
-	Labels map[string]string `json:"labels,omitempty"`
-	// Annotations are the annotations to be added to connection secret.
-	// - For Kubernetes secrets, this will be used as "metadata.annotations".
-	// - It is up to Secret Store implementation for others store types.
-	// +optional
-	Annotations map[string]string `json:"annotations,omitempty"`
-	// Type is the SecretType for the connection secret.
-	// - Only valid for Kubernetes Secret Stores.
-	// +optional
-	Type *corev1.SecretType `json:"type,omitempty"`
-}
-
-// SetOwnerUID sets owner object uid label.
-func (in *ConnectionSecretMetadata) SetOwnerUID(uid types.UID) {
-	if in.Labels == nil {
-		in.Labels = map[string]string{}
-	}
-	in.Labels[LabelKeyOwnerUID] = string(uid)
-}
-
-// GetOwnerUID gets owner object uid.
-func (in *ConnectionSecretMetadata) GetOwnerUID() string {
-	if u, ok := in.Labels[LabelKeyOwnerUID]; ok {
-		return u
-	}
-	return ""
-}
-
-// SecretStoreType represents a secret store type.
-type SecretStoreType string
-
-const (
-	// SecretStoreKubernetes indicates that secret store type is
-	// Kubernetes. In other words, connection secrets will be stored as K8s
-	// Secrets.
-	SecretStoreKubernetes SecretStoreType = "Kubernetes"
-
-	// SecretStoreVault indicates that secret store type is Vault.
-	SecretStoreVault SecretStoreType = "Vault"
-)
-
-// SecretStoreConfig represents configuration of a Secret Store.
-type SecretStoreConfig struct {
-	// Type configures which secret store to be used. Only the configuration
-	// block for this store will be used and others will be ignored if provided.
-	// Default is Kubernetes.
-	// +optional
-	// +kubebuilder:default=Kubernetes
-	Type *SecretStoreType `json:"type,omitempty"`
-
-	// DefaultScope used for scoping secrets for "cluster-scoped" resources.
-	// If store type is "Kubernetes", this would mean the default namespace to
-	// store connection secrets for cluster scoped resources.
-	// In case of "Vault", this would be used as the default parent path.
-	// Typically, should be set as Crossplane installation namespace.
-	DefaultScope string `json:"defaultScope"`
-
-	// Kubernetes configures a Kubernetes secret store.
-	// If the "type" is "Kubernetes" but no config provided, in cluster config
-	// will be used.
-	// +optional
-	Kubernetes *KubernetesSecretStoreConfig `json:"kubernetes,omitempty"`
-
-	// Vault configures a Vault secret store.
-	// +optional
-	Vault *VaultSecretStoreConfig `json:"vault,omitempty"`
-}
-
-// KubernetesAuthConfig required to authenticate to a K8s API. It expects
-// a "kubeconfig" file to be provided.
-type KubernetesAuthConfig struct {
-	// Source of the credentials.
-	// +kubebuilder:validation:Enum=None;Secret;Environment;Filesystem
-	Source CredentialsSource `json:"source"`
-
-	// CommonCredentialSelectors provides common selectors for extracting
-	// credentials.
-	CommonCredentialSelectors `json:",inline"`
-}
-
-// KubernetesSecretStoreConfig represents the required configuration
-// for a Kubernetes secret store.
-type KubernetesSecretStoreConfig struct {
-	// Credentials used to connect to the Kubernetes API.
-	Auth KubernetesAuthConfig `json:"auth"`
-
-	// TODO(turkenh): Support additional identities like
-	// https://github.com/crossplane-contrib/provider-kubernetes/blob/4d722ef914e6964e80e190317daca9872ae98738/apis/v1alpha1/types.go#L34
-}
-
-// VaultAuthMethod represent a Vault authentication method.
-// https://www.vaultproject.io/docs/auth
-type VaultAuthMethod string
-
-const (
-	// VaultAuthToken indicates that "Token Auth" will be used to
-	// authenticate to Vault.
-	// https://www.vaultproject.io/docs/auth/token
-	VaultAuthToken VaultAuthMethod = "Token"
-)
-
-// VaultAuthTokenConfig represents configuration for Vault Token Auth Method.
-// https://www.vaultproject.io/docs/auth/token
-type VaultAuthTokenConfig struct {
-	// Source of the credentials.
-	// +kubebuilder:validation:Enum=None;Secret;Environment;Filesystem
-	Source CredentialsSource `json:"source"`
-
-	// CommonCredentialSelectors provides common selectors for extracting
-	// credentials.
-	CommonCredentialSelectors `json:",inline"`
-}
-
-// VaultAuthConfig required to authenticate to a Vault API.
-type VaultAuthConfig struct {
-	// Method configures which auth method will be used.
-	Method VaultAuthMethod `json:"method"`
-	// Token configures Token Auth for Vault.
-	// +optional
-	Token *VaultAuthTokenConfig `json:"token,omitempty"`
-}
-
-// VaultCABundleConfig represents configuration for configuring a CA bundle.
-type VaultCABundleConfig struct {
-	// Source of the credentials.
-	// +kubebuilder:validation:Enum=None;Secret;Environment;Filesystem
-	Source CredentialsSource `json:"source"`
-
-	// CommonCredentialSelectors provides common selectors for extracting
-	// credentials.
-	CommonCredentialSelectors `json:",inline"`
-}
-
-// VaultKVVersion represent API version of the Vault KV engine
-// https://www.vaultproject.io/docs/secrets/kv
-type VaultKVVersion string
-
-const (
-	// VaultKVVersionV1 indicates that Secret API is KV Secrets Engine Version 1
-	// https://www.vaultproject.io/docs/secrets/kv/kv-v1
-	VaultKVVersionV1 VaultKVVersion = "v1"
-
-	// VaultKVVersionV2 indicates that Secret API is KV Secrets Engine Version 2
-	// https://www.vaultproject.io/docs/secrets/kv/kv-v2
-	VaultKVVersionV2 VaultKVVersion = "v2"
-)
-
-// VaultSecretStoreConfig represents the required configuration for a Vault
-// secret store.
-type VaultSecretStoreConfig struct {
-	// Server is the url of the Vault server, e.g. "https://vault.acme.org"
-	Server string `json:"server"`
-
-	// MountPath is the mount path of the KV secrets engine.
-	MountPath string `json:"mountPath"`
-
-	// Version of the KV Secrets engine of Vault.
-	// https://www.vaultproject.io/docs/secrets/kv
-	// +optional
-	// +kubebuilder:default=v2
-	Version *VaultKVVersion `json:"version,omitempty"`
-
-	// CABundle configures CA bundle for Vault Server.
-	// +optional
-	CABundle *VaultCABundleConfig `json:"caBundle,omitempty"`
-
-	// Auth configures an authentication method for Vault.
-	Auth VaultAuthConfig `json:"auth"`
-}
diff --git a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/doc.go b/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/doc.go
deleted file mode 100644
index 9b99de7be..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/doc.go
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package v1 contains core API types used by most Crossplane resources.
-// +kubebuilder:object:generate=true
-package v1
diff --git a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/merge.go b/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/merge.go
deleted file mode 100644
index efed85db7..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/merge.go
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-Copyright 2021 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1
-
-import (
-	"github.com/imdario/mergo"
-)
-
-// MergeOptions Specifies merge options on a field path
-type MergeOptions struct { // TODO(aru): add more options that control merging behavior
-	// Specifies that already existing values in a merged map should be preserved
-	// +optional
-	KeepMapValues *bool `json:"keepMapValues,omitempty"`
-	// Specifies that already existing elements in a merged slice should be preserved
-	// +optional
-	AppendSlice *bool `json:"appendSlice,omitempty"`
-}
-
-// MergoConfiguration the default behavior is to replace maps and slices
-func (mo *MergeOptions) MergoConfiguration() []func(*mergo.Config) {
-	config := []func(*mergo.Config){mergo.WithOverride}
-	if mo == nil {
-		return config
-	}
-
-	if mo.KeepMapValues != nil && *mo.KeepMapValues {
-		config = config[:0]
-	}
-	if mo.AppendSlice != nil && *mo.AppendSlice {
-		config = append(config, mergo.WithAppendSlice)
-	}
-	return config
-}
-
-// IsAppendSlice returns true if mo.AppendSlice is set to true
-func (mo *MergeOptions) IsAppendSlice() bool {
-	return mo != nil && mo.AppendSlice != nil && *mo.AppendSlice
-}
diff --git a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/policies.go b/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/policies.go
deleted file mode 100644
index ca0fa7d90..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/policies.go
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1
-
-// A DeletionPolicy determines what should happen to the underlying external
-// resource when a managed resource is deleted.
-// +kubebuilder:validation:Enum=Orphan;Delete
-type DeletionPolicy string
-
-const (
-	// DeletionOrphan means the external resource will orphaned when its managed
-	// resource is deleted.
-	DeletionOrphan DeletionPolicy = "Orphan"
-
-	// DeletionDelete means both the  external resource will be deleted when its
-	// managed resource is deleted.
-	DeletionDelete DeletionPolicy = "Delete"
-)
-
-// An UpdatePolicy determines how something should be updated - either
-// automatically (without human intervention) or manually.
-// +kubebuilder:validation:Enum=Automatic;Manual
-type UpdatePolicy string
-
-const (
-	// UpdateAutomatic means the resource should be updated automatically,
-	// without any human intervention.
-	UpdateAutomatic UpdatePolicy = "Automatic"
-
-	// UpdateManual means the resource requires human intervention to
-	// update.
-	UpdateManual UpdatePolicy = "Manual"
-)
-
-// ResolvePolicy is a type for resolve policy.
-type ResolvePolicy string
-
-// ResolutionPolicy is a type for resolution policy.
-type ResolutionPolicy string
-
-const (
-	// ResolvePolicyAlways is a resolve option.
-	// When the ResolvePolicy is set to ResolvePolicyAlways the reference will
-	// be tried to resolve for every reconcile loop.
-	ResolvePolicyAlways ResolvePolicy = "Always"
-
-	// ResolutionPolicyRequired is a resolution option.
-	// When the ResolutionPolicy is set to ResolutionPolicyRequired the execution
-	// could not continue even if the reference cannot be resolved.
-	ResolutionPolicyRequired ResolutionPolicy = "Required"
-
-	// ResolutionPolicyOptional is a resolution option.
-	// When the ReferenceResolutionPolicy is set to ReferencePolicyOptional the
-	// execution could continue even if the reference cannot be resolved.
-	ResolutionPolicyOptional ResolutionPolicy = "Optional"
-)
diff --git a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/resource.go b/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/resource.go
deleted file mode 100644
index 872d9a098..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/resource.go
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1
-
-import (
-	corev1 "k8s.io/api/core/v1"
-
-	"k8s.io/apimachinery/pkg/runtime/schema"
-	"k8s.io/apimachinery/pkg/types"
-)
-
-const (
-	// ResourceCredentialsSecretEndpointKey is the key inside a connection secret for the connection endpoint
-	ResourceCredentialsSecretEndpointKey = "endpoint"
-	// ResourceCredentialsSecretPortKey is the key inside a connection secret for the connection port
-	ResourceCredentialsSecretPortKey = "port"
-	// ResourceCredentialsSecretUserKey is the key inside a connection secret for the connection user
-	ResourceCredentialsSecretUserKey = "username"
-	// ResourceCredentialsSecretPasswordKey is the key inside a connection secret for the connection password
-	ResourceCredentialsSecretPasswordKey = "password"
-	// ResourceCredentialsSecretCAKey is the key inside a connection secret for the server CA certificate
-	ResourceCredentialsSecretCAKey = "clusterCA"
-	// ResourceCredentialsSecretClientCertKey is the key inside a connection secret for the client certificate
-	ResourceCredentialsSecretClientCertKey = "clientCert"
-	// ResourceCredentialsSecretClientKeyKey is the key inside a connection secret for the client key
-	ResourceCredentialsSecretClientKeyKey = "clientKey"
-	// ResourceCredentialsSecretTokenKey is the key inside a connection secret for the bearer token value
-	ResourceCredentialsSecretTokenKey = "token"
-	// ResourceCredentialsSecretKubeconfigKey is the key inside a connection secret for the raw kubeconfig yaml
-	ResourceCredentialsSecretKubeconfigKey = "kubeconfig"
-)
-
-// LabelKeyProviderName is added to ProviderConfigUsages to relate them to their
-// ProviderConfig.
-const LabelKeyProviderName = "crossplane.io/provider-config"
-
-// NOTE(negz): The below secret references differ from ObjectReference and
-// LocalObjectReference in that they include only the fields Crossplane needs to
-// reference a secret, and make those fields required. This reduces ambiguity in
-// the API for resource authors.
-
-// A LocalSecretReference is a reference to a secret in the same namespace as
-// the referencer.
-type LocalSecretReference struct {
-	// Name of the secret.
-	Name string `json:"name"`
-}
-
-// A SecretReference is a reference to a secret in an arbitrary namespace.
-type SecretReference struct {
-	// Name of the secret.
-	Name string `json:"name"`
-
-	// Namespace of the secret.
-	Namespace string `json:"namespace"`
-}
-
-// A SecretKeySelector is a reference to a secret key in an arbitrary namespace.
-type SecretKeySelector struct {
-	SecretReference `json:",inline"`
-
-	// The key to select.
-	Key string `json:"key"`
-}
-
-// Policy represents the Resolve and Resolution policies of Reference instance.
-type Policy struct {
-	// Resolve specifies when this reference should be resolved. The default
-	// is 'IfNotPresent', which will attempt to resolve the reference only when
-	// the corresponding field is not present. Use 'Always' to resolve the
-	// reference on every reconcile.
-	// +optional
-	// +kubebuilder:validation:Enum=Always;IfNotPresent
-	Resolve *ResolvePolicy `json:"resolve,omitempty"`
-
-	// Resolution specifies whether resolution of this reference is required.
-	// The default is 'Required', which means the reconcile will fail if the
-	// reference cannot be resolved. 'Optional' means this reference will be
-	// a no-op if it cannot be resolved.
-	// +optional
-	// +kubebuilder:default=Required
-	// +kubebuilder:validation:Enum=Required;Optional
-	Resolution *ResolutionPolicy `json:"resolution,omitempty"`
-}
-
-// IsResolutionPolicyOptional checks whether the resolution policy of relevant reference is Optional.
-func (p *Policy) IsResolutionPolicyOptional() bool {
-	if p == nil || p.Resolution == nil {
-		return false
-	}
-	return *p.Resolution == ResolutionPolicyOptional
-}
-
-// IsResolvePolicyAlways checks whether the resolution policy of relevant reference is Always.
-func (p *Policy) IsResolvePolicyAlways() bool {
-	if p == nil || p.Resolve == nil {
-		return false
-	}
-	return *p.Resolve == ResolvePolicyAlways
-}
-
-// A Reference to a named object.
-type Reference struct {
-	// Name of the referenced object.
-	Name string `json:"name"`
-
-	// Policies for referencing.
-	// +optional
-	Policy *Policy `json:"policy,omitempty"`
-}
-
-// A TypedReference refers to an object by Name, Kind, and APIVersion. It is
-// commonly used to reference cluster-scoped objects or objects where the
-// namespace is already known.
-type TypedReference struct {
-	// APIVersion of the referenced object.
-	APIVersion string `json:"apiVersion"`
-
-	// Kind of the referenced object.
-	Kind string `json:"kind"`
-
-	// Name of the referenced object.
-	Name string `json:"name"`
-
-	// UID of the referenced object.
-	// +optional
-	UID types.UID `json:"uid,omitempty"`
-}
-
-// A Selector selects an object.
-type Selector struct {
-	// MatchLabels ensures an object with matching labels is selected.
-	MatchLabels map[string]string `json:"matchLabels,omitempty"`
-
-	// MatchControllerRef ensures an object with the same controller reference
-	// as the selecting object is selected.
-	MatchControllerRef *bool `json:"matchControllerRef,omitempty"`
-
-	// Policies for selection.
-	// +optional
-	Policy *Policy `json:"policy,omitempty"`
-}
-
-// SetGroupVersionKind sets the Kind and APIVersion of a TypedReference.
-func (obj *TypedReference) SetGroupVersionKind(gvk schema.GroupVersionKind) {
-	obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
-}
-
-// GroupVersionKind gets the GroupVersionKind of a TypedReference.
-func (obj *TypedReference) GroupVersionKind() schema.GroupVersionKind {
-	return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
-}
-
-// GetObjectKind get the ObjectKind of a TypedReference.
-func (obj *TypedReference) GetObjectKind() schema.ObjectKind { return obj }
-
-// TODO(negz): Rename Resource* to Managed* to clarify that they enable the
-// resource.Managed interface.
-
-// A ResourceSpec defines the desired state of a managed resource.
-type ResourceSpec struct {
-	// WriteConnectionSecretToReference specifies the namespace and name of a
-	// Secret to which any connection details for this managed resource should
-	// be written. Connection details frequently include the endpoint, username,
-	// and password required to connect to the managed resource.
-	// This field is planned to be replaced in a future release in favor of
-	// PublishConnectionDetailsTo. Currently, both could be set independently
-	// and connection details would be published to both without affecting
-	// each other.
-	// +optional
-	WriteConnectionSecretToReference *SecretReference `json:"writeConnectionSecretToRef,omitempty"`
-
-	// PublishConnectionDetailsTo specifies the connection secret config which
-	// contains a name, metadata and a reference to secret store config to
-	// which any connection details for this managed resource should be written.
-	// Connection details frequently include the endpoint, username,
-	// and password required to connect to the managed resource.
-	// +optional
-	PublishConnectionDetailsTo *PublishConnectionDetailsTo `json:"publishConnectionDetailsTo,omitempty"`
-
-	// ProviderConfigReference specifies how the provider that will be used to
-	// create, observe, update, and delete this managed resource should be
-	// configured.
-	// +kubebuilder:default={"name": "default"}
-	ProviderConfigReference *Reference `json:"providerConfigRef,omitempty"`
-
-	// ProviderReference specifies the provider that will be used to create,
-	// observe, update, and delete this managed resource.
-	// Deprecated: Please use ProviderConfigReference, i.e. `providerConfigRef`
-	ProviderReference *Reference `json:"providerRef,omitempty"`
-
-	// DeletionPolicy specifies what will happen to the underlying external
-	// when this managed resource is deleted - either "Delete" or "Orphan" the
-	// external resource.
-	// +optional
-	// +kubebuilder:default=Delete
-	DeletionPolicy DeletionPolicy `json:"deletionPolicy,omitempty"`
-}
-
-// ResourceStatus represents the observed state of a managed resource.
-type ResourceStatus struct {
-	ConditionedStatus `json:",inline"`
-}
-
-// A CredentialsSource is a source from which provider credentials may be
-// acquired.
-type CredentialsSource string
-
-const (
-	// CredentialsSourceNone indicates that a provider does not require
-	// credentials.
-	CredentialsSourceNone CredentialsSource = "None"
-
-	// CredentialsSourceSecret indicates that a provider should acquire
-	// credentials from a secret.
-	CredentialsSourceSecret CredentialsSource = "Secret"
-
-	// CredentialsSourceInjectedIdentity indicates that a provider should use
-	// credentials via its (pod's) identity; i.e. via IRSA for AWS,
-	// Workload Identity for GCP, Pod Identity for Azure, or in-cluster
-	// authentication for the Kubernetes API.
-	CredentialsSourceInjectedIdentity CredentialsSource = "InjectedIdentity"
-
-	// CredentialsSourceEnvironment indicates that a provider should acquire
-	// credentials from an environment variable.
-	CredentialsSourceEnvironment CredentialsSource = "Environment"
-
-	// CredentialsSourceFilesystem indicates that a provider should acquire
-	// credentials from the filesystem.
-	CredentialsSourceFilesystem CredentialsSource = "Filesystem"
-)
-
-// CommonCredentialSelectors provides common selectors for extracting
-// credentials.
-type CommonCredentialSelectors struct {
-	// Fs is a reference to a filesystem location that contains credentials that
-	// must be used to connect to the provider.
-	// +optional
-	Fs *FsSelector `json:"fs,omitempty"`
-
-	// Env is a reference to an environment variable that contains credentials
-	// that must be used to connect to the provider.
-	// +optional
-	Env *EnvSelector `json:"env,omitempty"`
-
-	// A SecretRef is a reference to a secret key that contains the credentials
-	// that must be used to connect to the provider.
-	// +optional
-	SecretRef *SecretKeySelector `json:"secretRef,omitempty"`
-}
-
-// EnvSelector selects an environment variable.
-type EnvSelector struct {
-	// Name is the name of an environment variable.
-	Name string `json:"name"`
-}
-
-// FsSelector selects a filesystem location.
-type FsSelector struct {
-	// Path is a filesystem path.
-	Path string `json:"path"`
-}
-
-// A ProviderConfigStatus defines the observed status of a ProviderConfig.
-type ProviderConfigStatus struct {
-	ConditionedStatus `json:",inline"`
-
-	// Users of this provider configuration.
-	Users int64 `json:"users,omitempty"`
-}
-
-// A ProviderConfigUsage is a record that a particular managed resource is using
-// a particular provider configuration.
-type ProviderConfigUsage struct {
-	// ProviderConfigReference to the provider config being used.
-	ProviderConfigReference Reference `json:"providerConfigRef"`
-
-	// ResourceReference to the managed resource using the provider config.
-	ResourceReference TypedReference `json:"resourceRef"`
-}
-
-// A TargetSpec defines the common fields of objects used for exposing
-// infrastructure to workloads that can be scheduled to.
-//
-// Deprecated.
-type TargetSpec struct {
-	// WriteConnectionSecretToReference specifies the name of a Secret, in the
-	// same namespace as this target, to which any connection details for this
-	// target should be written or already exist. Connection secrets referenced
-	// by a target should contain information for connecting to a resource that
-	// allows for scheduling of workloads.
-	// +optional
-	WriteConnectionSecretToReference *LocalSecretReference `json:"connectionSecretRef,omitempty"`
-
-	// A ResourceReference specifies an existing managed resource, in any
-	// namespace, which this target should attempt to propagate a connection
-	// secret from.
-	// +optional
-	ResourceReference *corev1.ObjectReference `json:"clusterRef,omitempty"`
-}
-
-// A TargetStatus defines the observed status a target.
-//
-// Deprecated.
-type TargetStatus struct {
-	ConditionedStatus `json:",inline"`
-}
diff --git a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/zz_generated.deepcopy.go b/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/zz_generated.deepcopy.go
deleted file mode 100644
index 5f8a7e345..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/apis/common/v1/zz_generated.deepcopy.go
+++ /dev/null
@@ -1,611 +0,0 @@
-//go:build !ignore_autogenerated
-// +build !ignore_autogenerated
-
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Code generated by controller-gen. DO NOT EDIT.
-
-package v1
-
-import (
-	corev1 "k8s.io/api/core/v1"
-)
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *CommonCredentialSelectors) DeepCopyInto(out *CommonCredentialSelectors) {
-	*out = *in
-	if in.Fs != nil {
-		in, out := &in.Fs, &out.Fs
-		*out = new(FsSelector)
-		**out = **in
-	}
-	if in.Env != nil {
-		in, out := &in.Env, &out.Env
-		*out = new(EnvSelector)
-		**out = **in
-	}
-	if in.SecretRef != nil {
-		in, out := &in.SecretRef, &out.SecretRef
-		*out = new(SecretKeySelector)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonCredentialSelectors.
-func (in *CommonCredentialSelectors) DeepCopy() *CommonCredentialSelectors {
-	if in == nil {
-		return nil
-	}
-	out := new(CommonCredentialSelectors)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Condition) DeepCopyInto(out *Condition) {
-	*out = *in
-	in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
-func (in *Condition) DeepCopy() *Condition {
-	if in == nil {
-		return nil
-	}
-	out := new(Condition)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ConditionedStatus) DeepCopyInto(out *ConditionedStatus) {
-	*out = *in
-	if in.Conditions != nil {
-		in, out := &in.Conditions, &out.Conditions
-		*out = make([]Condition, len(*in))
-		for i := range *in {
-			(*in)[i].DeepCopyInto(&(*out)[i])
-		}
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConditionedStatus.
-func (in *ConditionedStatus) DeepCopy() *ConditionedStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(ConditionedStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ConnectionSecretMetadata) DeepCopyInto(out *ConnectionSecretMetadata) {
-	*out = *in
-	if in.Labels != nil {
-		in, out := &in.Labels, &out.Labels
-		*out = make(map[string]string, len(*in))
-		for key, val := range *in {
-			(*out)[key] = val
-		}
-	}
-	if in.Annotations != nil {
-		in, out := &in.Annotations, &out.Annotations
-		*out = make(map[string]string, len(*in))
-		for key, val := range *in {
-			(*out)[key] = val
-		}
-	}
-	if in.Type != nil {
-		in, out := &in.Type, &out.Type
-		*out = new(corev1.SecretType)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionSecretMetadata.
-func (in *ConnectionSecretMetadata) DeepCopy() *ConnectionSecretMetadata {
-	if in == nil {
-		return nil
-	}
-	out := new(ConnectionSecretMetadata)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *EnvSelector) DeepCopyInto(out *EnvSelector) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvSelector.
-func (in *EnvSelector) DeepCopy() *EnvSelector {
-	if in == nil {
-		return nil
-	}
-	out := new(EnvSelector)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FsSelector) DeepCopyInto(out *FsSelector) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FsSelector.
-func (in *FsSelector) DeepCopy() *FsSelector {
-	if in == nil {
-		return nil
-	}
-	out := new(FsSelector)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *KubernetesAuthConfig) DeepCopyInto(out *KubernetesAuthConfig) {
-	*out = *in
-	in.CommonCredentialSelectors.DeepCopyInto(&out.CommonCredentialSelectors)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesAuthConfig.
-func (in *KubernetesAuthConfig) DeepCopy() *KubernetesAuthConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(KubernetesAuthConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *KubernetesSecretStoreConfig) DeepCopyInto(out *KubernetesSecretStoreConfig) {
-	*out = *in
-	in.Auth.DeepCopyInto(&out.Auth)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesSecretStoreConfig.
-func (in *KubernetesSecretStoreConfig) DeepCopy() *KubernetesSecretStoreConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(KubernetesSecretStoreConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *LocalSecretReference) DeepCopyInto(out *LocalSecretReference) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LocalSecretReference.
-func (in *LocalSecretReference) DeepCopy() *LocalSecretReference {
-	if in == nil {
-		return nil
-	}
-	out := new(LocalSecretReference)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MergeOptions) DeepCopyInto(out *MergeOptions) {
-	*out = *in
-	if in.KeepMapValues != nil {
-		in, out := &in.KeepMapValues, &out.KeepMapValues
-		*out = new(bool)
-		**out = **in
-	}
-	if in.AppendSlice != nil {
-		in, out := &in.AppendSlice, &out.AppendSlice
-		*out = new(bool)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MergeOptions.
-func (in *MergeOptions) DeepCopy() *MergeOptions {
-	if in == nil {
-		return nil
-	}
-	out := new(MergeOptions)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Policy) DeepCopyInto(out *Policy) {
-	*out = *in
-	if in.Resolve != nil {
-		in, out := &in.Resolve, &out.Resolve
-		*out = new(ResolvePolicy)
-		**out = **in
-	}
-	if in.Resolution != nil {
-		in, out := &in.Resolution, &out.Resolution
-		*out = new(ResolutionPolicy)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy.
-func (in *Policy) DeepCopy() *Policy {
-	if in == nil {
-		return nil
-	}
-	out := new(Policy)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ProviderConfigStatus) DeepCopyInto(out *ProviderConfigStatus) {
-	*out = *in
-	in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigStatus.
-func (in *ProviderConfigStatus) DeepCopy() *ProviderConfigStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(ProviderConfigStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ProviderConfigUsage) DeepCopyInto(out *ProviderConfigUsage) {
-	*out = *in
-	in.ProviderConfigReference.DeepCopyInto(&out.ProviderConfigReference)
-	out.ResourceReference = in.ResourceReference
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigUsage.
-func (in *ProviderConfigUsage) DeepCopy() *ProviderConfigUsage {
-	if in == nil {
-		return nil
-	}
-	out := new(ProviderConfigUsage)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *PublishConnectionDetailsTo) DeepCopyInto(out *PublishConnectionDetailsTo) {
-	*out = *in
-	if in.Metadata != nil {
-		in, out := &in.Metadata, &out.Metadata
-		*out = new(ConnectionSecretMetadata)
-		(*in).DeepCopyInto(*out)
-	}
-	if in.SecretStoreConfigRef != nil {
-		in, out := &in.SecretStoreConfigRef, &out.SecretStoreConfigRef
-		*out = new(Reference)
-		(*in).DeepCopyInto(*out)
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PublishConnectionDetailsTo.
-func (in *PublishConnectionDetailsTo) DeepCopy() *PublishConnectionDetailsTo {
-	if in == nil {
-		return nil
-	}
-	out := new(PublishConnectionDetailsTo)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Reference) DeepCopyInto(out *Reference) {
-	*out = *in
-	if in.Policy != nil {
-		in, out := &in.Policy, &out.Policy
-		*out = new(Policy)
-		(*in).DeepCopyInto(*out)
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Reference.
-func (in *Reference) DeepCopy() *Reference {
-	if in == nil {
-		return nil
-	}
-	out := new(Reference)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) {
-	*out = *in
-	if in.WriteConnectionSecretToReference != nil {
-		in, out := &in.WriteConnectionSecretToReference, &out.WriteConnectionSecretToReference
-		*out = new(SecretReference)
-		**out = **in
-	}
-	if in.PublishConnectionDetailsTo != nil {
-		in, out := &in.PublishConnectionDetailsTo, &out.PublishConnectionDetailsTo
-		*out = new(PublishConnectionDetailsTo)
-		(*in).DeepCopyInto(*out)
-	}
-	if in.ProviderConfigReference != nil {
-		in, out := &in.ProviderConfigReference, &out.ProviderConfigReference
-		*out = new(Reference)
-		(*in).DeepCopyInto(*out)
-	}
-	if in.ProviderReference != nil {
-		in, out := &in.ProviderReference, &out.ProviderReference
-		*out = new(Reference)
-		(*in).DeepCopyInto(*out)
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec.
-func (in *ResourceSpec) DeepCopy() *ResourceSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(ResourceSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ResourceStatus) DeepCopyInto(out *ResourceStatus) {
-	*out = *in
-	in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceStatus.
-func (in *ResourceStatus) DeepCopy() *ResourceStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(ResourceStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
-	*out = *in
-	out.SecretReference = in.SecretReference
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
-func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
-	if in == nil {
-		return nil
-	}
-	out := new(SecretKeySelector)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SecretReference) DeepCopyInto(out *SecretReference) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference.
-func (in *SecretReference) DeepCopy() *SecretReference {
-	if in == nil {
-		return nil
-	}
-	out := new(SecretReference)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SecretStoreConfig) DeepCopyInto(out *SecretStoreConfig) {
-	*out = *in
-	if in.Type != nil {
-		in, out := &in.Type, &out.Type
-		*out = new(SecretStoreType)
-		**out = **in
-	}
-	if in.Kubernetes != nil {
-		in, out := &in.Kubernetes, &out.Kubernetes
-		*out = new(KubernetesSecretStoreConfig)
-		(*in).DeepCopyInto(*out)
-	}
-	if in.Vault != nil {
-		in, out := &in.Vault, &out.Vault
-		*out = new(VaultSecretStoreConfig)
-		(*in).DeepCopyInto(*out)
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreConfig.
-func (in *SecretStoreConfig) DeepCopy() *SecretStoreConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(SecretStoreConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Selector) DeepCopyInto(out *Selector) {
-	*out = *in
-	if in.MatchLabels != nil {
-		in, out := &in.MatchLabels, &out.MatchLabels
-		*out = make(map[string]string, len(*in))
-		for key, val := range *in {
-			(*out)[key] = val
-		}
-	}
-	if in.MatchControllerRef != nil {
-		in, out := &in.MatchControllerRef, &out.MatchControllerRef
-		*out = new(bool)
-		**out = **in
-	}
-	if in.Policy != nil {
-		in, out := &in.Policy, &out.Policy
-		*out = new(Policy)
-		(*in).DeepCopyInto(*out)
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector.
-func (in *Selector) DeepCopy() *Selector {
-	if in == nil {
-		return nil
-	}
-	out := new(Selector)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TargetSpec) DeepCopyInto(out *TargetSpec) {
-	*out = *in
-	if in.WriteConnectionSecretToReference != nil {
-		in, out := &in.WriteConnectionSecretToReference, &out.WriteConnectionSecretToReference
-		*out = new(LocalSecretReference)
-		**out = **in
-	}
-	if in.ResourceReference != nil {
-		in, out := &in.ResourceReference, &out.ResourceReference
-		*out = new(corev1.ObjectReference)
-		**out = **in
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetSpec.
-func (in *TargetSpec) DeepCopy() *TargetSpec {
-	if in == nil {
-		return nil
-	}
-	out := new(TargetSpec)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TargetStatus) DeepCopyInto(out *TargetStatus) {
-	*out = *in
-	in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetStatus.
-func (in *TargetStatus) DeepCopy() *TargetStatus {
-	if in == nil {
-		return nil
-	}
-	out := new(TargetStatus)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TypedReference) DeepCopyInto(out *TypedReference) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypedReference.
-func (in *TypedReference) DeepCopy() *TypedReference {
-	if in == nil {
-		return nil
-	}
-	out := new(TypedReference)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *VaultAuthConfig) DeepCopyInto(out *VaultAuthConfig) {
-	*out = *in
-	if in.Token != nil {
-		in, out := &in.Token, &out.Token
-		*out = new(VaultAuthTokenConfig)
-		(*in).DeepCopyInto(*out)
-	}
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAuthConfig.
-func (in *VaultAuthConfig) DeepCopy() *VaultAuthConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(VaultAuthConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *VaultAuthTokenConfig) DeepCopyInto(out *VaultAuthTokenConfig) {
-	*out = *in
-	in.CommonCredentialSelectors.DeepCopyInto(&out.CommonCredentialSelectors)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultAuthTokenConfig.
-func (in *VaultAuthTokenConfig) DeepCopy() *VaultAuthTokenConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(VaultAuthTokenConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *VaultCABundleConfig) DeepCopyInto(out *VaultCABundleConfig) {
-	*out = *in
-	in.CommonCredentialSelectors.DeepCopyInto(&out.CommonCredentialSelectors)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultCABundleConfig.
-func (in *VaultCABundleConfig) DeepCopy() *VaultCABundleConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(VaultCABundleConfig)
-	in.DeepCopyInto(out)
-	return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *VaultSecretStoreConfig) DeepCopyInto(out *VaultSecretStoreConfig) {
-	*out = *in
-	if in.Version != nil {
-		in, out := &in.Version, &out.Version
-		*out = new(VaultKVVersion)
-		**out = **in
-	}
-	if in.CABundle != nil {
-		in, out := &in.CABundle, &out.CABundle
-		*out = new(VaultCABundleConfig)
-		(*in).DeepCopyInto(*out)
-	}
-	in.Auth.DeepCopyInto(&out.Auth)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultSecretStoreConfig.
-func (in *VaultSecretStoreConfig) DeepCopy() *VaultSecretStoreConfig {
-	if in == nil {
-		return nil
-	}
-	out := new(VaultSecretStoreConfig)
-	in.DeepCopyInto(out)
-	return out
-}
diff --git a/vendor/github.com/evanphx/json-patch/v5/LICENSE b/vendor/github.com/evanphx/json-patch/v5/LICENSE
new file mode 100644
index 000000000..df76d7d77
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/v5/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2014, Evan Phoenix
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+* Neither the name of the Evan Phoenix nor the names of its contributors 
+  may be used to endorse or promote products derived from this software 
+  without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/evanphx/json-patch/v5/errors.go b/vendor/github.com/evanphx/json-patch/v5/errors.go
new file mode 100644
index 000000000..75304b443
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/v5/errors.go
@@ -0,0 +1,38 @@
+package jsonpatch
+
+import "fmt"
+
+// AccumulatedCopySizeError is an error type returned when the accumulated size
+// increase caused by copy operations in a patch operation has exceeded the
+// limit.
+type AccumulatedCopySizeError struct {
+	limit       int64
+	accumulated int64
+}
+
+// NewAccumulatedCopySizeError returns an AccumulatedCopySizeError.
+func NewAccumulatedCopySizeError(l, a int64) *AccumulatedCopySizeError {
+	return &AccumulatedCopySizeError{limit: l, accumulated: a}
+}
+
+// Error implements the error interface.
+func (a *AccumulatedCopySizeError) Error() string {
+	return fmt.Sprintf("Unable to complete the copy, the accumulated size increase of copy is %d, exceeding the limit %d", a.accumulated, a.limit)
+}
+
+// ArraySizeError is an error type returned when the array size has exceeded
+// the limit.
+type ArraySizeError struct {
+	limit int
+	size  int
+}
+
+// NewArraySizeError returns an ArraySizeError.
+func NewArraySizeError(l, s int) *ArraySizeError {
+	return &ArraySizeError{limit: l, size: s}
+}
+
+// Error implements the error interface.
+func (a *ArraySizeError) Error() string {
+	return fmt.Sprintf("Unable to create array of size %d, limit is %d", a.size, a.limit)
+}
diff --git a/vendor/github.com/evanphx/json-patch/v5/merge.go b/vendor/github.com/evanphx/json-patch/v5/merge.go
new file mode 100644
index 000000000..a7c457342
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/v5/merge.go
@@ -0,0 +1,408 @@
+package jsonpatch
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"reflect"
+)
+
+func merge(cur, patch *lazyNode, mergeMerge bool) *lazyNode {
+	curDoc, err := cur.intoDoc()
+
+	if err != nil {
+		pruneNulls(patch)
+		return patch
+	}
+
+	patchDoc, err := patch.intoDoc()
+
+	if err != nil {
+		return patch
+	}
+
+	mergeDocs(curDoc, patchDoc, mergeMerge)
+
+	return cur
+}
+
+func mergeDocs(doc, patch *partialDoc, mergeMerge bool) {
+	for k, v := range patch.obj {
+		if v == nil {
+			if mergeMerge {
+				idx := -1
+				for i, key := range doc.keys {
+					if key == k {
+						idx = i
+						break
+					}
+				}
+				if idx == -1 {
+					doc.keys = append(doc.keys, k)
+				}
+				doc.obj[k] = nil
+			} else {
+				_ = doc.remove(k, &ApplyOptions{})
+			}
+		} else {
+			cur, ok := doc.obj[k]
+
+			if !ok || cur == nil {
+				if !mergeMerge {
+					pruneNulls(v)
+				}
+				_ = doc.set(k, v, &ApplyOptions{})
+			} else {
+				_ = doc.set(k, merge(cur, v, mergeMerge), &ApplyOptions{})
+			}
+		}
+	}
+}
+
+func pruneNulls(n *lazyNode) {
+	sub, err := n.intoDoc()
+
+	if err == nil {
+		pruneDocNulls(sub)
+	} else {
+		ary, err := n.intoAry()
+
+		if err == nil {
+			pruneAryNulls(ary)
+		}
+	}
+}
+
+func pruneDocNulls(doc *partialDoc) *partialDoc {
+	for k, v := range doc.obj {
+		if v == nil {
+			_ = doc.remove(k, &ApplyOptions{})
+		} else {
+			pruneNulls(v)
+		}
+	}
+
+	return doc
+}
+
+func pruneAryNulls(ary *partialArray) *partialArray {
+	newAry := []*lazyNode{}
+
+	for _, v := range *ary {
+		if v != nil {
+			pruneNulls(v)
+		}
+		newAry = append(newAry, v)
+	}
+
+	*ary = newAry
+
+	return ary
+}
+
+var errBadJSONDoc = fmt.Errorf("Invalid JSON Document")
+var errBadJSONPatch = fmt.Errorf("Invalid JSON Patch")
+var errBadMergeTypes = fmt.Errorf("Mismatched JSON Documents")
+
+// MergeMergePatches merges two merge patches together, such that
+// applying this resulting merged merge patch to a document yields the same
+// as merging each merge patch to the document in succession.
+func MergeMergePatches(patch1Data, patch2Data []byte) ([]byte, error) {
+	return doMergePatch(patch1Data, patch2Data, true)
+}
+
+// MergePatch merges the patchData into the docData.
+func MergePatch(docData, patchData []byte) ([]byte, error) {
+	return doMergePatch(docData, patchData, false)
+}
+
+func doMergePatch(docData, patchData []byte, mergeMerge bool) ([]byte, error) {
+	doc := &partialDoc{}
+
+	docErr := json.Unmarshal(docData, doc)
+
+	patch := &partialDoc{}
+
+	patchErr := json.Unmarshal(patchData, patch)
+
+	if isSyntaxError(docErr) {
+		return nil, errBadJSONDoc
+	}
+
+	if isSyntaxError(patchErr) {
+		return nil, errBadJSONPatch
+	}
+
+	if docErr == nil && doc.obj == nil {
+		return nil, errBadJSONDoc
+	}
+
+	if patchErr == nil && patch.obj == nil {
+		return nil, errBadJSONPatch
+	}
+
+	if docErr != nil || patchErr != nil {
+		// Not an error, just not a doc, so we turn straight into the patch
+		if patchErr == nil {
+			if mergeMerge {
+				doc = patch
+			} else {
+				doc = pruneDocNulls(patch)
+			}
+		} else {
+			patchAry := &partialArray{}
+			patchErr = json.Unmarshal(patchData, patchAry)
+
+			if patchErr != nil {
+				return nil, errBadJSONPatch
+			}
+
+			pruneAryNulls(patchAry)
+
+			out, patchErr := json.Marshal(patchAry)
+
+			if patchErr != nil {
+				return nil, errBadJSONPatch
+			}
+
+			return out, nil
+		}
+	} else {
+		mergeDocs(doc, patch, mergeMerge)
+	}
+
+	return json.Marshal(doc)
+}
+
+func isSyntaxError(err error) bool {
+	if _, ok := err.(*json.SyntaxError); ok {
+		return true
+	}
+	if _, ok := err.(*syntaxError); ok {
+		return true
+	}
+	return false
+}
+
+// resemblesJSONArray indicates whether the byte-slice "appears" to be
+// a JSON array or not.
+// False-positives are possible, as this function does not check the internal
+// structure of the array. It only checks that the outer syntax is present and
+// correct.
+func resemblesJSONArray(input []byte) bool {
+	input = bytes.TrimSpace(input)
+
+	hasPrefix := bytes.HasPrefix(input, []byte("["))
+	hasSuffix := bytes.HasSuffix(input, []byte("]"))
+
+	return hasPrefix && hasSuffix
+}
+
+// CreateMergePatch will return a merge patch document capable of converting
+// the original document(s) to the modified document(s).
+// The parameters can be bytes of either two JSON Documents, or two arrays of
+// JSON documents.
+// The merge patch returned follows the specification defined at http://tools.ietf.org/html/draft-ietf-appsawg-json-merge-patch-07
+func CreateMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
+	originalResemblesArray := resemblesJSONArray(originalJSON)
+	modifiedResemblesArray := resemblesJSONArray(modifiedJSON)
+
+	// Do both byte-slices seem like JSON arrays?
+	if originalResemblesArray && modifiedResemblesArray {
+		return createArrayMergePatch(originalJSON, modifiedJSON)
+	}
+
+	// Are both byte-slices are not arrays? Then they are likely JSON objects...
+	if !originalResemblesArray && !modifiedResemblesArray {
+		return createObjectMergePatch(originalJSON, modifiedJSON)
+	}
+
+	// None of the above? Then return an error because of mismatched types.
+	return nil, errBadMergeTypes
+}
+
+// createObjectMergePatch will return a merge-patch document capable of
+// converting the original document to the modified document.
+func createObjectMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
+	originalDoc := map[string]interface{}{}
+	modifiedDoc := map[string]interface{}{}
+
+	err := json.Unmarshal(originalJSON, &originalDoc)
+	if err != nil {
+		return nil, errBadJSONDoc
+	}
+
+	err = json.Unmarshal(modifiedJSON, &modifiedDoc)
+	if err != nil {
+		return nil, errBadJSONDoc
+	}
+
+	dest, err := getDiff(originalDoc, modifiedDoc)
+	if err != nil {
+		return nil, err
+	}
+
+	return json.Marshal(dest)
+}
+
+// createArrayMergePatch will return an array of merge-patch documents capable
+// of converting the original document to the modified document for each
+// pair of JSON documents provided in the arrays.
+// Arrays of mismatched sizes will result in an error.
+func createArrayMergePatch(originalJSON, modifiedJSON []byte) ([]byte, error) {
+	originalDocs := []json.RawMessage{}
+	modifiedDocs := []json.RawMessage{}
+
+	err := json.Unmarshal(originalJSON, &originalDocs)
+	if err != nil {
+		return nil, errBadJSONDoc
+	}
+
+	err = json.Unmarshal(modifiedJSON, &modifiedDocs)
+	if err != nil {
+		return nil, errBadJSONDoc
+	}
+
+	total := len(originalDocs)
+	if len(modifiedDocs) != total {
+		return nil, errBadJSONDoc
+	}
+
+	result := []json.RawMessage{}
+	for i := 0; i < len(originalDocs); i++ {
+		original := originalDocs[i]
+		modified := modifiedDocs[i]
+
+		patch, err := createObjectMergePatch(original, modified)
+		if err != nil {
+			return nil, err
+		}
+
+		result = append(result, json.RawMessage(patch))
+	}
+
+	return json.Marshal(result)
+}
+
+// Returns true if the array matches (must be json types).
+// As is idiomatic for go, an empty array is not the same as a nil array.
+func matchesArray(a, b []interface{}) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	if (a == nil && b != nil) || (a != nil && b == nil) {
+		return false
+	}
+	for i := range a {
+		if !matchesValue(a[i], b[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// Returns true if the values matches (must be json types)
+// The types of the values must match, otherwise it will always return false
+// If two map[string]interface{} are given, all elements must match.
+func matchesValue(av, bv interface{}) bool {
+	if reflect.TypeOf(av) != reflect.TypeOf(bv) {
+		return false
+	}
+	switch at := av.(type) {
+	case string:
+		bt := bv.(string)
+		if bt == at {
+			return true
+		}
+	case float64:
+		bt := bv.(float64)
+		if bt == at {
+			return true
+		}
+	case bool:
+		bt := bv.(bool)
+		if bt == at {
+			return true
+		}
+	case nil:
+		// Both nil, fine.
+		return true
+	case map[string]interface{}:
+		bt := bv.(map[string]interface{})
+		if len(bt) != len(at) {
+			return false
+		}
+		for key := range bt {
+			av, aOK := at[key]
+			bv, bOK := bt[key]
+			if aOK != bOK {
+				return false
+			}
+			if !matchesValue(av, bv) {
+				return false
+			}
+		}
+		return true
+	case []interface{}:
+		bt := bv.([]interface{})
+		return matchesArray(at, bt)
+	}
+	return false
+}
+
+// getDiff returns the (recursive) difference between a and b as a map[string]interface{}.
+func getDiff(a, b map[string]interface{}) (map[string]interface{}, error) {
+	into := map[string]interface{}{}
+	for key, bv := range b {
+		av, ok := a[key]
+		// value was added
+		if !ok {
+			into[key] = bv
+			continue
+		}
+		// If types have changed, replace completely
+		if reflect.TypeOf(av) != reflect.TypeOf(bv) {
+			into[key] = bv
+			continue
+		}
+		// Types are the same, compare values
+		switch at := av.(type) {
+		case map[string]interface{}:
+			bt := bv.(map[string]interface{})
+			dst := make(map[string]interface{}, len(bt))
+			dst, err := getDiff(at, bt)
+			if err != nil {
+				return nil, err
+			}
+			if len(dst) > 0 {
+				into[key] = dst
+			}
+		case string, float64, bool:
+			if !matchesValue(av, bv) {
+				into[key] = bv
+			}
+		case []interface{}:
+			bt := bv.([]interface{})
+			if !matchesArray(at, bt) {
+				into[key] = bv
+			}
+		case nil:
+			switch bv.(type) {
+			case nil:
+				// Both nil, fine.
+			default:
+				into[key] = bv
+			}
+		default:
+			panic(fmt.Sprintf("Unknown type:%T in key %s", av, key))
+		}
+	}
+	// Now add all deleted values as nil
+	for key := range a {
+		_, found := b[key]
+		if !found {
+			into[key] = nil
+		}
+	}
+	return into, nil
+}
diff --git a/vendor/github.com/evanphx/json-patch/v5/patch.go b/vendor/github.com/evanphx/json-patch/v5/patch.go
new file mode 100644
index 000000000..117f2c00d
--- /dev/null
+++ b/vendor/github.com/evanphx/json-patch/v5/patch.go
@@ -0,0 +1,1135 @@
+package jsonpatch
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/pkg/errors"
+)
+
+const (
+	eRaw = iota
+	eDoc
+	eAry
+)
+
+var (
+	// SupportNegativeIndices decides whether to support non-standard practice of
+	// allowing negative indices to mean indices starting at the end of an array.
+	// Default to true.
+	SupportNegativeIndices bool = true
+	// AccumulatedCopySizeLimit limits the total size increase in bytes caused by
+	// "copy" operations in a patch.
+	AccumulatedCopySizeLimit int64 = 0
+	startObject                    = json.Delim('{')
+	endObject                      = json.Delim('}')
+	startArray                     = json.Delim('[')
+	endArray                       = json.Delim(']')
+)
+
+var (
+	ErrTestFailed   = errors.New("test failed")
+	ErrMissing      = errors.New("missing value")
+	ErrUnknownType  = errors.New("unknown object type")
+	ErrInvalid      = errors.New("invalid state detected")
+	ErrInvalidIndex = errors.New("invalid index referenced")
+
+	rawJSONArray  = []byte("[]")
+	rawJSONObject = []byte("{}")
+	rawJSONNull   = []byte("null")
+)
+
+type lazyNode struct {
+	raw   *json.RawMessage
+	doc   *partialDoc
+	ary   partialArray
+	which int
+}
+
+// Operation is a single JSON-Patch step, such as a single 'add' operation.
+type Operation map[string]*json.RawMessage
+
+// Patch is an ordered collection of Operations.
+type Patch []Operation
+
+type partialDoc struct {
+	keys []string
+	obj  map[string]*lazyNode
+}
+
+type partialArray []*lazyNode
+
+type container interface {
+	get(key string, options *ApplyOptions) (*lazyNode, error)
+	set(key string, val *lazyNode, options *ApplyOptions) error
+	add(key string, val *lazyNode, options *ApplyOptions) error
+	remove(key string, options *ApplyOptions) error
+}
+
+// ApplyOptions specifies options for calls to ApplyWithOptions.
+// Use NewApplyOptions to obtain default values for ApplyOptions.
+type ApplyOptions struct {
+	// SupportNegativeIndices decides whether to support non-standard practice of
+	// allowing negative indices to mean indices starting at the end of an array.
+	// Default to true.
+	SupportNegativeIndices bool
+	// AccumulatedCopySizeLimit limits the total size increase in bytes caused by
+	// "copy" operations in a patch.
+	AccumulatedCopySizeLimit int64
+	// AllowMissingPathOnRemove indicates whether to fail "remove" operations when the target path is missing.
+	// Default to false.
+	AllowMissingPathOnRemove bool
+	// EnsurePathExistsOnAdd instructs json-patch to recursively create the missing parts of path on "add" operation.
+	// Default to false.
+	EnsurePathExistsOnAdd bool
+}
+
+// NewApplyOptions creates a default set of options for calls to ApplyWithOptions.
+func NewApplyOptions() *ApplyOptions {
+	return &ApplyOptions{
+		SupportNegativeIndices:   SupportNegativeIndices,
+		AccumulatedCopySizeLimit: AccumulatedCopySizeLimit,
+		AllowMissingPathOnRemove: false,
+		EnsurePathExistsOnAdd:    false,
+	}
+}
+
+func newLazyNode(raw *json.RawMessage) *lazyNode {
+	return &lazyNode{raw: raw, doc: nil, ary: nil, which: eRaw}
+}
+
+func newRawMessage(buf []byte) *json.RawMessage {
+	ra := make(json.RawMessage, len(buf))
+	copy(ra, buf)
+	return &ra
+}
+
+func (n *lazyNode) MarshalJSON() ([]byte, error) {
+	switch n.which {
+	case eRaw:
+		return json.Marshal(n.raw)
+	case eDoc:
+		return json.Marshal(n.doc)
+	case eAry:
+		return json.Marshal(n.ary)
+	default:
+		return nil, ErrUnknownType
+	}
+}
+
+func (n *lazyNode) UnmarshalJSON(data []byte) error {
+	dest := make(json.RawMessage, len(data))
+	copy(dest, data)
+	n.raw = &dest
+	n.which = eRaw
+	return nil
+}
+
+func (n *partialDoc) MarshalJSON() ([]byte, error) {
+	var buf bytes.Buffer
+	if _, err := buf.WriteString("{"); err != nil {
+		return nil, err
+	}
+	for i, k := range n.keys {
+		if i > 0 {
+			if _, err := buf.WriteString(", "); err != nil {
+				return nil, err
+			}
+		}
+		key, err := json.Marshal(k)
+		if err != nil {
+			return nil, err
+		}
+		if _, err := buf.Write(key); err != nil {
+			return nil, err
+		}
+		if _, err := buf.WriteString(": "); err != nil {
+			return nil, err
+		}
+		value, err := json.Marshal(n.obj[k])
+		if err != nil {
+			return nil, err
+		}
+		if _, err := buf.Write(value); err != nil {
+			return nil, err
+		}
+	}
+	if _, err := buf.WriteString("}"); err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
+}
+
+type syntaxError struct {
+	msg string
+}
+
+func (err *syntaxError) Error() string {
+	return err.msg
+}
+
+func (n *partialDoc) UnmarshalJSON(data []byte) error {
+	if err := json.Unmarshal(data, &n.obj); err != nil {
+		return err
+	}
+	buffer := bytes.NewBuffer(data)
+	d := json.NewDecoder(buffer)
+	if t, err := d.Token(); err != nil {
+		return err
+	} else if t != startObject {
+		return &syntaxError{fmt.Sprintf("unexpected JSON token in document node: %s", t)}
+	}
+	for d.More() {
+		k, err := d.Token()
+		if err != nil {
+			return err
+		}
+		key, ok := k.(string)
+		if !ok {
+			return &syntaxError{fmt.Sprintf("unexpected JSON token as document node key: %s", k)}
+		}
+		if err := skipValue(d); err != nil {
+			return err
+		}
+		n.keys = append(n.keys, key)
+	}
+	return nil
+}
+
+func skipValue(d *json.Decoder) error {
+	t, err := d.Token()
+	if err != nil {
+		return err
+	}
+	if t != startObject && t != startArray {
+		return nil
+	}
+	for d.More() {
+		if t == startObject {
+			// consume key token
+			if _, err := d.Token(); err != nil {
+				return err
+			}
+		}
+		if err := skipValue(d); err != nil {
+			return err
+		}
+	}
+	end, err := d.Token()
+	if err != nil {
+		return err
+	}
+	if t == startObject && end != endObject {
+		return &syntaxError{msg: "expected close object token"}
+	}
+	if t == startArray && end != endArray {
+		return &syntaxError{msg: "expected close object token"}
+	}
+	return nil
+}
+
+func deepCopy(src *lazyNode) (*lazyNode, int, error) {
+	if src == nil {
+		return nil, 0, nil
+	}
+	a, err := src.MarshalJSON()
+	if err != nil {
+		return nil, 0, err
+	}
+	sz := len(a)
+	return newLazyNode(newRawMessage(a)), sz, nil
+}
+
+func (n *lazyNode) intoDoc() (*partialDoc, error) {
+	if n.which == eDoc {
+		return n.doc, nil
+	}
+
+	if n.raw == nil {
+		return nil, ErrInvalid
+	}
+
+	err := json.Unmarshal(*n.raw, &n.doc)
+
+	if err != nil {
+		return nil, err
+	}
+
+	n.which = eDoc
+	return n.doc, nil
+}
+
+func (n *lazyNode) intoAry() (*partialArray, error) {
+	if n.which == eAry {
+		return &n.ary, nil
+	}
+
+	if n.raw == nil {
+		return nil, ErrInvalid
+	}
+
+	err := json.Unmarshal(*n.raw, &n.ary)
+
+	if err != nil {
+		return nil, err
+	}
+
+	n.which = eAry
+	return &n.ary, nil
+}
+
+func (n *lazyNode) compact() []byte {
+	buf := &bytes.Buffer{}
+
+	if n.raw == nil {
+		return nil
+	}
+
+	err := json.Compact(buf, *n.raw)
+
+	if err != nil {
+		return *n.raw
+	}
+
+	return buf.Bytes()
+}
+
+func (n *lazyNode) tryDoc() bool {
+	if n.raw == nil {
+		return false
+	}
+
+	err := json.Unmarshal(*n.raw, &n.doc)
+
+	if err != nil {
+		return false
+	}
+
+	n.which = eDoc
+	return true
+}
+
+func (n *lazyNode) tryAry() bool {
+	if n.raw == nil {
+		return false
+	}
+
+	err := json.Unmarshal(*n.raw, &n.ary)
+
+	if err != nil {
+		return false
+	}
+
+	n.which = eAry
+	return true
+}
+
+func (n *lazyNode) equal(o *lazyNode) bool {
+	if n.which == eRaw {
+		if !n.tryDoc() && !n.tryAry() {
+			if o.which != eRaw {
+				return false
+			}
+
+			return bytes.Equal(n.compact(), o.compact())
+		}
+	}
+
+	if n.which == eDoc {
+		if o.which == eRaw {
+			if !o.tryDoc() {
+				return false
+			}
+		}
+
+		if o.which != eDoc {
+			return false
+		}
+
+		if len(n.doc.obj) != len(o.doc.obj) {
+			return false
+		}
+
+		for k, v := range n.doc.obj {
+			ov, ok := o.doc.obj[k]
+
+			if !ok {
+				return false
+			}
+
+			if (v == nil) != (ov == nil) {
+				return false
+			}
+
+			if v == nil && ov == nil {
+				continue
+			}
+
+			if !v.equal(ov) {
+				return false
+			}
+		}
+
+		return true
+	}
+
+	if o.which != eAry && !o.tryAry() {
+		return false
+	}
+
+	if len(n.ary) != len(o.ary) {
+		return false
+	}
+
+	for idx, val := range n.ary {
+		if !val.equal(o.ary[idx]) {
+			return false
+		}
+	}
+
+	return true
+}
+
+// Kind reads the "op" field of the Operation.
+func (o Operation) Kind() string {
+	if obj, ok := o["op"]; ok && obj != nil {
+		var op string
+
+		err := json.Unmarshal(*obj, &op)
+
+		if err != nil {
+			return "unknown"
+		}
+
+		return op
+	}
+
+	return "unknown"
+}
+
+// Path reads the "path" field of the Operation.
+func (o Operation) Path() (string, error) {
+	if obj, ok := o["path"]; ok && obj != nil {
+		var op string
+
+		err := json.Unmarshal(*obj, &op)
+
+		if err != nil {
+			return "unknown", err
+		}
+
+		return op, nil
+	}
+
+	return "unknown", errors.Wrapf(ErrMissing, "operation missing path field")
+}
+
+// From reads the "from" field of the Operation.
+func (o Operation) From() (string, error) {
+	if obj, ok := o["from"]; ok && obj != nil {
+		var op string
+
+		err := json.Unmarshal(*obj, &op)
+
+		if err != nil {
+			return "unknown", err
+		}
+
+		return op, nil
+	}
+
+	return "unknown", errors.Wrapf(ErrMissing, "operation, missing from field")
+}
+
+func (o Operation) value() *lazyNode {
+	if obj, ok := o["value"]; ok {
+		return newLazyNode(obj)
+	}
+
+	return nil
+}
+
+// ValueInterface decodes the operation value into an interface.
+func (o Operation) ValueInterface() (interface{}, error) {
+	if obj, ok := o["value"]; ok && obj != nil {
+		var v interface{}
+
+		err := json.Unmarshal(*obj, &v)
+
+		if err != nil {
+			return nil, err
+		}
+
+		return v, nil
+	}
+
+	return nil, errors.Wrapf(ErrMissing, "operation, missing value field")
+}
+
+func isArray(buf []byte) bool {
+Loop:
+	for _, c := range buf {
+		switch c {
+		case ' ':
+		case '\n':
+		case '\t':
+			continue
+		case '[':
+			return true
+		default:
+			break Loop
+		}
+	}
+
+	return false
+}
+
+func findObject(pd *container, path string, options *ApplyOptions) (container, string) {
+	doc := *pd
+
+	split := strings.Split(path, "/")
+
+	if len(split) < 2 {
+		return nil, ""
+	}
+
+	parts := split[1 : len(split)-1]
+
+	key := split[len(split)-1]
+
+	var err error
+
+	for _, part := range parts {
+
+		next, ok := doc.get(decodePatchKey(part), options)
+
+		if next == nil || ok != nil {
+			return nil, ""
+		}
+
+		if isArray(*next.raw) {
+			doc, err = next.intoAry()
+
+			if err != nil {
+				return nil, ""
+			}
+		} else {
+			doc, err = next.intoDoc()
+
+			if err != nil {
+				return nil, ""
+			}
+		}
+	}
+
+	return doc, decodePatchKey(key)
+}
+
+func (d *partialDoc) set(key string, val *lazyNode, options *ApplyOptions) error {
+	found := false
+	for _, k := range d.keys {
+		if k == key {
+			found = true
+			break
+		}
+	}
+	if !found {
+		d.keys = append(d.keys, key)
+	}
+	d.obj[key] = val
+	return nil
+}
+
+func (d *partialDoc) add(key string, val *lazyNode, options *ApplyOptions) error {
+	return d.set(key, val, options)
+}
+
+func (d *partialDoc) get(key string, options *ApplyOptions) (*lazyNode, error) {
+	v, ok := d.obj[key]
+	if !ok {
+		return v, errors.Wrapf(ErrMissing, "unable to get nonexistent key: %s", key)
+	}
+	return v, nil
+}
+
+func (d *partialDoc) remove(key string, options *ApplyOptions) error {
+	_, ok := d.obj[key]
+	if !ok {
+		if options.AllowMissingPathOnRemove {
+			return nil
+		}
+		return errors.Wrapf(ErrMissing, "unable to remove nonexistent key: %s", key)
+	}
+	idx := -1
+	for i, k := range d.keys {
+		if k == key {
+			idx = i
+			break
+		}
+	}
+	d.keys = append(d.keys[0:idx], d.keys[idx+1:]...)
+	delete(d.obj, key)
+	return nil
+}
+
+// set should only be used to implement the "replace" operation, so "key" must
+// be an already existing index in "d".
+func (d *partialArray) set(key string, val *lazyNode, options *ApplyOptions) error {
+	idx, err := strconv.Atoi(key)
+	if err != nil {
+		return err
+	}
+
+	if idx < 0 {
+		if !options.SupportNegativeIndices {
+			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		if idx < -len(*d) {
+			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		idx += len(*d)
+	}
+
+	(*d)[idx] = val
+	return nil
+}
+
+func (d *partialArray) add(key string, val *lazyNode, options *ApplyOptions) error {
+	if key == "-" {
+		*d = append(*d, val)
+		return nil
+	}
+
+	idx, err := strconv.Atoi(key)
+	if err != nil {
+		return errors.Wrapf(err, "value was not a proper array index: '%s'", key)
+	}
+
+	sz := len(*d) + 1
+
+	ary := make([]*lazyNode, sz)
+
+	cur := *d
+
+	if idx >= len(ary) {
+		return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+	}
+
+	if idx < 0 {
+		if !options.SupportNegativeIndices {
+			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		if idx < -len(ary) {
+			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		idx += len(ary)
+	}
+
+	copy(ary[0:idx], cur[0:idx])
+	ary[idx] = val
+	copy(ary[idx+1:], cur[idx:])
+
+	*d = ary
+	return nil
+}
+
+func (d *partialArray) get(key string, options *ApplyOptions) (*lazyNode, error) {
+	idx, err := strconv.Atoi(key)
+
+	if err != nil {
+		return nil, err
+	}
+
+	if idx < 0 {
+		if !options.SupportNegativeIndices {
+			return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		if idx < -len(*d) {
+			return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		idx += len(*d)
+	}
+
+	if idx >= len(*d) {
+		return nil, errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+	}
+
+	return (*d)[idx], nil
+}
+
+func (d *partialArray) remove(key string, options *ApplyOptions) error {
+	idx, err := strconv.Atoi(key)
+	if err != nil {
+		return err
+	}
+
+	cur := *d
+
+	if idx >= len(cur) {
+		if options.AllowMissingPathOnRemove {
+			return nil
+		}
+		return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+	}
+
+	if idx < 0 {
+		if !options.SupportNegativeIndices {
+			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		if idx < -len(cur) {
+			if options.AllowMissingPathOnRemove {
+				return nil
+			}
+			return errors.Wrapf(ErrInvalidIndex, "Unable to access invalid index: %d", idx)
+		}
+		idx += len(cur)
+	}
+
+	ary := make([]*lazyNode, len(cur)-1)
+
+	copy(ary[0:idx], cur[0:idx])
+	copy(ary[idx:], cur[idx+1:])
+
+	*d = ary
+	return nil
+}
+
+func (p Patch) add(doc *container, op Operation, options *ApplyOptions) error {
+	path, err := op.Path()
+	if err != nil {
+		return errors.Wrapf(ErrMissing, "add operation failed to decode path")
+	}
+
+	if options.EnsurePathExistsOnAdd {
+		err = ensurePathExists(doc, path, options)
+
+		if err != nil {
+			return err
+		}
+	}
+
+	con, key := findObject(doc, path, options)
+
+	if con == nil {
+		return errors.Wrapf(ErrMissing, "add operation does not apply: doc is missing path: \"%s\"", path)
+	}
+
+	err = con.add(key, op.value(), options)
+	if err != nil {
+		return errors.Wrapf(err, "error in add for path: '%s'", path)
+	}
+
+	return nil
+}
+
+// Given a document and a path to a key, walk the path and create all missing elements
+// creating objects and arrays as needed.
+func ensurePathExists(pd *container, path string, options *ApplyOptions) error {
+	doc := *pd
+
+	var err error
+	var arrIndex int
+
+	split := strings.Split(path, "/")
+
+	if len(split) < 2 {
+		return nil
+	}
+
+	parts := split[1:]
+
+	for pi, part := range parts {
+
+		// Have we reached the key part of the path?
+		// If yes, we're done.
+		if pi == len(parts)-1 {
+			return nil
+		}
+
+		target, ok := doc.get(decodePatchKey(part), options)
+
+		if target == nil || ok != nil {
+
+			// If the current container is an array which has fewer elements than our target index,
+			// pad the current container with nulls.
+			if arrIndex, err = strconv.Atoi(part); err == nil {
+				pa, ok := doc.(*partialArray)
+
+				if ok && arrIndex >= len(*pa)+1 {
+					// Pad the array with null values up to the required index.
+					for i := len(*pa); i <= arrIndex-1; i++ {
+						doc.add(strconv.Itoa(i), newLazyNode(newRawMessage(rawJSONNull)), options)
+					}
+				}
+			}
+
+			// Check if the next part is a numeric index or "-".
+			// If yes, then create an array, otherwise, create an object.
+			if arrIndex, err = strconv.Atoi(parts[pi+1]); err == nil || parts[pi+1] == "-" {
+				if arrIndex < 0 {
+
+					if !options.SupportNegativeIndices {
+						return errors.Wrapf(ErrInvalidIndex, "Unable to ensure path for invalid index: %d", arrIndex)
+					}
+
+					if arrIndex < -1 {
+						return errors.Wrapf(ErrInvalidIndex, "Unable to ensure path for negative index other than -1: %d", arrIndex)
+					}
+
+					arrIndex = 0
+				}
+
+				newNode := newLazyNode(newRawMessage(rawJSONArray))
+				doc.add(part, newNode, options)
+				doc, _ = newNode.intoAry()
+
+				// Pad the new array with null values up to the required index.
+				for i := 0; i < arrIndex; i++ {
+					doc.add(strconv.Itoa(i), newLazyNode(newRawMessage(rawJSONNull)), options)
+				}
+			} else {
+				newNode := newLazyNode(newRawMessage(rawJSONObject))
+
+				doc.add(part, newNode, options)
+				doc, _ = newNode.intoDoc()
+			}
+		} else {
+			if isArray(*target.raw) {
+				doc, err = target.intoAry()
+
+				if err != nil {
+					return err
+				}
+			} else {
+				doc, err = target.intoDoc()
+
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+func (p Patch) remove(doc *container, op Operation, options *ApplyOptions) error {
+	path, err := op.Path()
+	if err != nil {
+		return errors.Wrapf(ErrMissing, "remove operation failed to decode path")
+	}
+
+	con, key := findObject(doc, path, options)
+
+	if con == nil {
+		if options.AllowMissingPathOnRemove {
+			return nil
+		}
+		return errors.Wrapf(ErrMissing, "remove operation does not apply: doc is missing path: \"%s\"", path)
+	}
+
+	err = con.remove(key, options)
+	if err != nil {
+		return errors.Wrapf(err, "error in remove for path: '%s'", path)
+	}
+
+	return nil
+}
+
+func (p Patch) replace(doc *container, op Operation, options *ApplyOptions) error {
+	path, err := op.Path()
+	if err != nil {
+		return errors.Wrapf(err, "replace operation failed to decode path")
+	}
+
+	if path == "" {
+		val := op.value()
+
+		if val.which == eRaw {
+			if !val.tryDoc() {
+				if !val.tryAry() {
+					return errors.Wrapf(err, "replace operation value must be object or array")
+				}
+			}
+		}
+
+		switch val.which {
+		case eAry:
+			*doc = &val.ary
+		case eDoc:
+			*doc = val.doc
+		case eRaw:
+			return errors.Wrapf(err, "replace operation hit impossible case")
+		}
+
+		return nil
+	}
+
+	con, key := findObject(doc, path, options)
+
+	if con == nil {
+		return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing path: %s", path)
+	}
+
+	_, ok := con.get(key, options)
+	if ok != nil {
+		return errors.Wrapf(ErrMissing, "replace operation does not apply: doc is missing key: %s", path)
+	}
+
+	err = con.set(key, op.value(), options)
+	if err != nil {
+		return errors.Wrapf(err, "error in remove for path: '%s'", path)
+	}
+
+	return nil
+}
+
+func (p Patch) move(doc *container, op Operation, options *ApplyOptions) error {
+	from, err := op.From()
+	if err != nil {
+		return errors.Wrapf(err, "move operation failed to decode from")
+	}
+
+	con, key := findObject(doc, from, options)
+
+	if con == nil {
+		return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing from path: %s", from)
+	}
+
+	val, err := con.get(key, options)
+	if err != nil {
+		return errors.Wrapf(err, "error in move for path: '%s'", key)
+	}
+
+	err = con.remove(key, options)
+	if err != nil {
+		return errors.Wrapf(err, "error in move for path: '%s'", key)
+	}
+
+	path, err := op.Path()
+	if err != nil {
+		return errors.Wrapf(err, "move operation failed to decode path")
+	}
+
+	con, key = findObject(doc, path, options)
+
+	if con == nil {
+		return errors.Wrapf(ErrMissing, "move operation does not apply: doc is missing destination path: %s", path)
+	}
+
+	err = con.add(key, val, options)
+	if err != nil {
+		return errors.Wrapf(err, "error in move for path: '%s'", path)
+	}
+
+	return nil
+}
+
+func (p Patch) test(doc *container, op Operation, options *ApplyOptions) error {
+	path, err := op.Path()
+	if err != nil {
+		return errors.Wrapf(err, "test operation failed to decode path")
+	}
+
+	if path == "" {
+		var self lazyNode
+
+		switch sv := (*doc).(type) {
+		case *partialDoc:
+			self.doc = sv
+			self.which = eDoc
+		case *partialArray:
+			self.ary = *sv
+			self.which = eAry
+		}
+
+		if self.equal(op.value()) {
+			return nil
+		}
+
+		return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
+	}
+
+	con, key := findObject(doc, path, options)
+
+	if con == nil {
+		return errors.Wrapf(ErrMissing, "test operation does not apply: is missing path: %s", path)
+	}
+
+	val, err := con.get(key, options)
+	if err != nil && errors.Cause(err) != ErrMissing {
+		return errors.Wrapf(err, "error in test for path: '%s'", path)
+	}
+
+	if val == nil {
+		if op.value().raw == nil {
+			return nil
+		}
+		return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
+	} else if op.value() == nil {
+		return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
+	}
+
+	if val.equal(op.value()) {
+		return nil
+	}
+
+	return errors.Wrapf(ErrTestFailed, "testing value %s failed", path)
+}
+
+func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64, options *ApplyOptions) error {
+	from, err := op.From()
+	if err != nil {
+		return errors.Wrapf(err, "copy operation failed to decode from")
+	}
+
+	con, key := findObject(doc, from, options)
+
+	if con == nil {
+		return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing from path: %s", from)
+	}
+
+	val, err := con.get(key, options)
+	if err != nil {
+		return errors.Wrapf(err, "error in copy for from: '%s'", from)
+	}
+
+	path, err := op.Path()
+	if err != nil {
+		return errors.Wrapf(ErrMissing, "copy operation failed to decode path")
+	}
+
+	con, key = findObject(doc, path, options)
+
+	if con == nil {
+		return errors.Wrapf(ErrMissing, "copy operation does not apply: doc is missing destination path: %s", path)
+	}
+
+	valCopy, sz, err := deepCopy(val)
+	if err != nil {
+		return errors.Wrapf(err, "error while performing deep copy")
+	}
+
+	(*accumulatedCopySize) += int64(sz)
+	if options.AccumulatedCopySizeLimit > 0 && *accumulatedCopySize > options.AccumulatedCopySizeLimit {
+		return NewAccumulatedCopySizeError(options.AccumulatedCopySizeLimit, *accumulatedCopySize)
+	}
+
+	err = con.add(key, valCopy, options)
+	if err != nil {
+		return errors.Wrapf(err, "error while adding value during copy")
+	}
+
+	return nil
+}
+
+// Equal indicates if 2 JSON documents have the same structural equality.
+func Equal(a, b []byte) bool {
+	la := newLazyNode(newRawMessage(a))
+	lb := newLazyNode(newRawMessage(b))
+
+	return la.equal(lb)
+}
+
+// DecodePatch decodes the passed JSON document as an RFC 6902 patch.
+func DecodePatch(buf []byte) (Patch, error) {
+	var p Patch
+
+	err := json.Unmarshal(buf, &p)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+// Apply mutates a JSON document according to the patch, and returns the new
+// document.
+func (p Patch) Apply(doc []byte) ([]byte, error) {
+	return p.ApplyWithOptions(doc, NewApplyOptions())
+}
+
+// ApplyWithOptions mutates a JSON document according to the patch and the passed in ApplyOptions.
+// It returns the new document.
+func (p Patch) ApplyWithOptions(doc []byte, options *ApplyOptions) ([]byte, error) {
+	return p.ApplyIndentWithOptions(doc, "", options)
+}
+
+// ApplyIndent mutates a JSON document according to the patch, and returns the new
+// document indented.
+func (p Patch) ApplyIndent(doc []byte, indent string) ([]byte, error) {
+	return p.ApplyIndentWithOptions(doc, indent, NewApplyOptions())
+}
+
+// ApplyIndentWithOptions mutates a JSON document according to the patch and the passed in ApplyOptions.
+// It returns the new document indented.
+func (p Patch) ApplyIndentWithOptions(doc []byte, indent string, options *ApplyOptions) ([]byte, error) {
+	if len(doc) == 0 {
+		return doc, nil
+	}
+
+	var pd container
+	if doc[0] == '[' {
+		pd = &partialArray{}
+	} else {
+		pd = &partialDoc{}
+	}
+
+	err := json.Unmarshal(doc, pd)
+
+	if err != nil {
+		return nil, err
+	}
+
+	err = nil
+
+	var accumulatedCopySize int64
+
+	for _, op := range p {
+		switch op.Kind() {
+		case "add":
+			err = p.add(&pd, op, options)
+		case "remove":
+			err = p.remove(&pd, op, options)
+		case "replace":
+			err = p.replace(&pd, op, options)
+		case "move":
+			err = p.move(&pd, op, options)
+		case "test":
+			err = p.test(&pd, op, options)
+		case "copy":
+			err = p.copy(&pd, op, &accumulatedCopySize, options)
+		default:
+			err = fmt.Errorf("Unexpected kind: %s", op.Kind())
+		}
+
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if indent != "" {
+		return json.MarshalIndent(pd, "", indent)
+	}
+
+	return json.Marshal(pd)
+}
+
+// From http://tools.ietf.org/html/rfc6901#section-4 :
+//
+// Evaluation of each reference token begins by decoding any escaped
+// character sequence.  This is performed by first transforming any
+// occurrence of the sequence '~1' to '/', and then transforming any
+// occurrence of the sequence '~0' to '~'.
+
+var (
+	rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
+)
+
+func decodePatchKey(k string) string {
+	return rfc6901Decoder.Replace(k)
+}
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
deleted file mode 100644
index c49a75651..000000000
--- a/vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package cmpopts provides common options for the cmp package.
-package cmpopts
-
-import (
-	"errors"
-	"math"
-	"reflect"
-	"time"
-
-	"github.com/google/go-cmp/cmp"
-)
-
-func equateAlways(_, _ interface{}) bool { return true }
-
-// EquateEmpty returns a Comparer option that determines all maps and slices
-// with a length of zero to be equal, regardless of whether they are nil.
-//
-// EquateEmpty can be used in conjunction with SortSlices and SortMaps.
-func EquateEmpty() cmp.Option {
-	return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways))
-}
-
-func isEmpty(x, y interface{}) bool {
-	vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
-	return (x != nil && y != nil && vx.Type() == vy.Type()) &&
-		(vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) &&
-		(vx.Len() == 0 && vy.Len() == 0)
-}
-
-// EquateApprox returns a Comparer option that determines float32 or float64
-// values to be equal if they are within a relative fraction or absolute margin.
-// This option is not used when either x or y is NaN or infinite.
-//
-// The fraction determines that the difference of two values must be within the
-// smaller fraction of the two values, while the margin determines that the two
-// values must be within some absolute margin.
-// To express only a fraction or only a margin, use 0 for the other parameter.
-// The fraction and margin must be non-negative.
-//
-// The mathematical expression used is equivalent to:
-//	|x-y| ≤ max(fraction*min(|x|, |y|), margin)
-//
-// EquateApprox can be used in conjunction with EquateNaNs.
-func EquateApprox(fraction, margin float64) cmp.Option {
-	if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) {
-		panic("margin or fraction must be a non-negative number")
-	}
-	a := approximator{fraction, margin}
-	return cmp.Options{
-		cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)),
-		cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)),
-	}
-}
-
-type approximator struct{ frac, marg float64 }
-
-func areRealF64s(x, y float64) bool {
-	return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0)
-}
-func areRealF32s(x, y float32) bool {
-	return areRealF64s(float64(x), float64(y))
-}
-func (a approximator) compareF64(x, y float64) bool {
-	relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y))
-	return math.Abs(x-y) <= math.Max(a.marg, relMarg)
-}
-func (a approximator) compareF32(x, y float32) bool {
-	return a.compareF64(float64(x), float64(y))
-}
-
-// EquateNaNs returns a Comparer option that determines float32 and float64
-// NaN values to be equal.
-//
-// EquateNaNs can be used in conjunction with EquateApprox.
-func EquateNaNs() cmp.Option {
-	return cmp.Options{
-		cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)),
-		cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)),
-	}
-}
-
-func areNaNsF64s(x, y float64) bool {
-	return math.IsNaN(x) && math.IsNaN(y)
-}
-func areNaNsF32s(x, y float32) bool {
-	return areNaNsF64s(float64(x), float64(y))
-}
-
-// EquateApproxTime returns a Comparer option that determines two non-zero
-// time.Time values to be equal if they are within some margin of one another.
-// If both times have a monotonic clock reading, then the monotonic time
-// difference will be used. The margin must be non-negative.
-func EquateApproxTime(margin time.Duration) cmp.Option {
-	if margin < 0 {
-		panic("margin must be a non-negative number")
-	}
-	a := timeApproximator{margin}
-	return cmp.FilterValues(areNonZeroTimes, cmp.Comparer(a.compare))
-}
-
-func areNonZeroTimes(x, y time.Time) bool {
-	return !x.IsZero() && !y.IsZero()
-}
-
-type timeApproximator struct {
-	margin time.Duration
-}
-
-func (a timeApproximator) compare(x, y time.Time) bool {
-	// Avoid subtracting times to avoid overflow when the
-	// difference is larger than the largest representable duration.
-	if x.After(y) {
-		// Ensure x is always before y
-		x, y = y, x
-	}
-	// We're within the margin if x+margin >= y.
-	// Note: time.Time doesn't have AfterOrEqual method hence the negation.
-	return !x.Add(a.margin).Before(y)
-}
-
-// AnyError is an error that matches any non-nil error.
-var AnyError anyError
-
-type anyError struct{}
-
-func (anyError) Error() string     { return "any error" }
-func (anyError) Is(err error) bool { return err != nil }
-
-// EquateErrors returns a Comparer option that determines errors to be equal
-// if errors.Is reports them to match. The AnyError error can be used to
-// match any non-nil error.
-func EquateErrors() cmp.Option {
-	return cmp.FilterValues(areConcreteErrors, cmp.Comparer(compareErrors))
-}
-
-// areConcreteErrors reports whether x and y are types that implement error.
-// The input types are deliberately of the interface{} type rather than the
-// error type so that we can handle situations where the current type is an
-// interface{}, but the underlying concrete types both happen to implement
-// the error interface.
-func areConcreteErrors(x, y interface{}) bool {
-	_, ok1 := x.(error)
-	_, ok2 := y.(error)
-	return ok1 && ok2
-}
-
-func compareErrors(x, y interface{}) bool {
-	xe := x.(error)
-	ye := y.(error)
-	return errors.Is(xe, ye) || errors.Is(ye, xe)
-}
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go
deleted file mode 100644
index 80c60617e..000000000
--- a/vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cmpopts
-
-import (
-	"fmt"
-	"reflect"
-	"unicode"
-	"unicode/utf8"
-
-	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-cmp/cmp/internal/function"
-)
-
-// IgnoreFields returns an Option that ignores fields of the
-// given names on a single struct type. It respects the names of exported fields
-// that are forwarded due to struct embedding.
-// The struct type is specified by passing in a value of that type.
-//
-// The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a
-// specific sub-field that is embedded or nested within the parent struct.
-func IgnoreFields(typ interface{}, names ...string) cmp.Option {
-	sf := newStructFilter(typ, names...)
-	return cmp.FilterPath(sf.filter, cmp.Ignore())
-}
-
-// IgnoreTypes returns an Option that ignores all values assignable to
-// certain types, which are specified by passing in a value of each type.
-func IgnoreTypes(typs ...interface{}) cmp.Option {
-	tf := newTypeFilter(typs...)
-	return cmp.FilterPath(tf.filter, cmp.Ignore())
-}
-
-type typeFilter []reflect.Type
-
-func newTypeFilter(typs ...interface{}) (tf typeFilter) {
-	for _, typ := range typs {
-		t := reflect.TypeOf(typ)
-		if t == nil {
-			// This occurs if someone tries to pass in sync.Locker(nil)
-			panic("cannot determine type; consider using IgnoreInterfaces")
-		}
-		tf = append(tf, t)
-	}
-	return tf
-}
-func (tf typeFilter) filter(p cmp.Path) bool {
-	if len(p) < 1 {
-		return false
-	}
-	t := p.Last().Type()
-	for _, ti := range tf {
-		if t.AssignableTo(ti) {
-			return true
-		}
-	}
-	return false
-}
-
-// IgnoreInterfaces returns an Option that ignores all values or references of
-// values assignable to certain interface types. These interfaces are specified
-// by passing in an anonymous struct with the interface types embedded in it.
-// For example, to ignore sync.Locker, pass in struct{sync.Locker}{}.
-func IgnoreInterfaces(ifaces interface{}) cmp.Option {
-	tf := newIfaceFilter(ifaces)
-	return cmp.FilterPath(tf.filter, cmp.Ignore())
-}
-
-type ifaceFilter []reflect.Type
-
-func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) {
-	t := reflect.TypeOf(ifaces)
-	if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct {
-		panic("input must be an anonymous struct")
-	}
-	for i := 0; i < t.NumField(); i++ {
-		fi := t.Field(i)
-		switch {
-		case !fi.Anonymous:
-			panic("struct cannot have named fields")
-		case fi.Type.Kind() != reflect.Interface:
-			panic("embedded field must be an interface type")
-		case fi.Type.NumMethod() == 0:
-			// This matches everything; why would you ever want this?
-			panic("cannot ignore empty interface")
-		default:
-			tf = append(tf, fi.Type)
-		}
-	}
-	return tf
-}
-func (tf ifaceFilter) filter(p cmp.Path) bool {
-	if len(p) < 1 {
-		return false
-	}
-	t := p.Last().Type()
-	for _, ti := range tf {
-		if t.AssignableTo(ti) {
-			return true
-		}
-		if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) {
-			return true
-		}
-	}
-	return false
-}
-
-// IgnoreUnexported returns an Option that only ignores the immediate unexported
-// fields of a struct, including anonymous fields of unexported types.
-// In particular, unexported fields within the struct's exported fields
-// of struct types, including anonymous fields, will not be ignored unless the
-// type of the field itself is also passed to IgnoreUnexported.
-//
-// Avoid ignoring unexported fields of a type which you do not control (i.e. a
-// type from another repository), as changes to the implementation of such types
-// may change how the comparison behaves. Prefer a custom Comparer instead.
-func IgnoreUnexported(typs ...interface{}) cmp.Option {
-	ux := newUnexportedFilter(typs...)
-	return cmp.FilterPath(ux.filter, cmp.Ignore())
-}
-
-type unexportedFilter struct{ m map[reflect.Type]bool }
-
-func newUnexportedFilter(typs ...interface{}) unexportedFilter {
-	ux := unexportedFilter{m: make(map[reflect.Type]bool)}
-	for _, typ := range typs {
-		t := reflect.TypeOf(typ)
-		if t == nil || t.Kind() != reflect.Struct {
-			panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
-		}
-		ux.m[t] = true
-	}
-	return ux
-}
-func (xf unexportedFilter) filter(p cmp.Path) bool {
-	sf, ok := p.Index(-1).(cmp.StructField)
-	if !ok {
-		return false
-	}
-	return xf.m[p.Index(-2).Type()] && !isExported(sf.Name())
-}
-
-// isExported reports whether the identifier is exported.
-func isExported(id string) bool {
-	r, _ := utf8.DecodeRuneInString(id)
-	return unicode.IsUpper(r)
-}
-
-// IgnoreSliceElements returns an Option that ignores elements of []V.
-// The discard function must be of the form "func(T) bool" which is used to
-// ignore slice elements of type V, where V is assignable to T.
-// Elements are ignored if the function reports true.
-func IgnoreSliceElements(discardFunc interface{}) cmp.Option {
-	vf := reflect.ValueOf(discardFunc)
-	if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() {
-		panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
-	}
-	return cmp.FilterPath(func(p cmp.Path) bool {
-		si, ok := p.Index(-1).(cmp.SliceIndex)
-		if !ok {
-			return false
-		}
-		if !si.Type().AssignableTo(vf.Type().In(0)) {
-			return false
-		}
-		vx, vy := si.Values()
-		if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() {
-			return true
-		}
-		if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() {
-			return true
-		}
-		return false
-	}, cmp.Ignore())
-}
-
-// IgnoreMapEntries returns an Option that ignores entries of map[K]V.
-// The discard function must be of the form "func(T, R) bool" which is used to
-// ignore map entries of type K and V, where K and V are assignable to T and R.
-// Entries are ignored if the function reports true.
-func IgnoreMapEntries(discardFunc interface{}) cmp.Option {
-	vf := reflect.ValueOf(discardFunc)
-	if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() {
-		panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
-	}
-	return cmp.FilterPath(func(p cmp.Path) bool {
-		mi, ok := p.Index(-1).(cmp.MapIndex)
-		if !ok {
-			return false
-		}
-		if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) {
-			return false
-		}
-		k := mi.Key()
-		vx, vy := mi.Values()
-		if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() {
-			return true
-		}
-		if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() {
-			return true
-		}
-		return false
-	}, cmp.Ignore())
-}
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go
deleted file mode 100644
index a646d7475..000000000
--- a/vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cmpopts
-
-import (
-	"fmt"
-	"reflect"
-	"sort"
-
-	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-cmp/cmp/internal/function"
-)
-
-// SortSlices returns a Transformer option that sorts all []V.
-// The less function must be of the form "func(T, T) bool" which is used to
-// sort any slice with element type V that is assignable to T.
-//
-// The less function must be:
-//	• Deterministic: less(x, y) == less(x, y)
-//	• Irreflexive: !less(x, x)
-//	• Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
-//
-// The less function does not have to be "total". That is, if !less(x, y) and
-// !less(y, x) for two elements x and y, their relative order is maintained.
-//
-// SortSlices can be used in conjunction with EquateEmpty.
-func SortSlices(lessFunc interface{}) cmp.Option {
-	vf := reflect.ValueOf(lessFunc)
-	if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
-		panic(fmt.Sprintf("invalid less function: %T", lessFunc))
-	}
-	ss := sliceSorter{vf.Type().In(0), vf}
-	return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort))
-}
-
-type sliceSorter struct {
-	in  reflect.Type  // T
-	fnc reflect.Value // func(T, T) bool
-}
-
-func (ss sliceSorter) filter(x, y interface{}) bool {
-	vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
-	if !(x != nil && y != nil && vx.Type() == vy.Type()) ||
-		!(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) ||
-		(vx.Len() <= 1 && vy.Len() <= 1) {
-		return false
-	}
-	// Check whether the slices are already sorted to avoid an infinite
-	// recursion cycle applying the same transform to itself.
-	ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) })
-	ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) })
-	return !ok1 || !ok2
-}
-func (ss sliceSorter) sort(x interface{}) interface{} {
-	src := reflect.ValueOf(x)
-	dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len())
-	for i := 0; i < src.Len(); i++ {
-		dst.Index(i).Set(src.Index(i))
-	}
-	sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) })
-	ss.checkSort(dst)
-	return dst.Interface()
-}
-func (ss sliceSorter) checkSort(v reflect.Value) {
-	start := -1 // Start of a sequence of equal elements.
-	for i := 1; i < v.Len(); i++ {
-		if ss.less(v, i-1, i) {
-			// Check that first and last elements in v[start:i] are equal.
-			if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) {
-				panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i)))
-			}
-			start = -1
-		} else if start == -1 {
-			start = i
-		}
-	}
-}
-func (ss sliceSorter) less(v reflect.Value, i, j int) bool {
-	vx, vy := v.Index(i), v.Index(j)
-	return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
-}
-
-// SortMaps returns a Transformer option that flattens map[K]V types to be a
-// sorted []struct{K, V}. The less function must be of the form
-// "func(T, T) bool" which is used to sort any map with key K that is
-// assignable to T.
-//
-// Flattening the map into a slice has the property that cmp.Equal is able to
-// use Comparers on K or the K.Equal method if it exists.
-//
-// The less function must be:
-//	• Deterministic: less(x, y) == less(x, y)
-//	• Irreflexive: !less(x, x)
-//	• Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
-//	• Total: if x != y, then either less(x, y) or less(y, x)
-//
-// SortMaps can be used in conjunction with EquateEmpty.
-func SortMaps(lessFunc interface{}) cmp.Option {
-	vf := reflect.ValueOf(lessFunc)
-	if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
-		panic(fmt.Sprintf("invalid less function: %T", lessFunc))
-	}
-	ms := mapSorter{vf.Type().In(0), vf}
-	return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort))
-}
-
-type mapSorter struct {
-	in  reflect.Type  // T
-	fnc reflect.Value // func(T, T) bool
-}
-
-func (ms mapSorter) filter(x, y interface{}) bool {
-	vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
-	return (x != nil && y != nil && vx.Type() == vy.Type()) &&
-		(vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) &&
-		(vx.Len() != 0 || vy.Len() != 0)
-}
-func (ms mapSorter) sort(x interface{}) interface{} {
-	src := reflect.ValueOf(x)
-	outType := reflect.StructOf([]reflect.StructField{
-		{Name: "K", Type: src.Type().Key()},
-		{Name: "V", Type: src.Type().Elem()},
-	})
-	dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len())
-	for i, k := range src.MapKeys() {
-		v := reflect.New(outType).Elem()
-		v.Field(0).Set(k)
-		v.Field(1).Set(src.MapIndex(k))
-		dst.Index(i).Set(v)
-	}
-	sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) })
-	ms.checkSort(dst)
-	return dst.Interface()
-}
-func (ms mapSorter) checkSort(v reflect.Value) {
-	for i := 1; i < v.Len(); i++ {
-		if !ms.less(v, i-1, i) {
-			panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i)))
-		}
-	}
-}
-func (ms mapSorter) less(v reflect.Value, i, j int) bool {
-	vx, vy := v.Index(i).Field(0), v.Index(j).Field(0)
-	return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
-}
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go
deleted file mode 100644
index a09829c3a..000000000
--- a/vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2017, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cmpopts
-
-import (
-	"fmt"
-	"reflect"
-	"strings"
-
-	"github.com/google/go-cmp/cmp"
-)
-
-// filterField returns a new Option where opt is only evaluated on paths that
-// include a specific exported field on a single struct type.
-// The struct type is specified by passing in a value of that type.
-//
-// The name may be a dot-delimited string (e.g., "Foo.Bar") to select a
-// specific sub-field that is embedded or nested within the parent struct.
-func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option {
-	// TODO: This is currently unexported over concerns of how helper filters
-	// can be composed together easily.
-	// TODO: Add tests for FilterField.
-
-	sf := newStructFilter(typ, name)
-	return cmp.FilterPath(sf.filter, opt)
-}
-
-type structFilter struct {
-	t  reflect.Type // The root struct type to match on
-	ft fieldTree    // Tree of fields to match on
-}
-
-func newStructFilter(typ interface{}, names ...string) structFilter {
-	// TODO: Perhaps allow * as a special identifier to allow ignoring any
-	// number of path steps until the next field match?
-	// This could be useful when a concrete struct gets transformed into
-	// an anonymous struct where it is not possible to specify that by type,
-	// but the transformer happens to provide guarantees about the names of
-	// the transformed fields.
-
-	t := reflect.TypeOf(typ)
-	if t == nil || t.Kind() != reflect.Struct {
-		panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
-	}
-	var ft fieldTree
-	for _, name := range names {
-		cname, err := canonicalName(t, name)
-		if err != nil {
-			panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err))
-		}
-		ft.insert(cname)
-	}
-	return structFilter{t, ft}
-}
-
-func (sf structFilter) filter(p cmp.Path) bool {
-	for i, ps := range p {
-		if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) {
-			return true
-		}
-	}
-	return false
-}
-
-// fieldTree represents a set of dot-separated identifiers.
-//
-// For example, inserting the following selectors:
-//	Foo
-//	Foo.Bar.Baz
-//	Foo.Buzz
-//	Nuka.Cola.Quantum
-//
-// Results in a tree of the form:
-//	{sub: {
-//		"Foo": {ok: true, sub: {
-//			"Bar": {sub: {
-//				"Baz": {ok: true},
-//			}},
-//			"Buzz": {ok: true},
-//		}},
-//		"Nuka": {sub: {
-//			"Cola": {sub: {
-//				"Quantum": {ok: true},
-//			}},
-//		}},
-//	}}
-type fieldTree struct {
-	ok  bool                 // Whether this is a specified node
-	sub map[string]fieldTree // The sub-tree of fields under this node
-}
-
-// insert inserts a sequence of field accesses into the tree.
-func (ft *fieldTree) insert(cname []string) {
-	if ft.sub == nil {
-		ft.sub = make(map[string]fieldTree)
-	}
-	if len(cname) == 0 {
-		ft.ok = true
-		return
-	}
-	sub := ft.sub[cname[0]]
-	sub.insert(cname[1:])
-	ft.sub[cname[0]] = sub
-}
-
-// matchPrefix reports whether any selector in the fieldTree matches
-// the start of path p.
-func (ft fieldTree) matchPrefix(p cmp.Path) bool {
-	for _, ps := range p {
-		switch ps := ps.(type) {
-		case cmp.StructField:
-			ft = ft.sub[ps.Name()]
-			if ft.ok {
-				return true
-			}
-			if len(ft.sub) == 0 {
-				return false
-			}
-		case cmp.Indirect:
-		default:
-			return false
-		}
-	}
-	return false
-}
-
-// canonicalName returns a list of identifiers where any struct field access
-// through an embedded field is expanded to include the names of the embedded
-// types themselves.
-//
-// For example, suppose field "Foo" is not directly in the parent struct,
-// but actually from an embedded struct of type "Bar". Then, the canonical name
-// of "Foo" is actually "Bar.Foo".
-//
-// Suppose field "Foo" is not directly in the parent struct, but actually
-// a field in two different embedded structs of types "Bar" and "Baz".
-// Then the selector "Foo" causes a panic since it is ambiguous which one it
-// refers to. The user must specify either "Bar.Foo" or "Baz.Foo".
-func canonicalName(t reflect.Type, sel string) ([]string, error) {
-	var name string
-	sel = strings.TrimPrefix(sel, ".")
-	if sel == "" {
-		return nil, fmt.Errorf("name must not be empty")
-	}
-	if i := strings.IndexByte(sel, '.'); i < 0 {
-		name, sel = sel, ""
-	} else {
-		name, sel = sel[:i], sel[i:]
-	}
-
-	// Type must be a struct or pointer to struct.
-	if t.Kind() == reflect.Ptr {
-		t = t.Elem()
-	}
-	if t.Kind() != reflect.Struct {
-		return nil, fmt.Errorf("%v must be a struct", t)
-	}
-
-	// Find the canonical name for this current field name.
-	// If the field exists in an embedded struct, then it will be expanded.
-	sf, _ := t.FieldByName(name)
-	if !isExported(name) {
-		// Avoid using reflect.Type.FieldByName for unexported fields due to
-		// buggy behavior with regard to embeddeding and unexported fields.
-		// See https://golang.org/issue/4876 for details.
-		sf = reflect.StructField{}
-		for i := 0; i < t.NumField() && sf.Name == ""; i++ {
-			if t.Field(i).Name == name {
-				sf = t.Field(i)
-			}
-		}
-	}
-	if sf.Name == "" {
-		return []string{name}, fmt.Errorf("does not exist")
-	}
-	var ss []string
-	for i := range sf.Index {
-		ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name)
-	}
-	if sel == "" {
-		return ss, nil
-	}
-	ssPost, err := canonicalName(sf.Type, sel)
-	return append(ss, ssPost...), err
-}
diff --git a/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go b/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go
deleted file mode 100644
index 4eb49d63d..000000000
--- a/vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018, The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cmpopts
-
-import (
-	"github.com/google/go-cmp/cmp"
-)
-
-type xformFilter struct{ xform cmp.Option }
-
-func (xf xformFilter) filter(p cmp.Path) bool {
-	for _, ps := range p {
-		if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform {
-			return false
-		}
-	}
-	return true
-}
-
-// AcyclicTransformer returns a Transformer with a filter applied that ensures
-// that the transformer cannot be recursively applied upon its own output.
-//
-// An example use case is a transformer that splits a string by lines:
-//	AcyclicTransformer("SplitLines", func(s string) []string{
-//		return strings.Split(s, "\n")
-//	})
-//
-// Had this been an unfiltered Transformer instead, this would result in an
-// infinite cycle converting a string to []string to [][]string and so on.
-func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option {
-	xf := xformFilter{cmp.Transformer(name, xformFunc)}
-	return cmp.FilterPath(xf.filter, xf.xform)
-}
diff --git a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_proto.go b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_proto.go
index 6dd6d8999..ab68181e9 100644
--- a/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_proto.go
+++ b/vendor/k8s.io/apimachinery/pkg/apis/meta/v1/micro_time_proto.go
@@ -27,9 +27,12 @@ func (m *MicroTime) ProtoMicroTime() *Timestamp {
 	if m == nil {
 		return &Timestamp{}
 	}
+
+	// truncate precision to microseconds to match JSON marshaling/unmarshaling
+	truncatedNanoseconds := time.Duration(m.Time.Nanosecond()).Truncate(time.Microsecond)
 	return &Timestamp{
 		Seconds: m.Time.Unix(),
-		Nanos:   int32(m.Time.Nanosecond()),
+		Nanos:   int32(truncatedNanoseconds),
 	}
 }
 
@@ -51,7 +54,10 @@ func (m *MicroTime) Unmarshal(data []byte) error {
 	if err := p.Unmarshal(data); err != nil {
 		return err
 	}
-	m.Time = time.Unix(p.Seconds, int64(p.Nanos)).Local()
+
+	// truncate precision to microseconds to match JSON marshaling/unmarshaling
+	truncatedNanoseconds := time.Duration(p.Nanos).Truncate(time.Microsecond)
+	m.Time = time.Unix(p.Seconds, int64(truncatedNanoseconds)).Local()
 	return nil
 }
 
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 940b08a33..0b18e6e91 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -133,10 +133,6 @@ github.com/containers/common/pkg/seccomp
 # github.com/cpuguy83/go-md2man/v2 v2.0.2
 ## explicit; go 1.11
 github.com/cpuguy83/go-md2man/v2/md2man
-# github.com/crossplane/crossplane-runtime v0.18.0
-## explicit; go 1.18
-github.com/crossplane/crossplane-runtime/apis/common/v1
-github.com/crossplane/crossplane-runtime/pkg/test
 # github.com/davecgh/go-spew v1.1.1
 ## explicit
 github.com/davecgh/go-spew/spew
@@ -210,6 +206,9 @@ github.com/emirpasic/gods/utils
 # github.com/evanphx/json-patch v5.6.0+incompatible
 ## explicit
 github.com/evanphx/json-patch
+# github.com/evanphx/json-patch/v5 v5.6.0
+## explicit; go 1.12
+github.com/evanphx/json-patch/v5
 # github.com/fatih/color v1.13.0
 ## explicit; go 1.13
 github.com/fatih/color
@@ -326,7 +325,6 @@ github.com/google/gnostic/openapiv3
 # github.com/google/go-cmp v0.5.8
 ## explicit; go 1.13
 github.com/google/go-cmp/cmp
-github.com/google/go-cmp/cmp/cmpopts
 github.com/google/go-cmp/cmp/internal/diff
 github.com/google/go-cmp/cmp/internal/flags
 github.com/google/go-cmp/cmp/internal/function
@@ -873,7 +871,7 @@ k8s.io/api/storage/v1beta1
 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1
-# k8s.io/apimachinery v0.25.3
+# k8s.io/apimachinery v0.25.4
 ## explicit; go 1.19
 k8s.io/apimachinery/pkg/api/equality
 k8s.io/apimachinery/pkg/api/errors
@@ -1110,7 +1108,7 @@ oras.land/oras-go/pkg/registry/remote/auth
 oras.land/oras-go/pkg/registry/remote/internal/errutil
 oras.land/oras-go/pkg/registry/remote/internal/syncutil
 oras.land/oras-go/pkg/target
-# sigs.k8s.io/controller-runtime v0.13.0 => sigs.k8s.io/controller-runtime v0.12.3
+# sigs.k8s.io/controller-runtime v0.13.0
 ## explicit; go 1.17
 sigs.k8s.io/controller-runtime
 sigs.k8s.io/controller-runtime/pkg/builder
@@ -1295,4 +1293,3 @@ sigs.k8s.io/zeitgeist/dependency
 sigs.k8s.io/zeitgeist/pkg/container
 sigs.k8s.io/zeitgeist/pkg/gitlab
 sigs.k8s.io/zeitgeist/upstream
-# sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.12.3
diff --git a/vendor/sigs.k8s.io/controller-runtime/.golangci.yml b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
index 77f528ff0..7d1d3665c 100644
--- a/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
+++ b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
@@ -12,7 +12,6 @@ linters:
   - goconst
   - gocritic
   - gocyclo
-  - godot
   - gofmt
   - goimports
   - goprintffuncname
@@ -61,9 +60,9 @@ linters-settings:
       - pkg: sigs.k8s.io/controller-runtime
         alias: ctrl
   staticcheck:
-    go: "1.18"
+    go: "1.19"
   stylecheck:
-    go: "1.18"
+    go: "1.19"
   depguard:
     include-go-root: true
     packages:
@@ -132,6 +131,9 @@ issues:
   - linters:
     - gosec
     text: "G304: Potential file inclusion via variable"
+  - linters:
+    - revive
+    text: "package-comments: should have a package comment"
 
 run:
   timeout: 10m
diff --git a/vendor/sigs.k8s.io/controller-runtime/RELEASE.md b/vendor/sigs.k8s.io/controller-runtime/RELEASE.md
new file mode 100644
index 000000000..134a73a31
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/RELEASE.md
@@ -0,0 +1,47 @@
+# Release Process
+
+The Kubernetes controller-runtime Project is released on an as-needed basis. The process is as follows:
+
+**Note:** Releases are done from the `release-MAJOR.MINOR` branches. For PATCH releases is not required
+to create a new branch you will just need to ensure that all big fixes are cherry-picked into the respective
+`release-MAJOR.MINOR` branch. To know more about versioning check https://semver.org/. 
+
+## How to do a release 
+
+### Create the new branch and the release tag
+
+1. Create a new branch `git checkout -b release-<MAJOR.MINOR>` from master
+2. Push the new branch to the remote repository
+
+### Now, let's generate the changelog
+
+1. Create the changelog from the new branch `release-<MAJOR.MINOR>` (`git checkout release-<MAJOR.MINOR>`). 
+You will need to use the [kubebuilder-release-tools][kubebuilder-release-tools] to generate the notes. See [here][release-notes-generation]
+
+> **Note**
+> - You will need to have checkout locally from the remote repository the previous branch
+> - Also, ensure that you fetch all tags from the remote `git fetch --all --tags`
+
+### Draft a new release from GitHub
+
+1. Create a new tag with the correct version from the new `release-<MAJOR.MINOR>` branch 
+2. Add the changelog on it and publish. Now, the code source is released !
+
+### Add a new Prow test the for the new branch release
+
+1. Create a new prow test under [github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/controller-runtime](https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/controller-runtime) 
+for the new `release-<MAJOR.MINOR>` branch. (i.e. for the `0.11.0` release see the PR: https://github.com/kubernetes/test-infra/pull/25205)
+2. Ping the infra PR in the controller-runtime slack channel for reviews.
+
+### Announce the new release:
+
+1. Publish on the Slack channel the new release, i.e:
+
+````
+:announce: Controller-Runtime v0.12.0 has been released!
+This release includes a Kubernetes dependency bump to v1.24.
+For more info, see the release page: https://github.com/kubernetes-sigs/controller-runtime/releases.
+ :tada:  Thanks to all our contributors!
+````
+
+2. An announcement email is sent to `kubebuilder@googlegroups.com` with the subject `[ANNOUNCE] Controller-Runtime $VERSION is released`
diff --git a/vendor/sigs.k8s.io/controller-runtime/doc.go b/vendor/sigs.k8s.io/controller-runtime/doc.go
index 9f260c4f7..fa6c532c4 100644
--- a/vendor/sigs.k8s.io/controller-runtime/doc.go
+++ b/vendor/sigs.k8s.io/controller-runtime/doc.go
@@ -23,13 +23,14 @@ limitations under the License.
 // and uncommon cases should be possible.  In general, controller-runtime tries
 // to guide users towards Kubernetes controller best-practices.
 //
-// Getting Started
+// # Getting Started
 //
 // The main entrypoint for controller-runtime is this root package, which
 // contains all of the common types needed to get started building controllers:
-//  import (
-//      ctrl "sigs.k8s.io/controller-runtime"
-//  )
+//
+//	import (
+//		ctrl "sigs.k8s.io/controller-runtime"
+//	)
 //
 // The examples in this package walk through a basic controller setup.  The
 // kubebuilder book (https://book.kubebuilder.io) has some more in-depth
@@ -38,7 +39,7 @@ limitations under the License.
 // controller-runtime favors structs with sane defaults over constructors, so
 // it's fairly common to see structs being used directly in controller-runtime.
 //
-// Organization
+// # Organization
 //
 // A brief-ish walkthrough of the layout of this library can be found below. Each
 // package contains more information about how to use it.
@@ -47,7 +48,7 @@ limitations under the License.
 // controllers can be found at
 // https://github.com/kubernetes-sigs/controller-runtime/blob/master/FAQ.md.
 //
-// Managers
+// # Managers
 //
 // Every controller and webhook is ultimately run by a Manager (pkg/manager). A
 // manager is responsible for running controllers and webhooks, and setting up
@@ -56,7 +57,7 @@ limitations under the License.
 // generally configured to gracefully shut down controllers on pod termination
 // by wiring up a signal handler (pkg/manager/signals).
 //
-// Controllers
+// # Controllers
 //
 // Controllers (pkg/controller) use events (pkg/event) to eventually trigger
 // reconcile requests.  They may be constructed manually, but are often
@@ -67,7 +68,7 @@ limitations under the License.
 // trigger reconciles.  There are pre-written utilities for the common cases, and
 // interfaces and helpers for advanced cases.
 //
-// Reconcilers
+// # Reconcilers
 //
 // Controller logic is implemented in terms of Reconcilers (pkg/reconcile).  A
 // Reconciler implements a function which takes a reconcile Request containing
@@ -75,7 +76,7 @@ limitations under the License.
 // and returns a Response or an error indicating whether to requeue for a
 // second round of processing.
 //
-// Clients and Caches
+// # Clients and Caches
 //
 // Reconcilers use Clients (pkg/client) to access API objects.  The default
 // client provided by the manager reads from a local shared cache (pkg/cache)
@@ -91,19 +92,19 @@ limitations under the License.
 // may retrieve event recorders (pkg/recorder) to emit events using the
 // manager.
 //
-// Schemes
+// # Schemes
 //
 // Clients, Caches, and many other things in Kubernetes use Schemes
 // (pkg/scheme) to associate Go types to Kubernetes API Kinds
 // (Group-Version-Kinds, to be specific).
 //
-// Webhooks
+// # Webhooks
 //
 // Similarly, webhooks (pkg/webhook/admission) may be implemented directly, but
 // are often constructed using a builder (pkg/webhook/admission/builder).  They
 // are run via a server (pkg/webhook) which is managed by a Manager.
 //
-// Logging and Metrics
+// # Logging and Metrics
 //
 // Logging (pkg/log) in controller-runtime is done via structured logs, using a
 // log set of interfaces called logr
@@ -117,7 +118,7 @@ limitations under the License.
 // serve these by an HTTP endpoint, and additional metrics may be registered to
 // this Registry as normal.
 //
-// Testing
+// # Testing
 //
 // You can easily build integration and unit tests for your controllers and
 // webhooks using the test Environment (pkg/envtest).  This will automatically
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go
index eedda4932..efaf06920 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go
@@ -315,13 +315,11 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
 			"controllerKind", gvk.Kind,
 		)
 
-		lowerCamelCaseKind := strings.ToLower(gvk.Kind[:1]) + gvk.Kind[1:]
-
 		ctrlOptions.LogConstructor = func(req *reconcile.Request) logr.Logger {
 			log := log
 			if req != nil {
 				log = log.WithValues(
-					lowerCamelCaseKind, klog.KRef(req.Namespace, req.Name),
+					gvk.Kind, klog.KRef(req.Namespace, req.Name),
 					"namespace", req.Namespace, "name", req.Name,
 				)
 			}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
index 18feb1cd7..534e6d64c 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
@@ -39,6 +39,7 @@ type WebhookBuilder struct {
 	gvk           schema.GroupVersionKind
 	mgr           manager.Manager
 	config        *rest.Config
+	recoverPanic  bool
 }
 
 // WebhookManagedBy allows inform its manager.Manager.
@@ -68,6 +69,12 @@ func (blder *WebhookBuilder) WithValidator(validator admission.CustomValidator)
 	return blder
 }
 
+// RecoverPanic indicates whether the panic caused by webhook should be recovered.
+func (blder *WebhookBuilder) RecoverPanic() *WebhookBuilder {
+	blder.recoverPanic = true
+	return blder
+}
+
 // Complete builds the webhook.
 func (blder *WebhookBuilder) Complete() error {
 	// Set the Config
@@ -124,10 +131,10 @@ func (blder *WebhookBuilder) registerDefaultingWebhook() {
 
 func (blder *WebhookBuilder) getDefaultingWebhook() *admission.Webhook {
 	if defaulter := blder.withDefaulter; defaulter != nil {
-		return admission.WithCustomDefaulter(blder.apiType, defaulter)
+		return admission.WithCustomDefaulter(blder.apiType, defaulter).WithRecoverPanic(blder.recoverPanic)
 	}
 	if defaulter, ok := blder.apiType.(admission.Defaulter); ok {
-		return admission.DefaultingWebhookFor(defaulter)
+		return admission.DefaultingWebhookFor(defaulter).WithRecoverPanic(blder.recoverPanic)
 	}
 	log.Info(
 		"skip registering a mutating webhook, object does not implement admission.Defaulter or WithDefaulter wasn't called",
@@ -153,10 +160,10 @@ func (blder *WebhookBuilder) registerValidatingWebhook() {
 
 func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook {
 	if validator := blder.withValidator; validator != nil {
-		return admission.WithCustomValidator(blder.apiType, validator)
+		return admission.WithCustomValidator(blder.apiType, validator).WithRecoverPanic(blder.recoverPanic)
 	}
 	if validator, ok := blder.apiType.(admission.Validator); ok {
-		return admission.ValidatingWebhookFor(validator)
+		return admission.ValidatingWebhookFor(validator).WithRecoverPanic(blder.recoverPanic)
 	}
 	log.Info(
 		"skip registering a validating webhook, object does not implement admission.Validator or WithValidator wasn't called",
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
index 2a8f53347..3ff41ffe6 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
@@ -170,10 +170,10 @@ func New(config *rest.Config, opts Options) (Cache, error) {
 // BuilderWithOptions returns a Cache constructor that will build the a cache
 // honoring the options argument, this is useful to specify options like
 // SelectorsByObject
-// WARNING: if SelectorsByObject is specified. filtered out resources are not
-//          returned.
-// WARNING: if UnsafeDisableDeepCopy is enabled, you must DeepCopy any object
-//          returned from cache get/list before mutating it.
+// WARNING: If SelectorsByObject is specified, filtered out resources are not
+// returned.
+// WARNING: If UnsafeDisableDeepCopy is enabled, you must DeepCopy any object
+// returned from cache get/list before mutating it.
 func BuilderWithOptions(options Options) NewCacheFunc {
 	return func(config *rest.Config, opts Options) (Cache, error) {
 		if options.Scheme == nil {
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
index ac07be2a6..08e4e6df5 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
@@ -51,7 +51,7 @@ type informerCache struct {
 }
 
 // Get implements Reader.
-func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object) error {
+func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error {
 	gvk, err := apiutil.GVKForObject(out, ip.Scheme)
 	if err != nil {
 		return err
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
index b95af18d7..9c2255123 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
@@ -54,7 +54,7 @@ type CacheReader struct {
 }
 
 // Get checks the indexer for the object and writes a copy of it if found.
-func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object) error {
+func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error {
 	if c.scopeName == apimeta.RESTScopeNameRoot {
 		key.Namespace = ""
 	}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
index 47a5bb3b3..64514c0c5 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
@@ -200,7 +200,7 @@ func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object,
 	return nil
 }
 
-func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
+func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
 	isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
 	if err != nil {
 		return err
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
index e6cc51c6e..8b7c1c4b6 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
@@ -17,7 +17,6 @@ limitations under the License.
 package apiutil
 
 import (
-	"errors"
 	"sync"
 	"sync/atomic"
 
@@ -145,7 +144,7 @@ func (drm *dynamicRESTMapper) init() (err error) {
 // checkAndReload attempts to call the given callback, which is assumed to be dependent
 // on the data in the restmapper.
 //
-// If the callback returns an error that matches the given error, it will attempt to reload
+// If the callback returns an error matching meta.IsNoMatchErr, it will attempt to reload
 // the RESTMapper's data and re-call the callback once that's occurred.
 // If the callback returns any other error, the function will return immediately regardless.
 //
@@ -154,7 +153,7 @@ func (drm *dynamicRESTMapper) init() (err error) {
 // the callback.
 // It's thread-safe, and worries about thread-safety for the callback (so the callback does
 // not need to attempt to lock the restmapper).
-func (drm *dynamicRESTMapper) checkAndReload(needsReloadErr error, checkNeedsReload func() error) error {
+func (drm *dynamicRESTMapper) checkAndReload(checkNeedsReload func() error) error {
 	// first, check the common path -- data is fresh enough
 	// (use an IIFE for the lock's defer)
 	err := func() error {
@@ -164,10 +163,7 @@ func (drm *dynamicRESTMapper) checkAndReload(needsReloadErr error, checkNeedsRel
 		return checkNeedsReload()
 	}()
 
-	// NB(directxman12): `Is` and `As` have a confusing relationship --
-	// `Is` is like `== or does this implement .Is`, whereas `As` says
-	// `can I type-assert into`
-	needsReload := errors.As(err, &needsReloadErr)
+	needsReload := meta.IsNoMatchError(err)
 	if !needsReload {
 		return err
 	}
@@ -178,7 +174,7 @@ func (drm *dynamicRESTMapper) checkAndReload(needsReloadErr error, checkNeedsRel
 
 	// ... and double-check that we didn't reload in the meantime
 	err = checkNeedsReload()
-	needsReload = errors.As(err, &needsReloadErr)
+	needsReload = meta.IsNoMatchError(err)
 	if !needsReload {
 		return err
 	}
@@ -206,7 +202,7 @@ func (drm *dynamicRESTMapper) KindFor(resource schema.GroupVersionResource) (sch
 		return schema.GroupVersionKind{}, err
 	}
 	var gvk schema.GroupVersionKind
-	err := drm.checkAndReload(&meta.NoResourceMatchError{}, func() error {
+	err := drm.checkAndReload(func() error {
 		var err error
 		gvk, err = drm.staticMapper.KindFor(resource)
 		return err
@@ -219,7 +215,7 @@ func (drm *dynamicRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]
 		return nil, err
 	}
 	var gvks []schema.GroupVersionKind
-	err := drm.checkAndReload(&meta.NoResourceMatchError{}, func() error {
+	err := drm.checkAndReload(func() error {
 		var err error
 		gvks, err = drm.staticMapper.KindsFor(resource)
 		return err
@@ -233,7 +229,7 @@ func (drm *dynamicRESTMapper) ResourceFor(input schema.GroupVersionResource) (sc
 	}
 
 	var gvr schema.GroupVersionResource
-	err := drm.checkAndReload(&meta.NoResourceMatchError{}, func() error {
+	err := drm.checkAndReload(func() error {
 		var err error
 		gvr, err = drm.staticMapper.ResourceFor(input)
 		return err
@@ -246,7 +242,7 @@ func (drm *dynamicRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([
 		return nil, err
 	}
 	var gvrs []schema.GroupVersionResource
-	err := drm.checkAndReload(&meta.NoResourceMatchError{}, func() error {
+	err := drm.checkAndReload(func() error {
 		var err error
 		gvrs, err = drm.staticMapper.ResourcesFor(input)
 		return err
@@ -259,7 +255,7 @@ func (drm *dynamicRESTMapper) RESTMapping(gk schema.GroupKind, versions ...strin
 		return nil, err
 	}
 	var mapping *meta.RESTMapping
-	err := drm.checkAndReload(&meta.NoKindMatchError{}, func() error {
+	err := drm.checkAndReload(func() error {
 		var err error
 		mapping, err = drm.staticMapper.RESTMapping(gk, versions...)
 		return err
@@ -272,7 +268,7 @@ func (drm *dynamicRESTMapper) RESTMappings(gk schema.GroupKind, versions ...stri
 		return nil, err
 	}
 	var mappings []*meta.RESTMapping
-	err := drm.checkAndReload(&meta.NoKindMatchError{}, func() error {
+	err := drm.checkAndReload(func() error {
 		var err error
 		mappings, err = drm.staticMapper.RESTMappings(gk, versions...)
 		return err
@@ -285,7 +281,7 @@ func (drm *dynamicRESTMapper) ResourceSingularizer(resource string) (string, err
 		return "", err
 	}
 	var singular string
-	err := drm.checkAndReload(&meta.NoResourceMatchError{}, func() error {
+	err := drm.checkAndReload(func() error {
 		var err error
 		singular, err = drm.staticMapper.ResourceSingularizer(resource)
 		return err
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
index bbe36c467..730e0ba91 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
@@ -45,7 +45,7 @@ type WarningHandlerOptions struct {
 	// AllowDuplicateLogs does not deduplicate the to-be
 	// logged surfaced warnings messages. See
 	// log.WarningHandlerOptions for considerations
-	// regarding deuplication
+	// regarding deduplication
 	AllowDuplicateLogs bool
 }
 
@@ -88,13 +88,12 @@ func newClient(config *rest.Config, options Options) (*client, error) {
 		// is log.KubeAPIWarningLogger with deduplication enabled.
 		// See log.KubeAPIWarningLoggerOptions for considerations
 		// regarding deduplication.
-		rest.SetDefaultWarningHandler(
-			log.NewKubeAPIWarningLogger(
-				logger,
-				log.KubeAPIWarningLoggerOptions{
-					Deduplicate: !options.Opts.AllowDuplicateLogs,
-				},
-			),
+		config = rest.CopyConfig(config)
+		config.WarningHandler = log.NewKubeAPIWarningLogger(
+			logger,
+			log.KubeAPIWarningLoggerOptions{
+				Deduplicate: !options.Opts.AllowDuplicateLogs,
+			},
 		)
 	}
 
@@ -241,16 +240,16 @@ func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...Pat
 }
 
 // Get implements client.Client.
-func (c *client) Get(ctx context.Context, key ObjectKey, obj Object) error {
+func (c *client) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
 	switch obj.(type) {
 	case *unstructured.Unstructured:
-		return c.unstructuredClient.Get(ctx, key, obj)
+		return c.unstructuredClient.Get(ctx, key, obj, opts...)
 	case *metav1.PartialObjectMetadata:
 		// Metadata only object should always preserve the GVK coming in from the caller.
 		defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
-		return c.metadataClient.Get(ctx, key, obj)
+		return c.metadataClient.Get(ctx, key, obj, opts...)
 	default:
-		return c.typedClient.Get(ctx, key, obj)
+		return c.typedClient.Get(ctx, key, obj, opts...)
 	}
 }
 
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
index fd2772412..ff44a225f 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
@@ -47,7 +47,7 @@ func init() {
 // It also applies saner defaults for QPS and burst based on the Kubernetes
 // controller manager defaults (20 QPS, 30 burst)
 //
-// Config precedence
+// Config precedence:
 //
 // * --kubeconfig flag pointing at a file
 //
@@ -67,7 +67,7 @@ func GetConfig() (*rest.Config, error) {
 // It also applies saner defaults for QPS and burst based on the Kubernetes
 // controller manager defaults (20 QPS, 30 burst)
 //
-// Config precedence
+// Config precedence:
 //
 // * --kubeconfig flag pointing at a file
 //
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go
index 2965e5fa9..e0e288509 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go
@@ -17,7 +17,7 @@ limitations under the License.
 // Package client contains functionality for interacting with Kubernetes API
 // servers.
 //
-// Clients
+// # Clients
 //
 // Clients are split into two interfaces -- Readers and Writers.   Readers
 // get and list, while writers create, update, and delete.
@@ -25,18 +25,19 @@ limitations under the License.
 // The New function can be used to create a new client that talks directly
 // to the API server.
 //
-// A common pattern in Kubernetes to read from a cache and write to the API
+// It is a common pattern in Kubernetes to read from a cache and write to the API
 // server.  This pattern is covered by the DelegatingClient type, which can
 // be used to have a client whose Reader is different from the Writer.
 //
-// Options
+// # Options
 //
 // Many client operations in Kubernetes support options.  These options are
 // represented as variadic arguments at the end of a given method call.
 // For instance, to use a label selector on list, you can call
-//  err := someReader.List(context.Background(), &podList, client.MatchingLabels{"somelabel": "someval"})
 //
-// Indexing
+//	err := someReader.List(context.Background(), &podList, client.MatchingLabels{"somelabel": "someval"})
+//
+// # Indexing
 //
 // Indexes may be added to caches using a FieldIndexer.  This allows you to easily
 // and efficiently look up objects with certain properties.  You can then make
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
index ea25ea253..14606a579 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
@@ -72,8 +72,8 @@ func (c *dryRunClient) Patch(ctx context.Context, obj Object, patch Patch, opts
 }
 
 // Get implements client.Client.
-func (c *dryRunClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
-	return c.client.Get(ctx, key, obj)
+func (c *dryRunClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
+	return c.client.Get(ctx, key, obj, opts...)
 }
 
 // List implements client.Client.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
index 00d5b3bfe..b7ca2de47 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
@@ -329,7 +329,7 @@ func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Ob
 	return t.ObjectTracker.Update(gvr, obj, ns)
 }
 
-func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
+func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
 	gvr, err := getGVRFromObject(obj, c.scheme)
 	if err != nil {
 		return err
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go
index 7d680690d..d0614666e 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/doc.go
@@ -28,12 +28,11 @@ When in doubt, it's almost always better not to use this package and instead use
 envtest.Environment with a real client and API server.
 
 WARNING: ⚠️ Current Limitations / Known Issues with the fake Client ⚠️
-- This client does not have a way to inject specific errors to test handled vs. unhandled errors.
-- There is some support for sub resources which can cause issues with tests if you're trying to update
-  e.g. metadata and status in the same reconcile.
-- No OpeanAPI validation is performed when creating or updating objects.
-- ObjectMeta's `Generation` and `ResourceVersion` don't behave properly, Patch or Update
-operations that rely on these fields will fail, or give false positives.
-
+  - This client does not have a way to inject specific errors to test handled vs. unhandled errors.
+  - There is some support for sub resources which can cause issues with tests if you're trying to update
+    e.g. metadata and status in the same reconcile.
+  - No OpenAPI validation is performed when creating or updating objects.
+  - ObjectMeta's `Generation` and `ResourceVersion` don't behave properly, Patch or Update
+    operations that rely on these fields will fail, or give false positives.
 */
 package fake
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
index 58c2ece15..7f8f8f31c 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
@@ -50,7 +50,7 @@ type Reader interface {
 	// Get retrieves an obj for the given object key from the Kubernetes Cluster.
 	// obj must be a struct pointer so that obj can be updated with the response
 	// returned by the Server.
-	Get(ctx context.Context, key ObjectKey, obj Object) error
+	Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error
 
 	// List retrieves list of objects for a given namespace and list options. On a
 	// successful call, Items field in the list will be populated with the
@@ -143,3 +143,13 @@ func IgnoreNotFound(err error) error {
 	}
 	return err
 }
+
+// IgnoreAlreadyExists returns nil on AlreadyExists errors.
+// All other values that are not AlreadyExists errors or nil are returned unmodified.
+func IgnoreAlreadyExists(err error) error {
+	if apierrors.IsAlreadyExists(err) {
+		return nil
+	}
+
+	return err
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
index db495ca46..2854556f3 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
@@ -116,7 +116,7 @@ func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, op
 }
 
 // Get implements client.Client.
-func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
 	metadata, ok := obj.(*metav1.PartialObjectMetadata)
 	if !ok {
 		return fmt.Errorf("metadata client did not understand object: %T", obj)
@@ -124,12 +124,15 @@ func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object) er
 
 	gvk := metadata.GroupVersionKind()
 
+	getOpts := GetOptions{}
+	getOpts.ApplyOptions(opts)
+
 	resInt, err := mc.getResourceInterface(gvk, key.Namespace)
 	if err != nil {
 		return err
 	}
 
-	res, err := resInt.Get(ctx, key.Name, metav1.GetOptions{})
+	res, err := resInt.Get(ctx, key.Name, *getOpts.AsGetOptions())
 	if err != nil {
 		return err
 	}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
index 45a694543..674fe253d 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
@@ -52,7 +52,7 @@ func (n *namespacedClient) RESTMapper() meta.RESTMapper {
 	return n.client.RESTMapper()
 }
 
-// Create implements clinet.Client.
+// Create implements client.Client.
 func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
 	isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
 	if err != nil {
@@ -138,18 +138,18 @@ func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, o
 }
 
 // Get implements client.Client.
-func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
 	isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
 	if err != nil {
 		return fmt.Errorf("error finding the scope of the object: %w", err)
 	}
 	if isNamespaceScoped {
 		if key.Namespace != "" && key.Namespace != n.namespace {
-			return fmt.Errorf("namespace %s provided for the object %s does not match the namesapce %s on the client", key.Namespace, obj.GetName(), n.namespace)
+			return fmt.Errorf("namespace %s provided for the object %s does not match the namespace %s on the client", key.Namespace, obj.GetName(), n.namespace)
 		}
 		key.Namespace = n.namespace
 	}
-	return n.client.Get(ctx, key, obj)
+	return n.client.Get(ctx, key, obj, opts...)
 }
 
 // List implements client.Client.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
index 7990f56ab..495b86944 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
@@ -37,6 +37,12 @@ type DeleteOption interface {
 	ApplyToDelete(*DeleteOptions)
 }
 
+// GetOption is some configuration that modifies options for a get request.
+type GetOption interface {
+	// ApplyToGet applies this configuration to the given get options.
+	ApplyToGet(*GetOptions)
+}
+
 // ListOption is some configuration that modifies options for a list request.
 type ListOption interface {
 	// ApplyToList applies this configuration to the given list options.
@@ -311,6 +317,45 @@ func (p PropagationPolicy) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
 
 // }}}
 
+// {{{ Get Options
+
+// GetOptions contains options for get operation.
+// Now it only has a Raw field, with support for specific resourceVersion.
+type GetOptions struct {
+	// Raw represents raw GetOptions, as passed to the API server.  Note
+	// that these may not be respected by all implementations of interface.
+	Raw *metav1.GetOptions
+}
+
+var _ GetOption = &GetOptions{}
+
+// ApplyToGet implements GetOption for GetOptions.
+func (o *GetOptions) ApplyToGet(lo *GetOptions) {
+	if o.Raw != nil {
+		lo.Raw = o.Raw
+	}
+}
+
+// AsGetOptions returns these options as a flattened metav1.GetOptions.
+// This may mutate the Raw field.
+func (o *GetOptions) AsGetOptions() *metav1.GetOptions {
+	if o == nil || o.Raw == nil {
+		return &metav1.GetOptions{}
+	}
+	return o.Raw
+}
+
+// ApplyOptions applies the given get options on these options,
+// and then returns itself (for convenient chaining).
+func (o *GetOptions) ApplyOptions(opts []GetOption) *GetOptions {
+	for _, opt := range opts {
+		opt.ApplyToGet(o)
+	}
+	return o
+}
+
+// }}}
+
 // {{{ List Options
 
 // ListOptions contains options for limiting or filtering results.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
index 10984c534..11d608388 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
@@ -19,7 +19,7 @@ package client
 import (
 	"fmt"
 
-	jsonpatch "github.com/evanphx/json-patch"
+	jsonpatch "github.com/evanphx/json-patch/v5"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/json"
 	"k8s.io/apimachinery/pkg/util/strategicpatch"
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
index bf4b861f3..871734534 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
@@ -121,13 +121,13 @@ func (d *delegatingReader) shouldBypassCache(obj runtime.Object) (bool, error) {
 }
 
 // Get retrieves an obj for a given object key from the Kubernetes Cluster.
-func (d *delegatingReader) Get(ctx context.Context, key ObjectKey, obj Object) error {
+func (d *delegatingReader) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
 	if isUncached, err := d.shouldBypassCache(obj); err != nil {
 		return err
 	} else if isUncached {
-		return d.ClientReader.Get(ctx, key, obj)
+		return d.ClientReader.Get(ctx, key, obj, opts...)
 	}
-	return d.CacheReader.Get(ctx, key, obj)
+	return d.CacheReader.Get(ctx, key, obj, opts...)
 }
 
 // List retrieves list of objects for a given namespace and list options.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
index dde7b21f2..c4e56d9be 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
@@ -132,14 +132,17 @@ func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts .
 }
 
 // Get implements client.Client.
-func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
 	r, err := c.cache.getResource(obj)
 	if err != nil {
 		return err
 	}
+	getOpts := GetOptions{}
+	getOpts.ApplyOptions(opts)
 	return r.Get().
 		NamespaceIfScoped(key.Namespace, r.isNamespaced()).
 		Resource(r.resource()).
+		VersionedParams(getOpts.AsGetOptions(), c.paramCodec).
 		Name(key.Name).Do(ctx).Into(obj)
 }
 
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
index 819527e70..3d3dbe7b2 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
@@ -165,7 +165,7 @@ func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch
 }
 
 // Get implements client.Client.
-func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
 	u, ok := obj.(*unstructured.Unstructured)
 	if !ok {
 		return fmt.Errorf("unstructured client did not understand object: %T", obj)
@@ -173,6 +173,9 @@ func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object
 
 	gvk := u.GroupVersionKind()
 
+	getOpts := GetOptions{}
+	getOpts.ApplyOptions(opts)
+
 	r, err := uc.cache.getResource(obj)
 	if err != nil {
 		return err
@@ -181,6 +184,7 @@ func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object
 	result := r.Get().
 		NamespaceIfScoped(key.Namespace, r.isNamespaced()).
 		Resource(r.resource()).
+		VersionedParams(getOpts.AsGetOptions(), uc.paramCodec).
 		Name(key.Name).
 		Do(ctx).
 		Into(obj)
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
index 517b172e5..8e853d6a0 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
@@ -50,8 +50,8 @@ type DeferredFileLoader struct {
 // this will also configure the defaults for the loader if nothing is
 //
 // Defaults:
-//   Path: "./config.yaml"
-//   Kind: GenericControllerManagerConfiguration
+// * Path: "./config.yaml"
+// * Kind: GenericControllerManagerConfiguration
 func File() *DeferredFileLoader {
 	scheme := runtime.NewScheme()
 	utilruntime.Must(v1alpha1.AddToScheme(scheme))
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
index ebd8243f3..a169ec559 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
@@ -17,7 +17,7 @@ limitations under the License.
 // Package config contains functionality for interacting with ComponentConfig
 // files
 //
-// DeferredFileLoader
+// # DeferredFileLoader
 //
 // This uses a deferred file decoding allowing you to chain your configuration
 // setup. You can pass this into manager.Options#File and it will load your
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go
index 667b14fdd..228335e92 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go
@@ -17,7 +17,7 @@ limitations under the License.
 /*
 Package controller provides types and functions for building Controllers.  Controllers implement Kubernetes APIs.
 
-Creation
+# Creation
 
 To create a new Controller, first create a manager.Manager and pass it to the controller.New function.
 The Controller MUST be started by calling Manager.Start.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go
index 3b5b79048..e5fd177af 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go
@@ -21,7 +21,7 @@ Controller.Watch in order to generate and enqueue reconcile.Request work items.
 
 Generally, following premade event handlers should be sufficient for most use cases:
 
-EventHandlers
+EventHandlers:
 
 EnqueueRequestForObject - Enqueues a reconcile.Request containing the Name and Namespace of the object in the Event.  This will
 cause the object that was the source of the Event (e.g. the created / deleted / updated object) to be
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
index 46cc1714b..9d8b2f074 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
@@ -100,7 +100,7 @@ func (p *Provider) getBroadcaster() record.EventBroadcaster {
 		broadcaster.StartRecordingToSink(&corev1client.EventSinkImpl{Interface: p.evtClient})
 		broadcaster.StartEventWatcher(
 			func(e *corev1.Event) {
-				p.logger.V(1).Info(e.Type, "object", e.InvolvedObject, "reason", e.Reason, "message", e.Message)
+				p.logger.V(1).Info(e.Message, "type", e.Type, "object", e.InvolvedObject, "reason", e.Reason)
 			})
 		p.broadcaster = broadcaster
 		p.stopBroadcaster = stop
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
index 6fca63063..c82447d91 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
@@ -73,6 +73,9 @@ func (p *loggerPromise) Fulfill(parentLogSink logr.LogSink) {
 
 	p.logger.lock.Lock()
 	p.logger.logger = sink
+	if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok {
+		p.logger.logger = withCallDepth.WithCallDepth(1)
+	}
 	p.logger.promise = nil
 	p.logger.lock.Unlock()
 
@@ -141,7 +144,11 @@ func (l *DelegatingLogSink) WithName(name string) logr.LogSink {
 	defer l.lock.RUnlock()
 
 	if l.promise == nil {
-		return l.logger.WithName(name)
+		sink := l.logger.WithName(name)
+		if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok {
+			sink = withCallDepth.WithCallDepth(-1)
+		}
+		return sink
 	}
 
 	res := &DelegatingLogSink{logger: l.logger}
@@ -157,7 +164,11 @@ func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
 	defer l.lock.RUnlock()
 
 	if l.promise == nil {
-		return l.logger.WithValues(tags...)
+		sink := l.logger.WithValues(tags...)
+		if withCallDepth, ok := sink.(logr.CallDepthLogSink); ok {
+			sink = withCallDepth.WithCallDepth(-1)
+		}
+		return sink
 	}
 
 	res := &DelegatingLogSink{logger: l.logger}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go
index 3965769c3..082dce3ad 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go
@@ -17,7 +17,7 @@ limitations under the License.
 // Package log contains utilities for fetching a new logger
 // when one is not already available.
 //
-// The Log Handle
+// # The Log Handle
 //
 // This package contains a root logr.Logger Log.  It may be used to
 // get a handle to whatever the root logging implementation is.  By
@@ -25,7 +25,7 @@ limitations under the License.
 // to loggers.  When the implementation is set using SetLogger, these
 // "promises" will be converted over to real loggers.
 //
-// Logr
+// # Logr
 //
 // All logging in controller-runtime is structured, using a set of interfaces
 // defined by a package called logr
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
index 5f76b5a83..53716aa9f 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
@@ -142,18 +142,36 @@ type Options struct {
 	LeaderElection bool
 
 	// LeaderElectionResourceLock determines which resource lock to use for leader election,
-	// defaults to "configmapsleases". Change this value only if you know what you are doing.
-	// Otherwise, users of your controller might end up with multiple running instances that
+	// defaults to "leases". Change this value only if you know what you are doing.
+	//
+	// If you are using `configmaps`/`endpoints` resource lock and want to migrate to "leases",
+	// you might do so by migrating to the respective multilock first ("configmapsleases" or "endpointsleases"),
+	// which will acquire a leader lock on both resources.
+	// After all your users have migrated to the multilock, you can go ahead and migrate to "leases".
+	// Please also keep in mind, that users might skip versions of your controller.
+	//
+	// Note: before controller-runtime version v0.7, it was set to "configmaps".
+	// And from v0.7 to v0.11, the default was "configmapsleases", which was
+	// used to migrate from configmaps to leases.
+	// Since the default was "configmapsleases" for over a year, spanning five minor releases,
+	// any actively maintained operators are very likely to have a released version that uses
+	// "configmapsleases". Therefore defaulting to "leases" should be safe since v0.12.
+	//
+	// So, what do you have to do when you are updating your controller-runtime dependency
+	// from a lower version to v0.12 or newer?
+	// - If your operator matches at least one of these conditions:
+	//   - the LeaderElectionResourceLock in your operator has already been explicitly set to "leases"
+	//   - the old controller-runtime version is between v0.7.0 and v0.11.x and the
+	//     LeaderElectionResourceLock wasn't set or was set to "leases"/"configmapsleases"/"endpointsleases"
+	//   feel free to update controller-runtime to v0.12 or newer.
+	// - Otherwise, you may have to take these steps:
+	//   1. update controller-runtime to v0.12 or newer in your go.mod
+	//   2. set LeaderElectionResourceLock to "configmapsleases" (or "endpointsleases")
+	//   3. package your operator and upgrade it in all your clusters
+	//   4. only if you have finished 3, you can remove the LeaderElectionResourceLock to use the default "leases"
+	// Otherwise, your operator might end up with multiple running instances that
 	// each acquired leadership through different resource locks during upgrades and thus
 	// act on the same resources concurrently.
-	// If you want to migrate to the "leases" resource lock, you might do so by migrating to the
-	// respective multilock first ("configmapsleases" or "endpointsleases"), which will acquire a
-	// leader lock on both resources. After all your users have migrated to the multilock, you can
-	// go ahead and migrate to "leases". Please also keep in mind, that users might skip versions
-	// of your controller.
-	//
-	// Note: before controller-runtime version v0.7, the resource lock was set to "configmaps".
-	// Please keep this in mind, when planning a proper migration path for your controller.
 	LeaderElectionResourceLock string
 
 	// LeaderElectionNamespace determines the namespace in which the leader
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
index d32ce2534..dc805a9d0 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
@@ -22,7 +22,6 @@ import (
 	"time"
 
 	"github.com/prometheus/client_golang/prometheus"
-	reflectormetrics "k8s.io/client-go/tools/cache"
 	clientmetrics "k8s.io/client-go/tools/metrics"
 )
 
@@ -37,19 +36,6 @@ const (
 	ResultKey           = "requests_total"
 )
 
-// Metrics subsystem and all keys used by the reflectors.
-const (
-	ReflectorSubsystem     = "reflector"
-	ListsTotalKey          = "lists_total"
-	ListsDurationKey       = "list_duration_seconds"
-	ItemsPerListKey        = "items_per_list"
-	WatchesTotalKey        = "watches_total"
-	ShortWatchesTotalKey   = "short_watches_total"
-	WatchDurationKey       = "watch_duration_seconds"
-	ItemsPerWatchKey       = "items_per_watch"
-	LastResourceVersionKey = "last_resource_version"
-)
-
 var (
 	// client metrics.
 
@@ -81,64 +67,10 @@ var (
 		Name:      ResultKey,
 		Help:      "Number of HTTP requests, partitioned by status code, method, and host.",
 	}, []string{"code", "method", "host"})
-
-	// reflector metrics.
-
-	// TODO(directxman12): update these to be histograms once the metrics overhaul KEP
-	// PRs start landing.
-
-	listsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      ListsTotalKey,
-		Help:      "Total number of API lists done by the reflectors",
-	}, []string{"name"})
-
-	listsDuration = prometheus.NewSummaryVec(prometheus.SummaryOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      ListsDurationKey,
-		Help:      "How long an API list takes to return and decode for the reflectors",
-	}, []string{"name"})
-
-	itemsPerList = prometheus.NewSummaryVec(prometheus.SummaryOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      ItemsPerListKey,
-		Help:      "How many items an API list returns to the reflectors",
-	}, []string{"name"})
-
-	watchesTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      WatchesTotalKey,
-		Help:      "Total number of API watches done by the reflectors",
-	}, []string{"name"})
-
-	shortWatchesTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      ShortWatchesTotalKey,
-		Help:      "Total number of short API watches done by the reflectors",
-	}, []string{"name"})
-
-	watchDuration = prometheus.NewSummaryVec(prometheus.SummaryOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      WatchDurationKey,
-		Help:      "How long an API watch takes to return and decode for the reflectors",
-	}, []string{"name"})
-
-	itemsPerWatch = prometheus.NewSummaryVec(prometheus.SummaryOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      ItemsPerWatchKey,
-		Help:      "How many items an API watch returns to the reflectors",
-	}, []string{"name"})
-
-	lastResourceVersion = prometheus.NewGaugeVec(prometheus.GaugeOpts{
-		Subsystem: ReflectorSubsystem,
-		Name:      LastResourceVersionKey,
-		Help:      "Last resource version seen for the reflectors",
-	}, []string{"name"})
 )
 
 func init() {
 	registerClientMetrics()
-	registerReflectorMetrics()
 }
 
 // registerClientMetrics sets up the client latency metrics from client-go.
@@ -152,20 +84,6 @@ func registerClientMetrics() {
 	})
 }
 
-// registerReflectorMetrics sets up reflector (reconcile) loop metrics.
-func registerReflectorMetrics() {
-	Registry.MustRegister(listsTotal)
-	Registry.MustRegister(listsDuration)
-	Registry.MustRegister(itemsPerList)
-	Registry.MustRegister(watchesTotal)
-	Registry.MustRegister(shortWatchesTotal)
-	Registry.MustRegister(watchDuration)
-	Registry.MustRegister(itemsPerWatch)
-	Registry.MustRegister(lastResourceVersion)
-
-	reflectormetrics.SetReflectorMetricsProvider(reflectorMetricsProvider{})
-}
-
 // this section contains adapters, implementations, and other sundry organic, artisanally
 // hand-crafted syntax trees required to convince client-go that it actually wants to let
 // someone use its metrics.
@@ -191,41 +109,3 @@ type resultAdapter struct {
 func (r *resultAdapter) Increment(_ context.Context, code, method, host string) {
 	r.metric.WithLabelValues(code, method, host).Inc()
 }
-
-// Reflector metrics provider (method #2 for client-go metrics),
-// copied (more-or-less directly) from k8s.io/kubernetes setup code
-// (which isn't anywhere in an easily-importable place).
-
-type reflectorMetricsProvider struct{}
-
-func (reflectorMetricsProvider) NewListsMetric(name string) reflectormetrics.CounterMetric {
-	return listsTotal.WithLabelValues(name)
-}
-
-func (reflectorMetricsProvider) NewListDurationMetric(name string) reflectormetrics.SummaryMetric {
-	return listsDuration.WithLabelValues(name)
-}
-
-func (reflectorMetricsProvider) NewItemsInListMetric(name string) reflectormetrics.SummaryMetric {
-	return itemsPerList.WithLabelValues(name)
-}
-
-func (reflectorMetricsProvider) NewWatchesMetric(name string) reflectormetrics.CounterMetric {
-	return watchesTotal.WithLabelValues(name)
-}
-
-func (reflectorMetricsProvider) NewShortWatchesMetric(name string) reflectormetrics.CounterMetric {
-	return shortWatchesTotal.WithLabelValues(name)
-}
-
-func (reflectorMetricsProvider) NewWatchDurationMetric(name string) reflectormetrics.SummaryMetric {
-	return watchDuration.WithLabelValues(name)
-}
-
-func (reflectorMetricsProvider) NewItemsInWatchMetric(name string) reflectormetrics.SummaryMetric {
-	return itemsPerWatch.WithLabelValues(name)
-}
-
-func (reflectorMetricsProvider) NewLastResourceVersionMetric(name string) reflectormetrics.GaugeMetric {
-	return lastResourceVersion.WithLabelValues(name)
-}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
index 8608e22ac..e79c03072 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
@@ -176,9 +176,9 @@ func (GenerationChangedPredicate) Update(e event.UpdateEvent) bool {
 // This predicate will skip update events that have no change in the object's annotation.
 // It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example:
 //
-// Controller.Watch(
+//	Controller.Watch(
 //		&source.Kind{Type: v1.MyCustomKind},
-// 		&handler.EnqueueRequestForObject{},
+//		&handler.EnqueueRequestForObject{},
 //		predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}))
 //
 // This is mostly useful for controllers that needs to trigger both when the resource's generation is incremented
@@ -207,9 +207,10 @@ func (AnnotationChangedPredicate) Update(e event.UpdateEvent) bool {
 // It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example:
 //
 // Controller.Watch(
-//		&source.Kind{Type: v1.MyCustomKind},
-// 		&handler.EnqueueRequestForObject{},
-//		predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{}))
+//
+//	&source.Kind{Type: v1.MyCustomKind},
+//	&handler.EnqueueRequestForObject{},
+//	predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{}))
 //
 // This will be helpful when object's labels is carrying some extra specification information beyond object's spec,
 // and the controller will be triggered if any valid spec change (not only in spec, but also in labels) happens.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
index b044e6594..8285e2ca9 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
@@ -61,24 +61,24 @@ Deleting Kubernetes objects) or external Events (GitHub Webhooks, polling extern
 
 Example reconcile Logic:
 
-	* Read an object and all the Pods it owns.
-	* Observe that the object spec specifies 5 replicas but actual cluster contains only 1 Pod replica.
-	* Create 4 Pods and set their OwnerReferences to the object.
+* Read an object and all the Pods it owns.
+* Observe that the object spec specifies 5 replicas but actual cluster contains only 1 Pod replica.
+* Create 4 Pods and set their OwnerReferences to the object.
 
 reconcile may be implemented as either a type:
 
-	type reconcile struct {}
+	type reconciler struct {}
 
-	func (reconcile) reconcile(controller.Request) (controller.Result, error) {
+	func (reconciler) Reconcile(ctx context.Context, o reconcile.Request) (reconcile.Result, error) {
 		// Implement business logic of reading and writing objects here
-		return controller.Result{}, nil
+		return reconcile.Result{}, nil
 	}
 
 Or as a function:
 
-	controller.Func(func(o controller.Request) (controller.Result, error) {
+	reconcile.Func(func(ctx context.Context, o reconcile.Request) (reconcile.Result, error) {
 		// Implement business logic of reading and writing objects here
-		return controller.Result{}, nil
+		return reconcile.Result{}, nil
 	})
 
 Reconciliation is level-based, meaning action isn't driven off changes in individual Events, but instead is
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
index 9dc93a9b2..55ebe2177 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
@@ -21,37 +21,36 @@ limitations under the License.
 // Each API group should define a utility function
 // called AddToScheme for adding its types to a Scheme:
 //
-//  // in package myapigroupv1...
-//  var (
-//  	SchemeGroupVersion = schema.GroupVersion{Group: "my.api.group", Version: "v1"}
-//  	SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
-//  	AddToScheme = SchemeBuilder.AddToScheme
-//  )
+//	 // in package myapigroupv1...
+//	var (
+//		SchemeGroupVersion = schema.GroupVersion{Group: "my.api.group", Version: "v1"}
+//		SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
+//		AddToScheme = SchemeBuilder.AddToScheme
+//	)
 //
-//  func init() {
-//  	SchemeBuilder.Register(&MyType{}, &MyTypeList)
-//  }
-//  var (
-//  	scheme *runtime.Scheme = runtime.NewScheme()
-//  )
+//	func init() {
+//		SchemeBuilder.Register(&MyType{}, &MyTypeList)
+//	}
+//	var (
+//		scheme *runtime.Scheme = runtime.NewScheme()
+//	)
 //
 // This also true of the built-in Kubernetes types.  Then, in the entrypoint for
 // your manager, assemble the scheme containing exactly the types you need,
 // panicing if scheme registration failed. For instance, if our controller needs
 // types from the core/v1 API group (e.g. Pod), plus types from my.api.group/v1:
 //
-//  func init() {
-//  	utilruntime.Must(myapigroupv1.AddToScheme(scheme))
-//  	utilruntime.Must(kubernetesscheme.AddToScheme(scheme))
-//  }
-//
-//  func main() {
-//  	mgr := controllers.NewManager(context.Background(), controllers.GetConfigOrDie(), manager.Options{
-//  		Scheme: scheme,
-//  	})
-//  	// ...
-//  }
+//	func init() {
+//		utilruntime.Must(myapigroupv1.AddToScheme(scheme))
+//		utilruntime.Must(kubernetesscheme.AddToScheme(scheme))
+//	}
 //
+//	func main() {
+//		mgr := controllers.NewManager(context.Background(), controllers.GetConfigOrDie(), manager.Options{
+//			Scheme: scheme,
+//		})
+//		// ...
+//	}
 package scheme
 
 import (
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
index 0d9aa7a83..e4e0778f5 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
@@ -21,6 +21,8 @@ import (
 	"encoding/json"
 	"net/http"
 
+	admissionv1 "k8s.io/api/admission/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 )
 
@@ -56,6 +58,17 @@ func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
 		panic("defaulter should never be nil")
 	}
 
+	// always skip when a DELETE operation received in mutation handler
+	// describe in https://github.com/kubernetes-sigs/controller-runtime/issues/1762
+	if req.Operation == admissionv1.Delete {
+		return Response{AdmissionResponse: admissionv1.AdmissionResponse{
+			Allowed: true,
+			Result: &metav1.Status{
+				Code: http.StatusOK,
+			},
+		}}
+	}
+
 	// Get the object in the request
 	obj := h.defaulter.DeepCopyObject().(Defaulter)
 	if err := h.decoder.Decode(req, obj); err != nil {
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
index cfc46637c..d10b97ddd 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
@@ -19,6 +19,7 @@ package admission
 import (
 	"context"
 	"errors"
+	"fmt"
 	"net/http"
 
 	"github.com/go-logr/logr"
@@ -27,6 +28,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/json"
+	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/client-go/kubernetes/scheme"
 
 	logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
@@ -121,6 +123,9 @@ type Webhook struct {
 	// and potentially patches to apply to the handler.
 	Handler Handler
 
+	// RecoverPanic indicates whether the panic caused by webhook should be recovered.
+	RecoverPanic bool
+
 	// WithContextFunc will allow you to take the http.Request.Context() and
 	// add any additional information such as passing the request path or
 	// headers thus allowing you to read them from within the handler
@@ -138,11 +143,29 @@ func (wh *Webhook) InjectLogger(l logr.Logger) error {
 	return nil
 }
 
+// WithRecoverPanic takes a bool flag which indicates whether the panic caused by webhook should be recovered.
+func (wh *Webhook) WithRecoverPanic(recoverPanic bool) *Webhook {
+	wh.RecoverPanic = recoverPanic
+	return wh
+}
+
 // Handle processes AdmissionRequest.
 // If the webhook is mutating type, it delegates the AdmissionRequest to each handler and merge the patches.
 // If the webhook is validating type, it delegates the AdmissionRequest to each handler and
 // deny the request if anyone denies.
-func (wh *Webhook) Handle(ctx context.Context, req Request) Response {
+func (wh *Webhook) Handle(ctx context.Context, req Request) (response Response) {
+	if wh.RecoverPanic {
+		defer func() {
+			if r := recover(); r != nil {
+				for _, fn := range utilruntime.PanicHandlers {
+					fn(r)
+				}
+				response = Errored(http.StatusInternalServerError, fmt.Errorf("panic: %v [recovered]", r))
+				return
+			}
+		}()
+	}
+
 	resp := wh.Handler.Handle(ctx, req)
 	if err := resp.Complete(req); err != nil {
 		wh.log.Error(err, "unable to encode response")
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
index fa56be5d5..06f479208 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
@@ -299,7 +299,7 @@ func (s *Server) Start(ctx context.Context) error {
 // server has been started.
 func (s *Server) StartedChecker() healthz.Checker {
 	config := &tls.Config{
-		InsecureSkipVerify: true, // nolint:gosec // config is used to connect to our own webhook port.
+		InsecureSkipVerify: true, //nolint:gosec // config is used to connect to our own webhook port.
 	}
 	return func(req *http.Request) error {
 		s.mu.Lock()


Test patch:
diff --git a/hack/ci/e2e-olm.sh b/hack/ci/e2e-olm.sh
index 27400039a..cbd1bb13d 100755
--- a/hack/ci/e2e-olm.sh
+++ b/hack/ci/e2e-olm.sh
@@ -32,7 +32,7 @@ function build_and_push_packages() {
 
     # Create a manifest with local image
     cp deploy/operator.yaml ${OPERATOR_MANIFEST}
-    sed -i "s#k8s.gcr.io/security-profiles-operator/security-profiles-operator.*\$#${IMG}#" ${OPERATOR_MANIFEST}
+    sed -i "s#registry.k8s.io/security-profiles-operator/security-profiles-operator.*\$#${IMG}#" ${OPERATOR_MANIFEST}
 
     # this is a kludge, we need to make sure kustomize can be overwritten
     rm -f build/kustomize
diff --git a/internal/pkg/daemon/apparmorprofile/apparmorprofile_test.go b/internal/pkg/daemon/apparmorprofile/apparmorprofile_test.go
index 9d3499588..bbaa1f289 100644
--- a/internal/pkg/daemon/apparmorprofile/apparmorprofile_test.go
+++ b/internal/pkg/daemon/apparmorprofile/apparmorprofile_test.go
@@ -20,7 +20,6 @@ import (
 	"context"
 	"testing"
 
-	"github.com/crossplane/crossplane-runtime/pkg/test"
 	_ "github.com/go-logr/logr"
 	"github.com/stretchr/testify/require"
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -32,6 +31,7 @@ import (
 
 	profilebasev1alpha1 "sigs.k8s.io/security-profiles-operator/api/profilebase/v1alpha1"
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/daemon/metrics"
+	"sigs.k8s.io/security-profiles-operator/internal/pkg/util"
 )
 
 func TestReconcile(t *testing.T) {
@@ -50,8 +50,8 @@ func TestReconcile(t *testing.T) {
 		{
 			name: "ProfileNotFound",
 			rec: &Reconciler{
-				client: &test.MockClient{
-					MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, name)),
+				client: &util.MockClient{
+					MockGet: util.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, name)),
 				},
 				log:     log.Log,
 				metrics: metrics.New(),
@@ -64,10 +64,10 @@ func TestReconcile(t *testing.T) {
 		{
 			name: "GotProfile",
 			rec: &Reconciler{
-				client: &test.MockClient{
-					MockGet:          test.NewMockGetFn(nil),
-					MockUpdate:       test.NewMockUpdateFn(nil),
-					MockStatusUpdate: test.NewMockStatusUpdateFn(nil),
+				client: &util.MockClient{
+					MockGet:          util.NewMockGetFn(nil),
+					MockUpdate:       util.NewMockUpdateFn(nil),
+					MockStatusUpdate: util.NewMockStatusUpdateFn(nil),
 				},
 				log:     log.Log,
 				record:  record.NewFakeRecorder(10),
@@ -81,10 +81,10 @@ func TestReconcile(t *testing.T) {
 		{
 			name: "NotEnabled",
 			rec: &Reconciler{
-				client: &test.MockClient{
-					MockGet:          test.NewMockGetFn(nil),
-					MockUpdate:       test.NewMockUpdateFn(nil),
-					MockStatusUpdate: test.NewMockStatusUpdateFn(nil),
+				client: &util.MockClient{
+					MockGet:          util.NewMockGetFn(nil),
+					MockUpdate:       util.NewMockUpdateFn(nil),
+					MockStatusUpdate: util.NewMockStatusUpdateFn(nil),
 				},
 				log:     log.Log,
 				record:  record.NewFakeRecorder(10),
diff --git a/internal/pkg/daemon/seccompprofile/seccompprofile_test.go b/internal/pkg/daemon/seccompprofile/seccompprofile_test.go
index a67a75958..507b4fc98 100644
--- a/internal/pkg/daemon/seccompprofile/seccompprofile_test.go
+++ b/internal/pkg/daemon/seccompprofile/seccompprofile_test.go
@@ -25,7 +25,6 @@ import (
 	"testing"
 
 	"github.com/containers/common/pkg/seccomp"
-	"github.com/crossplane/crossplane-runtime/pkg/test"
 	"github.com/stretchr/testify/require"
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -40,6 +39,7 @@ import (
 	spodapi "sigs.k8s.io/security-profiles-operator/api/spod/v1alpha1"
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/daemon/metrics"
+	"sigs.k8s.io/security-profiles-operator/internal/pkg/util"
 )
 
 func TestReconcile(t *testing.T) {
@@ -59,8 +59,8 @@ func TestReconcile(t *testing.T) {
 		{
 			name: "ProfileNotFound",
 			rec: &Reconciler{
-				client: &test.MockClient{
-					MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, name)),
+				client: &util.MockClient{
+					MockGet: util.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, name)),
 				},
 				log:     log.Log,
 				metrics: metrics.New(),
@@ -72,8 +72,8 @@ func TestReconcile(t *testing.T) {
 		{
 			name: "ErrGetProfileIfSeccompEnabled",
 			rec: &Reconciler{
-				client: &test.MockClient{
-					MockGet: test.NewMockGetFn(errOops),
+				client: &util.MockClient{
+					MockGet: util.NewMockGetFn(errOops),
 				},
 				record:  record.NewFakeRecorder(10),
 				log:     log.Log,
@@ -91,10 +91,10 @@ func TestReconcile(t *testing.T) {
 		{
 			name: "GotProfile",
 			rec: &Reconciler{
-				client: &test.MockClient{
-					MockGet:          test.NewMockGetFn(nil),
-					MockUpdate:       test.NewMockUpdateFn(nil),
-					MockStatusUpdate: test.NewMockStatusUpdateFn(nil),
+				client: &util.MockClient{
+					MockGet:          util.NewMockGetFn(nil),
+					MockUpdate:       util.NewMockUpdateFn(nil),
+					MockStatusUpdate: util.NewMockStatusUpdateFn(nil),
 				},
 				log:     log.Log,
 				record:  record.NewFakeRecorder(10),
diff --git a/internal/pkg/translator/obj2cil_test.go b/internal/pkg/translator/obj2cil_test.go
index 5af5cdc7f..21578c558 100644
--- a/internal/pkg/translator/obj2cil_test.go
+++ b/internal/pkg/translator/obj2cil_test.go
@@ -190,6 +190,75 @@ func TestObject2CIL(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "Test errorlogger translation with permissive mode",
+			profile: &selxv1alpha2.SelinuxProfile{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "foo-permissive",
+					Namespace: "bar",
+				},
+				Spec: selxv1alpha2.SelinuxProfileSpec{
+					Permissive: true,
+					Inherit: []selxv1alpha2.PolicyRef{
+						{
+							Name: "container",
+						},
+					},
+					Allow: selxv1alpha2.Allow{
+						"var_log_t": {
+							"dir": []string{
+								"open",
+								"read",
+								"getattr",
+								"lock",
+								"search",
+								"ioctl",
+								"add_name",
+								"remove_name",
+								"write",
+							},
+							"file": []string{
+								"getattr",
+								"read",
+								"write",
+								"append",
+								"ioctl",
+								"lock",
+								"map",
+								"open",
+								"create",
+							},
+							"sock_file": []string{
+								"getattr",
+								"read",
+								"write",
+								"append",
+								"open",
+							},
+						},
+					},
+				},
+			},
+			wantMatches: []string{
+				"\\(block foo-permissive_bar",
+				"\\(blockinherit container\\)",
+				"\\(typepermissive process\\)",
+				// We match on several lines since we don't care about the order
+				"\\(allow process var_log_t \\( dir \\(.*open.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( dir \\(.*read.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( dir \\(.*remove_name.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( dir \\(.*write.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( file \\(.*getattr.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( file \\(.*map.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( file \\(.*create.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( sock_file \\(.*getattr.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( sock_file \\(.*append.*\\)\\)\\)\n",
+				"\\(allow process var_log_t \\( sock_file \\(.*open.*\\)\\)\\)\n",
+			},
+			inheritsys: []string{
+				"container",
+			},
+		},
 	}
 	for _, tt := range tests {
 		tt := tt
diff --git a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/fake.go b/internal/pkg/util/mock_client.go
similarity index 92%
rename from vendor/github.com/crossplane/crossplane-runtime/pkg/test/fake.go
rename to internal/pkg/util/mock_client.go
index f11f8cad1..05c1aaf5f 100644
--- a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/fake.go
+++ b/internal/pkg/util/mock_client.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2019 The Crossplane Authors.
+Copyright 2022 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package test
+package util
 
 import (
 	"context"
@@ -24,10 +24,8 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-var _ client.Client = &MockClient{}
-
 // A MockGetFn is used to mock client.Client's Get implementation.
-type MockGetFn func(ctx context.Context, key client.ObjectKey, obj client.Object) error
+type MockGetFn func(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error
 
 // A MockListFn is used to mock client.Client's List implementation.
 type MockListFn func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error
@@ -51,7 +49,9 @@ type MockPatchFn func(ctx context.Context, obj client.Object, patch client.Patch
 type MockStatusUpdateFn func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error
 
 // A MockStatusPatchFn is used to mock client.Client's StatusUpdate implementation.
-type MockStatusPatchFn func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error
+type MockStatusPatchFn func(
+	ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption,
+) error
 
 // A MockSchemeFn is used to mock client.Client's Scheme implementation.
 type MockSchemeFn func() *runtime.Scheme
@@ -66,7 +66,7 @@ type ObjectListFn func(obj client.ObjectList) error
 
 // NewMockGetFn returns a MockGetFn that returns the supplied error.
 func NewMockGetFn(err error, ofn ...ObjectFn) MockGetFn {
-	return func(_ context.Context, _ client.ObjectKey, obj client.Object) error {
+	return func(_ context.Context, _ client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
 		for _, fn := range ofn {
 			if err := fn(obj); err != nil {
 				return err
@@ -172,7 +172,7 @@ func NewMockStatusPatchFn(err error, ofn ...ObjectFn) MockStatusPatchFn {
 	}
 }
 
-// NewMockSchemeFn returns a MockSchemeFn that returns the scheme
+// NewMockSchemeFn returns a MockSchemeFn that returns the scheme.
 func NewMockSchemeFn(scheme *runtime.Scheme) MockSchemeFn {
 	return func() *runtime.Scheme {
 		return scheme
@@ -216,7 +216,7 @@ func NewMockClient() *MockClient {
 }
 
 // Get calls MockClient's MockGet function.
-func (c *MockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
+func (c *MockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
 	return c.MockGet(ctx, key, obj)
 }
 
@@ -246,11 +246,13 @@ func (c *MockClient) Update(ctx context.Context, obj client.Object, opts ...clie
 }
 
 // Patch calls MockClient's MockPatch function.
-func (c *MockClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+func (c *MockClient) Patch(
+	ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption,
+) error {
 	return c.MockPatch(ctx, obj, patch, opts...)
 }
 
-// Status returns status writer for status sub-resource
+// Status returns status writer for status sub-resource.
 func (c *MockClient) Status() client.StatusWriter {
 	return &MockStatusWriter{
 		MockUpdate: c.MockStatusUpdate,
@@ -263,23 +265,25 @@ func (c *MockClient) RESTMapper() meta.RESTMapper {
 	return nil
 }
 
-// Scheme calls MockClient's MockScheme function
+// Scheme calls MockClient's MockScheme function.
 func (c *MockClient) Scheme() *runtime.Scheme {
 	return c.MockScheme()
 }
 
-// MockStatusWriter provides mock functionality for status sub-resource
+// MockStatusWriter provides mock functionality for status sub-resource.
 type MockStatusWriter struct {
 	MockUpdate MockStatusUpdateFn
 	MockPatch  MockStatusPatchFn
 }
 
-// Update status sub-resource
+// Update status sub-resource.
 func (m *MockStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
 	return m.MockUpdate(ctx, obj, opts...)
 }
 
-// Patch mocks the patch method
-func (m *MockStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+// Patch mocks the patch method.
+func (m *MockStatusWriter) Patch(
+	ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption,
+) error {
 	return m.MockPatch(ctx, obj, patch, opts...)
 }
diff --git a/test/e2e_test.go b/test/e2e_test.go
index 87edde57b..e26e28df8 100644
--- a/test/e2e_test.go
+++ b/test/e2e_test.go
@@ -133,6 +133,11 @@ func (e *e2e) TestSecurityProfilesOperator() {
 		e.testCaseSelinuxProfileBindingNsNotEnabled()
 	})
 
+	e.Run("cluster-wide: Selinux: Verify the policy can be marked as permissive", func() {
+		e.testCaseSelinuxIncompletePolicy()
+		e.testCaseSelinuxIncompletePermissivePolicy()
+	})
+
 	e.Run("cluster-wide: Selinux: Verify SELinux profile recording logs", func() {
 		e.testCaseProfileRecordingStaticPodSELinuxLogs()
 		e.testCaseProfileRecordingMultiContainerSELinuxLogs()
diff --git a/test/tc_allowed_syscalls_test.go b/test/tc_allowed_syscalls_test.go
index 4a4cb568a..c5f5c8d96 100644
--- a/test/tc_allowed_syscalls_test.go
+++ b/test/tc_allowed_syscalls_test.go
@@ -22,9 +22,8 @@ import (
 	"path"
 	"time"
 
-	v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
-
 	secprofnodestatusv1alpha1 "sigs.k8s.io/security-profiles-operator/api/secprofnodestatus/v1alpha1"
+	spodv1alpha1 "sigs.k8s.io/security-profiles-operator/api/spod/v1alpha1"
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
 )
 
@@ -219,8 +218,8 @@ spec:
 	e.logf("Ensuring profile cannot be deleted while pod is active")
 	for i := 0; i < 10; i++ {
 		sp := e.getSeccompProfile(allowProfileName, namespace)
-		conReady := sp.Status.GetCondition(v1.TypeReady)
-		if conReady.Reason == v1.ReasonDeleting {
+		conReady := sp.Status.GetReadyCondition()
+		if conReady.Reason == spodv1alpha1.ReasonDeleting {
 			break
 		}
 		time.Sleep(time.Second)
diff --git a/test/tc_delete_profiles_test.go b/test/tc_delete_profiles_test.go
index 5b736f964..851bd0f52 100644
--- a/test/tc_delete_profiles_test.go
+++ b/test/tc_delete_profiles_test.go
@@ -21,9 +21,8 @@ import (
 	"path"
 	"time"
 
-	v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
-
 	secprofnodestatusv1alpha1 "sigs.k8s.io/security-profiles-operator/api/secprofnodestatus/v1alpha1"
+	spodv1alpha1 "sigs.k8s.io/security-profiles-operator/api/spod/v1alpha1"
 )
 
 func (e *e2e) testCaseDeleteProfiles(nodes []string) {
@@ -177,8 +176,8 @@ spec:
 		// TODO(jhrozek): deleting manifests as Ready=False, reason=Deleting, can we wait in a nicer way?
 		for i := 0; i < 10; i++ {
 			sp := e.getSeccompProfile(deleteProfileName, namespace)
-			conReady := sp.Status.GetCondition(v1.TypeReady)
-			if conReady.Reason == v1.ReasonDeleting {
+			conReady := sp.Status.GetReadyCondition()
+			if conReady.Reason == spodv1alpha1.ReasonDeleting {
 				break
 			}
 			time.Sleep(time.Second)
diff --git a/test/tc_selinux_base_usage_test.go b/test/tc_selinux_base_usage_test.go
index 22c08197e..61f41caab 100644
--- a/test/tc_selinux_base_usage_test.go
+++ b/test/tc_selinux_base_usage_test.go
@@ -61,6 +61,42 @@ spec:
         - open
 `
 
+	// this is the equivalent of errorloggerPolicy but with several calls removed. The idea is to
+	// ensure that the workload will fail if the policy in incomplete. Allows setting the permissive
+	// flag as needed.
+	errorloggerIncompletePolFmt = `
+apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
+kind: SelinuxProfile
+metadata:
+  name: errorlogger-incomplete-%s
+spec:
+  permissive: %s
+  allow:
+    var_log_t:
+      dir:
+        - getattr
+        - lock
+        - search
+        - ioctl
+        - add_name
+        - remove_name
+        - write
+      file:
+        - getattr
+        - read
+        - ioctl
+        - lock
+        - map
+        - open
+        - create
+      sock_file:
+        - getattr
+        - read
+        - write
+        - append
+        - open
+`
+
 	//nolint:lll // full yaml
 	podWithPolicyFmt = `
 apiVersion: v1
@@ -131,6 +167,80 @@ func (e *e2e) testCaseSelinuxBaseUsage(nodes []string) {
 	e.assertSelinuxPolicyIsRemoved(nodes, rawPolicyName, maxNodeIterations, sleepBetweenIterations)
 }
 
+func (e *e2e) testCaseSelinuxIncompletePolicy() {
+	e.selinuxOnlyTestCase()
+	enforcingProfileName := "errorlogger-incomplete-enforcing"
+
+	e.logf("The 'errorlogger' workload should error out with a wrong policy")
+
+	e.logf("creating incomplete policy")
+	removeFn := e.writeAndCreate(
+		fmt.Sprintf(errorloggerIncompletePolFmt, "enforcing", "false"),
+		"errorlogger-policy-incomplete-enforcing.yml")
+	defer removeFn()
+
+	// Let's wait for the policy to be processed
+	e.kubectl("wait", "--timeout", defaultSelinuxOpTimeout,
+		"--for", "condition=ready", "selinuxprofile", enforcingProfileName)
+
+	e.logf("creating workload - it should become ready, but fail")
+	podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage(enforcingProfileName))
+	e.writeAndCreate(podWithPolicy, "pod-w-incomplete-policy.yml")
+
+	// note: this would have been much nicer with kubectl wait --jsonpath, but I found it racy incase the status
+	// doesn't exist yet. So we're using a loop instead.
+	var exitCode string
+	for i := 0; i < 10; i++ {
+		exitCode = e.kubectl("get", "pods", "errorlogger",
+			"-o", "jsonpath={.status.containerStatuses[0].state.terminated.exitCode}")
+		if exitCode == "1" {
+			break
+		}
+		time.Sleep(2 * time.Second)
+	}
+	if exitCode != "1" {
+		e.Fail("The pod should have failed, but it didn't")
+	}
+
+	log := e.kubectl("logs", "errorlogger", "-c", "errorlogger")
+	e.Contains(log, "Permission denied")
+
+	e.logf("removing workload")
+	e.kubectl("delete", "pod", "errorlogger")
+
+	e.logf("removing policy")
+	e.kubectl("delete", "selinuxprofile", enforcingProfileName)
+}
+
+func (e *e2e) testCaseSelinuxIncompletePermissivePolicy() {
+	e.selinuxOnlyTestCase()
+	permissiveProfileName := "errorlogger-incomplete-permissive"
+
+	e.logf("The 'errorlogger' workload should run fine with a wrong policy in permissive mode")
+
+	e.logf("creating incomplete policy")
+	removeFn := e.writeAndCreate(
+		fmt.Sprintf(errorloggerIncompletePolFmt, "permissive", "true"),
+		"errorlogger-policy-incomplete-permissive.yml")
+	defer removeFn()
+
+	// Let's wait for the policy to be processed
+	e.kubectl("wait", "--timeout", defaultSelinuxOpTimeout,
+		"--for", "condition=ready", "selinuxprofile", permissiveProfileName)
+
+	e.logf("creating workload - it should become ready, but fail")
+	podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage(permissiveProfileName))
+	e.writeAndCreate(podWithPolicy, "pod-w-incomplete-permissive-policy.yml")
+
+	e.waitFor("condition=ready", "pod", "errorlogger")
+
+	e.logf("removing workload")
+	e.kubectl("delete", "pod", "errorlogger")
+
+	e.logf("removing policy")
+	e.kubectl("delete", "selinuxprofile", permissiveProfileName)
+}
+
 func (e *e2e) assertSelinuxPolicyIsInstalled(nodes []string, policy string, nodeIterations int, sleep time.Duration) {
 	for i := 0; i < nodeIterations; i++ {
 		var missingPolName string
diff --git a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/cmp.go b/vendor/github.com/crossplane/crossplane-runtime/pkg/test/cmp.go
deleted file mode 100644
index a7414c1bf..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/cmp.go
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package test
-
-import (
-	"reflect"
-
-	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-cmp/cmp/cmpopts"
-
-	xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
-)
-
-// EquateErrors returns true if the supplied errors are of the same type and
-// produce identical strings. This mirrors the error comparison behaviour of
-// https://github.com/go-test/deep, which most Crossplane tests targeted before
-// we switched to go-cmp.
-//
-// This differs from cmpopts.EquateErrors, which does not test for error strings
-// and instead returns whether one error 'is' (in the errors.Is sense) the
-// other.
-func EquateErrors() cmp.Option {
-	return cmp.Comparer(func(a, b error) bool {
-		if a == nil || b == nil {
-			return a == nil && b == nil
-		}
-
-		av := reflect.ValueOf(a)
-		bv := reflect.ValueOf(b)
-		if av.Type() != bv.Type() {
-			return false
-		}
-
-		return a.Error() == b.Error()
-	})
-}
-
-// EquateConditions sorts any slices of Condition before comparing them.
-func EquateConditions() cmp.Option {
-	return cmpopts.SortSlices(func(i, j xpv1.Condition) bool { return i.Type < j.Type })
-}
diff --git a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/doc.go b/vendor/github.com/crossplane/crossplane-runtime/pkg/test/doc.go
deleted file mode 100644
index 47b625b52..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/doc.go
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package test implements utilities that can be used to test Kubernetes
-// controllers that reconcile Crossplane resources.
-package test
diff --git a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/retry.go b/vendor/github.com/crossplane/crossplane-runtime/pkg/test/retry.go
deleted file mode 100644
index 72ef7b69d..000000000
--- a/vendor/github.com/crossplane/crossplane-runtime/pkg/test/retry.go
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-Copyright 2019 The Crossplane Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package test
-
-import (
-	"time"
-
-	"k8s.io/apimachinery/pkg/util/wait"
-)
-
-// DefaultRetry is the recommended retry parameters for unit testing scenarios where a condition is being
-// tested multiple times before it is expected to succeed.
-var DefaultRetry = wait.Backoff{
-	Steps:    500,
-	Duration: 10 * time.Millisecond,
-	Factor:   1.0,
-	Jitter:   0.1,
-}