From b6faf7327da0ae1aeef23c9168582d4ef00ac783 Mon Sep 17 00:00:00 2001 From: disaster37 Date: Mon, 3 Aug 2026 07:18:14 +0000 Subject: [PATCH 1/3] fix: fix issue #1668 about auto renew certificate on mutating / validation deployment Signed-off-by: disaster37 --- pkg/infrastructure/cluster.go | 24 +++++++++-- pkg/infrastructure/cluster_test.go | 58 +++++++++++++++++++++++++++ webhook/workspace/annotations.go | 32 +++++++++++++++ webhook/workspace/annotations_test.go | 53 ++++++++++++++++++++++++ webhook/workspace/mutating_cfg.go | 7 ++-- webhook/workspace/validating_cfg.go | 7 ++-- 6 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 pkg/infrastructure/cluster_test.go create mode 100644 webhook/workspace/annotations.go create mode 100644 webhook/workspace/annotations_test.go diff --git a/pkg/infrastructure/cluster.go b/pkg/infrastructure/cluster.go index 702d6e1ab..82e86c510 100644 --- a/pkg/infrastructure/cluster.go +++ b/pkg/infrastructure/cluster.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2019-2025 Red Hat, Inc. +// Copyright (c) 2019-2026 Red Hat, Inc. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -35,8 +35,9 @@ const ( var ( // current is the infrastructure that we're currently running on. - current Type - initialized = false + current Type + certManagerDetected bool + initialized = false ) // Initialize attempts to determine the type of cluster its currently running on (OpenShift or Kubernetes). This function @@ -57,6 +58,14 @@ func Initialize() error { // InitializeForTesting is used to mock running on a specific type of cluster (Kubernetes, OpenShift) in testing code. func InitializeForTesting(currentInfrastructure Type) { current = currentInfrastructure + certManagerDetected = false + initialized = true +} + +// InitializeForTestingWithCertManager is used to mock running on a cluster with cert-manager installed. +func InitializeForTestingWithCertManager(currentInfrastructure Type) { + current = currentInfrastructure + certManagerDetected = true initialized = true } @@ -72,6 +81,14 @@ func IsOpenShift() bool { return current == OpenShiftv4 } +// CertManagerDetected returns true if the cert-manager API group was detected on the cluster. +func CertManagerDetected() bool { + if !initialized { + panic("Attempting to determine information about the cluster without initializing first") + } + return certManagerDetected +} + func detect() (Type, error) { kubeCfg, err := config.GetConfig() if err != nil { @@ -85,6 +102,7 @@ func detect() (Type, error) { if err != nil { return Unsupported, fmt.Errorf("could not read API groups: %w", err) } + certManagerDetected = findAPIGroup(apiList.Groups, "cert-manager.io") != nil if findAPIGroup(apiList.Groups, "route.openshift.io") == nil { return Kubernetes, nil } else { diff --git a/pkg/infrastructure/cluster_test.go b/pkg/infrastructure/cluster_test.go new file mode 100644 index 000000000..d72c05b05 --- /dev/null +++ b/pkg/infrastructure/cluster_test.go @@ -0,0 +1,58 @@ +// +// Copyright (c) 2019-2026 Red Hat, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package infrastructure + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCertManagerDetectedReturnsTrueWhenCertManagerInstalled(t *testing.T) { + InitializeForTestingWithCertManager(Kubernetes) + assert.True(t, CertManagerDetected()) +} + +func TestCertManagerDetectedReturnsFalseWhenCertManagerNotInstalled(t *testing.T) { + InitializeForTesting(Kubernetes) + assert.False(t, CertManagerDetected()) +} + +func TestCertManagerDetectedWithOpenShift(t *testing.T) { + InitializeForTestingWithCertManager(OpenShiftv4) + assert.True(t, CertManagerDetected()) +} + +func TestCertManagerDetectedPanicsWhenNotInitialized(t *testing.T) { + initialized = false + defer func() { + InitializeForTesting(Kubernetes) + }() + assert.Panics(t, func() { + CertManagerDetected() + }) +} + +func TestInitializeForTestingSetsCertManagerDetectedToFalse(t *testing.T) { + InitializeForTesting(OpenShiftv4) + assert.False(t, CertManagerDetected()) + assert.True(t, IsOpenShift()) +} + +func TestInitializeForTestingWithCertManagerSetsDetectedToTrue(t *testing.T) { + InitializeForTestingWithCertManager(Kubernetes) + assert.True(t, CertManagerDetected()) +} diff --git a/webhook/workspace/annotations.go b/webhook/workspace/annotations.go new file mode 100644 index 000000000..9495b6fe6 --- /dev/null +++ b/webhook/workspace/annotations.go @@ -0,0 +1,32 @@ +// +// Copyright (c) 2019-2026 Red Hat, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package workspace + +import ( + "fmt" + + "github.com/devfile/devworkspace-operator/pkg/infrastructure" +) + +func getWebhookAnnotations(namespace string) map[string]string { + annotations := map[string]string{} + if infrastructure.CertManagerDetected() { + annotations["cert-manager.io/inject-ca-from"] = fmt.Sprintf("%s/devworkspace-controller-serving-cert", namespace) + } else if infrastructure.IsOpenShift() { + annotations["service.beta.openshift.io/inject-cabundle"] = "true" + } + return annotations +} diff --git a/webhook/workspace/annotations_test.go b/webhook/workspace/annotations_test.go new file mode 100644 index 000000000..0ad0379f1 --- /dev/null +++ b/webhook/workspace/annotations_test.go @@ -0,0 +1,53 @@ +// +// Copyright (c) 2019-2026 Red Hat, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package workspace + +import ( + "testing" + + "github.com/devfile/devworkspace-operator/pkg/infrastructure" + "github.com/stretchr/testify/assert" +) + +func TestGetWebhookAnnotationsWithCertManager(t *testing.T) { + infrastructure.InitializeForTestingWithCertManager(infrastructure.Kubernetes) + annotations := getWebhookAnnotations("test-namespace") + assert.Equal(t, map[string]string{ + "cert-manager.io/inject-ca-from": "test-namespace/devworkspace-controller-serving-cert", + }, annotations) +} + +func TestGetWebhookAnnotationsWithOpenShift(t *testing.T) { + infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) + annotations := getWebhookAnnotations("test-namespace") + assert.Equal(t, map[string]string{ + "service.beta.openshift.io/inject-cabundle": "true", + }, annotations) +} + +func TestGetWebhookAnnotationsWithKubernetes(t *testing.T) { + infrastructure.InitializeForTesting(infrastructure.Kubernetes) + annotations := getWebhookAnnotations("test-namespace") + assert.Empty(t, annotations) +} + +func TestGetWebhookAnnotationsWithCertManagerOnOpenShift(t *testing.T) { + infrastructure.InitializeForTestingWithCertManager(infrastructure.OpenShiftv4) + annotations := getWebhookAnnotations("test-namespace") + assert.Equal(t, map[string]string{ + "cert-manager.io/inject-ca-from": "test-namespace/devworkspace-controller-serving-cert", + }, annotations) +} diff --git a/webhook/workspace/mutating_cfg.go b/webhook/workspace/mutating_cfg.go index c7433c8c4..6a6e6d143 100644 --- a/webhook/workspace/mutating_cfg.go +++ b/webhook/workspace/mutating_cfg.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2019-2025 Red Hat, Inc. +// Copyright (c) 2019-2026 Red Hat, Inc. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -153,8 +153,9 @@ func BuildMutateWebhookCfg(namespace string) *admregv1.MutatingWebhookConfigurat return &admregv1.MutatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{ - Name: MutateWebhookCfgName, - Labels: server.WebhookServerAppLabels(), + Name: MutateWebhookCfgName, + Labels: server.WebhookServerAppLabels(), + Annotations: getWebhookAnnotations(namespace), }, Webhooks: []admregv1.MutatingWebhook{ workspaceMutateWebhook, diff --git a/webhook/workspace/validating_cfg.go b/webhook/workspace/validating_cfg.go index 86c22f15b..4c95cad7c 100644 --- a/webhook/workspace/validating_cfg.go +++ b/webhook/workspace/validating_cfg.go @@ -1,5 +1,5 @@ // -// Copyright (c) 2019-2025 Red Hat, Inc. +// Copyright (c) 2019-2026 Red Hat, Inc. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -34,8 +34,9 @@ func buildValidatingWebhookCfg(namespace string) *admregv1.ValidatingWebhookConf sideEffectsNone := admregv1.SideEffectClassNone return &admregv1.ValidatingWebhookConfiguration{ ObjectMeta: metav1.ObjectMeta{ - Name: ValidateWebhookCfgName, - Labels: server.WebhookServerAppLabels(), + Name: ValidateWebhookCfgName, + Labels: server.WebhookServerAppLabels(), + Annotations: getWebhookAnnotations(namespace), }, Webhooks: []admregv1.ValidatingWebhook{ { From 61067c003446fa1739a422f6f843877d1324a905 Mon Sep 17 00:00:00 2001 From: disaster37 Date: Mon, 17 Aug 2026 15:27:46 +0000 Subject: [PATCH 2/3] fix: use the right static annotations for kubernetes and OCP. No more needed to look if cert-manager is installed. Signed-off-by: disaster37 --- pkg/infrastructure/cluster_test.go | 58 ------------------------------ 1 file changed, 58 deletions(-) delete mode 100644 pkg/infrastructure/cluster_test.go diff --git a/pkg/infrastructure/cluster_test.go b/pkg/infrastructure/cluster_test.go deleted file mode 100644 index d72c05b05..000000000 --- a/pkg/infrastructure/cluster_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) 2019-2026 Red Hat, Inc. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package infrastructure - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCertManagerDetectedReturnsTrueWhenCertManagerInstalled(t *testing.T) { - InitializeForTestingWithCertManager(Kubernetes) - assert.True(t, CertManagerDetected()) -} - -func TestCertManagerDetectedReturnsFalseWhenCertManagerNotInstalled(t *testing.T) { - InitializeForTesting(Kubernetes) - assert.False(t, CertManagerDetected()) -} - -func TestCertManagerDetectedWithOpenShift(t *testing.T) { - InitializeForTestingWithCertManager(OpenShiftv4) - assert.True(t, CertManagerDetected()) -} - -func TestCertManagerDetectedPanicsWhenNotInitialized(t *testing.T) { - initialized = false - defer func() { - InitializeForTesting(Kubernetes) - }() - assert.Panics(t, func() { - CertManagerDetected() - }) -} - -func TestInitializeForTestingSetsCertManagerDetectedToFalse(t *testing.T) { - InitializeForTesting(OpenShiftv4) - assert.False(t, CertManagerDetected()) - assert.True(t, IsOpenShift()) -} - -func TestInitializeForTestingWithCertManagerSetsDetectedToTrue(t *testing.T) { - InitializeForTestingWithCertManager(Kubernetes) - assert.True(t, CertManagerDetected()) -} From f1694427f5f774122bbb4a8a8a427dc779aba396 Mon Sep 17 00:00:00 2001 From: disaster37 Date: Mon, 17 Aug 2026 15:29:29 +0000 Subject: [PATCH 3/3] fix:: use the right static annotation for kubernetes and OCP. Ne need to check if cert-manager is deployed on cluster. Signed-off-by: disaster37 --- pkg/infrastructure/cluster.go | 22 ++-------------------- webhook/workspace/annotations.go | 6 +++--- webhook/workspace/annotations_test.go | 14 -------------- 3 files changed, 5 insertions(+), 37 deletions(-) diff --git a/pkg/infrastructure/cluster.go b/pkg/infrastructure/cluster.go index 82e86c510..844343536 100644 --- a/pkg/infrastructure/cluster.go +++ b/pkg/infrastructure/cluster.go @@ -35,9 +35,8 @@ const ( var ( // current is the infrastructure that we're currently running on. - current Type - certManagerDetected bool - initialized = false + current Type + initialized = false ) // Initialize attempts to determine the type of cluster its currently running on (OpenShift or Kubernetes). This function @@ -58,14 +57,6 @@ func Initialize() error { // InitializeForTesting is used to mock running on a specific type of cluster (Kubernetes, OpenShift) in testing code. func InitializeForTesting(currentInfrastructure Type) { current = currentInfrastructure - certManagerDetected = false - initialized = true -} - -// InitializeForTestingWithCertManager is used to mock running on a cluster with cert-manager installed. -func InitializeForTestingWithCertManager(currentInfrastructure Type) { - current = currentInfrastructure - certManagerDetected = true initialized = true } @@ -81,14 +72,6 @@ func IsOpenShift() bool { return current == OpenShiftv4 } -// CertManagerDetected returns true if the cert-manager API group was detected on the cluster. -func CertManagerDetected() bool { - if !initialized { - panic("Attempting to determine information about the cluster without initializing first") - } - return certManagerDetected -} - func detect() (Type, error) { kubeCfg, err := config.GetConfig() if err != nil { @@ -102,7 +85,6 @@ func detect() (Type, error) { if err != nil { return Unsupported, fmt.Errorf("could not read API groups: %w", err) } - certManagerDetected = findAPIGroup(apiList.Groups, "cert-manager.io") != nil if findAPIGroup(apiList.Groups, "route.openshift.io") == nil { return Kubernetes, nil } else { diff --git a/webhook/workspace/annotations.go b/webhook/workspace/annotations.go index 9495b6fe6..6cb6fa8e0 100644 --- a/webhook/workspace/annotations.go +++ b/webhook/workspace/annotations.go @@ -23,10 +23,10 @@ import ( func getWebhookAnnotations(namespace string) map[string]string { annotations := map[string]string{} - if infrastructure.CertManagerDetected() { - annotations["cert-manager.io/inject-ca-from"] = fmt.Sprintf("%s/devworkspace-controller-serving-cert", namespace) - } else if infrastructure.IsOpenShift() { + if infrastructure.IsOpenShift() { annotations["service.beta.openshift.io/inject-cabundle"] = "true" + } else { + annotations["cert-manager.io/inject-ca-from"] = fmt.Sprintf("%s/devworkspace-controller-serving-cert", namespace) } return annotations } diff --git a/webhook/workspace/annotations_test.go b/webhook/workspace/annotations_test.go index 0ad0379f1..6bfb236e3 100644 --- a/webhook/workspace/annotations_test.go +++ b/webhook/workspace/annotations_test.go @@ -22,14 +22,6 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGetWebhookAnnotationsWithCertManager(t *testing.T) { - infrastructure.InitializeForTestingWithCertManager(infrastructure.Kubernetes) - annotations := getWebhookAnnotations("test-namespace") - assert.Equal(t, map[string]string{ - "cert-manager.io/inject-ca-from": "test-namespace/devworkspace-controller-serving-cert", - }, annotations) -} - func TestGetWebhookAnnotationsWithOpenShift(t *testing.T) { infrastructure.InitializeForTesting(infrastructure.OpenShiftv4) annotations := getWebhookAnnotations("test-namespace") @@ -41,12 +33,6 @@ func TestGetWebhookAnnotationsWithOpenShift(t *testing.T) { func TestGetWebhookAnnotationsWithKubernetes(t *testing.T) { infrastructure.InitializeForTesting(infrastructure.Kubernetes) annotations := getWebhookAnnotations("test-namespace") - assert.Empty(t, annotations) -} - -func TestGetWebhookAnnotationsWithCertManagerOnOpenShift(t *testing.T) { - infrastructure.InitializeForTestingWithCertManager(infrastructure.OpenShiftv4) - annotations := getWebhookAnnotations("test-namespace") assert.Equal(t, map[string]string{ "cert-manager.io/inject-ca-from": "test-namespace/devworkspace-controller-serving-cert", }, annotations)