Repository: kubernetes-sigs/cluster-api
Pull request #9173 (2023-08-14 08:30:43)

:book: Reword and list which deployments have to be edited for exp features.
<!-- Thanks for sending a pull request! Here are some tips for you:
    1. If this is your first time, please read our contributor guidelines: https://github.com/kubernetes-sigs/cluster-api/blob/main/CONTRIBUTING.md#contributing-a-patch and developer guide https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/book/src/developer/guide.md

    2. Please add an icon to the title of this PR (see https://sigs.k8s.io/cluster-api/CONTRIBUTING.md#contributing-a-patch), and delete this line and similar ones
    the icon will be either ⚠️ (:warning:, major or breaking changes), ✨ (:sparkles:, feature additions), 🐛 (:bug:, patch and bugfixes), 📖 (:book:, documentation or proposals), or 🌱 (:seedling:, minor or other) 
-->

**What this PR does / why we need it**:
This paragraph in the [section describing describing the experimental features](https://cluster-api.sigs.k8s.io/tasks/experimental-features/experimental-features#enabling-experimental-features-on-existing-management-clusters) explains how to enable/disable features in a running mgmt cluster. Trying this for the `ClusterToplogy` feature flag revealed that the flag must also to be enabled for KCP. Otherwise the Webhook for KubeadmControlPlaneTemplate will deny the request. See: https://github.com/kubernetes-sigs/cluster-api/blob/main/controlplane/kubeadm/api/v1beta1/kubeadmcontrolplanetemplate_webhook.go#L59

It might make sense for a user to get a list which deployments have to be edited for which feature. Not sure if this is the best way to communicate this or if this should rather be put into the corresponding sections of the experimental features. Up for suggestions :slightly_smiling_face:.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #

/area documentation

<sub>Johannes Frey <[johannes.frey@mercedes-benz.com](mailto:johannes.frey@mercedes-benz.com)>, Mercedes-Benz Tech Innovation GmbH ([Provider Information](https://github.com/mercedes-benz/daimler-foss/blob/master/PROVIDER_INFORMATION.md))</sub>

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

This pull-request has been approved by:
**Once this PR has been reviewed and has the lgtm label**, please assign [oscr](https://github.com/oscr) for approval. For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

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

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

- **[docs/OWNERS](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["oscr"]} -->
k8s-ci-robot: LGTM label has been added.  <details>Git tree hash: 1a052dd1ea941288e9d358b87acd428a0874698f</details>
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
**Once this PR has been reviewed and has the lgtm label**, please ask for approval from [killianmuldoon](https://github.com/killianmuldoon). For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

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

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

- **[docs/OWNERS](https://github.com/kubernetes-sigs/cluster-api/blob/main/docs/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["killianmuldoon"]} -->

Patch:
diff --git a/.github/workflows/pr-dependabot.yaml b/.github/workflows/pr-dependabot.yaml
index 44c14bf6a..d3b2f1d63 100644
--- a/.github/workflows/pr-dependabot.yaml
+++ b/.github/workflows/pr-dependabot.yaml
@@ -24,7 +24,7 @@ jobs:
       id: vars
       run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT
     - name: Set up Go
-      uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # tag=v4.1.0
+      uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # tag=v4.0.1
       with:
         go-version: ${{ steps.vars.outputs.go_version }}
     - uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # tag=v3.3.1
diff --git a/.github/workflows/pr-golangci-lint.yaml b/.github/workflows/pr-golangci-lint.yaml
index 12b00a39d..b5dbbaa98 100644
--- a/.github/workflows/pr-golangci-lint.yaml
+++ b/.github/workflows/pr-golangci-lint.yaml
@@ -24,12 +24,11 @@ jobs:
         id: vars
         run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT
       - name: Set up Go
-        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # tag=v4.1.0
+        uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # tag=v4.0.1
         with:
           go-version: ${{ steps.vars.outputs.go_version }}
       - name: golangci-lint
         uses: golangci/golangci-lint-action@639cd343e1d3b897ff35927a75193d57cfcba299 # tag=v3.6.0
         with:
-          version: v1.54.1
-          args: --out-format=colored-line-number
+          version: v1.53.3
           working-directory: ${{matrix.working-directory}}
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index c7eb22995..d76225d8b 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -23,7 +23,7 @@ jobs:
       - name: Calculate go version
         run: echo "go_version=$(make go-version)" >> $GITHUB_ENV
       - name: Set up Go
-        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # tag=v4.1.0
+        uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # tag=v4.0.1
         with:
           go-version: ${{ env.go_version }}
       - name: generate release artifacts
diff --git a/.github/workflows/weekly-security-scan.yaml b/.github/workflows/weekly-image-scan.yaml
similarity index 78%
rename from .github/workflows/weekly-security-scan.yaml
rename to .github/workflows/weekly-image-scan.yaml
index ada88d79e..cac026712 100644
--- a/.github/workflows/weekly-security-scan.yaml
+++ b/.github/workflows/weekly-image-scan.yaml
@@ -1,4 +1,4 @@
-name: Weekly security scan
+name: Weekly image scan
 
 on:
   schedule:
@@ -25,8 +25,8 @@ jobs:
       id: vars
       run: echo "go_version=$(make go-version)" >> $GITHUB_OUTPUT
     - name: Set up Go
-      uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # tag=v4.1.0
+      uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # tag=v4.0.1
       with:
         go-version: ${{ steps.vars.outputs.go_version }}
-    - name: Run verify security target
-      run: make verify-security
+    - name: Run verify container script
+      run: make verify-container-images
diff --git a/Makefile b/Makefile
index 1146a456e..5c3833881 100644
--- a/Makefile
+++ b/Makefile
@@ -164,11 +164,6 @@ GOLANGCI_LINT_VER := $(shell cat .github/workflows/pr-golangci-lint.yaml | grep
 GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER))
 GOLANGCI_LINT_PKG := github.com/golangci/golangci-lint/cmd/golangci-lint
 
-GOVULNCHECK_BIN := govulncheck
-GOVULNCHECK_VER := v1.0.0
-GOVULNCHECK := $(abspath $(TOOLS_BIN_DIR)/$(GOVULNCHECK_BIN)-$(GOVULNCHECK_VER))
-GOVULNCHECK_PKG := golang.org/x/vuln/cmd/govulncheck
-
 CONVERSION_VERIFIER_BIN := conversion-verifier
 CONVERSION_VERIFIER := $(abspath $(TOOLS_BIN_DIR)/$(CONVERSION_VERIFIER_BIN))
 
@@ -228,7 +223,7 @@ CAPI_KIND_CLUSTER_NAME ?= capi-test
 
 TAG ?= dev
 ARCH ?= $(shell go env GOARCH)
-ALL_ARCH ?= amd64 arm arm64 ppc64le s390x
+ALL_ARCH = amd64 arm arm64 ppc64le s390x
 
 # Allow overriding the imagePullPolicy
 PULL_POLICY ?= Always
@@ -605,7 +600,7 @@ APIDIFF_OLD_COMMIT ?= $(shell git rev-parse origin/main)
 apidiff: $(GO_APIDIFF) ## Check for API differences
 	$(GO_APIDIFF) $(APIDIFF_OLD_COMMIT) --print-compatible
 
-ALL_VERIFY_CHECKS = boilerplate shellcheck tiltfile modules gen conversions doctoc capi-book-summary
+ALL_VERIFY_CHECKS = doctoc boilerplate shellcheck tiltfile modules gen conversions doctoc capi-book-summary
 
 .PHONY: verify
 verify: $(addprefix verify-,$(ALL_VERIFY_CHECKS)) lint-dockerfiles ## Run all verify-* targets
@@ -659,24 +654,6 @@ verify-tiltfile: ## Verify Tiltfile format
 verify-container-images: ## Verify container images
 	TRACE=$(TRACE) ./hack/verify-container-images.sh
 
-.PHONY: verify-govulncheck
-verify-govulncheck: $(GOVULNCHECK) ## Verify code for vulnerabilities
-	$(GOVULNCHECK) ./... && R1=$$? || R1=$$?; \
-	$(GOVULNCHECK) -C "$(TOOLS_DIR)" ./... && R2=$$? || R2=$$?; \
-	$(GOVULNCHECK) -C "$(TEST_DIR)" ./... && R3=$$? || R3=$$?; \
-	if [ "$$R1" -ne "0" ] || [ "$$R2" -ne "0" ] || [ "$$R3" -ne "0" ]; then \
-		exit 1; \
-	fi
-
-.PHONY: verify-security
-verify-security: ## Verify code and images for vulnerabilities
-	$(MAKE) verify-container-images && R1=$$? || R1=$$?; \
-	$(MAKE) verify-govulncheck && R2=$$? || R2=$$?; \
-	if [ "$$R1" -ne "0" ] || [ "$$R2" -ne "0" ]; then \
-	  echo "Check for vulnerabilities failed! There are vulnerabilities to be fixed"; \
-		exit 1; \
-	fi
-
 ## --------------------------------------
 ## Binaries
 ## --------------------------------------
@@ -724,8 +701,7 @@ docker-build-all: $(addprefix docker-build-,$(ALL_ARCH)) ## Build docker images
 docker-build-%:
 	$(MAKE) ARCH=$* docker-build
 
-# Choice of images to build/push
-ALL_DOCKER_BUILD ?= core kubeadm-bootstrap kubeadm-control-plane docker-infrastructure in-memory-infrastructure test-extension clusterctl
+ALL_DOCKER_BUILD = core kubeadm-bootstrap kubeadm-control-plane docker-infrastructure in-memory-infrastructure test-extension clusterctl
 
 .PHONY: docker-build
 docker-build: docker-pull-prerequisites ## Run docker-build-* targets for all the images
@@ -1072,17 +1048,26 @@ promote-images: $(KPROMO)
 
 .PHONY: docker-push-all
 docker-push-all: $(addprefix docker-push-,$(ALL_ARCH))  ## Push the docker images to be included in the release for all architectures + related multiarch manifests
-	$(MAKE) ALL_ARCH="$(ALL_ARCH)" $(addprefix docker-push-manifest-,$(ALL_DOCKER_BUILD))
+	$(MAKE) docker-push-manifest-core
+	$(MAKE) docker-push-manifest-kubeadm-bootstrap
+	$(MAKE) docker-push-manifest-kubeadm-control-plane
+	$(MAKE) docker-push-manifest-docker-infrastructure
+	$(MAKE) docker-push-manifest-in-memory-infrastructure
+	$(MAKE) docker-push-manifest-test-extension
+	$(MAKE) docker-push-clusterctl
 
 docker-push-%:
 	$(MAKE) ARCH=$* docker-push
 
 .PHONY: docker-push
-docker-push: $(addprefix docker-push-,$(ALL_DOCKER_BUILD)) ## Push the docker images to be included in the release
-
-.PHONY: docker-push-core
-docker-push-core: ## Push the core docker image
+docker-push: ## Push the docker images to be included in the release
 	docker push $(CONTROLLER_IMG)-$(ARCH):$(TAG)
+	docker push $(KUBEADM_BOOTSTRAP_CONTROLLER_IMG)-$(ARCH):$(TAG)
+	docker push $(KUBEADM_CONTROL_PLANE_CONTROLLER_IMG)-$(ARCH):$(TAG)
+	docker push $(CLUSTERCTL_IMG)-$(ARCH):$(TAG)
+	docker push $(CAPD_CONTROLLER_IMG)-$(ARCH):$(TAG)
+	docker push $(CAPIM_CONTROLLER_IMG)-$(ARCH):$(TAG)
+	docker push $(TEST_EXTENSION_IMG)-$(ARCH):$(TAG)
 
 .PHONY: docker-push-manifest-core
 docker-push-manifest-core: ## Push the multiarch manifest for the core docker images
@@ -1092,10 +1077,6 @@ docker-push-manifest-core: ## Push the multiarch manifest for the core docker im
 	$(MAKE) set-manifest-image MANIFEST_IMG=$(CONTROLLER_IMG) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="./config/default/manager_image_patch.yaml"
 	$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./config/default/manager_pull_policy.yaml"
 
-.PHONY: docker-push-kubeadm-bootstrap
-docker-push-kubeadm-bootstrap: ## Push the kubeadm bootstrap docker image
-	docker push $(KUBEADM_BOOTSTRAP_CONTROLLER_IMG)-$(ARCH):$(TAG)
-
 .PHONY: docker-push-manifest-kubeadm-bootstrap
 docker-push-manifest-kubeadm-bootstrap: ## Push the multiarch manifest for the kubeadm bootstrap docker images
 	docker manifest create --amend $(KUBEADM_BOOTSTRAP_CONTROLLER_IMG):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(KUBEADM_BOOTSTRAP_CONTROLLER_IMG)\-&:$(TAG)~g")
@@ -1104,10 +1085,6 @@ docker-push-manifest-kubeadm-bootstrap: ## Push the multiarch manifest for the k
 	$(MAKE) set-manifest-image MANIFEST_IMG=$(KUBEADM_BOOTSTRAP_CONTROLLER_IMG) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="./bootstrap/kubeadm/config/default/manager_image_patch.yaml"
 	$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./bootstrap/kubeadm/config/default/manager_pull_policy.yaml"
 
-.PHONY: docker-push-kubeadm-control-plane
-docker-push-kubeadm-control-plane: ## Push the kubeadm control plane docker image
-	docker push $(KUBEADM_CONTROL_PLANE_CONTROLLER_IMG)-$(ARCH):$(TAG)
-
 .PHONY: docker-push-manifest-kubeadm-control-plane
 docker-push-manifest-kubeadm-control-plane: ## Push the multiarch manifest for the kubeadm control plane docker images
 	docker manifest create --amend $(KUBEADM_CONTROL_PLANE_CONTROLLER_IMG):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(KUBEADM_CONTROL_PLANE_CONTROLLER_IMG)\-&:$(TAG)~g")
@@ -1116,10 +1093,6 @@ docker-push-manifest-kubeadm-control-plane: ## Push the multiarch manifest for t
 	$(MAKE) set-manifest-image MANIFEST_IMG=$(KUBEADM_CONTROL_PLANE_CONTROLLER_IMG) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="./controlplane/kubeadm/config/default/manager_image_patch.yaml"
 	$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./controlplane/kubeadm/config/default/manager_pull_policy.yaml"
 
-.PHONY: docker-push-docker-infrastructure
-docker-push-docker-infrastructure: ## Push the docker infrastructure provider image
-	docker push $(CAPD_CONTROLLER_IMG)-$(ARCH):$(TAG)
-
 .PHONY: docker-push-manifest-docker-infrastructure
 docker-push-manifest-docker-infrastructure: ## Push the multiarch manifest for the docker infrastructure provider images
 	docker manifest create --amend $(CAPD_CONTROLLER_IMG):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(CAPD_CONTROLLER_IMG)\-&:$(TAG)~g")
@@ -1128,10 +1101,6 @@ docker-push-manifest-docker-infrastructure: ## Push the multiarch manifest for t
 	$(MAKE) set-manifest-image MANIFEST_IMG=$(CAPD_CONTROLLER_IMG) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="$(CAPD_DIR)/config/default/manager_image_patch.yaml"
 	$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="$(CAPD_DIR)/config/default/manager_pull_policy.yaml"
 
-.PHONY: docker-push-in-memory-infrastructure
-docker-push-in-memory-infrastructure: ## Push the in-memory infrastructure provider image
-	docker push $(CAPIM_CONTROLLER_IMG)-$(ARCH):$(TAG)
-
 .PHONY: docker-push-manifest-in-memory-infrastructure
 docker-push-manifest-in-memory-infrastructure: ## Push the multiarch manifest for the in-memory infrastructure provider images
 	docker manifest create --amend $(CAPIM_CONTROLLER_IMG):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(CAPIM_CONTROLLER_IMG)\-&:$(TAG)~g")
@@ -1140,10 +1109,6 @@ docker-push-manifest-in-memory-infrastructure: ## Push the multiarch manifest fo
 	$(MAKE) set-manifest-image MANIFEST_IMG=$(CAPIM_CONTROLLER_IMG) MANIFEST_TAG=$(TAG) TARGET_RESOURCE="$(CAPIM_DIR)/config/default/manager_image_patch.yaml"
 	$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="$(CAPIM_DIR)/config/default/manager_pull_policy.yaml"
 
-.PHONY: docker-push-test-extension
-docker-push-test-extension: ## Push the test extension provider image
-	docker push $(TEST_EXTENSION_IMG)-$(ARCH):$(TAG)
-
 .PHONY: docker-push-manifest-test-extension
 docker-push-manifest-test-extension: ## Push the multiarch manifest for the test extension provider images
 	docker manifest create --amend $(TEST_EXTENSION_IMG):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(TEST_EXTENSION_IMG)\-&:$(TAG)~g")
@@ -1153,11 +1118,7 @@ docker-push-manifest-test-extension: ## Push the multiarch manifest for the test
 	$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./test/extension/config/default/manager_pull_policy.yaml"
 
 .PHONY: docker-push-clusterctl
-docker-push-clusterctl: ## Push the clusterctl image
-	docker push $(CLUSTERCTL_IMG)-$(ARCH):$(TAG)
-
-.PHONY: docker-push-manifest-clusterctl
-docker-push-manifest-clusterctl: ## Push the multiarch manifest for the clusterctl images
+docker-push-clusterctl: ## Push the clusterctl images
 	docker manifest create --amend $(CLUSTERCTL_IMG):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(CLUSTERCTL_IMG)\-&:$(TAG)~g")
 	@for arch in $(ALL_ARCH); do docker manifest annotate --arch $${arch} ${CLUSTERCTL_IMG}:${TAG} ${CLUSTERCTL_IMG}-$${arch}:${TAG}; done
 	docker manifest push --purge $(CLUSTERCTL_IMG):$(TAG)
@@ -1289,9 +1250,6 @@ $(GINKGO_BIN): $(GINKGO) ## Build a local copy of ginkgo.
 .PHONY: $(GOLANGCI_LINT_BIN)
 $(GOLANGCI_LINT_BIN): $(GOLANGCI_LINT) ## Build a local copy of golangci-lint.
 
-.PHONY: $(GOVULNCHECK_BIN)
-$(GOVULNCHECK_BIN): $(GOVULNCHECK) ## Build a local copy of govulncheck.
-
 $(CONTROLLER_GEN): # Build controller-gen from tools folder.
 	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(CONTROLLER_GEN_PKG) $(CONTROLLER_GEN_BIN) $(CONTROLLER_GEN_VER)
 
@@ -1343,9 +1301,6 @@ $(GINKGO): # Build ginkgo from tools folder.
 $(GOLANGCI_LINT): # Build golangci-lint from tools folder.
 	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GOLANGCI_LINT_PKG) $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER)
 
-$(GOVULNCHECK): # Build govulncheck.
-	GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GOVULNCHECK_PKG) $(GOVULNCHECK_BIN) $(GOVULNCHECK_VER)
-
 ## --------------------------------------
 ## Helpers
 ## --------------------------------------
diff --git a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go
index dd0d572f2..18e1fce57 100644
--- a/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go
+++ b/bootstrap/kubeadm/internal/controllers/kubeadmconfig_controller.go
@@ -22,7 +22,7 @@ import (
 	"strconv"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
diff --git a/bootstrap/kubeadm/types/utils.go b/bootstrap/kubeadm/types/utils.go
index 7372d9378..0ee8c23bb 100644
--- a/bootstrap/kubeadm/types/utils.go
+++ b/bootstrap/kubeadm/types/utils.go
@@ -18,7 +18,7 @@ limitations under the License.
 package utils
 
 import (
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/cmd/clusterctl/api/v1alpha3/metadata_type.go b/cmd/clusterctl/api/v1alpha3/metadata_type.go
index 0009c160b..0eacecbf4 100644
--- a/cmd/clusterctl/api/v1alpha3/metadata_type.go
+++ b/cmd/clusterctl/api/v1alpha3/metadata_type.go
@@ -17,7 +17,7 @@ limitations under the License.
 package v1alpha3
 
 import (
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/version"
 )
diff --git a/cmd/clusterctl/client/cluster/cert_manager.go b/cmd/clusterctl/client/cluster/cert_manager.go
index 2c73c5d4b..954c401b9 100644
--- a/cmd/clusterctl/client/cluster/cert_manager.go
+++ b/cmd/clusterctl/client/cluster/cert_manager.go
@@ -21,7 +21,7 @@ import (
 	_ "embed"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/cmd/clusterctl/client/config/cert_manager_client.go b/cmd/clusterctl/client/config/cert_manager_client.go
index 5ea44244a..ea3858c27 100644
--- a/cmd/clusterctl/client/config/cert_manager_client.go
+++ b/cmd/clusterctl/client/config/cert_manager_client.go
@@ -29,7 +29,7 @@ const (
 	CertManagerConfigKey = "cert-manager"
 
 	// CertManagerDefaultVersion defines the default cert-manager version to be used by clusterctl.
-	CertManagerDefaultVersion = "v1.12.3"
+	CertManagerDefaultVersion = "v1.12.2"
 
 	// CertManagerDefaultURL defines the default cert-manager repository url to be used by clusterctl.
 	// NOTE: At runtime CertManagerDefaultVersion may be replaced with the
diff --git a/cmd/clusterctl/client/repository/repository_github.go b/cmd/clusterctl/client/repository/repository_github.go
index ab51f41fb..5cddd0128 100644
--- a/cmd/clusterctl/client/repository/repository_github.go
+++ b/cmd/clusterctl/client/repository/repository_github.go
@@ -28,7 +28,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/google/go-github/v53/github"
 	"github.com/pkg/errors"
 	"golang.org/x/oauth2"
diff --git a/cmd/clusterctl/cmd/version_checker.go b/cmd/clusterctl/cmd/version_checker.go
index f0334225c..c195a5eb0 100644
--- a/cmd/clusterctl/cmd/version_checker.go
+++ b/cmd/clusterctl/cmd/version_checker.go
@@ -26,7 +26,7 @@ import (
 	"time"
 
 	"github.com/adrg/xdg"
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/google/go-github/v53/github"
 	"github.com/pkg/errors"
 	"golang.org/x/oauth2"
diff --git a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go
index 84b55b454..9db8198d2 100644
--- a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go
+++ b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook.go
@@ -21,7 +21,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/coredns/corefile-migration/migration"
 	jsonpatch "github.com/evanphx/json-patch/v5"
 	"github.com/pkg/errors"
@@ -140,7 +140,6 @@ func (in *KubeadmControlPlane) ValidateUpdate(old runtime.Object) (admission.War
 	// For example, {"spec", "*"} will allow any path under "spec" to change.
 	allowedPaths := [][]string{
 		{"metadata", "*"},
-		{spec, kubeadmConfigSpec, "useExperimentalRetryJoin"},
 		{spec, kubeadmConfigSpec, clusterConfiguration, "etcd", "local", "imageRepository"},
 		{spec, kubeadmConfigSpec, clusterConfiguration, "etcd", "local", "imageTag"},
 		{spec, kubeadmConfigSpec, clusterConfiguration, "etcd", "local", "extraArgs"},
diff --git a/controlplane/kubeadm/internal/controllers/controller.go b/controlplane/kubeadm/internal/controllers/controller.go
index f71bdec07..73c2ae7b9 100644
--- a/controlplane/kubeadm/internal/controllers/controller.go
+++ b/controlplane/kubeadm/internal/controllers/controller.go
@@ -22,7 +22,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -85,6 +85,12 @@ type KubeadmControlPlaneReconciler struct {
 
 	managementCluster         internal.ManagementCluster
 	managementClusterUncached internal.ManagementCluster
+
+	// disableInPlacePropagation should only be used for tests. This is used to skip
+	// some parts of the controller that need SSA as the current test setup does not
+	// support SSA. This flag should be dropped after all affected tests are migrated
+	// to envtest.
+	disableInPlacePropagation bool
 	ssaCache                  ssa.Cache
 }
 
@@ -369,8 +375,10 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, controlPl
 		return result, err
 	}
 
-	if err := r.syncMachines(ctx, controlPlane); err != nil {
-		return ctrl.Result{}, errors.Wrap(err, "failed to sync Machines")
+	if !r.disableInPlacePropagation {
+		if err := r.syncMachines(ctx, controlPlane); err != nil {
+			return ctrl.Result{}, errors.Wrap(err, "failed to sync Machines")
+		}
 	}
 
 	// Aggregate the operational state of all the machines; while aggregating we are adding the
diff --git a/controlplane/kubeadm/internal/controllers/remediation.go b/controlplane/kubeadm/internal/controllers/remediation.go
index 698612437..d1c8fd44e 100644
--- a/controlplane/kubeadm/internal/controllers/remediation.go
+++ b/controlplane/kubeadm/internal/controllers/remediation.go
@@ -22,7 +22,7 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/controlplane/kubeadm/internal/controllers/scale.go b/controlplane/kubeadm/internal/controllers/scale.go
index 66608e60a..4ed1682c2 100644
--- a/controlplane/kubeadm/internal/controllers/scale.go
+++ b/controlplane/kubeadm/internal/controllers/scale.go
@@ -20,7 +20,7 @@ import (
 	"context"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/controlplane/kubeadm/internal/controllers/upgrade.go b/controlplane/kubeadm/internal/controllers/upgrade.go
index f51bce9d8..b1528283d 100644
--- a/controlplane/kubeadm/internal/controllers/upgrade.go
+++ b/controlplane/kubeadm/internal/controllers/upgrade.go
@@ -19,7 +19,7 @@ package controllers
 import (
 	"context"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	ctrl "sigs.k8s.io/controller-runtime"
 
diff --git a/controlplane/kubeadm/internal/workload_cluster.go b/controlplane/kubeadm/internal/workload_cluster.go
index 9d7de352b..4112106f5 100644
--- a/controlplane/kubeadm/internal/workload_cluster.go
+++ b/controlplane/kubeadm/internal/workload_cluster.go
@@ -29,7 +29,7 @@ import (
 	"reflect"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
diff --git a/controlplane/kubeadm/internal/workload_cluster_coredns.go b/controlplane/kubeadm/internal/workload_cluster_coredns.go
index 5699c9c06..9ebf7eda9 100644
--- a/controlplane/kubeadm/internal/workload_cluster_coredns.go
+++ b/controlplane/kubeadm/internal/workload_cluster_coredns.go
@@ -22,7 +22,7 @@ import (
 	"reflect"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/coredns/corefile-migration/migration"
 	"github.com/pkg/errors"
 	appsv1 "k8s.io/api/apps/v1"
diff --git a/controlplane/kubeadm/internal/workload_cluster_etcd.go b/controlplane/kubeadm/internal/workload_cluster_etcd.go
index bb4c4d417..3b3662a29 100644
--- a/controlplane/kubeadm/internal/workload_cluster_etcd.go
+++ b/controlplane/kubeadm/internal/workload_cluster_etcd.go
@@ -19,7 +19,7 @@ package internal
 import (
 	"context"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	kerrors "k8s.io/apimachinery/pkg/util/errors"
 
diff --git a/controlplane/kubeadm/internal/workload_cluster_rbac.go b/controlplane/kubeadm/internal/workload_cluster_rbac.go
index eb22e3480..d714c6329 100644
--- a/controlplane/kubeadm/internal/workload_cluster_rbac.go
+++ b/controlplane/kubeadm/internal/workload_cluster_rbac.go
@@ -20,7 +20,7 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	rbacv1 "k8s.io/api/rbac/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/docs/book/src/clusterctl/commands/init.md b/docs/book/src/clusterctl/commands/init.md
index 34479acef..73092f46c 100644
--- a/docs/book/src/clusterctl/commands/init.md
+++ b/docs/book/src/clusterctl/commands/init.md
@@ -190,7 +190,7 @@ If this happens, there are no guarantees about the proper functioning of `cluste
 Cluster API providers require a cert-manager version supporting the `cert-manager.io/v1` API to be installed in the cluster.
 
 While doing init, clusterctl checks if there is a version of cert-manager already installed. If not, clusterctl will
-install a default version (currently cert-manager v1.12.3). See [clusterctl configuration](../configuration.md) for
+install a default version (currently cert-manager v1.12.2). See [clusterctl configuration](../configuration.md) for
 available options to customize this operation.
 
 <aside class="note warning">
diff --git a/docs/book/src/developer/guide.md b/docs/book/src/developer/guide.md
index 350f6148a..3c055812b 100644
--- a/docs/book/src/developer/guide.md
+++ b/docs/book/src/developer/guide.md
@@ -81,7 +81,7 @@ The generated binary can be found at ./hack/tools/bin/envsubst
 You'll need to deploy [cert-manager] components on your [management cluster][mcluster], using `kubectl`
 
 ```bash
-kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.3/cert-manager.yaml
+kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.2/cert-manager.yaml
 ```
 
 Ensure the cert-manager webhook service is ready before creating the Cluster API components.
diff --git a/docs/book/src/tasks/experimental-features/experimental-features.md b/docs/book/src/tasks/experimental-features/experimental-features.md
index eca60612e..6144eced2 100644
--- a/docs/book/src/tasks/experimental-features/experimental-features.md
+++ b/docs/book/src/tasks/experimental-features/experimental-features.md
@@ -56,7 +56,9 @@ For more details on setting up a development environment with `tilt`, see [Devel
 
 ## Enabling Experimental Features on Existing Management Clusters
 
-To enable/disable features on existing management clusters, users can modify CAPI controller manager deployment which will restart all controllers with requested features.
+To enable/disable features on existing management clusters, users can edit the corresponding controller manager
+deployments, which will then trigger a restart with the requested features. E.g. for the CAPI controller manager
+deployment:
 
 ```
 kubectl edit -n capi-system deployment.apps/capi-controller-manager
@@ -68,12 +70,34 @@ kubectl edit -n capi-system deployment.apps/capi-controller-manager
       --feature-gates=MachinePool=true,ClusterResourceSet=true
 ```
 
-Similarly, to **validate** if a particular feature is enabled, see cluster-api-provider deployment arguments by:
+Similarly, to **validate** if a particular feature is enabled, see the arguments by issuing:
 
 ```bash
 kubectl describe -n capi-system deployment.apps/capi-controller-manager
 ```
 
+Following controller manager deployments have to be edited in order to enable/disable their respective experimental features:
+
+* [MachinePools](./machine-pools.md):
+  * [CAPI](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#capi).
+  * [CABPK](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#cabpk).
+  * [CAPD](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Providers#capd). Other [Infrastructure Providers](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Providers#infrastructure-provider)
+    might also require this. Please consult the docs of the concrete [Infrastructure Provider](https://cluster-api.sigs.k8s.io/reference/providers#infrastructure)
+    regarding this.
+* [ClusterResourceSet](./cluster-resource-set.md):
+  * [CAPI](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#capi).
+* [ClusterClass](./cluster-class/index.md):
+  * [CAPI](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#capi).
+  * [KCP](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#kcp).
+  * [CAPD](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Providers#capd). Other [Infrastructure Providers](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Providers#infrastructure-provider)
+    might also require this. Please consult the docs of the concrete [Infrastructure Provider](https://cluster-api.sigs.k8s.io/reference/providers#infrastructure)
+    regarding this.
+* [Ignition Bootstrap configuration](./ignition.md):
+  * [CABPK](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#cabpk).
+  * [KCP](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#kcp).
+* [Runtime SDK](runtime-sdk/index.md):
+  * [CAPI](https://cluster-api.sigs.k8s.io/reference/glossary.html?highlight=Gloss#capi).
+
 ## Active Experimental Features
 
 * [MachinePools](./machine-pools.md)
diff --git a/docs/release/release-tasks.md b/docs/release/release-tasks.md
index 03dd85bae..af9c0e6d4 100644
--- a/docs/release/release-tasks.md
+++ b/docs/release/release-tasks.md
@@ -426,7 +426,7 @@ While we add test coverage for the new release branch we will also drop the test
 3. Remove tests for old release branches according to our policy documented in [Support and guarantees](../../CONTRIBUTING.md#support-and-guarantees)
    For example, let's assume we just created tests for v1.4, then we can now drop test coverage for the release-1.1 branch.
 4. Verify the jobs and dashboards a day later by taking a look at: `https://testgrid.k8s.io/sig-cluster-lifecycle-cluster-api-1.4`
-5. Update `.github/workflows/weekly-security-scan.yaml` - to setup Trivy and govulncheck scanning - `.github/workflows/weekly-md-link-check.yaml` - to setup link checking in the CAPI book - and `.github/workflows/weekly-test-release.yaml` - to verify the release target is working - for the currently supported branches.
+5. Update `.github/workflows/weekly-image-scan.yaml` - to setup Trivy scanning - `.github/workflows/weekly-md-link-check.yaml` - to setup link checking in the CAPI book - and `.github/workflows/weekly-test-release.yaml` - to verify the release target is working - for the currently supported branches.
 
 
 Prior art:
diff --git a/exp/addons/api/v1beta1/clusterresourceset_types.go b/exp/addons/api/v1beta1/clusterresourceset_types.go
index 2800bf190..e64dccd29 100644
--- a/exp/addons/api/v1beta1/clusterresourceset_types.go
+++ b/exp/addons/api/v1beta1/clusterresourceset_types.go
@@ -140,5 +140,5 @@ type ClusterResourceSetList struct {
 }
 
 func init() {
-	objectTypes = append(objectTypes, &ClusterResourceSet{}, &ClusterResourceSetList{})
+	SchemeBuilder.Register(&ClusterResourceSet{}, &ClusterResourceSetList{})
 }
diff --git a/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go b/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go
index 299112258..d58c46461 100644
--- a/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go
+++ b/exp/addons/api/v1beta1/clusterresourcesetbinding_types.go
@@ -152,5 +152,5 @@ type ClusterResourceSetBindingList struct {
 }
 
 func init() {
-	objectTypes = append(objectTypes, &ClusterResourceSetBinding{}, &ClusterResourceSetBindingList{})
+	SchemeBuilder.Register(&ClusterResourceSetBinding{}, &ClusterResourceSetBindingList{})
 }
diff --git a/exp/addons/api/v1beta1/groupversion_info.go b/exp/addons/api/v1beta1/groupversion_info.go
index f02006147..c21f20bde 100644
--- a/exp/addons/api/v1beta1/groupversion_info.go
+++ b/exp/addons/api/v1beta1/groupversion_info.go
@@ -20,26 +20,17 @@ limitations under the License.
 package v1beta1
 
 import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
 )
 
 var (
 	// GroupVersion is group version used to register these objects.
 	GroupVersion = schema.GroupVersion{Group: "addons.cluster.x-k8s.io", Version: "v1beta1"}
 
-	// schemeBuilder is used to add go types to the GroupVersionKind scheme.
-	schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
 
 	// AddToScheme adds the types in this group-version to the given scheme.
-	AddToScheme = schemeBuilder.AddToScheme
-
-	objectTypes = []runtime.Object{}
+	AddToScheme = SchemeBuilder.AddToScheme
 )
-
-func addKnownTypes(scheme *runtime.Scheme) error {
-	scheme.AddKnownTypes(GroupVersion, objectTypes...)
-	metav1.AddToGroupVersion(scheme, GroupVersion)
-	return nil
-}
diff --git a/exp/api/v1beta1/groupversion_info.go b/exp/api/v1beta1/groupversion_info.go
index fd5c24e95..c92eaed36 100644
--- a/exp/api/v1beta1/groupversion_info.go
+++ b/exp/api/v1beta1/groupversion_info.go
@@ -20,26 +20,17 @@ limitations under the License.
 package v1beta1
 
 import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
 )
 
 var (
 	// GroupVersion is group version used to register these objects.
 	GroupVersion = schema.GroupVersion{Group: "cluster.x-k8s.io", Version: "v1beta1"}
 
-	// schemeBuilder is used to add go types to the GroupVersionKind scheme.
-	schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
 
 	// AddToScheme adds the types in this group-version to the given scheme.
-	AddToScheme = schemeBuilder.AddToScheme
-
-	objectTypes = []runtime.Object{}
+	AddToScheme = SchemeBuilder.AddToScheme
 )
-
-func addKnownTypes(scheme *runtime.Scheme) error {
-	scheme.AddKnownTypes(GroupVersion, objectTypes...)
-	metav1.AddToGroupVersion(scheme, GroupVersion)
-	return nil
-}
diff --git a/exp/api/v1beta1/machinepool_types.go b/exp/api/v1beta1/machinepool_types.go
index a2fc2957b..3d08de826 100644
--- a/exp/api/v1beta1/machinepool_types.go
+++ b/exp/api/v1beta1/machinepool_types.go
@@ -249,5 +249,5 @@ type MachinePoolList struct {
 }
 
 func init() {
-	objectTypes = append(objectTypes, &MachinePool{}, &MachinePoolList{})
+	SchemeBuilder.Register(&MachinePool{}, &MachinePoolList{})
 }
diff --git a/exp/ipam/api/v1alpha1/groupversion_info.go b/exp/ipam/api/v1alpha1/groupversion_info.go
index 221e76501..7be93c0c9 100644
--- a/exp/ipam/api/v1alpha1/groupversion_info.go
+++ b/exp/ipam/api/v1alpha1/groupversion_info.go
@@ -20,26 +20,17 @@ limitations under the License.
 package v1alpha1
 
 import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
 )
 
 var (
 	// GroupVersion is group version used to register these objects.
 	GroupVersion = schema.GroupVersion{Group: "ipam.cluster.x-k8s.io", Version: "v1alpha1"}
 
-	// schemeBuilder is used to add go types to the GroupVersionKind scheme.
-	schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
 
 	// AddToScheme adds the types in this group-version to the given scheme.
-	AddToScheme = schemeBuilder.AddToScheme
-
-	objectTypes = []runtime.Object{}
+	AddToScheme = SchemeBuilder.AddToScheme
 )
-
-func addKnownTypes(scheme *runtime.Scheme) error {
-	scheme.AddKnownTypes(GroupVersion, objectTypes...)
-	metav1.AddToGroupVersion(scheme, GroupVersion)
-	return nil
-}
diff --git a/exp/ipam/api/v1alpha1/ipaddress_types.go b/exp/ipam/api/v1alpha1/ipaddress_types.go
index b40982d96..01af31d26 100644
--- a/exp/ipam/api/v1alpha1/ipaddress_types.go
+++ b/exp/ipam/api/v1alpha1/ipaddress_types.go
@@ -65,5 +65,5 @@ type IPAddressList struct {
 }
 
 func init() {
-	objectTypes = append(objectTypes, &IPAddress{}, &IPAddressList{})
+	SchemeBuilder.Register(&IPAddress{}, &IPAddressList{})
 }
diff --git a/exp/ipam/api/v1alpha1/ipaddressclaim_types.go b/exp/ipam/api/v1alpha1/ipaddressclaim_types.go
index 16df8605e..af259b415 100644
--- a/exp/ipam/api/v1alpha1/ipaddressclaim_types.go
+++ b/exp/ipam/api/v1alpha1/ipaddressclaim_types.go
@@ -76,5 +76,5 @@ type IPAddressClaimList struct {
 }
 
 func init() {
-	objectTypes = append(objectTypes, &IPAddressClaim{}, &IPAddressClaimList{})
+	SchemeBuilder.Register(&IPAddressClaim{}, &IPAddressClaimList{})
 }
diff --git a/exp/ipam/api/v1alpha1/zz_generated.deepcopy.go b/exp/ipam/api/v1alpha1/zz_generated.deepcopy.go
index ea5de78b8..88cc359b9 100644
--- a/exp/ipam/api/v1alpha1/zz_generated.deepcopy.go
+++ b/exp/ipam/api/v1alpha1/zz_generated.deepcopy.go
@@ -22,7 +22,7 @@ limitations under the License.
 package v1alpha1
 
 import (
-	"k8s.io/apimachinery/pkg/runtime"
+	runtime "k8s.io/apimachinery/pkg/runtime"
 	"sigs.k8s.io/cluster-api/api/v1beta1"
 )
 
diff --git a/exp/runtime/api/v1alpha1/extensionconfig_types.go b/exp/runtime/api/v1alpha1/extensionconfig_types.go
index bd8c3e5d0..de426e366 100644
--- a/exp/runtime/api/v1alpha1/extensionconfig_types.go
+++ b/exp/runtime/api/v1alpha1/extensionconfig_types.go
@@ -197,7 +197,7 @@ type ExtensionConfigList struct {
 }
 
 func init() {
-	objectTypes = append(objectTypes, &ExtensionConfig{}, &ExtensionConfigList{})
+	SchemeBuilder.Register(&ExtensionConfig{}, &ExtensionConfigList{})
 }
 
 const (
diff --git a/exp/runtime/api/v1alpha1/groupversion_info.go b/exp/runtime/api/v1alpha1/groupversion_info.go
index 856a1ef0b..bac33a979 100644
--- a/exp/runtime/api/v1alpha1/groupversion_info.go
+++ b/exp/runtime/api/v1alpha1/groupversion_info.go
@@ -20,26 +20,17 @@ limitations under the License.
 package v1alpha1
 
 import (
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
 )
 
 var (
 	// GroupVersion is group version used to register these objects.
 	GroupVersion = schema.GroupVersion{Group: "runtime.cluster.x-k8s.io", Version: "v1alpha1"}
 
-	// schemeBuilder is used to add go types to the GroupVersionKind scheme.
-	schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
 
 	// AddToScheme adds the types in this group-version to the given scheme.
-	AddToScheme = schemeBuilder.AddToScheme
-
-	objectTypes = []runtime.Object{}
+	AddToScheme = SchemeBuilder.AddToScheme
 )
-
-func addKnownTypes(scheme *runtime.Scheme) error {
-	scheme.AddKnownTypes(GroupVersion, objectTypes...)
-	metav1.AddToGroupVersion(scheme, GroupVersion)
-	return nil
-}
diff --git a/exp/runtime/api/v1alpha1/zz_generated.deepcopy.go b/exp/runtime/api/v1alpha1/zz_generated.deepcopy.go
index 49f65c3e8..50a0cc037 100644
--- a/exp/runtime/api/v1alpha1/zz_generated.deepcopy.go
+++ b/exp/runtime/api/v1alpha1/zz_generated.deepcopy.go
@@ -23,7 +23,7 @@ package v1alpha1
 
 import (
 	"k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
+	runtime "k8s.io/apimachinery/pkg/runtime"
 	"sigs.k8s.io/cluster-api/api/v1beta1"
 )
 
diff --git a/go.mod b/go.mod
index ea491d378..782100a84 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/MakeNowJust/heredoc v1.0.0
 	github.com/Masterminds/sprig/v3 v3.2.3
 	github.com/adrg/xdg v0.4.0
-	github.com/blang/semver/v4 v4.0.0
+	github.com/blang/semver v3.5.1+incompatible
 	github.com/coredns/corefile-migration v1.0.20
 	github.com/davecgh/go-spew v1.1.1
 	github.com/docker/distribution v2.8.2+incompatible
@@ -20,20 +20,18 @@ require (
 	github.com/google/go-cmp v0.5.9
 	github.com/google/go-github/v53 v53.2.0
 	github.com/google/gofuzz v1.2.0
-	github.com/olekukonko/tablewriter v0.0.5
+	github.com/mattn/go-runewidth v0.0.14 // indirect
 	github.com/onsi/ginkgo/v2 v2.11.0
 	github.com/onsi/gomega v1.27.10
 	github.com/pkg/errors v0.9.1
-	github.com/prometheus/client_golang v1.16.0
 	github.com/spf13/cobra v1.7.0
 	github.com/spf13/pflag v1.0.5
 	github.com/spf13/viper v1.16.0
 	github.com/valyala/fastjson v1.6.4
 	go.etcd.io/etcd/api/v3 v3.5.9
 	go.etcd.io/etcd/client/v3 v3.5.9
+	golang.org/x/net v0.14.0 // indirect
 	golang.org/x/oauth2 v0.11.0
-	golang.org/x/text v0.12.0
-	gomodules.xyz/jsonpatch/v2 v2.4.0
 	google.golang.org/grpc v1.55.0
 	k8s.io/api v0.27.2
 	k8s.io/apiextensions-apiserver v0.27.2
@@ -43,7 +41,6 @@ require (
 	k8s.io/cluster-bootstrap v0.27.2
 	k8s.io/component-base v0.27.2
 	k8s.io/klog/v2 v2.90.1
-	k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f
 	k8s.io/kubectl v0.27.2
 	k8s.io/utils v0.0.0-20230209194617-a36077c30491
 	sigs.k8s.io/controller-runtime v0.15.1
@@ -54,7 +51,6 @@ require (
 	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver/v3 v3.2.0 // indirect
-	github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
 	github.com/ajeddeloh/go-json v0.0.0-20200220154158-5ae607161559 // indirect
 	github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
 	github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
@@ -62,32 +58,24 @@ require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/chai2010/gettext-go v1.0.2 // indirect
-	github.com/cloudflare/circl v1.3.3 // indirect
 	github.com/coredns/caddy v1.1.0 // indirect
 	github.com/coreos/go-semver v0.3.0 // indirect
 	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
 	github.com/coreos/go-systemd/v22 v22.4.0 // indirect
-	github.com/daviddengcn/go-colortext v1.0.0 // indirect
-	github.com/emicklei/go-restful/v3 v3.9.0 // indirect
 	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
 	github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
-	github.com/fatih/camelcase v1.0.0 // indirect
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
-	github.com/fvbommel/sortorder v1.0.1 // indirect
 	github.com/go-errors/errors v1.4.2 // indirect
 	github.com/go-logr/zapr v1.2.4 // indirect
 	github.com/go-openapi/jsonpointer v0.19.6 // indirect
 	github.com/go-openapi/jsonreference v0.20.1 // indirect
 	github.com/go-openapi/swag v0.22.3 // indirect
-	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/google/btree v1.0.1 // indirect
 	github.com/google/cel-go v0.12.6 // indirect
-	github.com/google/gnostic v0.6.9 // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
-	github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
 	github.com/google/uuid v1.3.0 // indirect
 	github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
@@ -95,16 +83,13 @@ require (
 	github.com/huandu/xstrings v1.3.3 // indirect
 	github.com/imdario/mergo v0.3.13 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
-	github.com/jonboulle/clockwork v0.2.2 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
-	github.com/lithammer/dedent v1.1.0 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
 	github.com/mattn/go-isatty v0.0.17 // indirect
-	github.com/mattn/go-runewidth v0.0.14 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/copystructure v1.2.0 // indirect
 	github.com/mitchellh/go-wordwrap v1.0.0 // indirect
@@ -115,16 +100,14 @@ require (
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
-	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
-	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+	github.com/olekukonko/tablewriter v0.0.5
 	github.com/opencontainers/go-digest v1.0.0 // indirect
-	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
 	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
+	github.com/prometheus/client_golang v1.16.0
 	github.com/prometheus/client_model v0.4.0 // indirect
 	github.com/prometheus/common v0.42.0 // indirect
 	github.com/prometheus/procfs v0.10.1 // indirect
 	github.com/rivo/uniseg v0.4.2 // indirect
-	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/shopspring/decimal v1.3.1 // indirect
 	github.com/spf13/afero v1.9.5 // indirect
 	github.com/spf13/cast v1.5.1 // indirect
@@ -140,11 +123,11 @@ require (
 	go.uber.org/zap v1.24.0 // indirect
 	go4.org v0.0.0-20201209231011-d4a079459e60 // indirect
 	golang.org/x/crypto v0.12.0 // indirect
-	golang.org/x/net v0.14.0 // indirect
 	golang.org/x/sys v0.11.0 // indirect
 	golang.org/x/term v0.11.0 // indirect
+	golang.org/x/text v0.12.0
 	golang.org/x/time v0.3.0 // indirect
-	golang.org/x/tools v0.9.3 // indirect
+	gomodules.xyz/jsonpatch/v2 v2.3.0
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	google.golang.org/protobuf v1.31.0 // indirect
@@ -153,11 +136,32 @@ require (
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	k8s.io/cli-runtime v0.27.2 // indirect
-	k8s.io/component-helpers v0.27.2 // indirect
-	k8s.io/metrics v0.27.2 // indirect
+	k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/kustomize/api v0.13.2 // indirect
-	sigs.k8s.io/kustomize/kustomize/v5 v5.0.1 // indirect
 	sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
 )
+
+require (
+	github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect
+	github.com/blang/semver/v4 v4.0.0 // indirect
+	github.com/cloudflare/circl v1.3.3 // indirect
+	github.com/daviddengcn/go-colortext v1.0.0 // indirect
+	github.com/emicklei/go-restful/v3 v3.9.0 // indirect
+	github.com/fatih/camelcase v1.0.0 // indirect
+	github.com/fvbommel/sortorder v1.0.1 // indirect
+	github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
+	github.com/google/gnostic v0.6.9 // indirect
+	github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
+	github.com/jonboulle/clockwork v0.2.2 // indirect
+	github.com/lithammer/dedent v1.1.0 // indirect
+	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+	github.com/pelletier/go-toml/v2 v2.0.8 // indirect
+	github.com/russross/blackfriday/v2 v2.1.0 // indirect
+	golang.org/x/tools v0.9.3 // indirect
+	k8s.io/component-helpers v0.27.2 // indirect
+	k8s.io/metrics v0.27.2 // indirect
+	sigs.k8s.io/kustomize/kustomize/v5 v5.0.1 // indirect
+)
diff --git a/go.sum b/go.sum
index 0a67015d4..0de4131ee 100644
--- a/go.sum
+++ b/go.sum
@@ -80,6 +80,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
 github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
 github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
@@ -822,8 +824,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
-gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
+gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc=
+gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
diff --git a/hack/kind-install-for-capd.sh b/hack/kind-install-for-capd.sh
index a0d3474c0..a9bc88882 100755
--- a/hack/kind-install-for-capd.sh
+++ b/hack/kind-install-for-capd.sh
@@ -31,8 +31,7 @@ if [[ "${TRACE-0}" == "1" ]]; then
 fi
 
 KIND_CLUSTER_NAME=${CAPI_KIND_CLUSTER_NAME:-"capi-test"}
-# See: https://kind.sigs.k8s.io/docs/user/configuration/#ip-family
-KIND_NETWORK_IPFAMILY=${KIND_NETWORK_IPFAMILY:-"dual"}
+
 
 # 1. If kind cluster already exists exit.
 if [[ "$(kind get clusters)" =~ .*"${KIND_CLUSTER_NAME}".* ]]; then
@@ -60,7 +59,7 @@ cat <<EOF | kind create cluster --name="$KIND_CLUSTER_NAME"  --config=-
 kind: Cluster
 apiVersion: kind.x-k8s.io/v1alpha4
 networking:
-  ipFamily: ${KIND_NETWORK_IPFAMILY}
+  ipFamily: dual
 nodes:
 - role: control-plane
   extraMounts:
diff --git a/hack/tools/conversion-verifier/main.go b/hack/tools/conversion-verifier/main.go
index ab1109014..02272b2e6 100644
--- a/hack/tools/conversion-verifier/main.go
+++ b/hack/tools/conversion-verifier/main.go
@@ -17,11 +17,11 @@ limitations under the License.
 package main
 
 import (
-	"fmt"
 	"go/types"
 	"path"
 	"strings"
 
+	"github.com/hashicorp/go-multierror"
 	"github.com/pkg/errors"
 	"k8s.io/klog/v2"
 	crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers"
@@ -70,7 +70,7 @@ func (s *storageVersionType) IsHub() bool {
 }
 
 func main() {
-	var errs []error
+	var result error
 
 	// Define the marker collector.
 	col := &markers.Collector{
@@ -118,7 +118,7 @@ func main() {
 				return
 			}
 			if _, ok := storageVersionTypes[info.Name]; ok {
-				errs = append(errs,
+				result = multierror.Append(result,
 					errors.Errorf("type %q has a redeclared storage version in package %q", info.Name, pkg.PkgPath),
 				)
 				return
@@ -197,24 +197,21 @@ func main() {
 		}
 
 		if !storageType.IsHub() {
-			errs = append(errs,
+			result = multierror.Append(result,
 				errors.Errorf("type %q in package %q marked as storage version but it's not convertible, missing Hub() method", name, storageType.pkg.PkgPath),
 			)
 		}
 		for _, decl := range storageType.otherDecls {
 			if !decl.IsConvertible() {
-				errs = append(errs,
+				result = multierror.Append(result,
 					errors.Errorf("type %q in package %q it's not convertible, missing ConvertFrom() and ConvertTo() methods", name, decl.pkg.PkgPath),
 				)
 			}
 		}
 	}
 
-	if len(errs) > 0 {
-		fmt.Printf("%d errors occurred:\n", len(errs))
-		for _, err := range errs {
-			fmt.Printf("\t* %s\n", err)
-		}
+	if result != nil {
+		klog.Exit(result.Error())
 	}
 }
 
diff --git a/hack/tools/go.mod b/hack/tools/go.mod
index 5dc4772e6..9952d8978 100644
--- a/hack/tools/go.mod
+++ b/hack/tools/go.mod
@@ -8,7 +8,8 @@ replace sigs.k8s.io/cluster-api/test => ../../test
 
 require (
 	cloud.google.com/go/storage v1.31.0
-	github.com/blang/semver/v4 v4.0.0
+	github.com/blang/semver v3.5.1+incompatible
+	github.com/hashicorp/go-multierror v1.1.1
 	github.com/pkg/errors v0.9.1
 	github.com/spf13/pflag v1.0.5
 	github.com/valyala/fastjson v1.6.4
@@ -45,6 +46,7 @@ require (
 	github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/blang/semver/v4 v4.0.0 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/cloudflare/circl v1.3.3 // indirect
 	github.com/coredns/caddy v1.1.0 // indirect
@@ -78,6 +80,7 @@ require (
 	github.com/google/uuid v1.3.0 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
 	github.com/googleapis/gax-go/v2 v2.12.0 // indirect
+	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/huandu/xstrings v1.3.3 // indirect
 	github.com/imdario/mergo v0.3.13 // indirect
@@ -118,7 +121,7 @@ require (
 	golang.org/x/text v0.12.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
-	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
+	gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect
diff --git a/hack/tools/go.sum b/hack/tools/go.sum
index 3ad40c9a6..424b1a675 100644
--- a/hack/tools/go.sum
+++ b/hack/tools/go.sum
@@ -81,6 +81,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
 github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
 github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
@@ -277,10 +279,14 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -742,8 +748,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
-gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
-gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
+gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc=
+gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
diff --git a/hack/tools/mdbook/releaselink/releaselink.go b/hack/tools/mdbook/releaselink/releaselink.go
index 96d9cf99f..4bd707e19 100644
--- a/hack/tools/mdbook/releaselink/releaselink.go
+++ b/hack/tools/mdbook/releaselink/releaselink.go
@@ -28,7 +28,7 @@ import (
 	"reflect"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"golang.org/x/tools/go/vcs"
 	"sigs.k8s.io/kubebuilder/docs/book/utils/plugin"
 
diff --git a/hack/verify-container-images.sh b/hack/verify-container-images.sh
index 496e03faa..5d8977a7e 100755
--- a/hack/verify-container-images.sh
+++ b/hack/verify-container-images.sh
@@ -72,7 +72,7 @@ NC='\033[0m' # No
 
 if [ "$R1" -ne "0" ] || [ "$R2"  -ne "0" ] || [ "$R3" -ne "0" ] || [ "$R4" -ne "0"  ] || [ "$R5" -ne "0"  ] || [ "$R6" -ne "0" ]
 then
-  echo -e "${BRed}Check container images failed! There are vulnerabilities to be fixed${NC}"
+  echo -e "${BRed}Check container images failed! There are vulnerability to be fixed${NC}"
   exit 1
 fi
 
diff --git a/internal/contract/controlplane.go b/internal/contract/controlplane.go
index 7bbc306e7..df322ddcd 100644
--- a/internal/contract/controlplane.go
+++ b/internal/contract/controlplane.go
@@ -19,7 +19,7 @@ package contract
 import (
 	"sync"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/utils/pointer"
diff --git a/internal/controllers/machineset/machineset_preflight.go b/internal/controllers/machineset/machineset_preflight.go
index c9ce691e8..00d5d67fc 100644
--- a/internal/controllers/machineset/machineset_preflight.go
+++ b/internal/controllers/machineset/machineset_preflight.go
@@ -22,7 +22,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/internal/goproxy/goproxy.go b/internal/goproxy/goproxy.go
index 3448de0fa..a44bd0ce1 100644
--- a/internal/goproxy/goproxy.go
+++ b/internal/goproxy/goproxy.go
@@ -28,7 +28,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/wait"
 )
diff --git a/internal/util/kubeadm/kubeadm.go b/internal/util/kubeadm/kubeadm.go
index a35d98401..bd6902711 100644
--- a/internal/util/kubeadm/kubeadm.go
+++ b/internal/util/kubeadm/kubeadm.go
@@ -17,7 +17,7 @@ limitations under the License.
 // Package kubeadm contains utils related to kubeadm.
 package kubeadm
 
-import "github.com/blang/semver/v4"
+import "github.com/blang/semver"
 
 const (
 	// DefaultImageRepository is the new default Kubernetes image registry.
diff --git a/internal/webhooks/cluster.go b/internal/webhooks/cluster.go
index 61eff982d..2e0da4f57 100644
--- a/internal/webhooks/cluster.go
+++ b/internal/webhooks/cluster.go
@@ -24,7 +24,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/util/annotations/helpers.go b/util/annotations/helpers.go
index 47dc7fc6b..0ec9ef938 100644
--- a/util/annotations/helpers.go
+++ b/util/annotations/helpers.go
@@ -71,6 +71,7 @@ func AddAnnotations(o metav1.Object, desired map[string]string) bool {
 	annotations := o.GetAnnotations()
 	if annotations == nil {
 		annotations = make(map[string]string)
+		o.SetAnnotations(annotations)
 	}
 	hasChanged := false
 	for k, v := range desired {
@@ -79,7 +80,6 @@ func AddAnnotations(o metav1.Object, desired map[string]string) bool {
 			hasChanged = true
 		}
 	}
-	o.SetAnnotations(annotations)
 	return hasChanged
 }
 
diff --git a/util/collections/machine_collection.go b/util/collections/machine_collection.go
index 83a50ad94..2958ee5d6 100644
--- a/util/collections/machine_collection.go
+++ b/util/collections/machine_collection.go
@@ -30,7 +30,7 @@ package collections
 import (
 	"sort"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 
 	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
 	"sigs.k8s.io/cluster-api/util/conditions"
diff --git a/util/collections/machine_filters.go b/util/collections/machine_filters.go
index 12c2e20f8..d85661012 100644
--- a/util/collections/machine_filters.go
+++ b/util/collections/machine_filters.go
@@ -19,7 +19,7 @@ package collections
 import (
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/selection"
diff --git a/util/util.go b/util/util.go
index d72947ecf..9edcf9123 100644
--- a/util/util.go
+++ b/util/util.go
@@ -27,7 +27,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
diff --git a/util/version/version.go b/util/version/version.go
index 601f934bd..277ed6105 100644
--- a/util/version/version.go
+++ b/util/version/version.go
@@ -22,7 +22,7 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 )
 


Test patch:
diff --git a/.github/workflows/weekly-test-release.yaml b/.github/workflows/weekly-test-release.yaml
index 77c9b30ff..0c4c6f662 100644
--- a/.github/workflows/weekly-test-release.yaml
+++ b/.github/workflows/weekly-test-release.yaml
@@ -32,7 +32,7 @@ jobs:
       - name: Calculate go version
         run: echo "go_version=$(make go-version)" >> $GITHUB_ENV
       - name: Set up Go
-        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # tag=v4.1.0
+        uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # tag=v4.0.1
         with:
           go-version: ${{ env.go_version }}
       - name: Test release
diff --git a/bootstrap/kubeadm/types/utils_test.go b/bootstrap/kubeadm/types/utils_test.go
index 62a0a72d4..5153d834a 100644
--- a/bootstrap/kubeadm/types/utils_test.go
+++ b/bootstrap/kubeadm/types/utils_test.go
@@ -19,7 +19,7 @@ package utils
 import (
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
 	"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook_test.go b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook_test.go
index 3b26d0130..cd230eb61 100644
--- a/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook_test.go
+++ b/controlplane/kubeadm/api/v1beta1/kubeadm_control_plane_webhook_test.go
@@ -698,11 +698,6 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) {
 		"/invalid-key": "foo",
 	}
 
-	beforeUseExperimentalRetryJoin := before.DeepCopy()
-	beforeUseExperimentalRetryJoin.Spec.KubeadmConfigSpec.UseExperimentalRetryJoin = true //nolint:staticcheck
-	updateUseExperimentalRetryJoin := before.DeepCopy()
-	updateUseExperimentalRetryJoin.Spec.KubeadmConfigSpec.UseExperimentalRetryJoin = false //nolint:staticcheck
-
 	tests := []struct {
 		name                  string
 		enableIgnitionFeature bool
@@ -1055,12 +1050,6 @@ func TestKubeadmControlPlaneValidateUpdate(t *testing.T) {
 			before:                before,
 			kcp:                   invalidMetadata,
 		},
-		{
-			name:      "should allow changes to useExperimentalRetryJoin",
-			expectErr: false,
-			before:    beforeUseExperimentalRetryJoin,
-			kcp:       updateUseExperimentalRetryJoin,
-		},
 	}
 
 	for _, tt := range tests {
diff --git a/controlplane/kubeadm/internal/controllers/controller_test.go b/controlplane/kubeadm/internal/controllers/controller_test.go
index 6f1808c47..8f8f73472 100644
--- a/controlplane/kubeadm/internal/controllers/controller_test.go
+++ b/controlplane/kubeadm/internal/controllers/controller_test.go
@@ -28,7 +28,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -1332,7 +1332,7 @@ kubernetesVersion: metav1.16.1`,
 				Status: internal.ClusterStatus{},
 			},
 		},
-		ssaCache: ssa.NewCache(),
+		disableInPlacePropagation: true,
 	}
 
 	result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: util.ObjectKey(kcp)})
diff --git a/controlplane/kubeadm/internal/controllers/fakes_test.go b/controlplane/kubeadm/internal/controllers/fakes_test.go
index ebc04e404..7f5a962e2 100644
--- a/controlplane/kubeadm/internal/controllers/fakes_test.go
+++ b/controlplane/kubeadm/internal/controllers/fakes_test.go
@@ -20,7 +20,7 @@ import (
 	"context"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
diff --git a/controlplane/kubeadm/internal/controllers/scale_test.go b/controlplane/kubeadm/internal/controllers/scale_test.go
index 393e08de4..a74cf0025 100644
--- a/controlplane/kubeadm/internal/controllers/scale_test.go
+++ b/controlplane/kubeadm/internal/controllers/scale_test.go
@@ -213,13 +213,14 @@ func TestKubeadmControlPlaneReconciler_scaleUpControlPlane(t *testing.T) {
 			managementCluster:         fmc,
 			managementClusterUncached: fmc,
 			recorder:                  record.NewFakeRecorder(32),
+			disableInPlacePropagation: true,
 		}
 
 		controlPlane, adoptableMachineFound, err := r.initControlPlaneScope(ctx, cluster, kcp)
 		g.Expect(err).ToNot(HaveOccurred())
 		g.Expect(adoptableMachineFound).To(BeFalse())
 
-		result, err := r.scaleUpControlPlane(context.Background(), controlPlane)
+		result, err := r.reconcile(context.Background(), controlPlane)
 		g.Expect(err).ToNot(HaveOccurred())
 		g.Expect(result).To(Equal(ctrl.Result{RequeueAfter: preflightFailedRequeueAfter}))
 
diff --git a/controlplane/kubeadm/internal/controllers/upgrade_test.go b/controlplane/kubeadm/internal/controllers/upgrade_test.go
index 78e4db4e9..ea591525a 100644
--- a/controlplane/kubeadm/internal/controllers/upgrade_test.go
+++ b/controlplane/kubeadm/internal/controllers/upgrade_test.go
@@ -35,7 +35,6 @@ import (
 	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
 	"sigs.k8s.io/cluster-api/controlplane/kubeadm/internal"
 	"sigs.k8s.io/cluster-api/internal/test/builder"
-	"sigs.k8s.io/cluster-api/internal/util/ssa"
 	"sigs.k8s.io/cluster-api/util"
 	"sigs.k8s.io/cluster-api/util/collections"
 )
@@ -94,7 +93,7 @@ func TestKubeadmControlPlaneReconciler_RolloutStrategy_ScaleUp(t *testing.T) {
 				Status: internal.ClusterStatus{Nodes: 1},
 			},
 		},
-		ssaCache: ssa.NewCache(),
+		disableInPlacePropagation: true,
 	}
 	controlPlane := &internal.ControlPlane{
 		KCP:      kcp,
diff --git a/controlplane/kubeadm/internal/workload_cluster_coredns_test.go b/controlplane/kubeadm/internal/workload_cluster_coredns_test.go
index 38e6aa1f4..bac6124e7 100644
--- a/controlplane/kubeadm/internal/workload_cluster_coredns_test.go
+++ b/controlplane/kubeadm/internal/workload_cluster_coredns_test.go
@@ -19,7 +19,7 @@ package internal
 import (
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
diff --git a/controlplane/kubeadm/internal/workload_cluster_etcd_test.go b/controlplane/kubeadm/internal/workload_cluster_etcd_test.go
index e80e869a5..9972cd283 100644
--- a/controlplane/kubeadm/internal/workload_cluster_etcd_test.go
+++ b/controlplane/kubeadm/internal/workload_cluster_etcd_test.go
@@ -21,7 +21,7 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
 	pb "go.etcd.io/etcd/api/v3/etcdserverpb"
diff --git a/controlplane/kubeadm/internal/workload_cluster_rbac_test.go b/controlplane/kubeadm/internal/workload_cluster_rbac_test.go
index 3463e10ad..f4f93e3d6 100644
--- a/controlplane/kubeadm/internal/workload_cluster_rbac_test.go
+++ b/controlplane/kubeadm/internal/workload_cluster_rbac_test.go
@@ -20,7 +20,7 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 	rbacv1 "k8s.io/api/rbac/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
diff --git a/controlplane/kubeadm/internal/workload_cluster_test.go b/controlplane/kubeadm/internal/workload_cluster_test.go
index b0e900387..f1540168a 100644
--- a/controlplane/kubeadm/internal/workload_cluster_test.go
+++ b/controlplane/kubeadm/internal/workload_cluster_test.go
@@ -21,7 +21,7 @@ import (
 	"errors"
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
 	appsv1 "k8s.io/api/apps/v1"
diff --git a/internal/goproxy/goproxy_test.go b/internal/goproxy/goproxy_test.go
index f25f69b83..c914fa6f2 100644
--- a/internal/goproxy/goproxy_test.go
+++ b/internal/goproxy/goproxy_test.go
@@ -25,7 +25,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 )
 
diff --git a/internal/util/kubeadm/kubeadm_test.go b/internal/util/kubeadm/kubeadm_test.go
index 2f4639b9f..4e1f7c81f 100644
--- a/internal/util/kubeadm/kubeadm_test.go
+++ b/internal/util/kubeadm/kubeadm_test.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 )
 
diff --git a/scripts/ci-e2e-lib.sh b/scripts/ci-e2e-lib.sh
index bf673e009..3a5af5016 100644
--- a/scripts/ci-e2e-lib.sh
+++ b/scripts/ci-e2e-lib.sh
@@ -204,9 +204,9 @@ EOL
 # the actual test run less sensible to the network speed.
 kind:prepullAdditionalImages () {
   # Pulling cert manager images so we can pre-load in kind nodes
-  kind::prepullImage "quay.io/jetstack/cert-manager-cainjector:v1.12.3"
-  kind::prepullImage "quay.io/jetstack/cert-manager-webhook:v1.12.3"
-  kind::prepullImage "quay.io/jetstack/cert-manager-controller:v1.12.3"
+  kind::prepullImage "quay.io/jetstack/cert-manager-cainjector:v1.12.2"
+  kind::prepullImage "quay.io/jetstack/cert-manager-webhook:v1.12.2"
+  kind::prepullImage "quay.io/jetstack/cert-manager-controller:v1.12.2"
 }
 
 # kind:prepullImage pre-pull a docker image if no already present locally.
diff --git a/test/e2e/cluster_upgrade_runtimesdk_test.go b/test/e2e/cluster_upgrade_runtimesdk_test.go
index b8a6af160..5596311b3 100644
--- a/test/e2e/cluster_upgrade_runtimesdk_test.go
+++ b/test/e2e/cluster_upgrade_runtimesdk_test.go
@@ -20,7 +20,7 @@ limitations under the License.
 package e2e
 
 import (
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	"k8s.io/utils/pointer"
diff --git a/test/e2e/common.go b/test/e2e/common.go
index 0e4990ed8..c0c46ae23 100644
--- a/test/e2e/common.go
+++ b/test/e2e/common.go
@@ -21,7 +21,7 @@ import (
 	"fmt"
 	"path/filepath"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/ginkgo/v2"
 	"github.com/onsi/gomega/types"
 	corev1 "k8s.io/api/core/v1"
diff --git a/test/e2e/config/docker.yaml b/test/e2e/config/docker.yaml
index 618ad842a..647502970 100644
--- a/test/e2e/config/docker.yaml
+++ b/test/e2e/config/docker.yaml
@@ -23,11 +23,11 @@ images:
   loadBehavior: tryLoad
 - name: gcr.io/k8s-staging-cluster-api/test-extension-{ARCH}:dev
   loadBehavior: tryLoad
-- name: quay.io/jetstack/cert-manager-cainjector:v1.12.3
+- name: quay.io/jetstack/cert-manager-cainjector:v1.12.2
   loadBehavior: tryLoad
-- name: quay.io/jetstack/cert-manager-webhook:v1.12.3
+- name: quay.io/jetstack/cert-manager-webhook:v1.12.2
   loadBehavior: tryLoad
-- name: quay.io/jetstack/cert-manager-controller:v1.12.3
+- name: quay.io/jetstack/cert-manager-controller:v1.12.2
   loadBehavior: tryLoad
 
 providers:
diff --git a/test/extension/handlers/topologymutation/handler.go b/test/extension/handlers/topologymutation/handler.go
index dc61ce921..1cae18815 100644
--- a/test/extension/handlers/topologymutation/handler.go
+++ b/test/extension/handlers/topologymutation/handler.go
@@ -25,7 +25,7 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/test/framework/clusterctl/clusterctl_helpers.go b/test/framework/clusterctl/clusterctl_helpers.go
index d970a5e3f..0b59feb29 100644
--- a/test/framework/clusterctl/clusterctl_helpers.go
+++ b/test/framework/clusterctl/clusterctl_helpers.go
@@ -315,7 +315,6 @@ func ApplyClusterTemplateAndWait(ctx context.Context, input ApplyClusterTemplate
 		ClusterName:                  input.ConfigCluster.ClusterName,
 		Namespace:                    input.ConfigCluster.Namespace,
 		CNIManifestPath:              input.CNIManifestPath,
-		Flavor:                       input.ConfigCluster.Flavor,
 		WaitForClusterIntervals:      input.WaitForClusterIntervals,
 		WaitForControlPlaneIntervals: input.WaitForControlPlaneIntervals,
 		WaitForMachineDeployments:    input.WaitForMachineDeployments,
@@ -334,7 +333,6 @@ type ApplyCustomClusterTemplateAndWaitInput struct {
 	ClusterName                  string
 	Namespace                    string
 	CNIManifestPath              string
-	Flavor                       string
 	WaitForClusterIntervals      []interface{}
 	WaitForControlPlaneIntervals []interface{}
 	WaitForMachineDeployments    []interface{}
diff --git a/test/framework/clusterctl/repository.go b/test/framework/clusterctl/repository.go
index 42c855a54..ff2067828 100644
--- a/test/framework/clusterctl/repository.go
+++ b/test/framework/clusterctl/repository.go
@@ -28,7 +28,7 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
 
diff --git a/test/framework/daemonset_helpers.go b/test/framework/daemonset_helpers.go
index a8322309a..40510638e 100644
--- a/test/framework/daemonset_helpers.go
+++ b/test/framework/daemonset_helpers.go
@@ -19,7 +19,7 @@ package framework
 import (
 	"context"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 	appsv1 "k8s.io/api/apps/v1"
diff --git a/test/framework/kubernetesversions/versions.go b/test/framework/kubernetesversions/versions.go
index 4af7cc3f8..6340229a1 100644
--- a/test/framework/kubernetesversions/versions.go
+++ b/test/framework/kubernetesversions/versions.go
@@ -23,7 +23,7 @@ import (
 	"net/http"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 )
 
diff --git a/test/go.mod b/test/go.mod
index c3f1c4840..1cc32a7ed 100644
--- a/test/go.mod
+++ b/test/go.mod
@@ -5,7 +5,7 @@ go 1.20
 replace sigs.k8s.io/cluster-api => ../
 
 require (
-	github.com/blang/semver/v4 v4.0.0
+	github.com/blang/semver v3.5.1+incompatible
 	github.com/docker/docker v24.0.5+incompatible
 	github.com/docker/go-connections v0.4.0
 	github.com/emicklei/go-restful/v3 v3.10.2
@@ -51,6 +51,7 @@ require (
 	github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/blang/semver/v4 v4.0.0 // indirect
 	github.com/cenkalti/backoff/v4 v4.1.3 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/cloudflare/circl v1.3.3 // indirect
@@ -142,7 +143,7 @@ require (
 	golang.org/x/text v0.12.0 // indirect
 	golang.org/x/time v0.3.0 // indirect
 	golang.org/x/tools v0.9.3 // indirect
-	gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
+	gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	google.golang.org/protobuf v1.31.0 // indirect
diff --git a/test/go.sum b/test/go.sum
index 37c0fb146..4978eb7a9 100644
--- a/test/go.sum
+++ b/test/go.sum
@@ -85,6 +85,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
 github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
 github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
@@ -843,8 +845,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
-gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
+gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc=
+gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
diff --git a/test/infrastructure/docker/exp/internal/docker/nodepool.go b/test/infrastructure/docker/exp/internal/docker/nodepool.go
index 12920be70..08683dea8 100644
--- a/test/infrastructure/docker/exp/internal/docker/nodepool.go
+++ b/test/infrastructure/docker/exp/internal/docker/nodepool.go
@@ -25,7 +25,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/klog/v2"
diff --git a/test/infrastructure/docker/internal/docker/machine.go b/test/infrastructure/docker/internal/docker/machine.go
index 96c9df5ed..c65c9a882 100644
--- a/test/infrastructure/docker/internal/docker/machine.go
+++ b/test/infrastructure/docker/internal/docker/machine.go
@@ -26,7 +26,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	corev1 "k8s.io/api/core/v1"
diff --git a/test/infrastructure/docker/internal/provisioning/cloudinit/adapter_test.go b/test/infrastructure/docker/internal/provisioning/cloudinit/adapter_test.go
index 1a4fdcea8..759d0550b 100644
--- a/test/infrastructure/docker/internal/provisioning/cloudinit/adapter_test.go
+++ b/test/infrastructure/docker/internal/provisioning/cloudinit/adapter_test.go
@@ -19,7 +19,7 @@ package cloudinit
 import (
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 
 	"sigs.k8s.io/cluster-api/test/infrastructure/docker/internal/provisioning"
diff --git a/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles.go b/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles.go
index aa47d0db2..6e31a29f9 100644
--- a/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles.go
+++ b/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles.go
@@ -25,7 +25,7 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/pkg/errors"
 	"sigs.k8s.io/yaml"
 
diff --git a/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles_test.go b/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles_test.go
index 28902c292..28077c652 100644
--- a/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles_test.go
+++ b/test/infrastructure/docker/internal/provisioning/cloudinit/writefiles_test.go
@@ -21,7 +21,7 @@ import (
 	"compress/gzip"
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	"github.com/google/go-cmp/cmp"
 	. "github.com/onsi/gomega"
 
diff --git a/test/infrastructure/kind/mapper.go b/test/infrastructure/kind/mapper.go
index d6db884d7..4bdb5e77f 100644
--- a/test/infrastructure/kind/mapper.go
+++ b/test/infrastructure/kind/mapper.go
@@ -37,7 +37,7 @@ package kind
 import (
 	"fmt"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 
 	clusterapicontainer "sigs.k8s.io/cluster-api/util/container"
 )
diff --git a/test/infrastructure/kind/mapper_test.go b/test/infrastructure/kind/mapper_test.go
index 863669112..42bf2556d 100644
--- a/test/infrastructure/kind/mapper_test.go
+++ b/test/infrastructure/kind/mapper_test.go
@@ -19,7 +19,7 @@ package kind
 import (
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 )
 
diff --git a/util/annotations/helpers_test.go b/util/annotations/helpers_test.go
index de973cfb9..9793fcf87 100644
--- a/util/annotations/helpers_test.go
+++ b/util/annotations/helpers_test.go
@@ -22,13 +22,12 @@ import (
 	. "github.com/onsi/gomega"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 )
 
 func TestAddAnnotations(t *testing.T) {
 	g := NewWithT(t)
 
-	testcases := []struct {
+	var testcases = []struct {
 		name     string
 		obj      metav1.Object
 		input    map[string]string
@@ -142,39 +141,6 @@ func TestAddAnnotations(t *testing.T) {
 			},
 			changed: true,
 		},
-		{
-			name: "should add annotations to an empty unstructured",
-			obj:  &unstructured.Unstructured{},
-			input: map[string]string{
-				"foo": "buzz",
-			},
-			expected: map[string]string{
-				"foo": "buzz",
-			},
-			changed: true,
-		},
-		{
-			name: "should add annotations to a non empty unstructured",
-			obj: &unstructured.Unstructured{
-				Object: map[string]interface{}{
-					"metadata": map[string]interface{}{
-						"annotations": map[string]interface{}{
-							"foo": "bar",
-						},
-					},
-				},
-			},
-			input: map[string]string{
-				"thing1": "thing2",
-				"buzz":   "blah",
-			},
-			expected: map[string]string{
-				"foo":    "bar",
-				"thing1": "thing2",
-				"buzz":   "blah",
-			},
-			changed: true,
-		},
 	}
 
 	for _, tc := range testcases {
diff --git a/util/util_test.go b/util/util_test.go
index 748ca0cbc..c736c02b6 100644
--- a/util/util_test.go
+++ b/util/util_test.go
@@ -21,7 +21,7 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/meta"
diff --git a/util/version/version_test.go b/util/version/version_test.go
index abe9501b0..a76ea9d2c 100644
--- a/util/version/version_test.go
+++ b/util/version/version_test.go
@@ -19,7 +19,7 @@ package version
 import (
 	"testing"
 
-	"github.com/blang/semver/v4"
+	"github.com/blang/semver"
 	. "github.com/onsi/gomega"
 )