From 13e57eae9d20bec2b92febdbde446a5a2cf8fd4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=BCnemann?= Date: Tue, 7 Oct 2025 15:36:58 +0200 Subject: [PATCH 1/4] fix: replace illegal characters in condition types and reasons --- pkg/controller/status_updater.go | 12 ++++++++++-- pkg/controller/status_updater_test.go | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pkg/controller/status_updater.go b/pkg/controller/status_updater.go index 53ae95d..79ef47e 100644 --- a/pkg/controller/status_updater.go +++ b/pkg/controller/status_updater.go @@ -449,11 +449,19 @@ func GenerateCreateConditionFunc[Obj client.Object](rr *ReconcileResult[Obj]) fu } return func(conType string, status metav1.ConditionStatus, reason, message string) { rr.Conditions = append(rr.Conditions, metav1.Condition{ - Type: conType, + Type: replaceIllegalCharsInConditionType(conType), Status: status, ObservedGeneration: gen, - Reason: reason, + Reason: replaceIllegalCharsInConditionReason(reason), Message: message, }) } } + +func replaceIllegalCharsInConditionType(s string) string { + return strings.NewReplacer(" ", "_", ",", "_", ";", "_", ":", "_").Replace(s) +} + +func replaceIllegalCharsInConditionReason(s string) string { + return strings.NewReplacer(" ", "_", "-", "_", ".", "_").Replace(s) +} diff --git a/pkg/controller/status_updater_test.go b/pkg/controller/status_updater_test.go index d73703e..d0b4c11 100644 --- a/pkg/controller/status_updater_test.go +++ b/pkg/controller/status_updater_test.go @@ -119,6 +119,21 @@ var _ = Describe("Status Updater", func() { )) }) + It("should replace illegal characters in condition type and reason", func() { + env := testutils.NewEnvironmentBuilder().WithFakeClient(coScheme).WithInitObjectPath("testdata", "test-02").WithDynamicObjectsWithStatus(&CustomObject{}).Build() + obj := &CustomObject{} + Expect(env.Client().Get(env.Ctx, controller.ObjectKey("status", "default"), obj)).To(Succeed()) + rr := &controller.ReconcileResult[*CustomObject]{ + Object: obj, + } + condFunc := controller.GenerateCreateConditionFunc(rr) + + condFunc("CondType :,;Test", metav1.ConditionTrue, "Reason -.Test", "Message") + Expect(rr.Conditions).To(HaveLen(1)) + Expect(rr.Conditions[0].Type).To(Equal("CondType____Test")) + Expect(rr.Conditions[0].Reason).To(Equal("Reason___Test")) + }) + It("should not update disabled fields", func() { env := testutils.NewEnvironmentBuilder().WithFakeClient(coScheme).WithInitObjectPath("testdata", "test-02").WithDynamicObjectsWithStatus(&CustomObject{}).Build() obj := &CustomObject{} From 0ea1b6d358cc9c6584b8faa8fd6a10081e492857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=BCnemann?= Date: Tue, 7 Oct 2025 15:38:47 +0200 Subject: [PATCH 2/4] feat: release v0.22.1 --- VERSION | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index dfd1422..0ce32aa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.23.0-dev \ No newline at end of file +v0.23.1 \ No newline at end of file diff --git a/go.mod b/go.mod index 072d88b..be2a112 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/uuid v1.6.0 github.com/onsi/ginkgo/v2 v2.25.3 github.com/onsi/gomega v1.38.2 - github.com/openmcp-project/controller-utils/api v0.23.0 + github.com/openmcp-project/controller-utils/api v0.23.1 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 go.uber.org/zap v1.27.0 From f67e1eecd0589c6c78fd202783ef26991d1b0542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=BCnemann?= Date: Tue, 7 Oct 2025 15:52:16 +0200 Subject: [PATCH 3/4] improve replace logic --- pkg/controller/status_updater.go | 54 ++++++++++++++++++++++++++- pkg/controller/status_updater_test.go | 6 +-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/pkg/controller/status_updater.go b/pkg/controller/status_updater.go index 79ef47e..b79ac4f 100644 --- a/pkg/controller/status_updater.go +++ b/pkg/controller/status_updater.go @@ -459,9 +459,59 @@ func GenerateCreateConditionFunc[Obj client.Object](rr *ReconcileResult[Obj]) fu } func replaceIllegalCharsInConditionType(s string) string { - return strings.NewReplacer(" ", "_", ",", "_", ";", "_", ":", "_").Replace(s) + if s == "" { + return s + } + + result := make([]rune, 0, len(s)) + for _, r := range s { + // Valid characters for condition types are: + // - lowercase letters (a-z) + // - uppercase letters (A-Z) + // - digits (0-9) + // - underscore (_) + // - hyphen (-) + // - dot (.) + // All other characters are replaced with underscore + if (r >= 'a' && r <= 'z') || + (r >= 'A' && r <= 'Z') || + (r >= '0' && r <= '9') || + r == '_' || + r == '-' || + r == '.' { + result = append(result, r) + } else { + result = append(result, '_') + } + } + return string(result) } func replaceIllegalCharsInConditionReason(s string) string { - return strings.NewReplacer(" ", "_", "-", "_", ".", "_").Replace(s) + if s == "" { + return s + } + + result := make([]rune, 0, len(s)) + for _, r := range s { + // Valid characters for condition types are: + // - lowercase letters (a-z) + // - uppercase letters (A-Z) + // - digits (0-9) + // - underscore (_) + // - colon (:) + //- comma (,) + // All other characters are replaced with underscore + if (r >= 'a' && r <= 'z') || + (r >= 'A' && r <= 'Z') || + (r >= '0' && r <= '9') || + r == '_' || + r == ':' || + r == ',' { + result = append(result, r) + } else { + result = append(result, '_') + } + } + return string(result) } diff --git a/pkg/controller/status_updater_test.go b/pkg/controller/status_updater_test.go index d0b4c11..7e598b3 100644 --- a/pkg/controller/status_updater_test.go +++ b/pkg/controller/status_updater_test.go @@ -128,10 +128,10 @@ var _ = Describe("Status Updater", func() { } condFunc := controller.GenerateCreateConditionFunc(rr) - condFunc("CondType :,;Test", metav1.ConditionTrue, "Reason -.Test", "Message") + condFunc("CondType :,;-_.Test02@", metav1.ConditionTrue, "Reason -.,:_Test93$", "Message") Expect(rr.Conditions).To(HaveLen(1)) - Expect(rr.Conditions[0].Type).To(Equal("CondType____Test")) - Expect(rr.Conditions[0].Reason).To(Equal("Reason___Test")) + Expect(rr.Conditions[0].Type).To(Equal("CondType____-_.Test02_")) + Expect(rr.Conditions[0].Reason).To(Equal("Reason___,:_Test93_")) }) It("should not update disabled fields", func() { From 6367ed3c30a449e716adc302f9dadca4d9ec3b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Sch=C3=BCnemann?= Date: Tue, 7 Oct 2025 15:55:59 +0200 Subject: [PATCH 4/4] export functions so that they can be used outside of GenerateCreateConditionFunc --- pkg/controller/status_updater.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/controller/status_updater.go b/pkg/controller/status_updater.go index b79ac4f..8349832 100644 --- a/pkg/controller/status_updater.go +++ b/pkg/controller/status_updater.go @@ -449,16 +449,17 @@ func GenerateCreateConditionFunc[Obj client.Object](rr *ReconcileResult[Obj]) fu } return func(conType string, status metav1.ConditionStatus, reason, message string) { rr.Conditions = append(rr.Conditions, metav1.Condition{ - Type: replaceIllegalCharsInConditionType(conType), + Type: ReplaceIllegalCharsInConditionType(conType), Status: status, ObservedGeneration: gen, - Reason: replaceIllegalCharsInConditionReason(reason), + Reason: ReplaceIllegalCharsInConditionReason(reason), Message: message, }) } } -func replaceIllegalCharsInConditionType(s string) string { +// ReplaceIllegalCharsInConditionType replaces all characters in the given string that are not allowed in condition types with underscores. +func ReplaceIllegalCharsInConditionType(s string) string { if s == "" { return s } @@ -487,7 +488,8 @@ func replaceIllegalCharsInConditionType(s string) string { return string(result) } -func replaceIllegalCharsInConditionReason(s string) string { +// ReplaceIllegalCharsInConditionReason replaces all characters in the given string that are not allowed in condition reasons with underscores. +func ReplaceIllegalCharsInConditionReason(s string) string { if s == "" { return s }