Repository: kubernetes-sigs/kueue

Issue:
Upgrade controller-runtime to v0.20.x
<!-- Please only use this template for submitting clean up requests -->

**What would you like to be cleaned**:
Once blocker dependencies (https://github.com/ray-project/kuberay/pull/3004) are fixed and released, we want to upgrade the controller-runtime version to v0.20.x.

**Why is this needed**:
Stabilize projects and dependencies.


Hints from issue comments:
@mimowo: cc @mszadkow 
who is already preparing the ground for it with the kuberay upgrades.
@tenzen-y: > cc [@mszadkow](https://github.com/mszadkow) who is already preparing the ground for it with the kuberay upgrades.

Thanks for working on this. I assign this to @mszadkow 
/assign @mszadkow 


Solution patch:
diff --git a/go.mod b/go.mod
index 8e2047bf0..624e0597d 100644
--- a/go.mod
+++ b/go.mod
@@ -34,16 +34,13 @@ require (
 	k8s.io/kubectl v0.32.3
 	k8s.io/metrics v0.32.3
 	k8s.io/utils v0.0.0-20241210054802-24370beab758
-	sigs.k8s.io/controller-runtime v0.20.3
+	sigs.k8s.io/controller-runtime v0.20.4
 	sigs.k8s.io/jobset v0.8.0
 	sigs.k8s.io/lws v0.5.1
 	sigs.k8s.io/structured-merge-diff/v4 v4.6.0
 	sigs.k8s.io/yaml v1.4.0
 )
 
-// TODO: Once https://github.com/kubernetes-sigs/kueue/issues/4470 is resolved, we should upgrade this.
-replace sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.19.4
-
 require (
 	cel.dev/expr v0.19.1 // indirect
 	github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
diff --git a/go.sum b/go.sum
index d5f856041..b2f6af6dd 100644
--- a/go.sum
+++ b/go.sum
@@ -377,8 +377,8 @@ k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJ
 k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.1 h1:uOuSLOMBWkJH0TWa9X6l+mj5nZdm6Ay6Bli8HL8rNfk=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.1/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/controller-runtime v0.19.4 h1:SUmheabttt0nx8uJtoII4oIP27BVVvAKFvdvGFwV/Qo=
-sigs.k8s.io/controller-runtime v0.19.4/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
+sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU=
+sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY=
 sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM=
 sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs=
 sigs.k8s.io/jobset v0.8.0 h1:80cJcPld+IMdKFOqzEW4et3Y6lGAPcP8YmBZ+aiKGYA=
diff --git a/vendor/golang.org/x/exp/maps/maps.go b/vendor/golang.org/x/exp/maps/maps.go
deleted file mode 100644
index 4a9747ef4..000000000
--- a/vendor/golang.org/x/exp/maps/maps.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2021 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 maps defines various functions useful with maps of any type.
-package maps
-
-import "maps"
-
-// Keys returns the keys of the map m.
-// The keys will be in an indeterminate order.
-//
-// The simplest true equivalent using the standard library  is:
-//
-//	slices.AppendSeq(make([]K, 0, len(m)), maps.Keys(m))
-func Keys[M ~map[K]V, K comparable, V any](m M) []K {
-
-	r := make([]K, 0, len(m))
-	for k := range m {
-		r = append(r, k)
-	}
-	return r
-}
-
-// Values returns the values of the map m.
-// The values will be in an indeterminate order.
-//
-// The simplest true equivalent using the standard library is:
-//
-//	slices.AppendSeq(make([]V, 0, len(m)), maps.Values(m))
-func Values[M ~map[K]V, K comparable, V any](m M) []V {
-
-	r := make([]V, 0, len(m))
-	for _, v := range m {
-		r = append(r, v)
-	}
-	return r
-}
-
-// Equal reports whether two maps contain the same key/value pairs.
-// Values are compared using ==.
-//
-//go:fix inline
-func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool {
-	return maps.Equal(m1, m2)
-}
-
-// EqualFunc is like Equal, but compares values using eq.
-// Keys are still compared with ==.
-//
-//go:fix inline
-func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool {
-	return maps.EqualFunc(m1, m2, eq)
-}
-
-// Clear removes all entries from m, leaving it empty.
-//
-//go:fix inline
-func Clear[M ~map[K]V, K comparable, V any](m M) {
-	clear(m)
-}
-
-// Clone returns a copy of m.  This is a shallow clone:
-// the new keys and values are set using ordinary assignment.
-//
-//go:fix inline
-func Clone[M ~map[K]V, K comparable, V any](m M) M {
-	return maps.Clone(m)
-}
-
-// Copy copies all key/value pairs in src adding them to dst.
-// When a key in src is already present in dst,
-// the value in dst will be overwritten by the value associated
-// with the key in src.
-//
-//go:fix inline
-func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) {
-	maps.Copy(dst, src)
-}
-
-// DeleteFunc deletes any key/value pairs from m for which del returns true.
-//
-//go:fix inline
-func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) {
-	maps.DeleteFunc(m, del)
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index d66536ffe..342a86dc3 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -463,7 +463,6 @@ golang.org/x/crypto/nacl/secretbox
 golang.org/x/crypto/salsa20/salsa
 # golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
 ## explicit; go 1.23.0
-golang.org/x/exp/maps
 golang.org/x/exp/slices
 # golang.org/x/mod v0.24.0
 ## explicit; go 1.23.0
@@ -1527,8 +1526,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
-# sigs.k8s.io/controller-runtime v0.20.3 => sigs.k8s.io/controller-runtime v0.19.4
-## explicit; go 1.22.0
+# sigs.k8s.io/controller-runtime v0.20.4
+## explicit; go 1.23.0
 sigs.k8s.io/controller-runtime
 sigs.k8s.io/controller-runtime/pkg/builder
 sigs.k8s.io/controller-runtime/pkg/cache
@@ -1544,6 +1543,7 @@ sigs.k8s.io/controller-runtime/pkg/cluster
 sigs.k8s.io/controller-runtime/pkg/config
 sigs.k8s.io/controller-runtime/pkg/controller
 sigs.k8s.io/controller-runtime/pkg/controller/controllerutil
+sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue
 sigs.k8s.io/controller-runtime/pkg/conversion
 sigs.k8s.io/controller-runtime/pkg/envtest
 sigs.k8s.io/controller-runtime/pkg/event
@@ -1555,6 +1555,7 @@ sigs.k8s.io/controller-runtime/pkg/internal/field/selector
 sigs.k8s.io/controller-runtime/pkg/internal/flock
 sigs.k8s.io/controller-runtime/pkg/internal/httpserver
 sigs.k8s.io/controller-runtime/pkg/internal/log
+sigs.k8s.io/controller-runtime/pkg/internal/metrics
 sigs.k8s.io/controller-runtime/pkg/internal/objectutil
 sigs.k8s.io/controller-runtime/pkg/internal/recorder
 sigs.k8s.io/controller-runtime/pkg/internal/source
@@ -1691,4 +1692,3 @@ sigs.k8s.io/structured-merge-diff/v4/value
 sigs.k8s.io/yaml
 sigs.k8s.io/yaml/goyaml.v2
 sigs.k8s.io/yaml/goyaml.v3
-# sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.19.4
diff --git a/vendor/sigs.k8s.io/controller-runtime/.golangci.yml b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
index 4c43665e2..7cb910fb8 100644
--- a/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
+++ b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
@@ -5,13 +5,13 @@ linters:
     - asciicheck
     - bidichk
     - bodyclose
+    - copyloopvar
     - dogsled
     - dupl
     - errcheck
     - errchkjson
     - errorlint
     - exhaustive
-    - exportloopref
     - ginkgolinter
     - goconst
     - gocritic
@@ -19,7 +19,6 @@ linters:
     - gofmt
     - goimports
     - goprintffuncname
-    - gosec
     - gosimple
     - govet
     - importas
@@ -165,8 +164,16 @@ issues:
     - linters:
         - dupl
       path: _test\.go
+    - linters:
+        - revive
+      path: .*/internal/.*
+    - linters:
+        - unused
+      # Seems to incorrectly trigger on the two implementations that are only
+      # used through an interface and not directly..?
+      path: pkg/controller/priorityqueue/metrics\.go
 
 run:
-  go: "1.22"
+  go: "1.23"
   timeout: 10m
   allow-parallel-runners: true
diff --git a/vendor/sigs.k8s.io/controller-runtime/.gomodcheck.yaml b/vendor/sigs.k8s.io/controller-runtime/.gomodcheck.yaml
index 75c5261fd..3608de331 100644
--- a/vendor/sigs.k8s.io/controller-runtime/.gomodcheck.yaml
+++ b/vendor/sigs.k8s.io/controller-runtime/.gomodcheck.yaml
@@ -12,3 +12,6 @@ excludedModules:
   # --- test dependencies:
   - github.com/onsi/ginkgo/v2
   - github.com/onsi/gomega
+
+  # --- We want a newer version with generics support for this
+  - github.com/google/btree
diff --git a/vendor/sigs.k8s.io/controller-runtime/Makefile b/vendor/sigs.k8s.io/controller-runtime/Makefile
index 9d92b9773..2361df981 100644
--- a/vendor/sigs.k8s.io/controller-runtime/Makefile
+++ b/vendor/sigs.k8s.io/controller-runtime/Makefile
@@ -27,7 +27,7 @@ SHELL:=/usr/bin/env bash
 #
 # Go.
 #
-GO_VERSION ?= 1.22.5
+GO_VERSION ?= 1.23.0
 
 # Use GOPROXY environment variable if set
 GOPROXY := $(shell go env GOPROXY)
@@ -88,7 +88,7 @@ GO_APIDIFF_PKG := github.com/joelanford/go-apidiff
 $(GO_APIDIFF): # Build go-apidiff from tools folder.
 	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GO_APIDIFF_PKG) $(GO_APIDIFF_BIN) $(GO_APIDIFF_VER)
 
-CONTROLLER_GEN_VER := v0.14.0
+CONTROLLER_GEN_VER := v0.17.1
 CONTROLLER_GEN_BIN := controller-gen
 CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER))
 CONTROLLER_GEN_PKG := sigs.k8s.io/controller-tools/cmd/controller-gen
@@ -174,7 +174,7 @@ release-binary: $(RELEASE_DIR)
 		-v "$$(pwd):/workspace$(DOCKER_VOL_OPTS)" \
 		-w /workspace/tools/setup-envtest \
 		golang:$(GO_VERSION) \
-		go build -a -trimpath -ldflags "-extldflags '-static'" \
+		go build -a -trimpath -ldflags "-X 'sigs.k8s.io/controller-runtime/tools/setup-envtest/version.version=$(RELEASE_TAG)' -extldflags '-static'" \
 		-o ./out/$(RELEASE_BINARY) ./
 
 ## --------------------------------------
