diff --git a/go.mod b/go.mod
index 526713514f99e71f0ea700ad04d73da5cb59c06b..edea8d1be6f48df9907c6a9f586193c61b200be4 100644
--- a/go.mod
+++ b/go.mod
@@ -151,6 +151,6 @@ require (
 	lukechampine.com/uint128 v1.2.0 // indirect
 	sigs.k8s.io/controller-runtime v0.20.0 // indirect
 	sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
-	sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
+	sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
 	sigs.k8s.io/yaml v1.4.0 // indirect
 )
diff --git a/go.sum b/go.sum
index fb092baabb2f811aaf51c62f21c55d68bef21ce9..6cffc78c2455f709160cbf39eda78d3f16e4a0af 100644
--- a/go.sum
+++ b/go.sum
@@ -1544,9 +1544,11 @@ sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1
 sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
 sigs.k8s.io/network-policy-api v0.1.5 h1:xyS7VAaM9EfyB428oFk7WjWaCK6B129i+ILUF4C8l6E=
 sigs.k8s.io/network-policy-api v0.1.5/go.mod h1:D7Nkr43VLNd7iYryemnj8qf0N/WjBzTZDxYA+g4u1/Y=
+sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016 h1:kXv6kKdoEtedwuqMmkqhbkgvYKeycVbC8+iPCP9j5kQ=
+sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
 sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
-sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
-sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
+sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
+sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
 sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 8ccdd81e7c795fafc96988efe87147be6d5759cb..8b27c7ce0baaf0d96d6cda45bd22c4a84ceedd44 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1336,7 +1336,7 @@ sigs.k8s.io/e2e-framework/third_party/kind
 ## explicit; go 1.21
 sigs.k8s.io/json
 sigs.k8s.io/json/internal/golang/encoding/json
-# sigs.k8s.io/structured-merge-diff/v4 v4.4.2
+# sigs.k8s.io/structured-merge-diff/v4 v4.7.0
 ## explicit; go 1.13
 sigs.k8s.io/structured-merge-diff/v4/fieldpath
 sigs.k8s.io/structured-merge-diff/v4/merge
diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
index 34ab2d6fb4f06d6d26753bef22e753709f220e4b..455818ff85873f82a7dfaf482bbc92476dd08434 100644
--- a/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
+++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
@@ -33,6 +33,9 @@ type UpdaterBuilder struct {
 	Converter    Converter
 	IgnoreFilter map[fieldpath.APIVersion]fieldpath.Filter
 
+	// IgnoredFields provides a set of fields to ignore for each
+	IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
+
 	// Stop comparing the new object with old object after applying.
 	// This was initially used to avoid spurious etcd update, but
 	// since that's vastly inefficient, we've come-up with a better
@@ -46,6 +49,7 @@ func (u *UpdaterBuilder) BuildUpdater() *Updater {
 	return &Updater{
 		Converter:         u.Converter,
 		IgnoreFilter:      u.IgnoreFilter,
+		IgnoredFields:     u.IgnoredFields,
 		returnInputOnNoop: u.ReturnInputOnNoop,
 	}
 }
@@ -56,6 +60,9 @@ type Updater struct {
 	// Deprecated: This will eventually become private.
 	Converter Converter
 
+	// Deprecated: This will eventually become private.
+	IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
+
 	// Deprecated: This will eventually become private.
 	IgnoreFilter map[fieldpath.APIVersion]fieldpath.Filter
 
@@ -70,8 +77,19 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa
 		return nil, nil, fmt.Errorf("failed to compare objects: %v", err)
 	}
 
-	versions := map[fieldpath.APIVersion]*typed.Comparison{
-		version: compare.FilterFields(s.IgnoreFilter[version]),
+	var versions map[fieldpath.APIVersion]*typed.Comparison
+
+	if s.IgnoredFields != nil && s.IgnoreFilter != nil {
+		return nil, nil, fmt.Errorf("IgnoreFilter and IgnoreFilter may not both be set")
+	}
+	if s.IgnoredFields != nil {
+		versions = map[fieldpath.APIVersion]*typed.Comparison{
+			version: compare.ExcludeFields(s.IgnoredFields[version]),
+		}
+	} else {
+		versions = map[fieldpath.APIVersion]*typed.Comparison{
+			version: compare.FilterFields(s.IgnoreFilter[version]),
+		}
 	}
 
 	for manager, managerSet := range managers {
@@ -101,7 +119,12 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa
 			if err != nil {
 				return nil, nil, fmt.Errorf("failed to compare objects: %v", err)
 			}
-			versions[managerSet.APIVersion()] = compare.FilterFields(s.IgnoreFilter[managerSet.APIVersion()])
+
+			if s.IgnoredFields != nil {
+				versions[managerSet.APIVersion()] = compare.ExcludeFields(s.IgnoredFields[managerSet.APIVersion()])
+			} else {
+				versions[managerSet.APIVersion()] = compare.FilterFields(s.IgnoreFilter[managerSet.APIVersion()])
+			}
 		}
 
 		conflictSet := managerSet.Set().Intersection(compare.Modified.Union(compare.Added))
@@ -154,7 +177,16 @@ func (s *Updater) Update(liveObject, newObject *typed.TypedValue, version fieldp
 		managers[manager] = fieldpath.NewVersionedSet(fieldpath.NewSet(), version, false)
 	}
 	set := managers[manager].Set().Difference(compare.Removed).Union(compare.Modified).Union(compare.Added)
-	ignoreFilter := s.IgnoreFilter[version]
+
+	if s.IgnoredFields != nil && s.IgnoreFilter != nil {
+		return nil, nil, fmt.Errorf("IgnoreFilter and IgnoreFilter may not both be set")
+	}
+	var ignoreFilter fieldpath.Filter
+	if s.IgnoredFields != nil {
+		ignoreFilter = fieldpath.NewExcludeSetFilter(s.IgnoredFields[version])
+	} else {
+		ignoreFilter = s.IgnoreFilter[version]
+	}
 	if ignoreFilter != nil {
 		set = ignoreFilter.Filter(set)
 	}
@@ -189,7 +221,15 @@ func (s *Updater) Apply(liveObject, configObject *typed.TypedValue, version fiel
 		return nil, fieldpath.ManagedFields{}, fmt.Errorf("failed to get field set: %v", err)
 	}
 
-	ignoreFilter := s.IgnoreFilter[version]
+	if s.IgnoredFields != nil && s.IgnoreFilter != nil {
+		return nil, nil, fmt.Errorf("IgnoreFilter and IgnoreFilter may not both be set")
+	}
+	var ignoreFilter fieldpath.Filter
+	if s.IgnoredFields != nil {
+		ignoreFilter = fieldpath.NewExcludeSetFilter(s.IgnoredFields[version])
+	} else {
+		ignoreFilter = s.IgnoreFilter[version]
+	}
 	if ignoreFilter != nil {
 		set = ignoreFilter.Filter(set)
 	}
diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/typed.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/typed.go
index 9be902828062eda4a3517db93e23824ea309ab00..7edaa6d4892000fabfa81174b532b3172f816068 100644
--- a/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/typed.go
+++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/typed.go
@@ -32,6 +32,21 @@ const (
 	AllowDuplicates ValidationOptions = iota
 )
 
+// extractItemsOptions is the options available when extracting items.
+type extractItemsOptions struct {
+	appendKeyFields bool
+}
+
+type ExtractItemsOption func(*extractItemsOptions)
+
+// WithAppendKeyFields configures ExtractItems to include key fields.
+// It is exported for use in configuring ExtractItems.
+func WithAppendKeyFields() ExtractItemsOption {
+	return func(opts *extractItemsOptions) {
+		opts.appendKeyFields = true
+	}
+}
+
 // AsTyped accepts a value and a type and returns a TypedValue. 'v' must have
 // type 'typeName' in the schema. An error is returned if the v doesn't conform
 // to the schema.
@@ -187,7 +202,37 @@ func (tv TypedValue) RemoveItems(items *fieldpath.Set) *TypedValue {
 }
 
 // ExtractItems returns a value with only the provided list or map items extracted from the value.
-func (tv TypedValue) ExtractItems(items *fieldpath.Set) *TypedValue {
+func (tv TypedValue) ExtractItems(items *fieldpath.Set, opts ...ExtractItemsOption) *TypedValue {
+	options := &extractItemsOptions{}
+	for _, opt := range opts {
+		opt(options)
+	}
+	if options.appendKeyFields {
+		tvPathSet, err := tv.ToFieldSet()
+		if err == nil {
+			keyFieldPathSet := fieldpath.NewSet()
+			items.Iterate(func(path fieldpath.Path) {
+				if !tvPathSet.Has(path) {
+					return
+				}
+				for i, pe := range path {
+					if pe.Key == nil {
+						continue
+					}
+					for _, keyField := range *pe.Key {
+						keyName := keyField.Name
+						// Create a new slice with the same elements as path[:i+1], but set its capacity to len(path[:i+1]).
+						// This ensures that appending to keyFieldPath creates a new underlying array, avoiding accidental
+						// modification of the original slice (path).
+						keyFieldPath := append(path[:i+1:i+1], fieldpath.PathElement{FieldName: &keyName})
+						keyFieldPathSet.Insert(keyFieldPath)
+					}
+				}
+			})
+			items = items.Union(keyFieldPathSet)
+		}
+	}
+
 	tv.value = removeItemsWithSchema(tv.value, items, tv.schema, tv.typeRef, true)
 	return &tv
 }
diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/validate.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/validate.go
index 652e24c819a00ec30dd0e75b3de27634274b9bbd..c38234c5ab968670b1c1de5cf76b1f02e1b0d248 100644
--- a/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/validate.go
+++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/typed/validate.go
@@ -157,7 +157,7 @@ func (v *validatingObjectWalker) visitListItems(t *schema.List, list value.List)
 func (v *validatingObjectWalker) doList(t *schema.List) (errs ValidationErrors) {
 	list, err := listValue(v.allocator, v.value)
 	if err != nil {
-		return errorf(err.Error())
+		return errorf("%v", err)
 	}
 
 	if list == nil {
@@ -193,7 +193,7 @@ func (v *validatingObjectWalker) visitMapItems(t *schema.Map, m value.Map) (errs
 func (v *validatingObjectWalker) doMap(t *schema.Map) (errs ValidationErrors) {
 	m, err := mapValue(v.allocator, v.value)
 	if err != nil {
-		return errorf(err.Error())
+		return errorf("%v", err)
 	}
 	if m == nil {
 		return nil
diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go
index d4adb8fc9d25d9415c03eb2c41c37370b0db356b..3aadceb2226280c8df65421d14d4bdc9da473859 100644
--- a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go
+++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/jsontagutil.go
@@ -22,22 +22,77 @@ import (
 	"strings"
 )
 
+type isZeroer interface {
+	IsZero() bool
+}
+
+var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem()
+
+func reflectIsZero(dv reflect.Value) bool {
+	return dv.IsZero()
+}
+
+// OmitZeroFunc returns a function for a type for a given struct field
+// which determines if the value for that field is a zero value, matching
+// how the stdlib JSON implementation.
+func OmitZeroFunc(t reflect.Type) func(reflect.Value) bool {
+	// Provide a function that uses a type's IsZero method.
+	// This matches the go 1.24 custom IsZero() implementation matching
+	switch {
+	case t.Kind() == reflect.Interface && t.Implements(isZeroerType):
+		return func(v reflect.Value) bool {
+			// Avoid panics calling IsZero on a nil interface or
+			// non-nil interface with nil pointer.
+			return safeIsNil(v) ||
+				(v.Elem().Kind() == reflect.Pointer && v.Elem().IsNil()) ||
+				v.Interface().(isZeroer).IsZero()
+		}
+	case t.Kind() == reflect.Pointer && t.Implements(isZeroerType):
+		return func(v reflect.Value) bool {
+			// Avoid panics calling IsZero on nil pointer.
+			return safeIsNil(v) || v.Interface().(isZeroer).IsZero()
+		}
+	case t.Implements(isZeroerType):
+		return func(v reflect.Value) bool {
+			return v.Interface().(isZeroer).IsZero()
+		}
+	case reflect.PointerTo(t).Implements(isZeroerType):
+		return func(v reflect.Value) bool {
+			if !v.CanAddr() {
+				// Temporarily box v so we can take the address.
+				v2 := reflect.New(v.Type()).Elem()
+				v2.Set(v)
+				v = v2
+			}
+			return v.Addr().Interface().(isZeroer).IsZero()
+		}
+	default:
+		// default to the reflect.IsZero implementation
+		return reflectIsZero
+	}
+}
+
 // TODO: This implements the same functionality as https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L236
 // but is based on the highly efficient approach from https://golang.org/src/encoding/json/encode.go
 
-func lookupJsonTags(f reflect.StructField) (name string, omit bool, inline bool, omitempty bool) {
+func lookupJsonTags(f reflect.StructField) (name string, omit bool, inline bool, omitempty bool, omitzero func(reflect.Value) bool) {
 	tag := f.Tag.Get("json")
 	if tag == "-" {
-		return "", true, false, false
+		return "", true, false, false, nil
 	}
 	name, opts := parseTag(tag)
 	if name == "" {
 		name = f.Name
 	}
-	return name, false, opts.Contains("inline"), opts.Contains("omitempty")
+
+	if opts.Contains("omitzero") {
+		omitzero = OmitZeroFunc(f.Type)
+	}
+
+	return name, false, opts.Contains("inline"), opts.Contains("omitempty"), omitzero
 }
 
-func isZero(v reflect.Value) bool {
+func isEmpty(v reflect.Value) bool {
 	switch v.Kind() {
 	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
 		return v.Len() == 0
diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go
index 88693b87e8fc5e929e38bb205eecdb21edfde8cc..3b4a402ee1ab8a3b39ac7e1e72da747fa18f1826 100644
--- a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go
+++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go
@@ -59,6 +59,8 @@ type FieldCacheEntry struct {
 	JsonName string
 	// isOmitEmpty is true if the field has the json 'omitempty' tag.
 	isOmitEmpty bool
+	// omitzero is set if the field has the json 'omitzero' tag.
+	omitzero func(reflect.Value) bool
 	// fieldPath is a list of field indices (see FieldByIndex) to lookup the value of
 	// a field in a reflect.Value struct. The field indices in the list form a path used
 	// to traverse through intermediary 'inline' fields.
@@ -69,7 +71,13 @@ type FieldCacheEntry struct {
 }
 
 func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool {
-	return f.isOmitEmpty && (safeIsNil(fieldVal) || isZero(fieldVal))
+	if f.isOmitEmpty && (safeIsNil(fieldVal) || isEmpty(fieldVal)) {
+		return true
+	}
+	if f.omitzero != nil && f.omitzero(fieldVal) {
+		return true
+	}
+	return false
 }
 
 // GetFrom returns the field identified by this FieldCacheEntry from the provided struct.
@@ -147,7 +155,7 @@ func typeReflectEntryOf(cm reflectCacheMap, t reflect.Type, updates reflectCache
 func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fieldPath [][]int) {
 	for i := 0; i < t.NumField(); i++ {
 		field := t.Field(i)
-		jsonName, omit, isInline, isOmitempty := lookupJsonTags(field)
+		jsonName, omit, isInline, isOmitempty, omitzero := lookupJsonTags(field)
 		if omit {
 			continue
 		}
@@ -161,7 +169,7 @@ func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fi
 			}
 			continue
 		}
-		info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type}
+		info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, omitzero: omitzero, fieldPath: append(fieldPath, field.Index), fieldType: field.Type}
 		infos[jsonName] = info
 	}
 }
diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/scalar.go b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/scalar.go
index c78a4c18d122bccc813040ddaee0ff6acd8e3c2c..5824219e5136d85749df8d480c0fc9f081b24645 100644
--- a/vendor/sigs.k8s.io/structured-merge-diff/v4/value/scalar.go
+++ b/vendor/sigs.k8s.io/structured-merge-diff/v4/value/scalar.go
@@ -43,7 +43,7 @@ func IntCompare(lhs, rhs int64) int {
 func BoolCompare(lhs, rhs bool) int {
 	if lhs == rhs {
 		return 0
-	} else if lhs == false {
+	} else if !lhs {
 		return -1
 	}
 	return 1