Skip to content

Commit 4cc2a78

Browse files
committed
extend tests
Signed-off-by: chiragkyal <ckyal@redhat.com>
1 parent 4fe0ecb commit 4cc2a78

3 files changed

Lines changed: 423 additions & 16 deletions

File tree

test/e2e/trustmanager_bundle_test.go

Lines changed: 185 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
// - Bundle deletion → target cleanup
1717
// - Negative: Secret target without SecretTargets enabled
1818
// - Negative: useDefaultCAs without DefaultCAPackage enabled
19-
// - Negative: ConfigMap source outside trust namespace not synced
19+
// - Negative: ConfigMap + Secret sources outside trust namespace not synced
2020
//
2121
// Group 2 — SecretTargets enabled:
2222
// - Inline source → Secret target
2323
// - Inline source → ConfigMap + Secret dual targets
2424
// - ConfigMap source → Secret target
25+
// - Secret target data drift reconciliation (tamper → restore)
2526
// - Negative: Bundle name not in authorizedSecrets list
27+
// - Transition: Enabled → Disabled → existing synced Bundle reports SecretTargetsDisabled
2628
//
2729
// Group 3 — DefaultCAPackage enabled:
2830
// - useDefaultCAs → ConfigMap target
@@ -33,14 +35,20 @@
3335
//
3436
// Group 5 — Custom TrustNamespace:
3537
// - ConfigMap source in custom trust namespace → ConfigMap target
36-
// - Negative: ConfigMap source in default namespace not synced when custom trust namespace is configured
38+
// - Secret source in custom trust namespace → ConfigMap target
39+
// - Negative: ConfigMap + Secret sources in default namespace not synced when custom trust namespace is configured
40+
//
41+
// Group 6 — FilterExpiredCertificates enabled:
42+
// - ConfigMap source with valid + expired certs → only valid cert in ConfigMap target
43+
// - Transition to Disabled → same Bundle re-syncs with both certs in target
3744
package e2e
3845