diff --git a/vendor/sigs.k8s.io/controller-runtime/README.md b/vendor/sigs.k8s.io/controller-runtime/README.md
index 7b4f34504..b9709fce3 100644
--- a/vendor/sigs.k8s.io/controller-runtime/README.md
+++ b/vendor/sigs.k8s.io/controller-runtime/README.md
@@ -53,6 +53,7 @@ Compatible k8s.io/*, client-go and minimum Go versions can be looked up in our [
 
 |          | k8s.io/*, client-go | minimum Go version |
 |----------|:-------------------:|:------------------:|
+| CR v0.20 |        v0.32        |        1.23        |
 | CR v0.19 |        v0.31        |        1.22        |
 | CR v0.18 |        v0.30        |        1.22        |
 | CR v0.17 |        v0.29        |        1.21        |
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 81d8f7405..c74742d6e 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
@@ -20,6 +20,7 @@ import (
 	"errors"
 	"net/http"
 	"net/url"
+	"regexp"
 	"strings"
 
 	"github.com/go-logr/logr"
@@ -36,15 +37,17 @@ import (
 
 // WebhookBuilder builds a Webhook.
 type WebhookBuilder struct {
-	apiType         runtime.Object
-	customDefaulter admission.CustomDefaulter
-	customValidator admission.CustomValidator
-	gvk             schema.GroupVersionKind
-	mgr             manager.Manager
-	config          *rest.Config
-	recoverPanic    *bool
-	logConstructor  func(base logr.Logger, req *admission.Request) logr.Logger
-	err             error
+	apiType             runtime.Object
+	customDefaulter     admission.CustomDefaulter
+	customDefaulterOpts []admission.DefaulterOption
+	customValidator     admission.CustomValidator
+	customPath          string
+	gvk                 schema.GroupVersionKind
+	mgr                 manager.Manager
+	config              *rest.Config
+	recoverPanic        *bool
+	logConstructor      func(base logr.Logger, req *admission.Request) logr.Logger
+	err                 error
 }
 
 // WebhookManagedBy returns a new webhook builder.
@@ -65,9 +68,11 @@ func (blder *WebhookBuilder) For(apiType runtime.Object) *WebhookBuilder {
 	return blder
 }
 
-// WithDefaulter takes an admission.CustomDefaulter interface, a MutatingWebhook will be wired for this type.
-func (blder *WebhookBuilder) WithDefaulter(defaulter admission.CustomDefaulter) *WebhookBuilder {
+// WithDefaulter takes an admission.CustomDefaulter interface, a MutatingWebhook with the provided opts (admission.DefaulterOption)
+// will be wired for this type.
+func (blder *WebhookBuilder) WithDefaulter(defaulter admission.CustomDefaulter, opts ...admission.DefaulterOption) *WebhookBuilder {
 	blder.customDefaulter = defaulter
+	blder.customDefaulterOpts = opts
 	return blder
 }
 
@@ -90,6 +95,12 @@ func (blder *WebhookBuilder) RecoverPanic(recoverPanic bool) *WebhookBuilder {
 	return blder
 }
 
+// WithCustomPath overrides the webhook's default path by the customPath
+func (blder *WebhookBuilder) WithCustomPath(customPath string) *WebhookBuilder {
+	blder.customPath = customPath
+	return blder
+}
+
 // Complete builds the webhook.
 func (blder *WebhookBuilder) Complete() error {
 	// Set the Config
@@ -140,8 +151,15 @@ func (blder *WebhookBuilder) registerWebhooks() error {
 	}
 
 	// Register webhook(s) for type
-	blder.registerDefaultingWebhook()
-	blder.registerValidatingWebhook()
+	err = blder.registerDefaultingWebhook()
+	if err != nil {
+		return err
+	}
+
+	err = blder.registerValidatingWebhook()
+	if err != nil {
+		return err
+	}
 
 	err = blder.registerConversionWebhook()
 	if err != nil {
@@ -151,11 +169,18 @@ func (blder *WebhookBuilder) registerWebhooks() error {
 }
 
 // registerDefaultingWebhook registers a defaulting webhook if necessary.
-func (blder *WebhookBuilder) registerDefaultingWebhook() {
+func (blder *WebhookBuilder) registerDefaultingWebhook() error {
 	mwh := blder.getDefaultingWebhook()
 	if mwh != nil {
 		mwh.LogConstructor = blder.logConstructor
 		path := generateMutatePath(blder.gvk)
+		if blder.customPath != "" {
+			generatedCustomPath, err := generateCustomPath(blder.customPath)
+			if err != nil {
+				return err
+			}
+			path = generatedCustomPath
+		}
 
 		// Checking if the path is already registered.
 		// If so, just skip it.
@@ -166,35 +191,34 @@ func (blder *WebhookBuilder) registerDefaultingWebhook() {
 			blder.mgr.GetWebhookServer().Register(path, mwh)
 		}
 	}
+
+	return nil
 }
 
 func (blder *WebhookBuilder) getDefaultingWebhook() *admission.Webhook {
 	if defaulter := blder.customDefaulter; defaulter != nil {
-		w := admission.WithCustomDefaulter(blder.mgr.GetScheme(), blder.apiType, defaulter)
+		w := admission.WithCustomDefaulter(blder.mgr.GetScheme(), blder.apiType, defaulter, blder.customDefaulterOpts...)
 		if blder.recoverPanic != nil {
 			w = w.WithRecoverPanic(*blder.recoverPanic)
 		}
 		return w
 	}
-	if defaulter, ok := blder.apiType.(admission.Defaulter); ok {
-		w := admission.DefaultingWebhookFor(blder.mgr.GetScheme(), defaulter)
-		if blder.recoverPanic != nil {
-			w = w.WithRecoverPanic(*blder.recoverPanic)
-		}
-		return w
-	}
-	log.Info(
-		"skip registering a mutating webhook, object does not implement admission.Defaulter or WithDefaulter wasn't called",
-		"GVK", blder.gvk)
 	return nil
 }
 
 // registerValidatingWebhook registers a validating webhook if necessary.
-func (blder *WebhookBuilder) registerValidatingWebhook() {
+func (blder *WebhookBuilder) registerValidatingWebhook() error {
 	vwh := blder.getValidatingWebhook()
 	if vwh != nil {
 		vwh.LogConstructor = blder.logConstructor
 		path := generateValidatePath(blder.gvk)
+		if blder.customPath != "" {
+			generatedCustomPath, err := generateCustomPath(blder.customPath)
+			if err != nil {
+				return err
+			}
+			path = generatedCustomPath
+		}
 
 		// Checking if the path is already registered.
 		// If so, just skip it.
@@ -205,6 +229,8 @@ func (blder *WebhookBuilder) registerValidatingWebhook() {
 			blder.mgr.GetWebhookServer().Register(path, vwh)
 		}
 	}
+
+	return nil
 }
 
 func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook {
@@ -215,16 +241,6 @@ func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook {
 		}
 		return w
 	}
-	if validator, ok := blder.apiType.(admission.Validator); ok {
-		w := admission.ValidatingWebhookFor(blder.mgr.GetScheme(), validator)
-		if blder.recoverPanic != nil {
-			w = w.WithRecoverPanic(*blder.recoverPanic)
-		}
-		return w
-	}
-	log.Info(
-		"skip registering a validating webhook, object does not implement admission.Validator or WithValidator wasn't called",
-		"GVK", blder.gvk)
 	return nil
 }
 
@@ -271,3 +287,14 @@ func generateValidatePath(gvk schema.GroupVersionKind) string {
 	return "/validate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" +
 		gvk.Version + "-" + strings.ToLower(gvk.Kind)
 }
+
+const webhookPathStringValidation = `^((/[a-zA-Z0-9-_]+)+|/)$`
+
+var validWebhookPathRegex = regexp.MustCompile(webhookPathStringValidation)
+
+func generateCustomPath(customPath string) (string, error) {
+	if !validWebhookPathRegex.MatchString(customPath) {
+		return "", errors.New("customPath \"" + customPath + "\" does not match this regex: " + webhookPathStringValidation)
+	}
+	return customPath, nil
+}
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 406380d32..8f14bfdbf 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
@@ -19,11 +19,12 @@ package cache
 import (
 	"context"
 	"fmt"
+	"maps"
 	"net/http"
+	"slices"
 	"sort"
 	"time"
 
-	"golang.org/x/exp/maps"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/meta"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -231,15 +232,16 @@ type Options struct {
 	// This will be used for all object types, unless it is set in ByObject or
 	// DefaultNamespaces.
 	//
-	// Defaults to false.
+	// Defaults to true.
 	DefaultEnableWatchBookmarks *bool
 
 	// ByObject restricts the cache's ListWatch to the desired fields per GVK at the specified object.
 	// If unset, this will fall through to the Default* settings.
 	ByObject map[client.Object]ByObject
 
-	// newInformer allows overriding of NewSharedIndexInformer for testing.
-	newInformer *func(toolscache.ListerWatcher, runtime.Object, time.Duration, toolscache.Indexers) toolscache.SharedIndexInformer
+	// NewInformer allows overriding of NewSharedIndexInformer, for example for testing
+	// or if someone wants to write their own Informer.
+	NewInformer func(toolscache.ListerWatcher, runtime.Object, time.Duration, toolscache.Indexers) toolscache.SharedIndexInformer
 }
 
 // ByObject offers more fine-grained control over the cache's ListWatch by object.
@@ -291,7 +293,7 @@ type ByObject struct {
 	// assume bookmarks are returned at any specific interval, nor may they
 	// assume the server will send any BOOKMARK event during a session.
 	//
-	// Defaults to false.
+	// Defaults to true.
 	EnableWatchBookmarks *bool
 }
 
@@ -326,7 +328,7 @@ type Config struct {
 	// assume bookmarks are returned at any specific interval, nor may they
 	// assume the server will send any BOOKMARK event during a session.
 	//
-	// Defaults to false.
+	// Defaults to true.
 	EnableWatchBookmarks *bool
 }
 
@@ -430,8 +432,8 @@ func newCache(restConfig *rest.Config, opts Options) newCacheFunc {
 				Transform:             config.Transform,
 				WatchErrorHandler:     opts.DefaultWatchErrorHandler,
 				UnsafeDisableDeepCopy: ptr.Deref(config.UnsafeDisableDeepCopy, false),
-				EnableWatchBookmarks:  ptr.Deref(config.EnableWatchBookmarks, false),
-				NewInformer:           opts.newInformer,
+				EnableWatchBookmarks:  ptr.Deref(config.EnableWatchBookmarks, true),
+				NewInformer:           opts.NewInformer,
 			}),
 			readerFailOnMissingInformer: opts.ReaderFailOnMissingInformer,
 		}
@@ -467,6 +469,8 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
 		}
 	}
 
+	opts.ByObject = maps.Clone(opts.ByObject)
+	opts.DefaultNamespaces = maps.Clone(opts.DefaultNamespaces)
 	for obj, byObject := range opts.ByObject {
 		isNamespaced, err := apiutil.IsObjectNamespaced(obj, opts.Scheme, opts.Mapper)
 		if err != nil {
@@ -478,6 +482,8 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
 
 		if isNamespaced && byObject.Namespaces == nil {
 			byObject.Namespaces = maps.Clone(opts.DefaultNamespaces)
+		} else {
+			byObject.Namespaces = maps.Clone(byObject.Namespaces)
 		}
 
 		// Default the namespace-level configs first, because they need to use the undefaulted type-level config
@@ -485,7 +491,6 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
 		for namespace, config := range byObject.Namespaces {
 			// 1. Default from the undefaulted type-level config
 			config = defaultConfig(config, byObjectToConfig(byObject))
-
 			// 2. Default from the namespace-level config. This was defaulted from the global default config earlier, but
 			//    might not have an entry for the current namespace.
 			if defaultNamespaceSettings, hasDefaultNamespace := opts.DefaultNamespaces[namespace]; hasDefaultNamespace {
@@ -498,7 +503,7 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
 			if namespace == metav1.NamespaceAll {
 				config.FieldSelector = fields.AndSelectors(
 					appendIfNotNil(
-						namespaceAllSelector(maps.Keys(byObject.Namespaces)),
+						namespaceAllSelector(slices.Collect(maps.Keys(byObject.Namespaces))),
 						config.FieldSelector,
 					)...,
 				)
@@ -529,7 +534,7 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
 		if namespace == metav1.NamespaceAll {
 			cfg.FieldSelector = fields.AndSelectors(
 				appendIfNotNil(
-					namespaceAllSelector(maps.Keys(opts.DefaultNamespaces)),
+					namespaceAllSelector(slices.Collect(maps.Keys(opts.DefaultNamespaces))),
 					cfg.FieldSelector,
 				)...,
 			)
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/delegating_by_gvk_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/delegating_by_gvk_cache.go
index 4db8208a6..46bd243c6 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/delegating_by_gvk_cache.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/delegating_by_gvk_cache.go
@@ -18,10 +18,11 @@ package cache
 
 import (
 	"context"
+	"maps"
+	"slices"
 	"strings"
 	"sync"
 
-	"golang.org/x/exp/maps"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -73,7 +74,7 @@ func (dbt *delegatingByGVKCache) GetInformerForKind(ctx context.Context, gvk sch
 }
 
 func (dbt *delegatingByGVKCache) Start(ctx context.Context) error {
-	allCaches := maps.Values(dbt.caches)
+	allCaches := slices.Collect(maps.Values(dbt.caches))
 	allCaches = append(allCaches, dbt.defaultCache)
 
 	wg := &sync.WaitGroup{}
@@ -100,7 +101,7 @@ func (dbt *delegatingByGVKCache) Start(ctx context.Context) error {
 
 func (dbt *delegatingByGVKCache) WaitForCacheSync(ctx context.Context) bool {
 	synced := true
-	for _, cache := range append(maps.Values(dbt.caches), dbt.defaultCache) {
+	for _, cache := range append(slices.Collect(maps.Values(dbt.caches)), dbt.defaultCache) {
 		if !cache.WaitForCacheSync(ctx) {
 			synced = false
 		}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
index a40382d6f..097ee7a45 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
@@ -47,7 +47,7 @@ type InformersOpts struct {
 	Mapper                meta.RESTMapper
 	ResyncPeriod          time.Duration
 	Namespace             string
-	NewInformer           *func(cache.ListerWatcher, runtime.Object, time.Duration, cache.Indexers) cache.SharedIndexInformer
+	NewInformer           func(cache.ListerWatcher, runtime.Object, time.Duration, cache.Indexers) cache.SharedIndexInformer
 	Selector              Selector
 	Transform             cache.TransformFunc
 	UnsafeDisableDeepCopy bool
@@ -59,7 +59,7 @@ type InformersOpts struct {
 func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
 	newInformer := cache.NewSharedIndexInformer
 	if options.NewInformer != nil {
-		newInformer = *options.NewInformer
+		newInformer = options.NewInformer
 	}
 	return &Informers{
 		config:     config,
@@ -585,7 +585,7 @@ func newGVKFixupWatcher(gvk schema.GroupVersionKind, watcher watch.Interface) wa
 // hammer the apiserver with list requests simultaneously.
 func calculateResyncPeriod(resync time.Duration) time.Duration {
 	// the factor will fall into [0.9, 1.1)
-	factor := rand.Float64()/5.0 + 0.9 //nolint:gosec
+	factor := rand.Float64()/5.0 + 0.9
 	return time.Duration(float64(resync.Nanoseconds()) * factor)
 }
 
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 da69f40f6..aeeeb6693 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
@@ -262,6 +262,9 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
 	if listOpts.Namespace != corev1.NamespaceAll {
 		cache, ok := c.namespaceToCache[listOpts.Namespace]
 		if !ok {
+			if global, hasGlobal := c.namespaceToCache[AllNamespaces]; hasGlobal {
+				return global.List(ctx, list, opts...)
+			}
 			return fmt.Errorf("unable to list: %v because of unknown namespace for the cache", listOpts.Namespace)
 		}
 		return cache.List(ctx, list, opts...)
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper.go
index 927be22b4..7a7a0d114 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/restmapper.go
@@ -28,6 +28,7 @@ import (
 	"k8s.io/client-go/discovery"
 	"k8s.io/client-go/rest"
 	"k8s.io/client-go/restmapper"
+	"k8s.io/utils/ptr"
 )
 
 // NewDynamicRESTMapper returns a dynamic RESTMapper for cfg. The dynamic
@@ -41,6 +42,7 @@ func NewDynamicRESTMapper(cfg *rest.Config, httpClient *http.Client) (meta.RESTM
 	if err != nil {
 		return nil, err
 	}
+
 	return &mapper{
 		mapper:      restmapper.NewDiscoveryRESTMapper([]*restmapper.APIGroupResources{}),
 		client:      client,
@@ -53,11 +55,15 @@ func NewDynamicRESTMapper(cfg *rest.Config, httpClient *http.Client) (meta.RESTM
 // client for discovery information to do REST mappings.
 type mapper struct {
 	mapper      meta.RESTMapper
-	client      discovery.DiscoveryInterface
+	client      discovery.AggregatedDiscoveryInterface
 	knownGroups map[string]*restmapper.APIGroupResources
 	apiGroups   map[string]*metav1.APIGroup
 
+	initialDiscoveryDone bool
+
 	// mutex to provide thread-safe mapper reloading.
+	// It protects all fields in the mapper as well as methods
+	// that have the `Locked` suffix.
 	mu sync.RWMutex
 }
 
@@ -159,28 +165,42 @@ func (m *mapper) addKnownGroupAndReload(groupName string, versions ...string) er
 		versions = nil
 	}
 
+	m.mu.Lock()
+	defer m.mu.Unlock()
 	// If no specific versions are set by user, we will scan all available ones for the API group.
 	// This operation requires 2 requests: /api and /apis, but only once. For all subsequent calls
 	// this data will be taken from cache.
-	if len(versions) == 0 {
-		apiGroup, err := m.findAPIGroupByName(groupName)
+	//
+	// We always run this once, because if the server supports aggregated discovery, this will
+	// load everything with two api calls which we assume is overall cheaper.
+	if len(versions) == 0 || !m.initialDiscoveryDone {
+		apiGroup, didAggregatedDiscovery, err := m.findAPIGroupByNameAndMaybeAggregatedDiscoveryLocked(groupName)
 		if err != nil {
 			return err
 		}
-		if apiGroup != nil {
+		if apiGroup != nil && len(versions) == 0 {
 			for _, version := range apiGroup.Versions {
 				versions = append(versions, version.Version)
 			}
 		}
-	}
-
-	m.mu.Lock()
-	defer m.mu.Unlock()
 
-	// Create or fetch group resources from cache.
-	groupResources := &restmapper.APIGroupResources{
-		Group:              metav1.APIGroup{Name: groupName},
-		VersionedResources: make(map[string][]metav1.APIResource),
+		// No need to do anything further if aggregatedDiscovery is supported and we did a lookup
+		if didAggregatedDiscovery {
+			failedGroups := make(map[schema.GroupVersion]error)
+			for _, version := range versions {
+				if m.knownGroups[groupName] == nil || m.knownGroups[groupName].VersionedResources[version] == nil {
+					failedGroups[schema.GroupVersion{Group: groupName, Version: version}] = &meta.NoResourceMatchError{
+						PartialResource: schema.GroupVersionResource{
+							Group:   groupName,
+							Version: version,
+						}}
+				}
+			}
+			if len(failedGroups) > 0 {
+				return ptr.To(ErrResourceDiscoveryFailed(failedGroups))
+			}
+			return nil
+		}
 	}
 
 	// Update information for group resources about versioned resources.
@@ -194,13 +214,26 @@ func (m *mapper) addKnownGroupAndReload(groupName string, versions ...string) er
 		return fmt.Errorf("failed to get API group resources: %w", err)
 	}
 
-	if _, ok := m.knownGroups[groupName]; ok {
-		groupResources = m.knownGroups[groupName]
-	}
+	m.addGroupVersionResourcesToCacheAndReloadLocked(groupVersionResources)
+	return nil
+}
 
+// addGroupVersionResourcesToCacheAndReloadLocked does what the name suggests. The mutex must be held when
+// calling it.
+func (m *mapper) addGroupVersionResourcesToCacheAndReloadLocked(gvr map[schema.GroupVersion]*metav1.APIResourceList) {
 	// Update information for group resources about the API group by adding new versions.
-	// Ignore the versions that are already registered.
-	for groupVersion, resources := range groupVersionResources {
+	// Ignore the versions that are already registered
+	for groupVersion, resources := range gvr {
+		var groupResources *restmapper.APIGroupResources
+		if _, ok := m.knownGroups[groupVersion.Group]; ok {
+			groupResources = m.knownGroups[groupVersion.Group]
+		} else {
+			groupResources = &restmapper.APIGroupResources{
+				Group:              metav1.APIGroup{Name: groupVersion.Group},
+				VersionedResources: make(map[string][]metav1.APIResource),
+			}
+		}
+
 		version := groupVersion.Version
 
 		groupResources.VersionedResources[version] = resources.APIResources
@@ -213,61 +246,65 @@ func (m *mapper) addKnownGroupAndReload(groupName string, versions ...string) er
 		}
 
 		if !found {
-			groupResources.Group.Versions = append(groupResources.Group.Versions, metav1.GroupVersionForDiscovery{
-				GroupVersion: metav1.GroupVersion{Group: groupName, Version: version}.String(),
+			gv := metav1.GroupVersionForDiscovery{
+				GroupVersion: metav1.GroupVersion{Group: groupVersion.Group, Version: version}.String(),
 				Version:      version,
-			})
+			}
+
+			// Prepend if preferred version, else append. The upstream DiscoveryRestMappper assumes
+			// the first version is the preferred one: https://github.com/kubernetes/kubernetes/blob/ef54ac803b712137871c1a1f8d635d50e69ffa6c/staging/src/k8s.io/apimachinery/pkg/api/meta/restmapper.go#L458-L461
+			if group, ok := m.apiGroups[groupVersion.Group]; ok && group.PreferredVersion.Version == version {
+				groupResources.Group.Versions = append([]metav1.GroupVersionForDiscovery{gv}, groupResources.Group.Versions...)
+			} else {
+				groupResources.Group.Versions = append(groupResources.Group.Versions, gv)
+			}
 		}
-	}
 
-	// Update data in the cache.
-	m.knownGroups[groupName] = groupResources
+		// Update data in the cache.
+		m.knownGroups[groupVersion.Group] = groupResources
+	}
 
-	// Finally, update the group with received information and regenerate the mapper.
+	// Finally, reload the mapper.
 	updatedGroupResources := make([]*restmapper.APIGroupResources, 0, len(m.knownGroups))
 	for _, agr := range m.knownGroups {
 		updatedGroupResources = append(updatedGroupResources, agr)
 	}
 
 	m.mapper = restmapper.NewDiscoveryRESTMapper(updatedGroupResources)
-	return nil
 }
 
-// findAPIGroupByNameLocked returns API group by its name.
-func (m *mapper) findAPIGroupByName(groupName string) (*metav1.APIGroup, error) {
-	// Looking in the cache first.
-	{
-		m.mu.RLock()
-		group, ok := m.apiGroups[groupName]
-		m.mu.RUnlock()
-		if ok {
-			return group, nil
-		}
+// findAPIGroupByNameAndMaybeAggregatedDiscoveryLocked tries to find the passed apiGroup.
+// If the server supports aggregated discovery, it will always perform that.
+func (m *mapper) findAPIGroupByNameAndMaybeAggregatedDiscoveryLocked(groupName string) (_ *metav1.APIGroup, didAggregatedDiscovery bool, _ error) {
+	// Looking in the cache first
+	group, ok := m.apiGroups[groupName]
+	if ok {
+		return group, false, nil
 	}
 
 	// Update the cache if nothing was found.
-	apiGroups, err := m.client.ServerGroups()
+	apiGroups, maybeResources, _, err := m.client.GroupsAndMaybeResources()
 	if err != nil {
-		return nil, fmt.Errorf("failed to get server groups: %w", err)
+		return nil, false, fmt.Errorf("failed to get server groups: %w", err)
 	}
 	if len(apiGroups.Groups) == 0 {
-		return nil, fmt.Errorf("received an empty API groups list")
+		return nil, false, fmt.Errorf("received an empty API groups list")
 	}
 
-	m.mu.Lock()
+	m.initialDiscoveryDone = true
 	for i := range apiGroups.Groups {
 		group := &apiGroups.Groups[i]
 		m.apiGroups[group.Name] = group
 	}
-	m.mu.Unlock()
+	if len(maybeResources) > 0 {
+		didAggregatedDiscovery = true
+		m.addGroupVersionResourcesToCacheAndReloadLocked(maybeResources)
+	}
 
 	// Looking in the cache again.
-	m.mu.RLock()
-	defer m.mu.RUnlock()
-
 	// Don't return an error here if the API group is not present.
 	// The reloaded RESTMapper will take care of returning a NoMatchError.
-	return m.apiGroups[groupName], nil
+	return m.apiGroups[groupName], didAggregatedDiscovery, nil
 }
 
 // fetchGroupVersionResourcesLocked fetches the resources for the specified group and its versions.
@@ -283,10 +320,10 @@ func (m *mapper) fetchGroupVersionResourcesLocked(groupName string, versions ...
 		if apierrors.IsNotFound(err) {
 			// If the version is not found, we remove the group from the cache
 			// so it gets refreshed on the next call.
-			if m.isAPIGroupCached(groupVersion) {
+			if m.isAPIGroupCachedLocked(groupVersion) {
 				delete(m.apiGroups, groupName)
 			}
-			if m.isGroupVersionCached(groupVersion) {
+			if m.isGroupVersionCachedLocked(groupVersion) {
 				delete(m.knownGroups, groupName)
 			}
 			continue
@@ -308,8 +345,8 @@ func (m *mapper) fetchGroupVersionResourcesLocked(groupName string, versions ...
 	return groupVersionResources, nil
 }
 
-// isGroupVersionCached checks if a version for a group is cached in the known groups cache.
-func (m *mapper) isGroupVersionCached(gv schema.GroupVersion) bool {
+// isGroupVersionCachedLocked checks if a version for a group is cached in the known groups cache.
+func (m *mapper) isGroupVersionCachedLocked(gv schema.GroupVersion) bool {
 	if cachedGroup, ok := m.knownGroups[gv.Group]; ok {
 		_, cached := cachedGroup.VersionedResources[gv.Version]
 		return cached
@@ -318,8 +355,8 @@ func (m *mapper) isGroupVersionCached(gv schema.GroupVersion) bool {
 	return false
 }
 
-// isAPIGroupCached checks if a version for a group is cached in the api groups cache.
-func (m *mapper) isAPIGroupCached(gv schema.GroupVersion) bool {
+// isAPIGroupCachedLocked checks if a version for a group is cached in the api groups cache.
+func (m *mapper) isAPIGroupCachedLocked(gv schema.GroupVersion) bool {
 	cachedGroup, ok := m.apiGroups[gv.Group]
 	if !ok {
 		return false
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 fe9862b81..6d8744017 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
@@ -113,11 +113,11 @@ func newClient(config *rest.Config, options Options) (*client, error) {
 	}
 
 	if config.WarningHandler == nil {
-		// By default, we de-duplicate and surface warnings.
+		// By default, we surface warnings.
 		config.WarningHandler = log.NewKubeAPIWarningLogger(
 			log.Log.WithName("KubeAPIWarningLogger"),
 			log.KubeAPIWarningLoggerOptions{
-				Deduplicate: true,
+				Deduplicate: false,
 			},
 		)
 	}
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 54f5b5d25..793219c72 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
@@ -32,6 +32,7 @@ import (
 	// Using v4 to match upstream
 	jsonpatch "gopkg.in/evanphx/json-patch.v4"
 	appsv1 "k8s.io/api/apps/v1"
+	authenticationv1 "k8s.io/api/authentication/v1"
 	autoscalingv1 "k8s.io/api/autoscaling/v1"
 	corev1 "k8s.io/api/core/v1"
 	policyv1 "k8s.io/api/policy/v1"
@@ -74,8 +75,8 @@ type fakeClient struct {
 	trackerWriteLock sync.Mutex
 	tracker          versionedTracker
 
-	schemeWriteLock sync.Mutex
-	scheme          *runtime.Scheme
+	schemeLock sync.RWMutex
+	scheme     *runtime.Scheme
 
 	restMapper            meta.RESTMapper
 	withStatusSubresource sets.Set[schema.GroupVersionKind]
@@ -83,6 +84,8 @@ type fakeClient struct {
 	// indexes maps each GroupVersionKind (GVK) to the indexes registered for that GVK.
 	// The inner map maps from index name to IndexerFunc.
 	indexes map[schema.GroupVersionKind]map[string]client.IndexerFunc
+	// indexesLock must be held when accessing indexes.
+	indexesLock sync.RWMutex
 }
 
 var _ client.WithWatch = &fakeClient{}
@@ -509,6 +512,8 @@ func (t versionedTracker) updateObject(gvr schema.GroupVersionResource, obj runt
 }
 
 func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
+	c.schemeLock.RLock()
+	defer c.schemeLock.RUnlock()
 	gvr, err := getGVRFromObject(obj, c.scheme)
 	if err != nil {
 		return err
@@ -558,6 +563,8 @@ func (c *fakeClient) Watch(ctx context.Context, list client.ObjectList, opts ...
 }
 
 func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
+	c.schemeLock.RLock()
+	defer c.schemeLock.RUnlock()
 	gvk, err := apiutil.GVKForObject(obj, c.scheme)
 	if err != nil {
 		return err
@@ -570,9 +577,11 @@ func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...cl
 	if _, isUnstructuredList := obj.(runtime.Unstructured); isUnstructuredList && !c.scheme.Recognizes(gvk) {
 		// We need to register the ListKind with UnstructuredList:
 		// https://github.com/kubernetes/kubernetes/blob/7b2776b89fb1be28d4e9203bdeec079be903c103/staging/src/k8s.io/client-go/dynamic/fake/simple.go#L44-L51
-		c.schemeWriteLock.Lock()
+		c.schemeLock.RUnlock()
+		c.schemeLock.Lock()
 		c.scheme.AddKnownTypeWithName(gvk.GroupVersion().WithKind(gvk.Kind+"List"), &unstructured.UnstructuredList{})
-		c.schemeWriteLock.Unlock()
+		c.schemeLock.Unlock()
+		c.schemeLock.RLock()
 	}
 
 	listOpts := client.ListOptions{}
@@ -598,21 +607,31 @@ func (c *fakeClient) List(ctx context.Context, obj client.ObjectList, opts ...cl
 		return err
 	}
 	zero(obj)
-	if err := json.Unmarshal(j, obj); err != nil {
+	objCopy := obj.DeepCopyObject().(client.ObjectList)
+	if err := json.Unmarshal(j, objCopy); err != nil {
 		return err
 	}
 
-	if listOpts.LabelSelector == nil && listOpts.FieldSelector == nil {
-		return nil
+	if _, isUnstructured := obj.(runtime.Unstructured); isUnstructured {
+		ta, err := meta.TypeAccessor(obj)
+		if err != nil {
+			return err
+		}
+		ta.SetKind(originalKind)
+		ta.SetAPIVersion(gvk.GroupVersion().String())
 	}
 
-	// If we're here, either a label or field selector are specified (or both), so before we return
-	// the list we must filter it. If both selectors are set, they are ANDed.
-	objs, err := meta.ExtractList(obj)
+	objs, err := meta.ExtractList(objCopy)
 	if err != nil {
 		return err
 	}
 
+	if listOpts.LabelSelector == nil && listOpts.FieldSelector == nil {
+		return meta.SetList(obj, objs)
+	}
+
+	// If we're here, either a label or field selector are specified (or both), so before we return
+	// the list we must filter it. If both selectors are set, they are ANDed.
 	filteredList, err := c.filterList(objs, gvk, listOpts.LabelSelector, listOpts.FieldSelector)
 	if err != nil {
 		return err
@@ -647,10 +666,11 @@ func (c *fakeClient) filterList(list []runtime.Object, gvk schema.GroupVersionKi
 func (c *fakeClient) filterWithFields(list []runtime.Object, gvk schema.GroupVersionKind, fs fields.Selector) ([]runtime.Object, error) {
 	requiresExact := selector.RequiresExactMatch(fs)
 	if !requiresExact {
-		return nil, fmt.Errorf("field selector %s is not in one of the two supported forms \"key==val\" or \"key=val\"",
-			fs)
+		return nil, fmt.Errorf(`field selector %s is not in one of the two supported forms "key==val" or "key=val"`, fs)
 	}
 
+	c.indexesLock.RLock()
+	defer c.indexesLock.RUnlock()
 	// Field selection is mimicked via indexes, so there's no sane answer this function can give
 	// if there are no indexes registered for the GroupVersionKind of the objects in the list.
 	indexes := c.indexes[gvk]
@@ -712,6 +732,8 @@ func (c *fakeClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
 }
 
 func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
+	c.schemeLock.RLock()
+	defer c.schemeLock.RUnlock()
 	createOptions := &client.CreateOptions{}
 	createOptions.ApplyOptions(opts)
 
@@ -748,6 +770,8 @@ func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...clie
 }
 
 func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
+	c.schemeLock.RLock()
+	defer c.schemeLock.RUnlock()
 	gvr, err := getGVRFromObject(obj, c.scheme)
 	if err != nil {
 		return err
@@ -793,6 +817,8 @@ func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...clie
 }
 
 func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
+	c.schemeLock.RLock()
+	defer c.schemeLock.RUnlock()
 	gvk, err := apiutil.GVKForObject(obj, c.scheme)
 	if err != nil {
 		return err
@@ -842,6 +868,8 @@ func (c *fakeClient) Update(ctx context.Context, obj client.Object, opts ...clie
 }
 
 func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.UpdateOption) error {
+	c.schemeLock.RLock()
+	defer c.schemeLock.RUnlock()
 	updateOptions := &client.UpdateOptions{}
 	updateOptions.ApplyOptions(opts)
 
@@ -870,6 +898,8 @@ func (c *fakeClient) Patch(ctx context.Context, obj client.Object, patch client.
 }
 
 func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+	c.schemeLock.RLock()
+	defer c.schemeLock.RUnlock()
 	patchOptions := &client.PatchOptions{}
 	patchOptions.ApplyOptions(opts)
 
@@ -1027,6 +1057,8 @@ func dryPatch(action testing.PatchActionImpl, tracker testing.ObjectTracker) (ru
 		}
 	case types.ApplyPatchType:
 		return nil, errors.New("apply patches are not supported in the fake client. Follow https://github.com/kubernetes/kubernetes/issues/115598 for the current status")
+	case types.ApplyCBORPatchType:
+		return nil, errors.New("apply CBOR patches are not supported in the fake client")
 	default:
 		return nil, fmt.Errorf("%s PatchType is not supported", action.GetPatchType())
 	}
@@ -1150,7 +1182,7 @@ func (sw *fakeSubResourceClient) Get(ctx context.Context, obj, subResource clien
 		}
 		scale, isScale := subResource.(*autoscalingv1.Scale)
 		if !isScale {
-			return apierrors.NewBadRequest(fmt.Sprintf("expected Scale, got %t", subResource))
+			return apierrors.NewBadRequest(fmt.Sprintf("expected Scale, got %T", subResource))
 		}
 		scaleOut, err := extractScale(obj)
 		if err != nil {
@@ -1171,13 +1203,26 @@ func (sw *fakeSubResourceClient) Create(ctx context.Context, obj client.Object,
 			_, isEviction = subResource.(*policyv1.Eviction)
 		}
 		if !isEviction {
-			return apierrors.NewBadRequest(fmt.Sprintf("got invalid type %t, expected Eviction", subResource))
+			return apierrors.NewBadRequest(fmt.Sprintf("got invalid type %T, expected Eviction", subResource))
 		}
 		if _, isPod := obj.(*corev1.Pod); !isPod {
 			return apierrors.NewNotFound(schema.GroupResource{}, "")
 		}
 
 		return sw.client.Delete(ctx, obj)
+	case "token":
+		tokenRequest, isTokenRequest := subResource.(*authenticationv1.TokenRequest)
+		if !isTokenRequest {
+			return apierrors.NewBadRequest(fmt.Sprintf("got invalid type %T, expected TokenRequest", subResource))
+		}
+		if _, isServiceAccount := obj.(*corev1.ServiceAccount); !isServiceAccount {
+			return apierrors.NewNotFound(schema.GroupResource{}, "")
+		}
+
+		tokenRequest.Status.Token = "fake-token"
+		tokenRequest.Status.ExpirationTimestamp = metav1.Date(6041, 1, 1, 0, 0, 0, 0, time.UTC)
+
+		return sw.client.Get(ctx, client.ObjectKeyFromObject(obj), obj)
 	default:
 		return fmt.Errorf("fakeSubResourceWriter does not support create for %s", sw.subResource)
 	}
@@ -1198,7 +1243,7 @@ func (sw *fakeSubResourceClient) Update(ctx context.Context, obj client.Object,
 
 		scale, isScale := updateOptions.SubResourceBody.(*autoscalingv1.Scale)
 		if !isScale {
-			return apierrors.NewBadRequest(fmt.Sprintf("expected Scale, got %t", updateOptions.SubResourceBody))
+			return apierrors.NewBadRequest(fmt.Sprintf("expected Scale, got %T", updateOptions.SubResourceBody))
 		}
 		if err := applyScale(obj, scale); err != nil {
 			return err
@@ -1512,3 +1557,37 @@ func applyScale(obj client.Object, scale *autoscalingv1.Scale) error {
 	}
 	return nil
 }
+
+// AddIndex adds an index to a fake client. It will panic if used with a client that is not a fake client.
+// It will error if there is already an index for given object with the same name as field.
+//
+// It can be used to test code that adds indexes to the cache at runtime.
+func AddIndex(c client.Client, obj runtime.Object, field string, extractValue client.IndexerFunc) error {
+	fakeClient, isFakeClient := c.(*fakeClient)
+	if !isFakeClient {
+		panic("AddIndex can only be used with a fake client")
+	}
+	fakeClient.indexesLock.Lock()
+	defer fakeClient.indexesLock.Unlock()
+
+	if fakeClient.indexes == nil {
+		fakeClient.indexes = make(map[schema.GroupVersionKind]map[string]client.IndexerFunc, 1)
+	}
+
+	gvk, err := apiutil.GVKForObject(obj, fakeClient.scheme)
+	if err != nil {
+		return fmt.Errorf("failed to get gvk for %T: %w", obj, err)
+	}
+
+	if fakeClient.indexes[gvk] == nil {
+		fakeClient.indexes[gvk] = make(map[string]client.IndexerFunc, 1)
+	}
+
+	if fakeClient.indexes[gvk][field] != nil {
+		return fmt.Errorf("index %s already exists", field)
+	}
+
+	fakeClient.indexes[gvk][field] = extractValue
+
+	return nil
+}
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 d42347a2e..47cad3980 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
@@ -20,7 +20,7 @@ Package fake provides a fake client for testing.
 A fake client is backed by its simple object store indexed by GroupVersionResource.
 You can create a fake client with optional objects.
 
-	client := NewClientBuilder().WithScheme(scheme).WithObj(initObjs...).Build()
+	client := NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build()
 
 You can invoke the methods defined in the Client interface.
 
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 3cd745e4c..3b282fc2c 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
@@ -94,16 +94,16 @@ type SubResourceClientConstructor interface {
 	// - ServiceAccount token creation:
 	//     sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
 	//     token := &authenticationv1.TokenRequest{}
-	//     c.SubResourceClient("token").Create(ctx, sa, token)
+	//     c.SubResource("token").Create(ctx, sa, token)
 	//
 	// - Pod eviction creation:
 	//     pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
-	//     c.SubResourceClient("eviction").Create(ctx, pod, &policyv1.Eviction{})
+	//     c.SubResource("eviction").Create(ctx, pod, &policyv1.Eviction{})
 	//
 	// - Pod binding creation:
 	//     pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
 	//     binding := &corev1.Binding{Target: corev1.ObjectReference{Name: "my-node"}}
-	//     c.SubResourceClient("binding").Create(ctx, pod, binding)
+	//     c.SubResource("binding").Create(ctx, pod, binding)
 	//
 	// - CertificateSigningRequest approval:
 	//     csr := &certificatesv1.CertificateSigningRequest{
@@ -115,17 +115,17 @@ type SubResourceClientConstructor interface {
 	//         }},
 	//       },
 	//     }
-	//     c.SubResourceClient("approval").Update(ctx, csr)
+	//     c.SubResource("approval").Update(ctx, csr)
 	//
 	// - Scale retrieval:
 	//     dep := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
 	//     scale := &autoscalingv1.Scale{}
-	//     c.SubResourceClient("scale").Get(ctx, dep, scale)
+	//     c.SubResource("scale").Get(ctx, dep, scale)
 	//
 	// - Scale update:
 	//     dep := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"}}
 	//     scale := &autoscalingv1.Scale{Spec: autoscalingv1.ScaleSpec{Replicas: 2}}
-	//     c.SubResourceClient("scale").Update(ctx, dep, client.WithSubResourceBody(scale))
+	//     c.SubResource("scale").Update(ctx, dep, client.WithSubResourceBody(scale))
 	SubResource(subResource string) SubResourceClient
 }
 
@@ -193,7 +193,7 @@ type IndexerFunc func(Object) []string
 // FieldIndexer knows how to index over a particular "field" such that it
 // can later be used by a field selector.
 type FieldIndexer interface {
-	// IndexFields adds an index with the given field name on the given object type
+	// IndexField adds an index with the given field name on the given object type
 	// by using the given function to extract the value for that field.  If you want
 	// compatibility with the Kubernetes API server, only return one key, and only use
 	// fields that the API server supports.  Otherwise, you can return multiple keys,
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
index 248893ea3..0603f4cde 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
@@ -20,7 +20,6 @@ import (
 	"context"
 	"errors"
 	"net/http"
-	"time"
 
 	"github.com/go-logr/logr"
 	"k8s.io/apimachinery/pkg/api/meta"
@@ -65,8 +64,8 @@ type Cluster interface {
 	// GetRESTMapper returns a RESTMapper
 	GetRESTMapper() meta.RESTMapper
 
-	// GetAPIReader returns a reader that will be configured to use the API server.
-	// This should be used sparingly and only when the client does not fit your
+	// GetAPIReader returns a reader that will be configured to use the API server directly.
+	// This should be used sparingly and only when the cached client does not fit your
 	// use case.
 	GetAPIReader() client.Reader
 
@@ -88,16 +87,6 @@ type Options struct {
 	// If none is set, it defaults to log.Log global logger.
 	Logger logr.Logger
 
-	// SyncPeriod determines the minimum frequency at which watched resources are
-	// reconciled. A lower period will correct entropy more quickly, but reduce
-	// responsiveness to change if there are many watched resources. Change this
-	// value only if you know what you are doing. Defaults to 10 hours if unset.
-	// there will a 10 percent jitter between the SyncPeriod of all controllers
-	// so that all controllers will not send list requests simultaneously.
-	//
-	// Deprecated: Use Cache.SyncPeriod instead.
-	SyncPeriod *time.Duration
-
 	// HTTPClient is the http client that will be used to create the default
 	// Cache and Client. If not set the rest.HTTPClientFor function will be used
 	// to create the http client.
@@ -194,9 +183,6 @@ func New(config *rest.Config, opts ...Option) (Cluster, error) {
 		if cacheOpts.HTTPClient == nil {
 			cacheOpts.HTTPClient = options.HTTPClient
 		}
-		if cacheOpts.SyncPeriod == nil {
-			cacheOpts.SyncPeriod = options.SyncPeriod
-		}
 	}
 	cache, err := options.NewCache(config, cacheOpts)
 	if err != nil {
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go
index 999ef07e2..0b2aa0cb7 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go
@@ -53,4 +53,10 @@ type Controller struct {
 	// NeedLeaderElection indicates whether the controller needs to use leader election.
 	// Defaults to true, which means the controller will use leader election.
 	NeedLeaderElection *bool
+
+	// UsePriorityQueue configures the controllers queue to use the controller-runtime provided
+	// priority queue.
+	//
+	// Note: This flag is disabled by default until a future version. It's currently in beta.
+	UsePriorityQueue *bool
 }
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
index f2496236d..5c5b249ef 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
@@ -24,7 +24,9 @@ import (
 	"github.com/go-logr/logr"
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
+	"k8s.io/utils/ptr"
 
+	"sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue"
 	"sigs.k8s.io/controller-runtime/pkg/internal/controller"
 	"sigs.k8s.io/controller-runtime/pkg/manager"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -189,11 +191,21 @@ func NewTypedUnmanaged[request comparable](name string, mgr manager.Manager, opt
 	}
 
 	if options.RateLimiter == nil {
-		options.RateLimiter = workqueue.DefaultTypedControllerRateLimiter[request]()
+		if ptr.Deref(mgr.GetControllerOptions().UsePriorityQueue, false) {
+			options.RateLimiter = workqueue.NewTypedItemExponentialFailureRateLimiter[request](5*time.Millisecond, 1000*time.Second)
+		} else {
+			options.RateLimiter = workqueue.DefaultTypedControllerRateLimiter[request]()
+		}
 	}
 
 	if options.NewQueue == nil {
 		options.NewQueue = func(controllerName string, rateLimiter workqueue.TypedRateLimiter[request]) workqueue.TypedRateLimitingInterface[request] {
+			if ptr.Deref(mgr.GetControllerOptions().UsePriorityQueue, false) {
+				return priorityqueue.New(controllerName, func(o *priorityqueue.Opts[request]) {
+					o.Log = mgr.GetLogger().WithValues("controller", controllerName)
+					o.RateLimiter = rateLimiter
+				})
+			}
 			return workqueue.NewTypedRateLimitingQueueWithConfig(rateLimiter, workqueue.TypedRateLimitingQueueConfig[request]{
 				Name: controllerName,
 			})
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
index 176ce0db0..ba3f931e4 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
@@ -181,6 +181,21 @@ func HasControllerReference(object metav1.Object) bool {
 	return false
 }
 
+// HasOwnerReference returns true if the owners list contains an owner reference
+// that matches the object's group, kind, and name.
+func HasOwnerReference(ownerRefs []metav1.OwnerReference, obj client.Object, scheme *runtime.Scheme) (bool, error) {
+	gvk, err := apiutil.GVKForObject(obj, scheme)
+	if err != nil {
+		return false, err
+	}
+	idx := indexOwnerRef(ownerRefs, metav1.OwnerReference{
+		APIVersion: gvk.GroupVersion().String(),
+		Name:       obj.GetName(),
+		Kind:       gvk.Kind,
+	})
+	return idx != -1, nil
+}
+
 // RemoveControllerReference removes an owner reference where the controller
 // equals true
 func RemoveControllerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/name.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/name.go
index 0e71a01c6..00ca65512 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/name.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/name.go
@@ -34,7 +34,7 @@ func checkName(name string) error {
 	}
 
 	if usedNames.Has(name) {
-		return fmt.Errorf("controller with name %s already exists. Controller names must be unique to avoid multiple controllers reporting to the same metric", name)
+		return fmt.Errorf("controller with name %s already exists. Controller names must be unique to avoid multiple controllers reporting the same metric. This validation can be disabled via the SkipNameValidation option", name)
 	}
 
 	usedNames.Insert(name)
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue/metrics.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue/metrics.go
new file mode 100644
index 000000000..36626646f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue/metrics.go
@@ -0,0 +1,146 @@
+package priorityqueue
+
+import (
+	"sync"
+	"time"
+
+	"k8s.io/client-go/util/workqueue"
+	"k8s.io/utils/clock"
+)
+
+// This file is mostly a copy of unexported code from
+// https://github.com/kubernetes/kubernetes/blob/1d8828ce707ed9dd7a6a9756385419cce1d202ac/staging/src/k8s.io/client-go/util/workqueue/metrics.go
+//
+// The only two differences are the addition of mapLock in defaultQueueMetrics and converging retryMetrics into queueMetrics.
+
+type queueMetrics[T comparable] interface {
+	add(item T)
+	get(item T)
+	done(item T)
+	updateUnfinishedWork()
+	retry()
+}
+
+func newQueueMetrics[T comparable](mp workqueue.MetricsProvider, name string, clock clock.Clock) queueMetrics[T] {
+	if len(name) == 0 {
+		return noMetrics[T]{}
+	}
+	return &defaultQueueMetrics[T]{
+		clock:                   clock,
+		depth:                   mp.NewDepthMetric(name),
+		adds:                    mp.NewAddsMetric(name),
+		latency:                 mp.NewLatencyMetric(name),
+		workDuration:            mp.NewWorkDurationMetric(name),
+		unfinishedWorkSeconds:   mp.NewUnfinishedWorkSecondsMetric(name),
+		longestRunningProcessor: mp.NewLongestRunningProcessorSecondsMetric(name),
+		addTimes:                map[T]time.Time{},
+		processingStartTimes:    map[T]time.Time{},
+		retries:                 mp.NewRetriesMetric(name),
+	}
+}
+
+// defaultQueueMetrics expects the caller to lock before setting any metrics.
+type defaultQueueMetrics[T comparable] struct {
+	clock clock.Clock
+
+	// current depth of a workqueue
+	depth workqueue.GaugeMetric
+	// total number of adds handled by a workqueue
+	adds workqueue.CounterMetric
+	// how long an item stays in a workqueue
+	latency workqueue.HistogramMetric
+	// how long processing an item from a workqueue takes
+	workDuration workqueue.HistogramMetric
+
+	mapLock              sync.RWMutex
+	addTimes             map[T]time.Time
+	processingStartTimes map[T]time.Time
+
+	// how long have current threads been working?
+	unfinishedWorkSeconds   workqueue.SettableGaugeMetric
+	longestRunningProcessor workqueue.SettableGaugeMetric
+
+	retries workqueue.CounterMetric
+}
+
+// add is called for ready items only
+func (m *defaultQueueMetrics[T]) add(item T) {
+	if m == nil {
+		return
+	}
+
+	m.adds.Inc()
+	m.depth.Inc()
+
+	m.mapLock.Lock()
+	defer m.mapLock.Unlock()
+
+	if _, exists := m.addTimes[item]; !exists {
+		m.addTimes[item] = m.clock.Now()
+	}
+}
+
+func (m *defaultQueueMetrics[T]) get(item T) {
+	if m == nil {
+		return
+	}
+
+	m.depth.Dec()
+
+	m.mapLock.Lock()
+	defer m.mapLock.Unlock()
+
+	m.processingStartTimes[item] = m.clock.Now()
+	if startTime, exists := m.addTimes[item]; exists {
+		m.latency.Observe(m.sinceInSeconds(startTime))
+		delete(m.addTimes, item)
+	}
+}
+
+func (m *defaultQueueMetrics[T]) done(item T) {
+	if m == nil {
+		return
+	}
+
+	m.mapLock.Lock()
+	defer m.mapLock.Unlock()
+	if startTime, exists := m.processingStartTimes[item]; exists {
+		m.workDuration.Observe(m.sinceInSeconds(startTime))
+		delete(m.processingStartTimes, item)
+	}
+}
+
+func (m *defaultQueueMetrics[T]) updateUnfinishedWork() {
+	m.mapLock.RLock()
+	defer m.mapLock.RUnlock()
+	// Note that a summary metric would be better for this, but prometheus
+	// doesn't seem to have non-hacky ways to reset the summary metrics.
+	var total float64
+	var oldest float64
+	for _, t := range m.processingStartTimes {
+		age := m.sinceInSeconds(t)
+		total += age
+		if age > oldest {
+			oldest = age
+		}
+	}
+	m.unfinishedWorkSeconds.Set(total)
+	m.longestRunningProcessor.Set(oldest)
+}
+
+// Gets the time since the specified start in seconds.
+func (m *defaultQueueMetrics[T]) sinceInSeconds(start time.Time) float64 {
+	return m.clock.Since(start).Seconds()
+}
+
+func (m *defaultQueueMetrics[T]) retry() {
+	m.retries.Inc()
+}
+
+type noMetrics[T any] struct{}
+
+func (noMetrics[T]) add(item T)            {}
+func (noMetrics[T]) get(item T)            {}
+func (noMetrics[T]) done(item T)           {}
+func (noMetrics[T]) updateUnfinishedWork() {}
+func (noMetrics[T]) retry()                {}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue/priorityqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue/priorityqueue.go
new file mode 100644
index 000000000..ff5dea902
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue/priorityqueue.go
@@ -0,0 +1,403 @@
+package priorityqueue
+
+import (
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/go-logr/logr"
+	"github.com/google/btree"
+	"k8s.io/apimachinery/pkg/util/sets"
+	"k8s.io/client-go/util/workqueue"
+	"k8s.io/utils/clock"
+	"k8s.io/utils/ptr"
+
+	"sigs.k8s.io/controller-runtime/pkg/internal/metrics"
+)
+
+// AddOpts describes the options for adding items to the queue.
+type AddOpts struct {
+	After       time.Duration
+	RateLimited bool
+	Priority    int
+}
+
+// PriorityQueue is a priority queue for a controller. It
+// internally de-duplicates all items that are added to
+// it. It will use the max of the passed priorities and the
+// min of possible durations.
+type PriorityQueue[T comparable] interface {
+	workqueue.TypedRateLimitingInterface[T]
+	AddWithOpts(o AddOpts, Items ...T)
+	GetWithPriority() (item T, priority int, shutdown bool)
+}
+
+// Opts contains the options for a PriorityQueue.
+type Opts[T comparable] struct {
+	// Ratelimiter is being used when AddRateLimited is called. Defaults to a per-item exponential backoff
+	// limiter with an initial delay of five milliseconds and a max delay of 1000 seconds.
+	RateLimiter    workqueue.TypedRateLimiter[T]
+	MetricProvider workqueue.MetricsProvider
+	Log            logr.Logger
+}
+
+// Opt allows to configure a PriorityQueue.
+type Opt[T comparable] func(*Opts[T])
+
+// New constructs a new PriorityQueue.
+func New[T comparable](name string, o ...Opt[T]) PriorityQueue[T] {
+	opts := &Opts[T]{}
+	for _, f := range o {
+		f(opts)
+	}
+
+	if opts.RateLimiter == nil {
+		opts.RateLimiter = workqueue.NewTypedItemExponentialFailureRateLimiter[T](5*time.Millisecond, 1000*time.Second)
+	}
+
+	if opts.MetricProvider == nil {
+		opts.MetricProvider = metrics.WorkqueueMetricsProvider{}
+	}
+
+	pq := &priorityqueue[T]{
+		log:         opts.Log,
+		items:       map[T]*item[T]{},
+		queue:       btree.NewG(32, less[T]),
+		becameReady: sets.Set[T]{},
+		metrics:     newQueueMetrics[T](opts.MetricProvider, name, clock.RealClock{}),
+		// itemOrWaiterAdded indicates that an item or
+		// waiter was added. It must be buffered, because
+		// if we currently process items we can't tell
+		// if that included the new item/waiter.
+		itemOrWaiterAdded: make(chan struct{}, 1),
+		rateLimiter:       opts.RateLimiter,
+		locked:            sets.Set[T]{},
+		done:              make(chan struct{}),
+		get:               make(chan item[T]),
+		now:               time.Now,
+		tick:              time.Tick,
+	}
+
+	go pq.spin()
+	go pq.logState()
+	if _, ok := pq.metrics.(noMetrics[T]); !ok {
+		go pq.updateUnfinishedWorkLoop()
+	}
+
+	return pq
+}
+
+type priorityqueue[T comparable] struct {
+	log logr.Logger
+	// lock has to be acquired for any access any of items, queue, addedCounter
+	// or becameReady
+	lock  sync.Mutex
+	items map[T]*item[T]
+	queue bTree[*item[T]]
+
+	// addedCounter is a counter of elements added, we need it
+	// because unixNano is not guaranteed to be unique.
+	addedCounter uint64
+
+	// becameReady holds items that are in the queue, were added
+	// with non-zero after and became ready. We need it to call the
+	// metrics add exactly once for them.
+	becameReady sets.Set[T]
+	metrics     queueMetrics[T]
+
+	itemOrWaiterAdded chan struct{}
+
+	rateLimiter workqueue.TypedRateLimiter[T]
+
+	// locked contains the keys we handed out through Get() and that haven't
+	// yet been returned through Done().
+	locked     sets.Set[T]
+	lockedLock sync.RWMutex
+
+	shutdown atomic.Bool
+	done     chan struct{}
+
+	get chan item[T]
+
+	// waiters is the number of routines blocked in Get, we use it to determine
+	// if we can push items.
+	waiters atomic.Int64
+
+	// Configurable for testing
+	now  func() time.Time
+	tick func(time.Duration) <-chan time.Time
+}
+
+func (w *priorityqueue[T]) AddWithOpts(o AddOpts, items ...T) {
+	w.lock.Lock()
+	defer w.lock.Unlock()
+
+	for _, key := range items {
+		after := o.After
+		if o.RateLimited {
+			rlAfter := w.rateLimiter.When(key)
+			if after == 0 || rlAfter < after {
+				after = rlAfter
+			}
+		}
+
+		var readyAt *time.Time
+		if after > 0 {
+			readyAt = ptr.To(w.now().Add(after))
+			w.metrics.retry()
+		}
+		if _, ok := w.items[key]; !ok {
+			item := &item[T]{
+				Key:          key,
+				AddedCounter: w.addedCounter,
+				Priority:     o.Priority,
+				ReadyAt:      readyAt,
+			}
+			w.items[key] = item
+			w.queue.ReplaceOrInsert(item)
+			if item.ReadyAt == nil {
+				w.metrics.add(key)
+			}
+			w.addedCounter++
+			continue
+		}
+
+		// The b-tree de-duplicates based on ordering and any change here
+		// will affect the order - Just delete and re-add.
+		item, _ := w.queue.Delete(w.items[key])
+		if o.Priority > item.Priority {
+			item.Priority = o.Priority
+		}
+
+		if item.ReadyAt != nil && (readyAt == nil || readyAt.Before(*item.ReadyAt)) {
+			if readyAt == nil && !w.becameReady.Has(key) {
+				w.metrics.add(key)
+			}
+			item.ReadyAt = readyAt
+		}
+
+		w.queue.ReplaceOrInsert(item)
+	}
+
+	if len(items) > 0 {
+		w.notifyItemOrWaiterAdded()
+	}
+}
+
+func (w *priorityqueue[T]) notifyItemOrWaiterAdded() {
+	select {
+	case w.itemOrWaiterAdded <- struct{}{}:
+	default:
+	}
+}
+
+func (w *priorityqueue[T]) spin() {
+	blockForever := make(chan time.Time)
+	var nextReady <-chan time.Time
+	nextReady = blockForever
+
+	for {
+		select {
+		case <-w.done:
+			return
+		case <-w.itemOrWaiterAdded:
+		case <-nextReady:
+		}
+
+		nextReady = blockForever
+
+		func() {
+			w.lock.Lock()
+			defer w.lock.Unlock()
+
+			w.lockedLock.Lock()
+			defer w.lockedLock.Unlock()
+
+			// manipulating the tree from within Ascend might lead to panics, so
+			// track what we want to delete and do it after we are done ascending.
+			var toDelete []*item[T]
+			w.queue.Ascend(func(item *item[T]) bool {
+				if item.ReadyAt != nil {
+					if readyAt := item.ReadyAt.Sub(w.now()); readyAt > 0 {
+						nextReady = w.tick(readyAt)
+						return false
+					}
+					if !w.becameReady.Has(item.Key) {
+						w.metrics.add(item.Key)
+						w.becameReady.Insert(item.Key)
+					}
+				}
+
+				if w.waiters.Load() == 0 {
+					// Have to keep iterating here to ensure we update metrics
+					// for further items that became ready and set nextReady.
+					return true
+				}
+
+				// Item is locked, we can not hand it out
+				if w.locked.Has(item.Key) {
+					return true
+				}
+
+				w.metrics.get(item.Key)
+				w.locked.Insert(item.Key)
+				w.waiters.Add(-1)
+				delete(w.items, item.Key)
+				toDelete = append(toDelete, item)
+				w.becameReady.Delete(item.Key)
+				w.get <- *item
+
+				return true
+			})
+
+			for _, item := range toDelete {
+				w.queue.Delete(item)
+			}
+		}()
+	}
+}
+
+func (w *priorityqueue[T]) Add(item T) {
+	w.AddWithOpts(AddOpts{}, item)
+}
+
+func (w *priorityqueue[T]) AddAfter(item T, after time.Duration) {
+	w.AddWithOpts(AddOpts{After: after}, item)
+}
+
+func (w *priorityqueue[T]) AddRateLimited(item T) {
+	w.AddWithOpts(AddOpts{RateLimited: true}, item)
+}
+
+func (w *priorityqueue[T]) GetWithPriority() (_ T, priority int, shutdown bool) {
+	w.waiters.Add(1)
+
+	w.notifyItemOrWaiterAdded()
+	item := <-w.get
+
+	return item.Key, item.Priority, w.shutdown.Load()
+}
+
+func (w *priorityqueue[T]) Get() (item T, shutdown bool) {
+	key, _, shutdown := w.GetWithPriority()
+	return key, shutdown
+}
+
+func (w *priorityqueue[T]) Forget(item T) {
+	w.rateLimiter.Forget(item)
+}
+
+func (w *priorityqueue[T]) NumRequeues(item T) int {
+	return w.rateLimiter.NumRequeues(item)
+}
+
+func (w *priorityqueue[T]) ShuttingDown() bool {
+	return w.shutdown.Load()
+}
+
+func (w *priorityqueue[T]) Done(item T) {
+	w.lockedLock.Lock()
+	defer w.lockedLock.Unlock()
+	w.locked.Delete(item)
+	w.metrics.done(item)
+	w.notifyItemOrWaiterAdded()
+}
+
+func (w *priorityqueue[T]) ShutDown() {
+	w.shutdown.Store(true)
+	close(w.done)
+}
+
+// ShutDownWithDrain just calls ShutDown, as the draining
+// functionality is not used by controller-runtime.
+func (w *priorityqueue[T]) ShutDownWithDrain() {
+	w.ShutDown()
+}
+
+// Len returns the number of items that are ready to be
+// picked up. It does not include items that are not yet
+// ready.
+func (w *priorityqueue[T]) Len() int {
+	w.lock.Lock()
+	defer w.lock.Unlock()
+
+	var result int
+	w.queue.Ascend(func(item *item[T]) bool {
+		if item.ReadyAt == nil || item.ReadyAt.Compare(w.now()) <= 0 {
+			result++
+			return true
+		}
+		return false
+	})
+
+	return result
+}
+
+func (w *priorityqueue[T]) logState() {
+	t := time.Tick(10 * time.Second)
+	for {
+		select {
+		case <-w.done:
+			return
+		case <-t:
+		}
+
+		// Log level may change at runtime, so keep the
+		// loop going even if a given level is currently
+		// not enabled.
+		if !w.log.V(5).Enabled() {
+			continue
+		}
+		w.lock.Lock()
+		items := make([]*item[T], 0, len(w.items))
+		w.queue.Ascend(func(item *item[T]) bool {
+			items = append(items, item)
+			return true
+		})
+		w.lock.Unlock()
+
+		w.log.V(5).Info("workqueue_items", "items", items)
+	}
+}
+
+func less[T comparable](a, b *item[T]) bool {
+	if a.ReadyAt == nil && b.ReadyAt != nil {
+		return true
+	}
+	if b.ReadyAt == nil && a.ReadyAt != nil {
+		return false
+	}
+	if a.ReadyAt != nil && b.ReadyAt != nil && !a.ReadyAt.Equal(*b.ReadyAt) {
+		return a.ReadyAt.Before(*b.ReadyAt)
+	}
+	if a.Priority != b.Priority {
+		return a.Priority > b.Priority
+	}
+
+	return a.AddedCounter < b.AddedCounter
+}
+
+type item[T comparable] struct {
+	Key          T          `json:"key"`
+	AddedCounter uint64     `json:"addedCounter"`
+	Priority     int        `json:"priority"`
+	ReadyAt      *time.Time `json:"readyAt,omitempty"`
+}
+
+func (w *priorityqueue[T]) updateUnfinishedWorkLoop() {
+	t := time.Tick(500 * time.Millisecond) // borrowed from workqueue: https://github.com/kubernetes/kubernetes/blob/67a807bf142c7a2a5ecfdb2a5d24b4cdea4cc79c/staging/src/k8s.io/client-go/util/workqueue/queue.go#L182
+	for {
+		select {
+		case <-w.done:
+			return
+		case <-t:
+		}
+		w.metrics.updateUnfinishedWork()
+	}
+}
+
+type bTree[T any] interface {
+	ReplaceOrInsert(item T) (_ T, _ bool)
+	Delete(item T) (T, bool)
+	Ascend(iterator btree.ItemIteratorG[T])
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
index 1a1d1ab2f..64cbe8a4d 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
@@ -52,25 +52,32 @@ func (e *TypedEnqueueRequestForObject[T]) Create(ctx context.Context, evt event.
 		enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
 		return
 	}
-	q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+
+	item := reconcile.Request{NamespacedName: types.NamespacedName{
 		Name:      evt.Object.GetName(),
 		Namespace: evt.Object.GetNamespace(),
-	}})
+	}}
+
+	addToQueueCreate(q, evt, item)
 }
 
 // Update implements EventHandler.
 func (e *TypedEnqueueRequestForObject[T]) Update(ctx context.Context, evt event.TypedUpdateEvent[T], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
 	switch {
 	case !isNil(evt.ObjectNew):
-		q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+		item := reconcile.Request{NamespacedName: types.NamespacedName{
 			Name:      evt.ObjectNew.GetName(),
 			Namespace: evt.ObjectNew.GetNamespace(),
-		}})
+		}}
+
+		addToQueueUpdate(q, evt, item)
 	case !isNil(evt.ObjectOld):
-		q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+		item := reconcile.Request{NamespacedName: types.NamespacedName{
 			Name:      evt.ObjectOld.GetName(),
 			Namespace: evt.ObjectOld.GetNamespace(),
-		}})
+		}}
+
+		addToQueueUpdate(q, evt, item)
 	default:
 		enqueueLog.Error(nil, "UpdateEvent received with no metadata", "event", evt)
 	}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
index 491bc40c4..be97fa378 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
@@ -21,6 +21,7 @@ import (
 
 	"k8s.io/client-go/util/workqueue"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue"
 	"sigs.k8s.io/controller-runtime/pkg/event"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 )
@@ -63,7 +64,8 @@ func EnqueueRequestsFromMapFunc(fn MapFunc) EventHandler {
 // TypedEnqueueRequestsFromMapFunc is experimental and subject to future change.
 func TypedEnqueueRequestsFromMapFunc[object any, request comparable](fn TypedMapFunc[object, request]) TypedEventHandler[object, request] {
 	return &enqueueRequestsFromMapFunc[object, request]{
-		toRequests: fn,
+		toRequests:                   fn,
+		objectImplementsClientObject: implementsClientObject[object](),
 	}
 }
 
@@ -71,7 +73,8 @@ var _ EventHandler = &enqueueRequestsFromMapFunc[client.Object, reconcile.Reques
 
 type enqueueRequestsFromMapFunc[object any, request comparable] struct {
 	// Mapper transforms the argument into a slice of keys to be reconciled
-	toRequests TypedMapFunc[object, request]
+	toRequests                   TypedMapFunc[object, request]
+	objectImplementsClientObject bool
 }
 
 // Create implements EventHandler.
@@ -81,7 +84,15 @@ func (e *enqueueRequestsFromMapFunc[object, request]) Create(
 	q workqueue.TypedRateLimitingInterface[request],
 ) {
 	reqs := map[request]empty{}
-	e.mapAndEnqueue(ctx, q, evt.Object, reqs)
+
+	var lowPriority bool
+	if e.objectImplementsClientObject && isPriorityQueue(q) && !isNil(evt.Object) {
+		clientObjectEvent := event.CreateEvent{Object: any(evt.Object).(client.Object)}
+		if isObjectUnchanged(clientObjectEvent) {
+			lowPriority = true
+		}
+	}
+	e.mapAndEnqueue(ctx, q, evt.Object, reqs, lowPriority)
 }
 
 // Update implements EventHandler.
@@ -90,9 +101,13 @@ func (e *enqueueRequestsFromMapFunc[object, request]) Update(
 	evt event.TypedUpdateEvent[object],
 	q workqueue.TypedRateLimitingInterface[request],
 ) {
+	var lowPriority bool
+	if e.objectImplementsClientObject && isPriorityQueue(q) && !isNil(evt.ObjectOld) && !isNil(evt.ObjectNew) {
+		lowPriority = any(evt.ObjectOld).(client.Object).GetResourceVersion() == any(evt.ObjectNew).(client.Object).GetResourceVersion()
+	}
 	reqs := map[request]empty{}
-	e.mapAndEnqueue(ctx, q, evt.ObjectOld, reqs)
-	e.mapAndEnqueue(ctx, q, evt.ObjectNew, reqs)
+	e.mapAndEnqueue(ctx, q, evt.ObjectOld, reqs, lowPriority)
+	e.mapAndEnqueue(ctx, q, evt.ObjectNew, reqs, lowPriority)
 }
 
 // Delete implements EventHandler.
@@ -102,7 +117,7 @@ func (e *enqueueRequestsFromMapFunc[object, request]) Delete(
 	q workqueue.TypedRateLimitingInterface[request],
 ) {
 	reqs := map[request]empty{}
-	e.mapAndEnqueue(ctx, q, evt.Object, reqs)
+	e.mapAndEnqueue(ctx, q, evt.Object, reqs, false)
 }
 
 // Generic implements EventHandler.
@@ -112,14 +127,26 @@ func (e *enqueueRequestsFromMapFunc[object, request]) Generic(
 	q workqueue.TypedRateLimitingInterface[request],
 ) {
 	reqs := map[request]empty{}
-	e.mapAndEnqueue(ctx, q, evt.Object, reqs)
+	e.mapAndEnqueue(ctx, q, evt.Object, reqs, false)
 }
 
-func (e *enqueueRequestsFromMapFunc[object, request]) mapAndEnqueue(ctx context.Context, q workqueue.TypedRateLimitingInterface[request], o object, reqs map[request]empty) {
+func (e *enqueueRequestsFromMapFunc[object, request]) mapAndEnqueue(
+	ctx context.Context,
+	q workqueue.TypedRateLimitingInterface[request],
+	o object,
+	reqs map[request]empty,
+	lowPriority bool,
+) {
 	for _, req := range e.toRequests(ctx, o) {
 		_, ok := reqs[req]
 		if !ok {
-			q.Add(req)
+			if lowPriority {
+				q.(priorityqueue.PriorityQueue[request]).AddWithOpts(priorityqueue.AddOpts{
+					Priority: LowPriority,
+				}, req)
+			} else {
+				q.Add(req)
+			}
 			reqs[req] = empty{}
 		}
 	}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
index 1680043b4..e8fc8eb46 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
@@ -72,7 +72,7 @@ func TypedEnqueueRequestForOwner[object client.Object](scheme *runtime.Scheme, m
 	for _, opt := range opts {
 		opt(e)
 	}
-	return e
+	return WithLowPriorityWhenUnchanged(e)
 }
 
 // OnlyControllerOwner if provided will only look at the first OwnerReference with Controller: true.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
index ea4bcee31..84a10ac07 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
@@ -18,9 +18,12 @@ package handler
 
 import (
 	"context"
+	"reflect"
+	"time"
 
 	"k8s.io/client-go/util/workqueue"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue"
 	"sigs.k8s.io/controller-runtime/pkg/event"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 )
@@ -106,10 +109,46 @@ type TypedFuncs[object any, request comparable] struct {
 	GenericFunc func(context.Context, event.TypedGenericEvent[object], workqueue.TypedRateLimitingInterface[request])
 }
 
+var typeForClientObject = reflect.TypeFor[client.Object]()
+
+func implementsClientObject[object any]() bool {
+	return reflect.TypeFor[object]().Implements(typeForClientObject)
+}
+
+func isPriorityQueue[request comparable](q workqueue.TypedRateLimitingInterface[request]) bool {
+	_, ok := q.(priorityqueue.PriorityQueue[request])
+	return ok
+}
+
 // Create implements EventHandler.
 func (h TypedFuncs[object, request]) Create(ctx context.Context, e event.TypedCreateEvent[object], q workqueue.TypedRateLimitingInterface[request]) {
 	if h.CreateFunc != nil {
-		h.CreateFunc(ctx, e, q)
+		if !implementsClientObject[object]() || !isPriorityQueue(q) || isNil(e.Object) {
+			h.CreateFunc(ctx, e, q)
+			return
+		}
+		wq := workqueueWithCustomAddFunc[request]{
+			TypedRateLimitingInterface: q,
+			// We already know that we have a priority queue, that event.Object implements
+			// client.Object and that its not nil
+			addFunc: func(item request, q workqueue.TypedRateLimitingInterface[request]) {
+				// We construct a new event typed to client.Object because isObjectUnchanged
+				// is a generic and hence has to know at compile time the type of the event
+				// it gets. We only figure that out at runtime though, but we know for sure
+				// that it implements client.Object at this point so we can hardcode the event
+				// type to that.
+				evt := event.CreateEvent{Object: any(e.Object).(client.Object)}
+				var priority int
+				if isObjectUnchanged(evt) {
+					priority = LowPriority
+				}
+				q.(priorityqueue.PriorityQueue[request]).AddWithOpts(
+					priorityqueue.AddOpts{Priority: priority},
+					item,
+				)
+			},
+		}
+		h.CreateFunc(ctx, e, wq)
 	}
 }
 
@@ -123,7 +162,27 @@ func (h TypedFuncs[object, request]) Delete(ctx context.Context, e event.TypedDe
 // Update implements EventHandler.
 func (h TypedFuncs[object, request]) Update(ctx context.Context, e event.TypedUpdateEvent[object], q workqueue.TypedRateLimitingInterface[request]) {
 	if h.UpdateFunc != nil {
-		h.UpdateFunc(ctx, e, q)
+		if !implementsClientObject[object]() || !isPriorityQueue(q) || isNil(e.ObjectOld) || isNil(e.ObjectNew) {
+			h.UpdateFunc(ctx, e, q)
+			return
+		}
+
+		wq := workqueueWithCustomAddFunc[request]{
+			TypedRateLimitingInterface: q,
+			// We already know that we have a priority queue, that event.ObjectOld and ObjectNew implement
+			// client.Object and that they are  not nil
+			addFunc: func(item request, q workqueue.TypedRateLimitingInterface[request]) {
+				var priority int
+				if any(e.ObjectOld).(client.Object).GetResourceVersion() == any(e.ObjectNew).(client.Object).GetResourceVersion() {
+					priority = LowPriority
+				}
+				q.(priorityqueue.PriorityQueue[request]).AddWithOpts(
+					priorityqueue.AddOpts{Priority: priority},
+					item,
+				)
+			},
+		}
+		h.UpdateFunc(ctx, e, wq)
 	}
 }
 
@@ -133,3 +192,66 @@ func (h TypedFuncs[object, request]) Generic(ctx context.Context, e event.TypedG
 		h.GenericFunc(ctx, e, q)
 	}
 }
+
+// LowPriority is the priority set by WithLowPriorityWhenUnchanged
+const LowPriority = -100
+
+// WithLowPriorityWhenUnchanged reduces the priority of events stemming from the initial listwatch or from a resync if
+// and only if a priorityqueue.PriorityQueue is used. If not, it does nothing.
+func WithLowPriorityWhenUnchanged[object client.Object, request comparable](u TypedEventHandler[object, request]) TypedEventHandler[object, request] {
+	// TypedFuncs already implements this so just wrap
+	return TypedFuncs[object, request]{
+		CreateFunc:  u.Create,
+		UpdateFunc:  u.Update,
+		DeleteFunc:  u.Delete,
+		GenericFunc: u.Generic,
+	}
+}
+
+type workqueueWithCustomAddFunc[request comparable] struct {
+	workqueue.TypedRateLimitingInterface[request]
+	addFunc func(item request, q workqueue.TypedRateLimitingInterface[request])
+}
+
+func (w workqueueWithCustomAddFunc[request]) Add(item request) {
+	w.addFunc(item, w.TypedRateLimitingInterface)
+}
+
+// isObjectUnchanged checks if the object in a create event is unchanged, for example because
+// we got it in our initial listwatch. The heuristic it uses is to check if the object is older
+// than one minute.
+func isObjectUnchanged[object client.Object](e event.TypedCreateEvent[object]) bool {
+	return e.Object.GetCreationTimestamp().Time.Before(time.Now().Add(-time.Minute))
+}
+
+// addToQueueCreate adds the reconcile.Request to the priorityqueue in the handler
+// for Create requests if and only if the workqueue being used is of type priorityqueue.PriorityQueue[reconcile.Request]
+func addToQueueCreate[T client.Object, request comparable](q workqueue.TypedRateLimitingInterface[request], evt event.TypedCreateEvent[T], item request) {
+	priorityQueue, isPriorityQueue := q.(priorityqueue.PriorityQueue[request])
+	if !isPriorityQueue {
+		q.Add(item)
+		return
+	}
+
+	var priority int
+	if isObjectUnchanged(evt) {
+		priority = LowPriority
+	}
+	priorityQueue.AddWithOpts(priorityqueue.AddOpts{Priority: priority}, item)
+}
+
+// addToQueueUpdate adds the reconcile.Request to the priorityqueue in the handler
+// for Update requests if and only if the workqueue being used is of type priorityqueue.PriorityQueue[reconcile.Request]
+func addToQueueUpdate[T client.Object, request comparable](q workqueue.TypedRateLimitingInterface[request], evt event.TypedUpdateEvent[T], item request) {
+	priorityQueue, isPriorityQueue := q.(priorityqueue.PriorityQueue[request])
+	if !isPriorityQueue {
+		q.Add(item)
+		return
+	}
+
+	var priority int
+	if evt.ObjectOld.GetResourceVersion() == evt.ObjectNew.GetResourceVersion() {
+		priority = LowPriority
+	}
+	priorityQueue.AddWithOpts(priorityqueue.AddOpts{Priority: priority}, item)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
index dfe407f3b..3f8cfdaa0 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
@@ -21,14 +21,17 @@ import (
 	"errors"
 	"fmt"
 	"sync"
+	"sync/atomic"
 	"time"
 
 	"github.com/go-logr/logr"
+	"golang.org/x/sync/errgroup"
 	"k8s.io/apimachinery/pkg/types"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/apimachinery/pkg/util/uuid"
 	"k8s.io/client-go/util/workqueue"
 
+	"sigs.k8s.io/controller-runtime/pkg/controller/priorityqueue"
 	ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -58,7 +61,7 @@ type Controller[request comparable] struct {
 
 	// Queue is an listeningQueue that listens for events from Informers and adds object keys to
 	// the Queue for processing
-	Queue workqueue.TypedRateLimitingInterface[request]
+	Queue priorityqueue.PriorityQueue[request]
 
 	// mu is used to synchronize Controller setup
 	mu sync.Mutex
@@ -155,7 +158,12 @@ func (c *Controller[request]) Start(ctx context.Context) error {
 	// Set the internal context.
 	c.ctx = ctx
 
-	c.Queue = c.NewQueue(c.Name, c.RateLimiter)
+	queue := c.NewQueue(c.Name, c.RateLimiter)
+	if priorityQueue, isPriorityQueue := queue.(priorityqueue.PriorityQueue[request]); isPriorityQueue {
+		c.Queue = priorityQueue
+	} else {
+		c.Queue = &priorityQueueWrapper[request]{TypedRateLimitingInterface: queue}
+	}
 	go func() {
 		<-ctx.Done()
 		c.Queue.ShutDown()
@@ -169,44 +177,67 @@ func (c *Controller[request]) Start(ctx context.Context) error {
 		defer utilruntime.HandleCrash()
 
 		// NB(directxman12): launch the sources *before* trying to wait for the
-		// caches to sync so that they have a chance to register their intendeded
+		// caches to sync so that they have a chance to register their intended
 		// caches.
+		errGroup := &errgroup.Group{}
 		for _, watch := range c.startWatches {
-			c.LogConstructor(nil).Info("Starting EventSource", "source", fmt.Sprintf("%s", watch))
-
-			if err := watch.Start(ctx, c.Queue); err != nil {
-				return err
-			}
-		}
-
-		// Start the SharedIndexInformer factories to begin populating the SharedIndexInformer caches
-		c.LogConstructor(nil).Info("Starting Controller")
+			log := c.LogConstructor(nil)
+			_, ok := watch.(interface {
+				String() string
+			})
 
-		for _, watch := range c.startWatches {
-			syncingSource, ok := watch.(source.SyncingSource)
 			if !ok {
-				continue
+				log = log.WithValues("source", fmt.Sprintf("%T", watch))
+			} else {
+				log = log.WithValues("source", fmt.Sprintf("%s", watch))
 			}
-
-			if err := func() error {
-				// use a context with timeout for launching sources and syncing caches.
+			didStartSyncingSource := &atomic.Bool{}
+			errGroup.Go(func() error {
+				// Use a timeout for starting and syncing the source to avoid silently
+				// blocking startup indefinitely if it doesn't come up.
 				sourceStartCtx, cancel := context.WithTimeout(ctx, c.CacheSyncTimeout)
 				defer cancel()
 
-				// WaitForSync waits for a definitive timeout, and returns if there
-				// is an error or a timeout
-				if err := syncingSource.WaitForSync(sourceStartCtx); err != nil {
-					err := fmt.Errorf("failed to wait for %s caches to sync: %w", c.Name, err)
-					c.LogConstructor(nil).Error(err, "Could not wait for Cache to sync")
+				sourceStartErrChan := make(chan error, 1) // Buffer chan to not leak goroutine if we time out
+				go func() {
+					defer close(sourceStartErrChan)
+					log.Info("Starting EventSource")
+					if err := watch.Start(ctx, c.Queue); err != nil {
+						sourceStartErrChan <- err
+						return
+					}
+					syncingSource, ok := watch.(source.TypedSyncingSource[request])
+					if !ok {
+						return
+					}
+					didStartSyncingSource.Store(true)
+					if err := syncingSource.WaitForSync(sourceStartCtx); err != nil {
+						err := fmt.Errorf("failed to wait for %s caches to sync %v: %w", c.Name, syncingSource, err)
+						log.Error(err, "Could not wait for Cache to sync")
+						sourceStartErrChan <- err
+					}
+				}()
+
+				select {
+				case err := <-sourceStartErrChan:
 					return err
+				case <-sourceStartCtx.Done():
+					if didStartSyncingSource.Load() { // We are racing with WaitForSync, wait for it to let it tell us what happened
+						return <-sourceStartErrChan
+					}
+					if ctx.Err() != nil { // Don't return an error if the root context got cancelled
+						return nil
+					}
+					return fmt.Errorf("timed out waiting for source %s to Start. Please ensure that its Start() method is non-blocking", watch)
 				}
-
-				return nil
-			}(); err != nil {
-				return err
-			}
+			})
+		}
+		if err := errGroup.Wait(); err != nil {
+			return err
 		}
 
+		c.LogConstructor(nil).Info("Starting Controller")
+
 		// All the watches have been started, we can reset the local slice.
 		//
 		// We should never hold watches more than necessary, each watch source can hold a backing cache,
@@ -243,7 +274,7 @@ func (c *Controller[request]) Start(ctx context.Context) error {
 // processNextWorkItem will read a single work item off the workqueue and
 // attempt to process it, by calling the reconcileHandler.
 func (c *Controller[request]) processNextWorkItem(ctx context.Context) bool {
-	obj, shutdown := c.Queue.Get()
+	obj, priority, shutdown := c.Queue.GetWithPriority()
 	if shutdown {
 		// Stop working
 		return false
@@ -260,7 +291,7 @@ func (c *Controller[request]) processNextWorkItem(ctx context.Context) bool {
 	ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(1)
 	defer ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(-1)
 
-	c.reconcileHandler(ctx, obj)
+	c.reconcileHandler(ctx, obj, priority)
 	return true
 }
 
@@ -283,7 +314,7 @@ func (c *Controller[request]) initMetrics() {
 	ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Set(0)
 }
 
-func (c *Controller[request]) reconcileHandler(ctx context.Context, req request) {
+func (c *Controller[request]) reconcileHandler(ctx context.Context, req request, priority int) {
 	// Update metrics after processing each item
 	reconcileStartTS := time.Now()
 	defer func() {
@@ -306,12 +337,12 @@ func (c *Controller[request]) reconcileHandler(ctx context.Context, req request)
 		if errors.Is(err, reconcile.TerminalError(nil)) {
 			ctrlmetrics.TerminalReconcileErrors.WithLabelValues(c.Name).Inc()
 		} else {
-			c.Queue.AddRateLimited(req)
+			c.Queue.AddWithOpts(priorityqueue.AddOpts{RateLimited: true, Priority: priority}, req)
 		}
 		ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc()
 		ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Inc()
 		if !result.IsZero() {
-			log.Info("Warning: Reconciler returned both a non-zero result and a non-nil error. The result will always be ignored if the error is non-nil and the non-nil error causes reqeueuing with exponential backoff. For more details, see: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile#Reconciler")
+			log.Info("Warning: Reconciler returned both a non-zero result and a non-nil error. The result will always be ignored if the error is non-nil and the non-nil error causes requeuing with exponential backoff. For more details, see: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile#Reconciler")
 		}
 		log.Error(err, "Reconciler error")
 	case result.RequeueAfter > 0:
@@ -321,11 +352,11 @@ func (c *Controller[request]) reconcileHandler(ctx context.Context, req request)
 		// We need to drive to stable reconcile loops before queuing due
 		// to result.RequestAfter
 		c.Queue.Forget(req)
-		c.Queue.AddAfter(req, result.RequeueAfter)
+		c.Queue.AddWithOpts(priorityqueue.AddOpts{After: result.RequeueAfter, Priority: priority}, req)
 		ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Inc()
 	case result.Requeue:
 		log.V(5).Info("Reconcile done, requeueing")
-		c.Queue.AddRateLimited(req)
+		c.Queue.AddWithOpts(priorityqueue.AddOpts{RateLimited: true, Priority: priority}, req)
 		ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Inc()
 	default:
 		log.V(5).Info("Reconcile successful")
@@ -363,3 +394,25 @@ type reconcileIDKey struct{}
 func addReconcileID(ctx context.Context, reconcileID types.UID) context.Context {
 	return context.WithValue(ctx, reconcileIDKey{}, reconcileID)
 }
+
+type priorityQueueWrapper[request comparable] struct {
+	workqueue.TypedRateLimitingInterface[request]
+}
+
+func (p *priorityQueueWrapper[request]) AddWithOpts(opts priorityqueue.AddOpts, items ...request) {
+	for _, item := range items {
+		switch {
+		case opts.RateLimited:
+			p.TypedRateLimitingInterface.AddRateLimited(item)
+		case opts.After > 0:
+			p.TypedRateLimitingInterface.AddAfter(item, opts.After)
+		default:
+			p.TypedRateLimitingInterface.Add(item)
+		}
+	}
+}
+
+func (p *priorityQueueWrapper[request]) GetWithPriority() (request, int, bool) {
+	item, shutdown := p.TypedRateLimitingInterface.Get()
+	return item, 0, shutdown
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/metrics/workqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/metrics/workqueue.go
new file mode 100644
index 000000000..86da340af
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/metrics/workqueue.go
@@ -0,0 +1,131 @@
+/*
+Copyright 2018 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.
+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 metrics
+
+import (
+	"github.com/prometheus/client_golang/prometheus"
+	"k8s.io/client-go/util/workqueue"
+	"sigs.k8s.io/controller-runtime/pkg/metrics"
+)
+
+// This file is copied and adapted from k8s.io/component-base/metrics/prometheus/workqueue
+// which registers metrics to the k8s legacy Registry. We require very
+// similar functionality, but must register metrics to a different Registry.
+
+// Metrics subsystem and all keys used by the workqueue.
+const (
+	WorkQueueSubsystem         = metrics.WorkQueueSubsystem
+	DepthKey                   = metrics.DepthKey
+	AddsKey                    = metrics.AddsKey
+	QueueLatencyKey            = metrics.QueueLatencyKey
+	WorkDurationKey            = metrics.WorkDurationKey
+	UnfinishedWorkKey          = metrics.UnfinishedWorkKey
+	LongestRunningProcessorKey = metrics.LongestRunningProcessorKey
+	RetriesKey                 = metrics.RetriesKey
+)
+
+var (
+	depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+		Subsystem: WorkQueueSubsystem,
+		Name:      DepthKey,
+		Help:      "Current depth of workqueue",
+	}, []string{"name", "controller"})
+
+	adds = prometheus.NewCounterVec(prometheus.CounterOpts{
+		Subsystem: WorkQueueSubsystem,
+		Name:      AddsKey,
+		Help:      "Total number of adds handled by workqueue",
+	}, []string{"name", "controller"})
+
+	latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+		Subsystem: WorkQueueSubsystem,
+		Name:      QueueLatencyKey,
+		Help:      "How long in seconds an item stays in workqueue before being requested",
+		Buckets:   prometheus.ExponentialBuckets(10e-9, 10, 12),
+	}, []string{"name", "controller"})
+
+	workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+		Subsystem: WorkQueueSubsystem,
+		Name:      WorkDurationKey,
+		Help:      "How long in seconds processing an item from workqueue takes.",
+		Buckets:   prometheus.ExponentialBuckets(10e-9, 10, 12),
+	}, []string{"name", "controller"})
+
+	unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+		Subsystem: WorkQueueSubsystem,
+		Name:      UnfinishedWorkKey,
+		Help: "How many seconds of work has been done that " +
+			"is in progress and hasn't been observed by work_duration. Large " +
+			"values indicate stuck threads. One can deduce the number of stuck " +
+			"threads by observing the rate at which this increases.",
+	}, []string{"name", "controller"})
+
+	longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+		Subsystem: WorkQueueSubsystem,
+		Name:      LongestRunningProcessorKey,
+		Help: "How many seconds has the longest running " +
+			"processor for workqueue been running.",
+	}, []string{"name", "controller"})
+
+	retries = prometheus.NewCounterVec(prometheus.CounterOpts{
+		Subsystem: WorkQueueSubsystem,
+		Name:      RetriesKey,
+		Help:      "Total number of retries handled by workqueue",
+	}, []string{"name", "controller"})
+)
+
+func init() {
+	metrics.Registry.MustRegister(depth)
+	metrics.Registry.MustRegister(adds)
+	metrics.Registry.MustRegister(latency)
+	metrics.Registry.MustRegister(workDuration)
+	metrics.Registry.MustRegister(unfinished)
+	metrics.Registry.MustRegister(longestRunningProcessor)
+	metrics.Registry.MustRegister(retries)
+
+	workqueue.SetProvider(WorkqueueMetricsProvider{})
+}
+
+type WorkqueueMetricsProvider struct{}
+
+func (WorkqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
+	return depth.WithLabelValues(name, name)
+}
+
+func (WorkqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
+	return adds.WithLabelValues(name, name)
+}
+
+func (WorkqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
+	return latency.WithLabelValues(name, name)
+}
+
+func (WorkqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
+	return workDuration.WithLabelValues(name, name)
+}
+
+func (WorkqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
+	return unfinished.WithLabelValues(name, name)
+}
+
+func (WorkqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
+	return longestRunningProcessor.WithLabelValues(name, name)
+}
+
+func (WorkqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
+	return retries.WithLabelValues(name, name)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
index 4999edc43..2fdfbde8e 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
@@ -52,7 +52,7 @@ func (ks *Kind[object, request]) Start(ctx context.Context, queue workqueue.Type
 	// cache.GetInformer will block until its context is cancelled if the cache was already started and it can not
 	// sync that informer (most commonly due to RBAC issues).
 	ctx, ks.startCancel = context.WithCancel(ctx)
-	ks.startedErr = make(chan error)
+	ks.startedErr = make(chan error, 1) // Buffer chan to not leak goroutines if WaitForSync isn't called
 	go func() {
 		var (
 			i       cache.Informer
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go
index 5eb0c62a7..939c333f7 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go
@@ -275,7 +275,7 @@ func (s *defaultServer) createListener(ctx context.Context, log logr.Logger) (ne
 		return s.options.ListenConfig.Listen(ctx, "tcp", s.options.BindAddress)
 	}
 
-	cfg := &tls.Config{ //nolint:gosec
+	cfg := &tls.Config{
 		NextProtos: []string{"h2"},
 	}
 	// fallback TLS config ready, will now mutate if passer wants full control over it
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
index 590653e70..cd7ccc773 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
@@ -16,15 +16,6 @@ limitations under the License.
 
 package metrics
 
-import (
-	"github.com/prometheus/client_golang/prometheus"
-	"k8s.io/client-go/util/workqueue"
-)
-
-// This file is copied and adapted from k8s.io/component-base/metrics/prometheus/workqueue
-// which registers metrics to the k8s legacy Registry. We require very
-// similar functionality, but must register metrics to a different Registry.
-
 // Metrics subsystem and all keys used by the workqueue.
 const (
 	WorkQueueSubsystem         = "workqueue"
@@ -36,95 +27,3 @@ const (
 	LongestRunningProcessorKey = "longest_running_processor_seconds"
 	RetriesKey                 = "retries_total"
 )
-
-var (
-	depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
-		Subsystem: WorkQueueSubsystem,
-		Name:      DepthKey,
-		Help:      "Current depth of workqueue",
-	}, []string{"name", "controller"})
-
-	adds = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Subsystem: WorkQueueSubsystem,
-		Name:      AddsKey,
-		Help:      "Total number of adds handled by workqueue",
-	}, []string{"name", "controller"})
-
-	latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
-		Subsystem: WorkQueueSubsystem,
-		Name:      QueueLatencyKey,
-		Help:      "How long in seconds an item stays in workqueue before being requested",
-		Buckets:   prometheus.ExponentialBuckets(10e-9, 10, 12),
-	}, []string{"name", "controller"})
-
-	workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
-		Subsystem: WorkQueueSubsystem,
-		Name:      WorkDurationKey,
-		Help:      "How long in seconds processing an item from workqueue takes.",
-		Buckets:   prometheus.ExponentialBuckets(10e-9, 10, 12),
-	}, []string{"name", "controller"})
-
-	unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{
-		Subsystem: WorkQueueSubsystem,
-		Name:      UnfinishedWorkKey,
-		Help: "How many seconds of work has been done that " +
-			"is in progress and hasn't been observed by work_duration. Large " +
-			"values indicate stuck threads. One can deduce the number of stuck " +
-			"threads by observing the rate at which this increases.",
-	}, []string{"name", "controller"})
-
-	longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{
-		Subsystem: WorkQueueSubsystem,
-		Name:      LongestRunningProcessorKey,
-		Help: "How many seconds has the longest running " +
-			"processor for workqueue been running.",
-	}, []string{"name", "controller"})
-
-	retries = prometheus.NewCounterVec(prometheus.CounterOpts{
-		Subsystem: WorkQueueSubsystem,
-		Name:      RetriesKey,
-		Help:      "Total number of retries handled by workqueue",
-	}, []string{"name", "controller"})
-)
-
-func init() {
-	Registry.MustRegister(depth)
-	Registry.MustRegister(adds)
-	Registry.MustRegister(latency)
-	Registry.MustRegister(workDuration)
-	Registry.MustRegister(unfinished)
-	Registry.MustRegister(longestRunningProcessor)
-	Registry.MustRegister(retries)
-
-	workqueue.SetProvider(workqueueMetricsProvider{})
-}
-
-type workqueueMetricsProvider struct{}
-
-func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
-	return depth.WithLabelValues(name, name)
-}
-
-func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
-	return adds.WithLabelValues(name, name)
-}
-
-func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
-	return latency.WithLabelValues(name, name)
-}
-
-func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
-	return workDuration.WithLabelValues(name, name)
-}
-
-func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
-	return unfinished.WithLabelValues(name, name)
-}
-
-func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
-	return longestRunningProcessor.WithLabelValues(name, name)
-}
-
-func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
-	return retries.WithLabelValues(name, 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 90918db57..ce33975f3 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
@@ -173,7 +173,8 @@ func (TypedResourceVersionChangedPredicate[T]) Update(e event.TypedUpdateEvent[T
 // The metadata.generation field of an object is incremented by the API server when writes are made to the spec field of an object.
 // This allows a controller to ignore update events where the spec is unchanged, and only the metadata and/or status fields are changed.
 //
-// For CustomResource objects the Generation is only incremented when the status subresource is enabled.
+// For CustomResource objects the Generation is incremented when spec is changed, or status changed and status not modeled as subresource.
+// subresource status update will not increase Generation.
 //
 // Caveats:
 //
@@ -191,7 +192,8 @@ type GenerationChangedPredicate = TypedGenerationChangedPredicate[client.Object]
 // The metadata.generation field of an object is incremented by the API server when writes are made to the spec field of an object.
 // This allows a controller to ignore update events where the spec is unchanged, and only the metadata and/or status fields are changed.
 //
-// For CustomResource objects the Generation is only incremented when the status subresource is enabled.
+// For CustomResource objects the Generation is incremented when spec is changed, or status changed and status not modeled as subresource.
+// subresource status update will not increase Generation.
 //
 // Caveats:
 //
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
deleted file mode 100644
index efbbf6028..000000000
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-Copyright 2018 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.
-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 admission
-
-import (
-	"context"
-	"encoding/json"
-	"net/http"
-
-	admissionv1 "k8s.io/api/admission/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-)
-
-// Defaulter defines functions for setting defaults on resources.
-// Deprecated: Ue CustomDefaulter instead.
-type Defaulter interface {
-	runtime.Object
-	Default()
-}
-
-// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type.
-// Deprecated: Use WithCustomDefaulter instead.
-func DefaultingWebhookFor(scheme *runtime.Scheme, defaulter Defaulter) *Webhook {
-	return &Webhook{
-		Handler: &mutatingHandler{defaulter: defaulter, decoder: NewDecoder(scheme)},
-	}
-}
-
-type mutatingHandler struct {
-	defaulter Defaulter
-	decoder   Decoder
-}
-
-// Handle handles admission requests.
-func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
-	if h.decoder == nil {
-		panic("decoder should never be nil")
-	}
-	if h.defaulter == nil {
-		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 {
-		return Errored(http.StatusBadRequest, err)
-	}
-
-	// Default the object
-	obj.Default()
-	marshalled, err := json.Marshal(obj)
-	if err != nil {
-		return Errored(http.StatusInternalServerError, err)
-	}
-
-	// Create the patch
-	return PatchResponseFromRaw(req.Object.Raw, marshalled)
-}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
index d15dec7a0..a703cbd2c 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
@@ -21,11 +21,14 @@ import (
 	"encoding/json"
 	"errors"
 	"net/http"
+	"slices"
 
+	"gomodules.xyz/jsonpatch/v2"
 	admissionv1 "k8s.io/api/admission/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/util/sets"
 )
 
 // CustomDefaulter defines functions for setting defaults on resources.
@@ -33,17 +36,41 @@ type CustomDefaulter interface {
 	Default(ctx context.Context, obj runtime.Object) error
 }
 
+type defaulterOptions struct {
+	removeUnknownOrOmitableFields bool
+}
+
+// DefaulterOption defines the type of a CustomDefaulter's option
+type DefaulterOption func(*defaulterOptions)
+
+// DefaulterRemoveUnknownOrOmitableFields makes the defaulter prune fields that are in the json object retrieved by the
+// webhook but not in the local go type json representation. This happens for example when the CRD in the apiserver has
+// fields that our go type doesn't know about, because it's outdated, or the field has a zero value and is `omitempty`.
+func DefaulterRemoveUnknownOrOmitableFields(o *defaulterOptions) {
+	o.removeUnknownOrOmitableFields = true
+}
+
 // WithCustomDefaulter creates a new Webhook for a CustomDefaulter interface.
-func WithCustomDefaulter(scheme *runtime.Scheme, obj runtime.Object, defaulter CustomDefaulter) *Webhook {
+func WithCustomDefaulter(scheme *runtime.Scheme, obj runtime.Object, defaulter CustomDefaulter, opts ...DefaulterOption) *Webhook {
+	options := &defaulterOptions{}
+	for _, o := range opts {
+		o(options)
+	}
 	return &Webhook{
-		Handler: &defaulterForType{object: obj, defaulter: defaulter, decoder: NewDecoder(scheme)},
+		Handler: &defaulterForType{
+			object:                        obj,
+			defaulter:                     defaulter,
+			decoder:                       NewDecoder(scheme),
+			removeUnknownOrOmitableFields: options.removeUnknownOrOmitableFields,
+		},
 	}
 }
 
 type defaulterForType struct {
-	defaulter CustomDefaulter
-	object    runtime.Object
-	decoder   Decoder
+	defaulter                     CustomDefaulter
+	object                        runtime.Object
+	decoder                       Decoder
+	removeUnknownOrOmitableFields bool
 }
 
 // Handle handles admission requests.
@@ -76,6 +103,12 @@ func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
 		return Errored(http.StatusBadRequest, err)
 	}
 
+	// Keep a copy of the object if needed
+	var originalObj runtime.Object
+	if !h.removeUnknownOrOmitableFields {
+		originalObj = obj.DeepCopyObject()
+	}
+
 	// Default the object
 	if err := h.defaulter.Default(ctx, obj); err != nil {
 		var apiStatus apierrors.APIStatus
@@ -90,5 +123,43 @@ func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
 	if err != nil {
 		return Errored(http.StatusInternalServerError, err)
 	}
-	return PatchResponseFromRaw(req.Object.Raw, marshalled)
+
+	handlerResponse := PatchResponseFromRaw(req.Object.Raw, marshalled)
+	if !h.removeUnknownOrOmitableFields {
+		handlerResponse = h.dropSchemeRemovals(handlerResponse, originalObj, req.Object.Raw)
+	}
+	return handlerResponse
+}
+
+func (h *defaulterForType) dropSchemeRemovals(r Response, original runtime.Object, raw []byte) Response {
+	const opRemove = "remove"
+	if !r.Allowed || r.PatchType == nil {
+		return r
+	}
+
+	// If we don't have removals in the patch.
+	if !slices.ContainsFunc(r.Patches, func(o jsonpatch.JsonPatchOperation) bool { return o.Operation == opRemove }) {
+		return r
+	}
+
+	// Get the raw to original patch
+	marshalledOriginal, err := json.Marshal(original)
+	if err != nil {
+		return Errored(http.StatusInternalServerError, err)
+	}
+
+	patchOriginal, err := jsonpatch.CreatePatch(raw, marshalledOriginal)
+	if err != nil {
+		return Errored(http.StatusInternalServerError, err)
+	}
+	removedByScheme := sets.New(slices.DeleteFunc(patchOriginal, func(p jsonpatch.JsonPatchOperation) bool { return p.Operation != opRemove })...)
+
+	r.Patches = slices.DeleteFunc(r.Patches, func(p jsonpatch.JsonPatchOperation) bool {
+		return p.Operation == opRemove && removedByScheme.Has(p)
+	})
+
+	if len(r.Patches) == 0 {
+		r.PatchType = nil
+	}
+	return r
 }
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
deleted file mode 100644
index b28a56eef..000000000
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-Copyright 2018 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.
-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 admission
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"net/http"
-
-	v1 "k8s.io/api/admission/v1"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
-	"k8s.io/apimachinery/pkg/runtime"
-)
-
-// Warnings represents warning messages.
-type Warnings []string
-
-// Validator defines functions for validating an operation.
-// The custom resource kind which implements this interface can validate itself.
-// To validate the custom resource with another specific struct, use CustomValidator instead.
-// Deprecated: Use CustomValidator instead.
-type Validator interface {
-	runtime.Object
-
-	// ValidateCreate validates the object on creation.
-	// The optional warnings will be added to the response as warning messages.
-	// Return an error if the object is invalid.
-	ValidateCreate() (warnings Warnings, err error)
-
-	// ValidateUpdate validates the object on update. The oldObj is the object before the update.
-	// The optional warnings will be added to the response as warning messages.
-	// Return an error if the object is invalid.
-	ValidateUpdate(old runtime.Object) (warnings Warnings, err error)
-
-	// ValidateDelete validates the object on deletion.
-	// The optional warnings will be added to the response as warning messages.
-	// Return an error if the object is invalid.
-	ValidateDelete() (warnings Warnings, err error)
-}
-
-// ValidatingWebhookFor creates a new Webhook for validating the provided type.
-// Deprecated: Use WithCustomValidator instead.
-func ValidatingWebhookFor(scheme *runtime.Scheme, validator Validator) *Webhook {
-	return &Webhook{
-		Handler: &validatingHandler{validator: validator, decoder: NewDecoder(scheme)},
-	}
-}
-
-type validatingHandler struct {
-	validator Validator
-	decoder   Decoder
-}
-
-// Handle handles admission requests.
-func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
-	if h.decoder == nil {
-		panic("decoder should never be nil")
-	}
-	if h.validator == nil {
-		panic("validator should never be nil")
-	}
-	// Get the object in the request
-	obj := h.validator.DeepCopyObject().(Validator)
-
-	var err error
-	var warnings []string
-
-	switch req.Operation {
-	case v1.Connect:
-		// No validation for connect requests.
-		// TODO(vincepri): Should we validate CONNECT requests? In what cases?
-	case v1.Create:
-		if err = h.decoder.Decode(req, obj); err != nil {
-			return Errored(http.StatusBadRequest, err)
-		}
-
-		warnings, err = obj.ValidateCreate()
-	case v1.Update:
-		oldObj := obj.DeepCopyObject()
-
-		err = h.decoder.DecodeRaw(req.Object, obj)
-		if err != nil {
-			return Errored(http.StatusBadRequest, err)
-		}
-		err = h.decoder.DecodeRaw(req.OldObject, oldObj)
-		if err != nil {
-			return Errored(http.StatusBadRequest, err)
-		}
-
-		warnings, err = obj.ValidateUpdate(oldObj)
-	case v1.Delete:
-		// In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
-		// OldObject contains the object being deleted
-		err = h.decoder.DecodeRaw(req.OldObject, obj)
-		if err != nil {
-			return Errored(http.StatusBadRequest, err)
-		}
-
-		warnings, err = obj.ValidateDelete()
-	default:
-		return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
-	}
-
-	if err != nil {
-		var apiStatus apierrors.APIStatus
-		if errors.As(err, &apiStatus) {
-			return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
-		}
-		return Denied(err.Error()).WithWarnings(warnings...)
-	}
-	return Allowed("").WithWarnings(warnings...)
-}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
index b8f194401..ef1be52a8 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
@@ -27,6 +27,9 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 )
 
+// Warnings represents warning messages.
+type Warnings []string
+
 // CustomValidator defines functions for validating an operation.
 // The object to be validated is passed into methods as a parameter.
 type CustomValidator interface {
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
index e8439e2ea..2882e7bab 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
@@ -23,14 +23,6 @@ import (
 
 // define some aliases for common bits of the webhook functionality
 
-// Defaulter defines functions for setting defaults on resources.
-// Deprecated: Use CustomDefaulter instead.
-type Defaulter = admission.Defaulter
-
-// Validator defines functions for validating an operation.
-// Deprecated: Use CustomValidator instead.
-type Validator = admission.Validator
-
 // CustomDefaulter defines functions for setting defaults on resources.
 type CustomDefaulter = admission.CustomDefaulter
 
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 f8820e8b7..4d8ae9ec7 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
@@ -190,7 +190,7 @@ func (s *DefaultServer) Start(ctx context.Context) error {
 
 	log.Info("Starting webhook server")
 
-	cfg := &tls.Config{ //nolint:gosec
+	cfg := &tls.Config{
 		NextProtos: []string{"h2"},
 	}
 	// fallback TLS config ready, will now mutate if passer wants full control over it
@@ -272,7 +272,7 @@ func (s *DefaultServer) Start(ctx context.Context) error {
 // server has been started.
 func (s *DefaultServer) StartedChecker() healthz.Checker {
 	config := &tls.Config{
-		InsecureSkipVerify: true, //nolint:gosec // config is used to connect to our own webhook port.
+		InsecureSkipVerify: true,
 	}
 	return func(req *http.Request) error {
 		s.mu.Lock()



Test patch:
diff --git a/pkg/controller/jobs/pod/pod_controller_test.go b/pkg/controller/jobs/pod/pod_controller_test.go
index deaa8c9ce..1fba8882d 100644
--- a/pkg/controller/jobs/pod/pod_controller_test.go
+++ b/pkg/controller/jobs/pod/pod_controller_test.go
@@ -3284,6 +3284,7 @@ func TestReconciler(t *testing.T) {
 					Delete().
 					Obj(),
 			},
+			workloadCmpOpts: defaultWorkloadCmpOpts,
 			wantEvents: []utiltesting.EventRecord{
 				{
 					Key:       types.NamespacedName{Name: "p1", Namespace: "ns"},
@@ -4164,7 +4165,8 @@ func TestReconciler(t *testing.T) {
 				GroupTotalCount("1").
 				Obj(),
 			},
-			wantErr: utilpod.ErrValidation,
+			workloadCmpOpts: defaultWorkloadCmpOpts,
+			wantErr:         utilpod.ErrValidation,
 		},
 		"reconciler returns error in case pod group pod index is less than 0": {
 			pods: []corev1.Pod{*basePodWrapper.
@@ -4177,7 +4179,8 @@ func TestReconciler(t *testing.T) {
 				GroupTotalCount("1").
 				Obj(),
 			},
-			wantErr: utilpod.ErrInvalidUInt,
+			workloadCmpOpts: defaultWorkloadCmpOpts,
+			wantErr:         utilpod.ErrInvalidUInt,
 		},
 		"reconciler returns error in case of label mismatch in pod group": {
 			pods: []corev1.Pod{
@@ -4208,8 +4211,9 @@ func TestReconciler(t *testing.T) {
 			reconcilerOptions: []jobframework.Option{
 				jobframework.WithLabelKeysToCopy([]string{"toCopyKey1", "toCopyKey2"}),
 			},
-			wantWorkloads: nil,
-			wantErr:       errPodGroupLabelsMismatch,
+			wantWorkloads:   nil,
+			workloadCmpOpts: defaultWorkloadCmpOpts,
+			wantErr:         errPodGroupLabelsMismatch,
 		},
 		"admission check message is recorded as event for a single pod": {
 			pods: []corev1.Pod{*basePodWrapper.
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go
index 5fdd657cd..8ed2224cf 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/crd.go
@@ -94,7 +94,7 @@ func InstallCRDs(config *rest.Config, options CRDInstallOptions) ([]*apiextensio
 	defaultCRDOptions(&options)
 
 	// Read the CRD yamls into options.CRDs
-	if err := readCRDFiles(&options); err != nil {
+	if err := ReadCRDFiles(&options); err != nil {
 		return nil, fmt.Errorf("unable to read CRD files: %w", err)
 	}
 
@@ -115,8 +115,8 @@ func InstallCRDs(config *rest.Config, options CRDInstallOptions) ([]*apiextensio
 	return options.CRDs, nil
 }
 
-// readCRDFiles reads the directories of CRDs in options.Paths and adds the CRD structs to options.CRDs.
-func readCRDFiles(options *CRDInstallOptions) error {
+// ReadCRDFiles reads the directories of CRDs in options.Paths and adds the CRD structs to options.CRDs.
+func ReadCRDFiles(options *CRDInstallOptions) error {
 	if len(options.Paths) > 0 {
 		crdList, err := renderCRDs(options)
 		if err != nil {
@@ -217,7 +217,7 @@ func (p *poller) poll(ctx context.Context) (done bool, err error) {
 // UninstallCRDs uninstalls a collection of CRDs by reading the crd yaml files from a directory.
 func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error {
 	// Read the CRD yamls into options.CRDs
-	if err := readCRDFiles(&options); err != nil {
+	if err := ReadCRDFiles(&options); err != nil {
 		return err
 	}
 
@@ -229,7 +229,6 @@ func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error {
 
 	// Uninstall each CRD
 	for _, crd := range options.CRDs {
-		crd := crd
 		log.V(1).Info("uninstalling CRD", "crd", crd.GetName())
 		if err := cs.Delete(context.TODO(), crd); err != nil {
 			// If CRD is not found, we can consider success
@@ -251,7 +250,6 @@ func CreateCRDs(config *rest.Config, crds []*apiextensionsv1.CustomResourceDefin
 
 	// Create each CRD
 	for _, crd := range crds {
-		crd := crd
 		log.V(1).Info("installing CRD", "crd", crd.GetName())
 		existingCrd := crd.DeepCopy()
 		err := cs.Get(context.TODO(), client.ObjectKey{Name: crd.GetName()}, existingCrd)
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go
index e4e54e472..f6bfe95cc 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/envtest/webhook.go
@@ -294,10 +294,10 @@ func (o *WebhookInstallOptions) setupCA() error {
 		return fmt.Errorf("unable to marshal webhook serving certs: %w", err)
 	}
 
-	if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.crt"), certData, 0640); err != nil { //nolint:gosec
+	if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.crt"), certData, 0640); err != nil {
 		return fmt.Errorf("unable to write webhook serving cert to disk: %w", err)
 	}
-	if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.key"), keyData, 0640); err != nil { //nolint:gosec
+	if err := os.WriteFile(filepath.Join(localServingCertsDir, "tls.key"), keyData, 0640); err != nil {
 		return fmt.Errorf("unable to write webhook serving key to disk: %w", err)
 	}
 
@@ -313,14 +313,12 @@ func createWebhooks(config *rest.Config, mutHooks []*admissionv1.MutatingWebhook
 
 	// Create each webhook
 	for _, hook := range mutHooks {
-		hook := hook
 		log.V(1).Info("installing mutating webhook", "webhook", hook.GetName())
 		if err := ensureCreated(cs, hook); err != nil {
 			return err
 		}
 	}
 	for _, hook := range valHooks {
-		hook := hook
 		log.V(1).Info("installing validating webhook", "webhook", hook.GetName())
 		if err := ensureCreated(cs, hook); err != nil {
 			return err
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver.go
index c9a1a232e..b3592eccf 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/apiserver.go
@@ -384,10 +384,10 @@ func (s *APIServer) populateAPIServerCerts() error {
 		return err
 	}
 
-	if err := os.WriteFile(filepath.Join(s.CertDir, "apiserver.crt"), certData, 0640); err != nil { //nolint:gosec
+	if err := os.WriteFile(filepath.Join(s.CertDir, "apiserver.crt"), certData, 0640); err != nil {
 		return err
 	}
-	if err := os.WriteFile(filepath.Join(s.CertDir, "apiserver.key"), keyData, 0640); err != nil { //nolint:gosec
+	if err := os.WriteFile(filepath.Join(s.CertDir, "apiserver.key"), keyData, 0640); err != nil {
 		return err
 	}
 
@@ -404,10 +404,10 @@ func (s *APIServer) populateAPIServerCerts() error {
 		return err
 	}
 
-	if err := os.WriteFile(filepath.Join(s.CertDir, saCertFile), saCert, 0640); err != nil { //nolint:gosec
+	if err := os.WriteFile(filepath.Join(s.CertDir, saCertFile), saCert, 0640); err != nil {
 		return err
 	}
-	return os.WriteFile(filepath.Join(s.CertDir, saKeyFile), saKey, 0640) //nolint:gosec
+	return os.WriteFile(filepath.Join(s.CertDir, saKeyFile), saKey, 0640)
 }
 
 // Stop stops this process gracefully, waits for its termination, and cleans up
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth.go
index 16c86a712..b44035ebf 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane/auth.go
@@ -128,7 +128,7 @@ func (c *CertAuthn) Start() error {
 		return fmt.Errorf("start called before configure")
 	}
 	caCrt := c.ca.CA.CertBytes()
-	if err := os.WriteFile(c.caCrtPath(), caCrt, 0640); err != nil { //nolint:gosec
+	if err := os.WriteFile(c.caCrtPath(), caCrt, 0640); err != nil {
 		return fmt.Errorf("unable to save the client certificate CA to %s: %w", c.caCrtPath(), err)
 	}
 
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process.go
index 03f252524..0d541921e 100644
--- a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process.go
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/process.go
@@ -215,7 +215,7 @@ func pollURLUntilOK(url url.URL, interval time.Duration, ready chan bool, stopCh
 				// there's probably certs *somewhere*,
 				// but it's fine to just skip validating
 				// them for health checks during testing
-				InsecureSkipVerify: true, //nolint:gosec
+				InsecureSkipVerify: true,
 			},
 		},
 	}