Files
Oliver BählerandGitHub 647b113702 chore: add deprecation notices (#2089)
* fix: revert pv labeling to dircet api reads

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* fix: revert pv labeling to dircet api reads

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* feat: add deprecation warnings

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* chore: implement playground

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

* chore: implement playground

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>

---------

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
2026-08-19 15:08:47 +02:00

166 lines
4.4 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package tls
import (
"bytes"
"context"
"testing"
"time"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/runtime/cert"
"github.com/projectcapsule/capsule/pkg/runtime/configuration"
)
func TestReconcileCertificatesMigratesExternalTLSSecret(t *testing.T) {
t.Parallel()
const (
namespace = "capsule-system"
secretName = "capsule-tls"
serviceName = "capsule-webhook-service"
)
ctx := context.Background()
externalCABundle, externalCertificate, externalKey := generateTestTLSMaterial(t, cert.CertificateSANs{
DNSNames: []string{serviceName + "." + namespace + ".svc"},
})
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: namespace,
},
Type: corev1.SecretTypeTLS,
Data: map[string][]byte{
corev1.ServiceAccountRootCAKey: externalCABundle,
corev1.TLSCertKey: externalCertificate,
corev1.TLSPrivateKeyKey: externalKey,
},
}
configurationObject := &capsulev1beta2.CapsuleConfiguration{
ObjectMeta: metav1.ObjectMeta{Name: "capsule"},
Spec: capsulev1beta2.CapsuleConfigurationSpec{
EnableTLSReconciler: true,
CapsuleResources: capsulev1beta2.CapsuleResources{
TLSSecretName: secretName,
},
Admission: capsulev1beta2.DynamicAdmission{
ServiceName: serviceName,
Mutating: &capsulev1beta2.DynamicMutatingAdmissionConfig{},
Validating: &capsulev1beta2.DynamicValidatingAdmissionConfig{},
},
},
}
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
t.Fatal(err)
}
if err := apiextensionsv1.AddToScheme(scheme); err != nil {
t.Fatal(err)
}
if err := capsulev1beta2.AddToScheme(scheme); err != nil {
t.Fatal(err)
}
kubeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(secret, configurationObject).
Build()
reconciler := &Reconciler{
Client: kubeClient,
Log: logr.Discard(),
Namespace: namespace,
Configuration: configuration.NewCapsuleConfiguration(
ctx,
kubeClient,
kubeClient,
nil,
configurationObject.Name,
),
}
desiredSANs, err := reconciler.desiredWebhookSANs(ctx)
if err != nil {
t.Fatalf("desiredWebhookSANs() error = %v", err)
}
if err := reconciler.validateSecretCertificate(secret, desiredSANs); err == nil {
t.Fatal("external serving certificate unexpectedly satisfies all desired SANs")
}
if err := reconciler.ReconcileCertificates(ctx, logr.Discard(), secret.DeepCopy()); err != nil {
t.Fatalf("ReconcileCertificates() error = %v", err)
}
updated := &corev1.Secret{}
if err := kubeClient.Get(ctx, client.ObjectKeyFromObject(secret), updated); err != nil {
t.Fatalf("get reconciled TLS Secret: %v", err)
}
if len(updated.Data["ca.key"]) == 0 {
t.Fatal("reconciled TLS Secret does not contain ca.key")
}
if bytes.Equal(updated.Data[corev1.ServiceAccountRootCAKey], externalCABundle) {
t.Fatal("reconciled TLS Secret retained the external CA bundle")
}
if bytes.Equal(updated.Data[corev1.TLSCertKey], externalCertificate) {
t.Fatal("reconciled TLS Secret retained the external serving certificate")
}
if _, err := cert.NewCertificateAuthorityFromBytes(
updated.Data[corev1.ServiceAccountRootCAKey],
updated.Data["ca.key"],
); err != nil {
t.Fatalf("reconciled CA certificate/key pair is invalid: %v", err)
}
if err := reconciler.validateSecretCertificate(updated, desiredSANs); err != nil {
t.Fatalf("reconciled serving certificate is invalid: %v", err)
}
}
func generateTestTLSMaterial(
t *testing.T,
sans cert.CertificateSANs,
) ([]byte, []byte, []byte) {
t.Helper()
ca, err := cert.GenerateCertificateAuthority()
if err != nil {
t.Fatalf("generate test CA: %v", err)
}
caBundle, err := ca.CACertificatePem()
if err != nil {
t.Fatalf("encode test CA: %v", err)
}
certificate, key, err := ca.GenerateCertificate(cert.NewCertOpts(
time.Now().Add(certificateValidity),
sans,
))
if err != nil {
t.Fatalf("generate test serving certificate: %v", err)
}
return caBundle.Bytes(), certificate.Bytes(), key.Bytes()
}