Skip to content

Commit 6c6de5b

Browse files
authored
fix: replace illegal chars in all condition updates (#175)
* fix: ensure compliant condition type and reason * feat: release v0.23.3 * update
1 parent e8f83f7 commit 6c6de5b

File tree

6 files changed

+85
-70
lines changed

6 files changed

+85
-70
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.23.2-dev
1+
v0.23.3

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/google/uuid v1.6.0
1212
github.com/onsi/ginkgo/v2 v2.27.2
1313
github.com/onsi/gomega v1.38.2
14-
github.com/openmcp-project/controller-utils/api v0.23.2
14+
github.com/openmcp-project/controller-utils/api v0.23.3
1515
github.com/spf13/pflag v1.0.10
1616
github.com/stretchr/testify v1.11.1
1717
go.uber.org/zap v1.27.0

pkg/conditions/updater.go

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ func (c *conditionUpdater) WithEventRecorder(recorder record.EventRecorder, verb
9090
func (c *conditionUpdater) UpdateCondition(conType string, status metav1.ConditionStatus, observedGeneration int64, reason, message string) *conditionUpdater {
9191
if reason == "" {
9292
// the metav1.Condition type requires a reason, so let's add a dummy if none is given
93-
// the type field allows dots ('.'), while the reason field does not, so replace them with colons (':') (which are not allowed in the type field)
94-
reason = strings.ReplaceAll(conType, ".", ":") + "_" + string(status)
93+
reason = ReplaceIllegalCharsInConditionReason(conType + "_" + string(status))
9594
}
9695
con := metav1.Condition{
9796
Type: conType,
@@ -263,3 +262,79 @@ func (c *conditionUpdater) Record(obj runtime.Object) *conditionUpdater {
263262

264263
return c
265264
}
265+
266+
// ReplaceIllegalCharsInConditionType replaces all characters in the given string that are not allowed in condition types with underscores.
267+
func ReplaceIllegalCharsInConditionType(s string) string {
268+
if s == "" {
269+
return s
270+
}
271+
272+
result := make([]rune, 0, len(s))
273+
for _, r := range s {
274+
// Valid characters for condition types are:
275+
// - lowercase letters (a-z)
276+
// - uppercase letters (A-Z)
277+
// - digits (0-9)
278+
// - underscore (_)
279+
// - hyphen (-)
280+
// - dot (.)
281+
// All other characters are replaced with underscore
282+
if (r >= 'a' && r <= 'z') ||
283+
(r >= 'A' && r <= 'Z') ||
284+
(r >= '0' && r <= '9') ||
285+
r == '_' ||
286+
r == '-' ||
287+
r == '.' {
288+
result = append(result, r)
289+
} else {
290+
result = append(result, '_')
291+
}
292+
}
293+
return ensureStartsAndEndsWithLetter(string(result), 'T', 't')
294+
}
295+
296+
// ReplaceIllegalCharsInConditionReason replaces all characters in the given string that are not allowed in condition reasons with underscores.
297+
func ReplaceIllegalCharsInConditionReason(s string) string {
298+
if s == "" {
299+
return s
300+
}
301+
302+
result := make([]rune, 0, len(s))
303+
for _, r := range s {
304+
// Valid characters for condition types are:
305+
// - lowercase letters (a-z)
306+
// - uppercase letters (A-Z)
307+
// - digits (0-9)
308+
// - underscore (_)
309+
// - colon (:)
310+
//- comma (,)
311+
// All other characters are replaced with underscore
312+
if (r >= 'a' && r <= 'z') ||
313+
(r >= 'A' && r <= 'Z') ||
314+
(r >= '0' && r <= '9') ||
315+
r == '_' ||
316+
r == ':' ||
317+
r == ',' {
318+
result = append(result, r)
319+
} else {
320+
result = append(result, '_')
321+
}
322+
}
323+
return ensureStartsAndEndsWithLetter(string(result), 'R', 'r')
324+
}
325+
326+
func ensureStartsAndEndsWithLetter(s string, start, end rune) string {
327+
if s == "" {
328+
return s
329+
}
330+
runes := []rune(s)
331+
// Ensure starts with letter
332+
if (runes[0] < 'a' || runes[0] > 'z') && (runes[0] < 'A' || runes[0] > 'Z') {
333+
runes = append([]rune{start}, runes...)
334+
}
335+
// Ensure ends with letter
336+
if (runes[len(runes)-1] < 'a' || runes[len(runes)-1] > 'z') && (runes[len(runes)-1] < 'A' || runes[len(runes)-1] > 'Z') {
337+
runes = append(runes, end)
338+
}
339+
return string(runes)
340+
}

pkg/conditions/updater_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ var _ = Describe("Conditions", func() {
238238
MatchCondition(TestCondition().
239239
WithType("TestCondition.Test").
240240
WithStatus(metav1.ConditionFalse).
241-
WithReason("TestCondition:Test_False").
241+
WithReason("TestCondition_Test_False").
242242
WithMessage("")),
243243
))
244244
})

pkg/controller/status_updater.go

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -449,71 +449,11 @@ func GenerateCreateConditionFunc[Obj client.Object](rr *ReconcileResult[Obj]) fu
449449
}
450450
return func(conType string, status metav1.ConditionStatus, reason, message string) {
451451
rr.Conditions = append(rr.Conditions, metav1.Condition{
452-
Type: ReplaceIllegalCharsInConditionType(conType),
452+
Type: conditions.ReplaceIllegalCharsInConditionType(conType),
453453
Status: status,
454454
ObservedGeneration: gen,
455-
Reason: ReplaceIllegalCharsInConditionReason(reason),
455+
Reason: conditions.ReplaceIllegalCharsInConditionReason(reason),
456456
Message: message,
457457
})
458458
}
459459
}
460-
461-
// ReplaceIllegalCharsInConditionType replaces all characters in the given string that are not allowed in condition types with underscores.
462-
func ReplaceIllegalCharsInConditionType(s string) string {
463-
if s == "" {
464-
return s
465-
}
466-
467-
result := make([]rune, 0, len(s))
468-
for _, r := range s {
469-
// Valid characters for condition types are:
470-
// - lowercase letters (a-z)
471-
// - uppercase letters (A-Z)
472-
// - digits (0-9)
473-
// - underscore (_)
474-
// - hyphen (-)
475-
// - dot (.)
476-
// All other characters are replaced with underscore
477-
if (r >= 'a' && r <= 'z') ||
478-
(r >= 'A' && r <= 'Z') ||
479-
(r >= '0' && r <= '9') ||
480-
r == '_' ||
481-
r == '-' ||
482-
r == '.' {
483-
result = append(result, r)
484-
} else {
485-
result = append(result, '_')
486-
}
487-
}
488-
return string(result)
489-
}
490-
491-
// ReplaceIllegalCharsInConditionReason replaces all characters in the given string that are not allowed in condition reasons with underscores.
492-
func ReplaceIllegalCharsInConditionReason(s string) string {
493-
if s == "" {
494-
return s
495-
}
496-
497-
result := make([]rune, 0, len(s))
498-
for _, r := range s {
499-
// Valid characters for condition types are:
500-
// - lowercase letters (a-z)
501-
// - uppercase letters (A-Z)
502-
// - digits (0-9)
503-
// - underscore (_)
504-
// - colon (:)
505-
//- comma (,)
506-
// All other characters are replaced with underscore
507-
if (r >= 'a' && r <= 'z') ||
508-
(r >= 'A' && r <= 'Z') ||
509-
(r >= '0' && r <= '9') ||
510-
r == '_' ||
511-
r == ':' ||
512-
r == ',' {
513-
result = append(result, r)
514-
} else {
515-
result = append(result, '_')
516-
}
517-
}
518-
return string(result)
519-
}

pkg/controller/status_updater_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,10 @@ var _ = Describe("Status Updater", func() {
128128
}
129129
condFunc := controller.GenerateCreateConditionFunc(rr)
130130

131-
condFunc("CondType :,;-_.Test02@", metav1.ConditionTrue, "Reason -.,:_Test93$", "Message")
131+
condFunc("0CondType :,;-_.Test02@", metav1.ConditionTrue, "1Reason -.,:_Test93$", "Message")
132132
Expect(rr.Conditions).To(HaveLen(1))
133-
Expect(rr.Conditions[0].Type).To(Equal("CondType____-_.Test02_"))
134-
Expect(rr.Conditions[0].Reason).To(Equal("Reason___,:_Test93_"))
133+
Expect(rr.Conditions[0].Type).To(Equal("T0CondType____-_.Test02_t"))
134+
Expect(rr.Conditions[0].Reason).To(Equal("R1Reason___,:_Test93_r"))
135135
})
136136

137137
It("should not update disabled fields", func() {

0 commit comments

Comments
 (0)