3946
import (
4047
"context"
4148
"crypto/x509"
4249
"fmt"
4350
"strings"
51+
"time"
4452

4553
. "github.com/onsi/ginkgo/v2"
4654
. "github.com/onsi/gomega"
@@ -65,8 +73,8 @@ var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() {
6573
ctx := context.TODO()
6674

6775
var (
68-
testNS *corev1.Namespace
69-
testCertPEM1, testCertPEM2 string
76+
testNS *corev1.Namespace
77+
testCertPEM1, testCertPEM2, expiredCertPEM string
7078
)
7179

7280
BeforeAll(func() {
@@ -89,6 +97,14 @@ var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() {
8997
testCertPEM1 = testutils.GenerateCertificate("e2e-test-ca-1", []string{"cert-manager-operator-e2e"}, caTweak)
9098
testCertPEM2 = testutils.GenerateCertificate("e2e-test-ca-2", []string{"cert-manager-operator-e2e"}, caTweak)
9199

100+
expiredCATweak := func(cert *x509.Certificate) {
101+
cert.IsCA = true
102+
cert.KeyUsage |= x509.KeyUsageCertSign
103+
cert.NotBefore = time.Now().Add(-48 * time.Hour)
104+
cert.NotAfter = time.Now().Add(-24 * time.Hour)
105+
}
106+
expiredCertPEM = testutils.GenerateCertificate("e2e-expired-ca", []string{"cert-manager-operator-e2e"}, expiredCATweak)
107+
92108
By("creating test namespace for target verification")
93109
testNS = createNamespaceWithCleanup(ctx, "bundle-e2e-", map[string]string{bundleTestNamespaceLabel: "true"})
94110
})
@@ -330,21 +346,24 @@ var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() {
330346
verifyBundleNeverSynced(ctx, bundleName)
331347
})
332348

333-
It("should not sync ConfigMap source that exists outside the trust namespace", func() {
349+
It("should not sync sources that exist outside the trust namespace", func() {
334350
bundleName := "bundle-wrong-ns-" + randomStr(5)
335351
sourceCMName := "src-wrong-ns-" + randomStr(5)
352+
sourceSecretName := "src-secret-wrong-ns-" + randomStr(5)
336353

337-
By(fmt.Sprintf("creating source ConfigMap in test namespace %q instead of trust namespace %q", testNS.Name, trustManagerNamespace))
354+
By(fmt.Sprintf("creating source ConfigMap and Secret in test namespace %q instead of trust namespace %q", testNS.Name, trustManagerNamespace))
338355
createSourceConfigMap(ctx, testNS.Name, sourceCMName, bundleSourceKey, testCertPEM1)
356+
createSourceSecret(ctx, testNS.Name, sourceSecretName, bundleSourceKey, testCertPEM2)
339357

340358
bundle := newBundle(bundleName).
341359
WithConfigMapSource(sourceCMName, bundleSourceKey).
360+
WithSecretSource(sourceSecretName, bundleSourceKey).
342361
WithConfigMapTarget(bundleTargetKey).
343362
Build()
344363

345364
createBundleWithCleanup(ctx, bundle)
346365

347-
By("verifying Bundle does not reach Synced=True because source is not in trust namespace")
366+
By("verifying Bundle does not reach Synced=True because sources are not in trust namespace")
348367
verifyBundleNeverSynced(ctx, bundleName)
349368

350369
By("verifying no target ConfigMap is created in test namespace")
@@ -359,12 +378,14 @@ var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() {
359378
bundleSecretTarget = "bundle-secret-tgt"
360379
bundleDualTarget = "bundle-dual-tgt"
361380
bundleCMToSecretTarget = "bundle-cm-to-secret"
381+
bundleSecretDrift = "bundle-secret-drift"
382+
bundleSecretDisable = "bundle-secret-disable"
362383
)
363384

364385
BeforeAll(func() {
365386
createTrustManager(ctx, newTrustManagerCR().WithSecretTargets(
366387
v1alpha1.SecretTargetsPolicyCustom,
367-
[]string{bundleSecretTarget, bundleDualTarget, bundleCMToSecretTarget},
388+
[]string{bundleSecretTarget, bundleDualTarget, bundleCMToSecretTarget, bundleSecretDrift, bundleSecretDisable},
368389
))
369390
})
370391
AfterAll(func() { deleteTrustManager(ctx) })
@@ -422,6 +443,30 @@ var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() {
422443
verifyBundleSynced(ctx, bundleCMToSecretTarget)
423444
})
424445

446+
It("should restore Secret target when tampered", func() {
447+
bundle := newBundle(bundleSecretDrift).
448+
WithInLineSource(testCertPEM1).
449+
WithSecretTarget(bundleTargetKey).
450+
Build()
451+
452+
createBundleWithCleanup(ctx, bundle)
453+
454+
By("verifying Secret target is synced")
455+
err := waitForSecretTarget(ctx, bundleClient, bundleSecretDrift, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout)
456+
Expect(err).ShouldNot(HaveOccurred())
457+
458+
By("tampering with the target Secret data")
459+
targetSecret, err := k8sClientSet.CoreV1().Secrets(testNS.Name).Get(ctx, bundleSecretDrift, metav1.GetOptions{})
460+
Expect(err).ShouldNot(HaveOccurred())
461+
targetSecret.Data[bundleTargetKey] = []byte("tampered-data")
462+
_, err = k8sClientSet.CoreV1().Secrets(testNS.Name).Update(ctx, targetSecret, metav1.UpdateOptions{})
463+
Expect(err).ShouldNot(HaveOccurred())
464+
465+
By("verifying trust-manager restores the target Secret")
466+
err = waitForSecretTarget(ctx, bundleClient, bundleSecretDrift, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout)
467+
Expect(err).ShouldNot(HaveOccurred())
468+
})
469+
425470
It("should not sync Secret when Bundle name is not in authorizedSecrets list", func() {
426471
bundleName := "bundle-not-authorized"
427472
bundle := newBundle(bundleName).
@@ -438,6 +483,39 @@ var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() {
438483
_, err := k8sClientSet.CoreV1().Secrets(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{})
439484
Expect(apierrors.IsNotFound(err)).Should(BeTrue())
440485
})
486+
487+
It("should report SecretTargetsDisabled on existing synced Bundle after disabling secretTargets", func() {
488+
bundle := newBundle(bundleSecretDisable).
489+
WithInLineSource(testCertPEM1).
490+
WithSecretTarget(bundleTargetKey).
491+
Build()
492+
493+
createBundleWithCleanup(ctx, bundle)
494+
495+
By("verifying Secret target syncs while feature is enabled")
496+
err := waitForSecretTarget(ctx, bundleClient, bundleSecretDisable, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout)
497+
Expect(err).ShouldNot(HaveOccurred())
498+
verifyBundleSynced(ctx, bundleSecretDisable)
499+
500+
By("disabling secretTargets on TrustManager CR")
501+
Eventually(func() error {
502+
tm, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{})
503+
if err != nil {
504+
return err
505+
}
506+
tm.Spec.TrustManagerConfig.SecretTargets = v1alpha1.SecretTargetsConfig{
507+
Policy: v1alpha1.SecretTargetsPolicyDisabled,
508+
}
509+
_, err = trustManagerClient().Update(ctx, tm, metav1.UpdateOptions{})
510+
return err
511+
}, lowTimeout, fastPollInterval).Should(Succeed())
512+
513+
waitForTrustManagerReady(ctx)
514+
515+
By("verifying Bundle status transitions to Synced=False")
516+
err = waitForBundleCondition(ctx, bundleClient, bundleSecretDisable, trustapi.BundleConditionSynced, metav1.ConditionFalse, highTimeout)
517+
Expect(err).ShouldNot(HaveOccurred())
518+
})
441519
})
442520

443521
// ===== Group 3: DefaultCAPackage enabled =====
@@ -590,26 +668,122 @@ var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() {
590668
verifyBundleSynced(ctx, bundleName)
591669
})
592670

593-
It("should not sync ConfigMap source from default namespace when custom trust namespace is configured", func() {
671+
It("should sync Secret source from custom trust namespace to target", func() {
672+
bundleName := "bundle-secret-custom-ns-" + randomStr(5)
673+
sourceSecretName := "src-secret-custom-ns-" + randomStr(5)
674+
675+
By(fmt.Sprintf("creating source Secret in custom trust namespace %q", customTrustNS.Name))
676+
createSourceSecret(ctx, customTrustNS.Name, sourceSecretName, bundleSourceKey, testCertPEM1)
677+
678+
bundle := newBundle(bundleName).
679+
WithSecretSource(sourceSecretName, bundleSourceKey).
680+
WithConfigMapTarget(bundleTargetKey).
681+
Build()
682+
683+
createBundleWithCleanup(ctx, bundle)
684+
685+
By("verifying ConfigMap target is synced in test namespace")
686+
err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout)
687+
Expect(err).ShouldNot(HaveOccurred())
688+
689+
verifyBundleSynced(ctx, bundleName)
690+
})
691+
692+
It("should not sync sources from default namespace when custom trust namespace is configured", func() {
594693
bundleName := "bundle-default-ns-miss-" + randomStr(5)
595694
sourceCMName := "src-default-ns-miss-" + randomStr(5)
695+
sourceSecretName := "src-secret-default-miss-" + randomStr(5)
596696

597-
By(fmt.Sprintf("creating source ConfigMap in default namespace %q (not the custom trust namespace %q)", trustManagerNamespace, customTrustNS.Name))
697+
By(fmt.Sprintf("creating source ConfigMap and Secret in default namespace %q (not the custom trust namespace %q)", trustManagerNamespace, customTrustNS.Name))
598698
createSourceConfigMap(ctx, trustManagerNamespace, sourceCMName, bundleSourceKey, testCertPEM1)
699+
createSourceSecret(ctx, trustManagerNamespace, sourceSecretName, bundleSourceKey, testCertPEM2)
599700

600701
bundle := newBundle(bundleName).
601702
WithConfigMapSource(sourceCMName, bundleSourceKey).
703+
WithSecretSource(sourceSecretName, bundleSourceKey).
602704
WithConfigMapTarget(bundleTargetKey).
603705
Build()
604706

605707
createBundleWithCleanup(ctx, bundle)
606708

607-
By("verifying Bundle does not reach Synced=True because source is not in custom trust namespace")
709+
By("verifying Bundle does not reach Synced=True because sources are not in custom trust namespace")
608710
verifyBundleNeverSynced(ctx, bundleName)
609711

610712
By("verifying no target ConfigMap is created in test namespace")
611713
_, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{})
612714
Expect(apierrors.IsNotFound(err)).Should(BeTrue())
613715
})
614716
})
717+
718+
// ===== Group 6: FilterExpiredCertificates =====
719+
Context("with FilterExpiredCertificates enabled", Ordered, func() {
720+
var (
721+
filterBundleName string
722+
sourceCMName string
723+
)
724+
725+
BeforeAll(func() {
726+
createTrustManager(ctx, newTrustManagerCR().
727+
WithFilterExpiredCertificates(v1alpha1.FilterExpiredCertificatesPolicyEnabled))
728+
729+
sourceCMName = "filter-src-cm-" + randomStr(5)
730+
combinedPEM := testCertPEM1 + expiredCertPEM
731+
732+
By("creating source ConfigMap with valid + expired certs in trust namespace")
733+
createSourceConfigMap(ctx, trustManagerNamespace, sourceCMName, bundleSourceKey, combinedPEM)
734+
})
735+
AfterAll(func() { deleteTrustManager(ctx) })
736+
737+
It("should exclude expired certificates from ConfigMap target when using ConfigMap source", func() {
738+
filterBundleName = "bundle-filter-expired-" + randomStr(5)
739+
740+
bundle := newBundle(filterBundleName).
741+
WithConfigMapSource(sourceCMName, bundleSourceKey).
742+
WithConfigMapTarget(bundleTargetKey).
743+
Build()
744+
745+
createBundleWithCleanup(ctx, bundle)
746+
747+
By("verifying target contains the valid certificate")
748+
err := waitForConfigMapTarget(ctx, bundleClient, filterBundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout)
749+
Expect(err).ShouldNot(HaveOccurred())
750+
751+
By("verifying target does NOT contain the expired certificate")
752+
Eventually(func(g Gomega) {
753+
cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, filterBundleName, metav1.GetOptions{})
754+
g.Expect(err).ShouldNot(HaveOccurred())
755+
data := cm.Data[bundleTargetKey]
756+
g.Expect(strings.Contains(data, strings.TrimSpace(testCertPEM1))).Should(BeTrue(), "should contain valid cert")
757+
g.Expect(strings.Contains(data, strings.TrimSpace(expiredCertPEM))).Should(BeFalse(), "should not contain expired cert")
758+
}, highTimeout, fastPollInterval).Should(Succeed())
759+
760+
verifyBundleSynced(ctx, filterBundleName)
761+
})
762+
763+
It("should re-sync same Bundle with expired certs included after disabling filter", func() {
764+
By("disabling filterExpiredCertificates on TrustManager CR")
765+
Eventually(func() error {
766+
tm, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{})
767+
if err != nil {
768+
return err
769+
}
770+
tm.Spec.TrustManagerConfig.FilterExpiredCertificates = v1alpha1.FilterExpiredCertificatesPolicyDisabled
771+
_, err = trustManagerClient().Update(ctx, tm, metav1.UpdateOptions{})
772+
return err
773+
}, lowTimeout, fastPollInterval).Should(Succeed())
774+
775+
waitForTrustManagerReady(ctx)
776+
777+
By("verifying the same Bundle's target now includes the expired certificate")
778+
Eventually(func(g Gomega) {
779+
cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, filterBundleName, metav1.GetOptions{})
780+
g.Expect(err).ShouldNot(HaveOccurred())
781+
data := cm.Data[bundleTargetKey]
782+
g.Expect(strings.Contains(data, strings.TrimSpace(testCertPEM1))).Should(BeTrue(), "should contain valid cert")
783+
g.Expect(strings.Contains(data, strings.TrimSpace(expiredCertPEM))).Should(BeTrue(), "should contain expired cert after disabling filter")
784+
}, highTimeout, fastPollInterval).Should(Succeed())
785+
786+
verifyBundleSynced(ctx, filterBundleName)
787+
})
788+
})
615789
})

test/e2e/trustmanager_helpers_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ func (b *trustManagerCRBuilder) WithDefaultCAPackage(policy v1alpha1.DefaultCAPa
9191
return b
9292
}
9393

94+
func (b *trustManagerCRBuilder) WithFilterExpiredCertificates(policy v1alpha1.FilterExpiredCertificatesPolicy) *trustManagerCRBuilder {
95+
b.tm.Spec.TrustManagerConfig.FilterExpiredCertificates = policy
96+
return b
97+
}
98+
9499
func (b *trustManagerCRBuilder) Build() *v1alpha1.TrustManager {
95100
return b.tm
96101
}

0 commit comments

Comments
 (0)