diff --git a/pkg/webhook/webhook.go b/pkg/webhook/webhook.go index 1129f5b..be02168 100644 --- a/pkg/webhook/webhook.go +++ b/pkg/webhook/webhook.go @@ -246,6 +246,11 @@ func (whs *WebhookServer) addVolume(target []corev1.Volume, added []corev1.Volum return patch } +// patchFriendly replaces any / with ~1 in a string for use in a JSON patch +func patchFriendly(str string) string { + return strings.ReplaceAll(str, "/", "~1") +} + // updateAnnotations updates/adds annotations func (whs *WebhookServer) updateAnnotations(target map[string]string, added map[string]string) (patch []patchOperation) { @@ -264,13 +269,13 @@ func (whs *WebhookServer) updateAnnotations(target map[string]string, added map[ if _, ok := target[key]; !ok { patch = append(patch, patchOperation{ Op: "add", - Path: "/metadata/annotations/" + key, + Path: "/metadata/annotations/" + patchFriendly(key), Value: value, }) } else { patch = append(patch, patchOperation{ Op: "replace", - Path: "/metadata/annotations/" + key, + Path: "/metadata/annotations/" + patchFriendly(key), Value: value, }) } diff --git a/pkg/webhook/webhook_test.go b/pkg/webhook/webhook_test.go index 77ede2a..9c5a455 100644 --- a/pkg/webhook/webhook_test.go +++ b/pkg/webhook/webhook_test.go @@ -490,6 +490,45 @@ func TestUpdateAnnotationsWithNonNilTargetAndExistingAnnotations(t *testing.T) { } } +// TestUpdateAnnotationsWithEscapedKeys tests the updateAnnotation method of the WebhookServer struct. +// It verifies that the method correctly escapes annotation keys. +func TestUpdateAnnotationsWithEscapedKeys(t *testing.T) { + whs := &WebhookServer{} + + target := map[string]string{ + "existing/annotation": "existing-value", + } + + added := map[string]string{ + "existing/annotation": "new-value", + "new/annotation": "new-value", + } + + patch := whs.updateAnnotations(target, added) + + assert.Equal(t, 2, len(patch), "Expected 2 patch operations") + + expectedPatches := map[string]patchOperation{ + "/metadata/annotations/existing~1annotation": { + Op: "replace", + Path: "/metadata/annotations/existing~1annotation", + Value: "new-value", + }, + "/metadata/annotations/new~1annotation": { + Op: "add", + Path: "/metadata/annotations/new~1annotation", + Value: "new-value", + }, + } + + for _, p := range patch { + expectedPatch, exists := expectedPatches[p.Path] + assert.True(t, exists, "Unexpected patch path: %s", p.Path) + assert.Equal(t, expectedPatch.Op, p.Op, "Unexpected operation for path: %s", p.Path) + assert.Equal(t, expectedPatch.Value, p.Value, "Unexpected value for path: %s", p.Path) + } +} + // Test case: Verify addVolumeMounts adds volume mounts to containers in a pod, // where some containers already have volume mounts and some do not. // Ensures 'volumeMounts' fields are created for containers without them