From f4b2630b264f7ddfd384dea8731563b57dc558ac Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 26 Mar 2024 21:10:17 +0200 Subject: [PATCH] Updated testing --- go.mod | 2 - sthome/config.go | 12 ++- sthome/solver_local.go | 6 +- sthome/utils.go | 4 +- sthome/utils_test.go | 201 +++++++++++++++++++++++++++++++++++++++++ tests/suite_test.go | 2 +- 6 files changed, 217 insertions(+), 10 deletions(-) create mode 100644 sthome/utils_test.go diff --git a/go.mod b/go.mod index 13be743..c2fe649 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,6 @@ go 1.21 toolchain go1.22.1 require ( - /// uncomment and fix tag when github repo is made public - //github.com/stuurmcp/cert-manager-webhook-sthome v0.0.1-alpha github.com/cert-manager/cert-manager v1.14.4 github.com/miekg/dns v1.1.58 github.com/stretchr/testify v1.8.4 diff --git a/sthome/config.go b/sthome/config.go index 66bb1be..a58e44d 100644 --- a/sthome/config.go +++ b/sthome/config.go @@ -6,6 +6,11 @@ import ( v1 "k8s.io/api/core/v1" ) +const ( + SthomeAccessKeyEnv = "STHOME_ACCESS_KEY" + SthomeSecretKeyEnv = "STHOME_SECRET_KEY" +) + // localDNSProviderConfig is a structure that is used to decode into when // solving a DNS01 challenge. // This information is provided by cert-manager, and may be a reference to @@ -20,7 +25,10 @@ import ( // You should not include sensitive information here. If credentials need to // be used by your provider here, you should reference a Kubernetes Secret // resource and fetch these credentials using a Kubernetes clientset. -type localDNSProviderConfig struct { +type LocalDNSProviderConfig struct { + AccessKey *v1.SecretKeySelector `json:"accessKeySecretRef,omitempty"` + SecretKey *v1.SecretKeySelector `json:"secretKeySecretRef,omitempty"` + // Change the two fields below according to the format of the configuration // to be decoded. // These fields will be set by users in the @@ -78,7 +86,7 @@ type localDNSProviderConfig struct { // IsAllowedZone checks if the webhook is allowed to edit the given zone, per // AllowedZones setting. All zones allowed if AllowedZones is empty (the default setting) -func (cfg localDNSProviderConfig) IsAllowedZone(zone string) bool { +func (cfg LocalDNSProviderConfig) IsAllowedZone(zone string) bool { if len(cfg.AllowedZones) == 0 { return true } diff --git a/sthome/solver_local.go b/sthome/solver_local.go index 56b9c36..3a7be9a 100644 --- a/sthome/solver_local.go +++ b/sthome/solver_local.go @@ -21,8 +21,8 @@ const ( // To do so, it must implement the `github.com/cert-manager/cert-manager/pkg/acme/webhook.Solver` // interface. type LocalDNSProviderSolver struct { - client kubernetes.Clientset - //client kubernetes.Interface + //client kubernetes.Clientset + client kubernetes.Interface } // Name is used as the name for this DNS solver when referencing it on the ACME @@ -127,7 +127,7 @@ func (loc *LocalDNSProviderSolver) Initialize(kubeClientConfig *rest.Config, sto if err != nil { return fmt.Errorf("failed to get kubernetes client: %w", err) } - loc.client = *cl + loc.client = cl klog.InfoS("Successfully initialised kubernetes client!") return nil } diff --git a/sthome/utils.go b/sthome/utils.go index 7e996bd..8f1c8ba 100644 --- a/sthome/utils.go +++ b/sthome/utils.go @@ -12,8 +12,8 @@ import ( // loadConfig is a small helper function that decodes JSON configuration into // the typed config struct. -func loadConfig(cfgJSON *extapi.JSON) (localDNSProviderConfig, error) { - cfg := localDNSProviderConfig{} +func loadConfig(cfgJSON *extapi.JSON) (LocalDNSProviderConfig, error) { + cfg := LocalDNSProviderConfig{} // handle the 'base case' where no configuration has been provided if cfgJSON == nil { return cfg, nil diff --git a/sthome/utils_test.go b/sthome/utils_test.go new file mode 100644 index 0000000..113da77 --- /dev/null +++ b/sthome/utils_test.go @@ -0,0 +1,201 @@ +package sthome + +import ( + "context" + "fmt" + "os" + "reflect" + "testing" + + "github.com/cert-manager/cert-manager/pkg/acme/webhook/apis/acme/v1alpha1" + //client "github.com/kubernetes-sdk-for-go-101/pkg/client" + v1 "k8s.io/api/core/v1" + extapi "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + testclient "k8s.io/client-go/kubernetes/fake" +) + +func Test_loadConfig(t *testing.T) { + testCases := []struct { + json string + config LocalDNSProviderConfig + shouldErr bool + }{ + { + json: `{ + "accessKeySecretRef": { + "name": "sthome-secret", + "key": "STHOME_ACCESS_KEY" + }, + "secretKeySecretRef": { + "name": "sthome-secret", + "key": "STHOME_SECRET_KEY" + } +}`, + config: LocalDNSProviderConfig{ + AccessKey: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "sthome-secret", + }, + Key: "STHOME_ACCESS_KEY", + }, + SecretKey: &v1.SecretKeySelector{ + LocalObjectReference: v1.LocalObjectReference{ + Name: "sthome-secret", + }, + Key: "STHOME_SECRET_KEY", + }, + }, + shouldErr: false, + }, + { + json: `{ + "dummy": } +}`, + shouldErr: true, + }, + { + shouldErr: false, + config: LocalDNSProviderConfig{}, + }, + } + + for _, test := range testCases { + json := &extapi.JSON{ + Raw: []byte(test.json), + } + if test.json == "" { + json = nil + } + config, err := loadConfig(json) + if err != nil { + if !test.shouldErr { + t.Errorf("got error %v where no error was expected", err) + } + } else if test.shouldErr { + t.Errorf("didn't get an error where an error was expected") + } + if !reflect.DeepEqual(config, test.config) { + t.Errorf("Wrong config value: wanted %v got %v", test.config, config) + } + } +} + +func Test_getDomainAPI(t *testing.T) { + jsonBothKey := &extapi.JSON{ + Raw: []byte(`{ + "accessKeySecretRef": { + "name": "sthome-secret", + "key": "STHOME_ACCESS_KEY" + }, + "secretKeySecretRef": { + "name": "sthome-secret", + "key": "STHOME_SECRET_KEY" + } +}`), + } + + testCases := []struct { + ch *v1alpha1.ChallengeRequest + env map[string]string + secret *v1.Secret + shouldErr bool + errMessage string + }{ + { + ch: &v1alpha1.ChallengeRequest{}, + shouldErr: true, + errMessage: "failed to initialize sthome client: access key cannot be empty", + }, + { + ch: &v1alpha1.ChallengeRequest{}, + env: map[string]string{ + SthomeAccessKeyEnv: "STHOMEXXXXXXXXXXXXXXXXX", + }, + shouldErr: true, + errMessage: "failed to initialize sthome client: ssecret key cannot be empty", + }, + { + ch: &v1alpha1.ChallengeRequest{}, + env: map[string]string{ + SthomeAccessKeyEnv: "STHOMEXXXXXXXXXXXXXX", + SthomeSecretKeyEnv: "66666666-7777-8888-9999-000000000000", + }, + shouldErr: false, + }, + { + ch: &v1alpha1.ChallengeRequest{ + Config: jsonBothKey, + ResourceNamespace: "test", + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sthome-secret", + Namespace: "test", + }, + Data: map[string][]byte{ + SthomeAccessKeyEnv: []byte("STHOMEXXXXXXXXXXXXXX"), + }, + }, + shouldErr: true, + errMessage: "could not get key STHOME_SECRET_KEY in secret sthome-secret", + }, + { + ch: &v1alpha1.ChallengeRequest{ + Config: jsonBothKey, + ResourceNamespace: "test", + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sthome-secret", + Namespace: "test", + }, + Data: map[string][]byte{ + SthomeSecretKeyEnv: []byte("66666666-7777-8888-9999-000000000000"), + SthomeAccessKeyEnv: []byte("STHOMEXXXXXXXXXXXXXXXXX"), + }, + }, + shouldErr: false, + }, + } + + for _, test := range testCases { + fakeKubernetesClient := testclient.NewSimpleClientset() + pSolver := &LocalDNSProviderSolver{ + client: fakeKubernetesClient, + } + + if test.secret != nil { + _, err := pSolver.client.CoreV1().Secrets(test.ch.ResourceNamespace).Create(context.Background(), test.secret, metav1.CreateOptions{}) + if err != nil { + t.Errorf("failed to create kubernetes secret") + } + } + for k, v := range test.env { + os.Setenv(k, v) + } + _, err := getDomainAPI(test.ch) + if err != nil { + if !test.shouldErr { + t.Errorf("got error %v where no error was expected", err) + } + if err.Error() != test.errMessage { + t.Errorf("expected error %s, got %s", test.errMessage, err.Error()) + } + } else if test.shouldErr { + t.Errorf("didn't get an error where an error was expected with message %s", test.errMessage) + } + for k := range test.env { + os.Unsetenv(k) + } + } +} + +// dummy, should actually return the API, but here we just return the config +func getDomainAPI(ch *v1alpha1.ChallengeRequest) (*LocalDNSProviderConfig, error) { + config, err := loadConfig(ch.Config) + if err != nil { + return nil, fmt.Errorf("failed to load config: %w", err) + } + return &config, err +} diff --git a/tests/suite_test.go b/tests/suite_test.go index b9214b5..281f0bd 100644 --- a/tests/suite_test.go +++ b/tests/suite_test.go @@ -9,7 +9,7 @@ import ( "github.com/cert-manager/cert-manager/test/acme/dns" - sthome "github.com/cert-manager/cert-manager-webhook-sthome/sthome" + "github.com/cert-manager/cert-manager-webhook-sthome/sthome" ) var (