Skip to content

Commit 5fd7424

Browse files
authored
fix: panic when patching empty secret (#1474)
When patching an empty secret, i.e. one with no data field, the controller will panic as it's trying to assign to a nil map. Same will happen with the labels. - Always initialize the Data and Labels maps if they are empty - Add a test to cover this use case fixes: #1282 Signed-off-by: Alejandro Moreno <[email protected]>
1 parent 269c66f commit 5fd7424

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

integration/controller_test.go

+44
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,50 @@ var _ = Describe("create", func() {
438438
}, Timeout, PollingInterval).Should(WithTransform(getLabels, Equal(expectedLabels)))
439439
})
440440
})
441+
442+
Context("With patch annotation and empty secret", func() {
443+
BeforeEach(func() {
444+
// Empty secret has no data nor labels field
445+
s.Data = nil
446+
s.Labels = nil
447+
s.Annotations = map[string]string{
448+
ssv1alpha1.SealedSecretPatchAnnotation: "true",
449+
}
450+
c.Secrets(ns).Create(ctx, s, metav1.CreateOptions{})
451+
})
452+
453+
It("should not take ownership of existing Secret while patching the Secret", func() {
454+
expectedData := map[string][]byte{
455+
"foo": []byte("bar"),
456+
}
457+
expectedAnnotations := map[string]string{
458+
ssv1alpha1.SealedSecretPatchAnnotation: "true",
459+
}
460+
expectedLabels := map[string]string{
461+
"mylabel": "myvalue",
462+
}
463+
Eventually(func() (*v1.EventList, error) {
464+
return c.Events(ns).Search(scheme.Scheme, ss)
465+
}, Timeout, PollingInterval).Should(
466+
containEventWithReason(Equal("Unsealed")),
467+
)
468+
Eventually(func() (*ssv1alpha1.SealedSecret, error) {
469+
return ssc.BitnamiV1alpha1().SealedSecrets(ns).Get(context.Background(), secretName, metav1.GetOptions{})
470+
}, Timeout, PollingInterval).ShouldNot(WithTransform(getStatus, BeNil()))
471+
Eventually(func() (*v1.Secret, error) {
472+
return c.Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
473+
}, Timeout, PollingInterval).Should(WithTransform(getNumberOfOwners, Equal(0)))
474+
Eventually(func() (*v1.Secret, error) {
475+
return c.Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
476+
}, Timeout, PollingInterval).Should(WithTransform(getData, Equal(expectedData)))
477+
Eventually(func() (*v1.Secret, error) {
478+
return c.Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
479+
}, Timeout, PollingInterval).Should(WithTransform(getAnnotations, Equal(expectedAnnotations)))
480+
Eventually(func() (*v1.Secret, error) {
481+
return c.Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
482+
}, Timeout, PollingInterval).Should(WithTransform(getLabels, Equal(expectedLabels)))
483+
})
484+
})
441485
})
442486

443487
Describe("Secret Recreation", func() {

pkg/controller/controller.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -359,18 +359,26 @@ func (c *Controller) unseal(ctx context.Context, key string) (unsealErr error) {
359359
secret = secret.DeepCopy()
360360

361361
if isAnnotatedToBePatched(secret) {
362+
if secret.Data == nil {
363+
secret.Data = make(map[string][]byte)
364+
}
365+
362366
for k, v := range newSecret.Data {
363367
secret.Data[k] = v
364368
}
365369

366-
for k, v := range newSecret.ObjectMeta.Annotations {
367-
secret.ObjectMeta.Annotations[k] = v
370+
if secret.ObjectMeta.Labels == nil {
371+
secret.ObjectMeta.Labels = make(map[string]string)
368372
}
369373

370374
for k, v := range newSecret.ObjectMeta.Labels {
371375
secret.ObjectMeta.Labels[k] = v
372376
}
373377

378+
for k, v := range newSecret.ObjectMeta.Annotations {
379+
secret.ObjectMeta.Annotations[k] = v
380+
}
381+
374382
if isAnnotatedToBeManaged(secret) {
375383
secret.ObjectMeta.OwnerReferences = newSecret.ObjectMeta.OwnerReferences
376384
}

0 commit comments

Comments
 (0)