From dd90cf09f877ef470df5598ceda8427dc38e0e20 Mon Sep 17 00:00:00 2001 From: Rafael Thalhofer <48678421+rafalgalaw@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:10:27 +0200 Subject: [PATCH] feat: specify certbundle secretref on github endpoint CR (#196) fixes #189 --- api/v1beta1/githubendpoint_types.go | 12 +- api/v1beta1/zz_generated.deepcopy.go | 8 +- ...tor.mercedes-benz.com_githubendpoints.yaml | 17 +- .../githubcredentials_controller.go | 4 +- .../controller/githubendpoint_controller.go | 75 ++++- .../githubendpoint_controller_test.go | 276 ++++++++++++++++-- 6 files changed, 344 insertions(+), 48 deletions(-) diff --git a/api/v1beta1/githubendpoint_types.go b/api/v1beta1/githubendpoint_types.go index b8df006..661f895 100644 --- a/api/v1beta1/githubendpoint_types.go +++ b/api/v1beta1/githubendpoint_types.go @@ -8,13 +8,11 @@ import ( // GitHubEndpointSpec defines the desired state of GitHubEndpoint type GitHubEndpointSpec struct { - Description string `json:"description,omitempty"` - APIBaseURL string `json:"apiBaseUrl,omitempty"` - UploadBaseURL string `json:"uploadBaseUrl,omitempty"` - BaseURL string `json:"baseUrl,omitempty"` - //nolint:godox - // TODO: This should be a secret reference - CACertBundle []byte `json:"caCertBundle,omitempty"` + Description string `json:"description,omitempty"` + APIBaseURL string `json:"apiBaseUrl,omitempty"` + UploadBaseURL string `json:"uploadBaseUrl,omitempty"` + BaseURL string `json:"baseUrl,omitempty"` + CACertBundleSecretRef SecretRef `json:"caCertBundleSecretRef,omitempty"` } // GitHubEndpointStatus defines the observed state of GitHubEndpoint diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index f4c6923..69fe493 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -324,7 +324,7 @@ func (in *GitHubEndpoint) DeepCopyInto(out *GitHubEndpoint) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) + out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) } @@ -381,11 +381,7 @@ func (in *GitHubEndpointList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GitHubEndpointSpec) DeepCopyInto(out *GitHubEndpointSpec) { *out = *in - if in.CACertBundle != nil { - in, out := &in.CACertBundle, &out.CACertBundle - *out = make([]byte, len(*in)) - copy(*out, *in) - } + out.CACertBundleSecretRef = in.CACertBundleSecretRef } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubEndpointSpec. diff --git a/config/crd/bases/garm-operator.mercedes-benz.com_githubendpoints.yaml b/config/crd/bases/garm-operator.mercedes-benz.com_githubendpoints.yaml index 961004f..7721fa2 100644 --- a/config/crd/bases/garm-operator.mercedes-benz.com_githubendpoints.yaml +++ b/config/crd/bases/garm-operator.mercedes-benz.com_githubendpoints.yaml @@ -63,10 +63,19 @@ spec: type: string baseUrl: type: string - caCertBundle: - description: 'TODO: This should be a secret reference' - format: byte - type: string + caCertBundleSecretRef: + properties: + key: + description: Key is the key in the secret's data map for this + value + type: string + name: + description: Name of the kubernetes secret to use + type: string + required: + - key + - name + type: object description: type: string uploadBaseUrl: diff --git a/internal/controller/githubcredentials_controller.go b/internal/controller/githubcredentials_controller.go index 9e1150e..81dc1ae 100644 --- a/internal/controller/githubcredentials_controller.go +++ b/internal/controller/githubcredentials_controller.go @@ -320,7 +320,7 @@ func (r *GitHubCredentialReconciler) ensureFinalizer(ctx context.Context, creden } func (r *GitHubCredentialReconciler) findCredentialsForSecret(ctx context.Context, obj client.Object) []reconcile.Request { - secret, ok := obj.(*corev1.Secret) + secretObj, ok := obj.(*corev1.Secret) if !ok { return nil } @@ -332,7 +332,7 @@ func (r *GitHubCredentialReconciler) findCredentialsForSecret(ctx context.Contex var requests []reconcile.Request for _, c := range creds.Items { - if c.Spec.SecretRef.Name == secret.Name { + if c.Spec.SecretRef.Name == secretObj.Name { requests = append(requests, reconcile.Request{ NamespacedName: types.NamespacedName{ Namespace: c.Namespace, diff --git a/internal/controller/githubendpoint_controller.go b/internal/controller/githubendpoint_controller.go index d76d590..6a37d53 100644 --- a/internal/controller/githubendpoint_controller.go +++ b/internal/controller/githubendpoint_controller.go @@ -9,13 +9,19 @@ import ( "github.com/cloudbase/garm/client/endpoints" "github.com/cloudbase/garm/params" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" garmoperatorv1beta1 "github.com/mercedes-benz/garm-operator/api/v1beta1" "github.com/mercedes-benz/garm-operator/pkg/annotations" @@ -23,6 +29,7 @@ import ( "github.com/mercedes-benz/garm-operator/pkg/client/key" "github.com/mercedes-benz/garm-operator/pkg/conditions" "github.com/mercedes-benz/garm-operator/pkg/event" + "github.com/mercedes-benz/garm-operator/pkg/secret" "github.com/mercedes-benz/garm-operator/pkg/util" ) @@ -76,6 +83,12 @@ func (r *GitHubEndpointReconciler) reconcileNormal(ctx context.Context, client g return ctrl.Result{}, err } + // fetch CACertbundle from secret + caCertBundleSecret, err := r.handleCaCertBundleSecret(ctx, endpoint) + if err != nil { + return ctrl.Result{}, err + } + // get endpoint in garm db with resource name garmEndpoint, err := r.getExistingEndpoint(client, endpoint.Name) if err != nil { @@ -89,7 +102,7 @@ func (r *GitHubEndpointReconciler) reconcileNormal(ctx context.Context, client g // if not found, create endpoint in garm db if reflect.ValueOf(garmEndpoint).IsZero() { - garmEndpoint, err = r.createEndpoint(ctx, client, endpoint) // nolint:wastedassign + garmEndpoint, err = r.createEndpoint(ctx, client, endpoint, caCertBundleSecret) // nolint:wastedassign if err != nil { event.Error(r.Recorder, endpoint, err.Error()) conditions.MarkFalse(endpoint, conditions.ReadyCondition, conditions.GarmAPIErrorReason, err.Error()) @@ -101,7 +114,7 @@ func (r *GitHubEndpointReconciler) reconcileNormal(ctx context.Context, client g } // update endpoint cr anytime the endpoint in garm db changes - garmEndpoint, err = r.updateEndpoint(ctx, client, endpoint) + garmEndpoint, err = r.updateEndpoint(ctx, client, endpoint, caCertBundleSecret) if err != nil { event.Error(r.Recorder, endpoint, err.Error()) conditions.MarkFalse(endpoint, conditions.ReadyCondition, conditions.GarmAPIErrorReason, err.Error()) @@ -135,7 +148,7 @@ func (r *GitHubEndpointReconciler) getExistingEndpoint(client garmClient.Endpoin return endpoint.Payload, nil } -func (r *GitHubEndpointReconciler) createEndpoint(ctx context.Context, client garmClient.EndpointClient, endpoint *garmoperatorv1beta1.GitHubEndpoint) (params.GithubEndpoint, error) { +func (r *GitHubEndpointReconciler) createEndpoint(ctx context.Context, client garmClient.EndpointClient, endpoint *garmoperatorv1beta1.GitHubEndpoint, caCertBundleSecret string) (params.GithubEndpoint, error) { log := log.FromContext(ctx) log.WithValues("endpoint", endpoint.Name) @@ -148,7 +161,7 @@ func (r *GitHubEndpointReconciler) createEndpoint(ctx context.Context, client ga APIBaseURL: endpoint.Spec.APIBaseURL, UploadBaseURL: endpoint.Spec.UploadBaseURL, BaseURL: endpoint.Spec.BaseURL, - CACertBundle: endpoint.Spec.CACertBundle, + CACertBundle: []byte(caCertBundleSecret), })) if err != nil { log.V(1).Info(fmt.Sprintf("client.CreateEndpoint error: %s", err)) @@ -163,7 +176,7 @@ func (r *GitHubEndpointReconciler) createEndpoint(ctx context.Context, client ga return retValue.Payload, nil } -func (r *GitHubEndpointReconciler) updateEndpoint(ctx context.Context, client garmClient.EndpointClient, endpoint *garmoperatorv1beta1.GitHubEndpoint) (params.GithubEndpoint, error) { +func (r *GitHubEndpointReconciler) updateEndpoint(ctx context.Context, client garmClient.EndpointClient, endpoint *garmoperatorv1beta1.GitHubEndpoint, caCertBundleSecret string) (params.GithubEndpoint, error) { log := log.FromContext(ctx) log.V(1).Info("update endpoint") @@ -175,7 +188,7 @@ func (r *GitHubEndpointReconciler) updateEndpoint(ctx context.Context, client ga APIBaseURL: util.StringPtr(endpoint.Spec.APIBaseURL), UploadBaseURL: util.StringPtr(endpoint.Spec.UploadBaseURL), BaseURL: util.StringPtr(endpoint.Spec.BaseURL), - CACertBundle: endpoint.Spec.CACertBundle, + CACertBundle: []byte(caCertBundleSecret), })) if err != nil { log.V(1).Info(fmt.Sprintf("client.UpdateEndpoint error: %s", err)) @@ -222,6 +235,25 @@ func (r *GitHubEndpointReconciler) reconcileDelete(ctx context.Context, client g return ctrl.Result{}, nil } +func (r *GitHubEndpointReconciler) handleCaCertBundleSecret(ctx context.Context, endpoint *garmoperatorv1beta1.GitHubEndpoint) (string, error) { + // as caCertBundle is optional we exit early if it is not set and do not set any conditions + if reflect.ValueOf(endpoint.Spec.CACertBundleSecretRef).IsZero() { + return "", nil + } + + caCertBundleSecret, err := secret.FetchRef(ctx, r.Client, &endpoint.Spec.CACertBundleSecretRef, endpoint.Namespace) + if err != nil { + conditions.MarkFalse(endpoint, conditions.ReadyCondition, conditions.FetchingSecretRefFailedReason, err.Error()) + conditions.MarkFalse(endpoint, conditions.SecretReference, conditions.FetchingSecretRefFailedReason, err.Error()) + if err := r.Status().Update(ctx, endpoint); err != nil { + return "", err + } + return "", err + } + conditions.MarkTrue(endpoint, conditions.SecretReference, conditions.FetchingSecretRefSuccessReason, "") + return caCertBundleSecret, nil +} + func (r *GitHubEndpointReconciler) ensureFinalizer(ctx context.Context, endpoint *garmoperatorv1beta1.GitHubEndpoint) error { if !controllerutil.ContainsFinalizer(endpoint, key.GitHubEndpointFinalizerName) { controllerutil.AddFinalizer(endpoint, key.GitHubEndpointFinalizerName) @@ -230,9 +262,40 @@ func (r *GitHubEndpointReconciler) ensureFinalizer(ctx context.Context, endpoint return nil } +func (r *GitHubEndpointReconciler) findEndpointsForSecret(ctx context.Context, obj client.Object) []reconcile.Request { + secretObj, ok := obj.(*corev1.Secret) + if !ok { + return nil + } + + var endpointList garmoperatorv1beta1.GitHubEndpointList + if err := r.List(ctx, &endpointList); err != nil { + return nil + } + + var requests []reconcile.Request + for _, c := range endpointList.Items { + if c.Spec.CACertBundleSecretRef.Name == secretObj.Name { + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: c.Namespace, + Name: c.Name, + }, + }) + } + } + + return requests +} + // SetupWithManager sets up the controller with the Manager. func (r *GitHubEndpointReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&garmoperatorv1beta1.GitHubEndpoint{}). + Watches( + &corev1.Secret{}, + handler.EnqueueRequestsFromMapFunc(r.findEndpointsForSecret), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Complete(r) } diff --git a/internal/controller/githubendpoint_controller_test.go b/internal/controller/githubendpoint_controller_test.go index 4e75244..f65c7c3 100644 --- a/internal/controller/githubendpoint_controller_test.go +++ b/internal/controller/githubendpoint_controller_test.go @@ -11,6 +11,7 @@ import ( "github.com/cloudbase/garm/client/endpoints" "github.com/cloudbase/garm/params" "go.uber.org/mock/gomock" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/scheme" @@ -52,10 +53,23 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "gh-endpoint-ca-cert-bundle", + Key: "caCertBundle", + }, + }, + }, + runtimeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "gh-endpoint-ca-cert-bundle", + }, + Data: map[string][]byte{ + "caCertBundle": []byte("foobar"), + }, }, }, - runtimeObjects: []runtime.Object{}, expectedObject: &garmoperatorv1beta1.GitHubEndpoint{ ObjectMeta: metav1.ObjectMeta{ Name: "existing-github-endpoint", @@ -69,7 +83,10 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "gh-endpoint-ca-cert-bundle", + Key: "caCertBundle", + }, }, Status: garmoperatorv1beta1.GitHubEndpointStatus{ Conditions: []metav1.Condition{ @@ -80,6 +97,13 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { Message: "", LastTransitionTime: metav1.NewTime(time.Now()), }, + { + Type: string(conditions.SecretReference), + Reason: string(conditions.FetchingSecretRefSuccessReason), + Status: metav1.ConditionTrue, + Message: "", + LastTransitionTime: metav1.NewTime(time.Now()), + }, }, }, }, @@ -101,7 +125,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: util.StringPtr("https://api.github.com"), UploadBaseURL: util.StringPtr("https://uploads.github.com"), BaseURL: util.StringPtr("https://github.com"), - CACertBundle: nil, + CACertBundle: []byte("foobar"), })).Return(&endpoints.UpdateGithubEndpointOK{ Payload: params.GithubEndpoint{ Name: "existing-github-endpoint", @@ -109,7 +133,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundle: []byte("foobar"), }, }, nil) }, @@ -130,7 +154,10 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github-enterprise.com", UploadBaseURL: "https://uploads.github-enterprise.com", BaseURL: "https://github-enterprise.com", - CACertBundle: nil, + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "gh-endpoint-ca-cert-bundle", + Key: "caCertBundle", + }, }, Status: garmoperatorv1beta1.GitHubEndpointStatus{ Conditions: []metav1.Condition{ @@ -141,10 +168,27 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { Message: "", LastTransitionTime: metav1.NewTime(time.Now()), }, + { + Type: string(conditions.SecretReference), + Reason: string(conditions.FetchingSecretRefSuccessReason), + Status: metav1.ConditionTrue, + Message: "", + LastTransitionTime: metav1.NewTime(time.Now()), + }, + }, + }, + }, + runtimeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "gh-endpoint-ca-cert-bundle", + }, + Data: map[string][]byte{ + "caCertBundle": []byte("foobar"), }, }, }, - runtimeObjects: []runtime.Object{}, expectedObject: &garmoperatorv1beta1.GitHubEndpoint{ ObjectMeta: metav1.ObjectMeta{ Name: "existing-github-endpoint", @@ -158,7 +202,10 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github-enterprise.com", UploadBaseURL: "https://uploads.github-enterprise.com", BaseURL: "https://github-enterprise.com", - CACertBundle: nil, + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "gh-endpoint-ca-cert-bundle", + Key: "caCertBundle", + }, }, Status: garmoperatorv1beta1.GitHubEndpointStatus{ Conditions: []metav1.Condition{ @@ -169,6 +216,13 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { Message: "", LastTransitionTime: metav1.NewTime(time.Now()), }, + { + Type: string(conditions.SecretReference), + Reason: string(conditions.FetchingSecretRefSuccessReason), + Status: metav1.ConditionTrue, + Message: "", + LastTransitionTime: metav1.NewTime(time.Now()), + }, }, }, }, @@ -182,7 +236,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundle: []byte("foobar"), }, }, nil) m.UpdateEndpoint(endpoints.NewUpdateGithubEndpointParams(). @@ -192,7 +246,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: util.StringPtr("https://api.github-enterprise.com"), UploadBaseURL: util.StringPtr("https://uploads.github-enterprise.com"), BaseURL: util.StringPtr("https://github-enterprise.com"), - CACertBundle: nil, + CACertBundle: []byte("foobar"), })).Return(&endpoints.UpdateGithubEndpointOK{ Payload: params.GithubEndpoint{ Name: "existing-github-endpoint", @@ -200,7 +254,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github-enterprise.com", UploadBaseURL: "https://uploads.github-enterprise.com", BaseURL: "https://github-enterprise.com", - CACertBundle: nil, + CACertBundle: []byte("foobar"), }, }, nil) }, @@ -218,7 +272,10 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "gh-endpoint-ca-cert-bundle", + Key: "caCertBundle", + }, }, }, expectedObject: &garmoperatorv1beta1.GitHubEndpoint{ @@ -234,7 +291,10 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "gh-endpoint-ca-cert-bundle", + Key: "caCertBundle", + }, }, Status: garmoperatorv1beta1.GitHubEndpointStatus{ Conditions: []metav1.Condition{ @@ -245,10 +305,27 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { Message: "", LastTransitionTime: metav1.NewTime(time.Now()), }, + { + Type: string(conditions.SecretReference), + Reason: string(conditions.FetchingSecretRefSuccessReason), + Status: metav1.ConditionTrue, + Message: "", + LastTransitionTime: metav1.NewTime(time.Now()), + }, + }, + }, + }, + runtimeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "gh-endpoint-ca-cert-bundle", + }, + Data: map[string][]byte{ + "caCertBundle": []byte("foobar"), }, }, }, - runtimeObjects: []runtime.Object{}, expectGarmRequest: func(m *mock.MockEndpointClientMockRecorder) { m.GetEndpoint(endpoints.NewGetGithubEndpointParams(). WithName("new-github-endpoint")). @@ -260,7 +337,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundle: []byte("foobar"), })).Return(&endpoints.CreateGithubEndpointOK{ Payload: params.GithubEndpoint{ Name: "new-github-endpoint", @@ -268,7 +345,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundle: []byte("foobar"), }, }, nil) m.UpdateEndpoint(endpoints.NewUpdateGithubEndpointParams(). @@ -278,7 +355,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: util.StringPtr("https://api.github.com"), UploadBaseURL: util.StringPtr("https://uploads.github.com"), BaseURL: util.StringPtr("https://github.com"), - CACertBundle: nil, + CACertBundle: []byte("foobar"), })).Return(&endpoints.UpdateGithubEndpointOK{ Payload: params.GithubEndpoint{ Name: "new-github-endpoint", @@ -286,7 +363,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundle: []byte("foobar"), }, }, nil) }, @@ -304,7 +381,6 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "", UploadBaseURL: "", BaseURL: "", - CACertBundle: nil, }, }, expectedObject: &garmoperatorv1beta1.GitHubEndpoint{ @@ -339,7 +415,7 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: nil, + CACertBundle: []byte("foobar"), }, }, nil) m.UpdateEndpoint(endpoints.NewUpdateGithubEndpointParams(). @@ -349,11 +425,145 @@ func TestGitHubEndpointReconciler_reconcileNormal(t *testing.T) { APIBaseURL: util.StringPtr(""), UploadBaseURL: util.StringPtr(""), BaseURL: util.StringPtr(""), - CACertBundle: nil, + CACertBundle: []byte(""), })).Return(nil, endpoints.NewUpdateGithubEndpointDefault(400)) }, wantErr: true, }, + { + name: "github-endpoint update - no ca cert bundle secret found", + object: &garmoperatorv1beta1.GitHubEndpoint{ + ObjectMeta: metav1.ObjectMeta{ + Name: "existing-github-endpoint", + Namespace: "default", + }, + Spec: garmoperatorv1beta1.GitHubEndpointSpec{ + Description: "existing-github-endpoint", + APIBaseURL: "https://api.github.com", + UploadBaseURL: "https://uploads.github.com", + BaseURL: "https://github.com", + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "ca-cert-bundle", + Key: "caCertBundle", + }, + }, + }, + expectedObject: &garmoperatorv1beta1.GitHubEndpoint{ + ObjectMeta: metav1.ObjectMeta{ + Name: "existing-github-endpoint", + Namespace: "default", + Finalizers: []string{ + key.GitHubEndpointFinalizerName, + }, + }, + Spec: garmoperatorv1beta1.GitHubEndpointSpec{ + Description: "existing-github-endpoint", + APIBaseURL: "https://api.github.com", + UploadBaseURL: "https://uploads.github.com", + BaseURL: "https://github.com", + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "ca-cert-bundle", + Key: "caCertBundle", + }, + }, + Status: garmoperatorv1beta1.GitHubEndpointStatus{ + Conditions: []metav1.Condition{ + { + Type: string(conditions.ReadyCondition), + Reason: string(conditions.FetchingSecretRefFailedReason), + Status: metav1.ConditionFalse, + Message: "secrets \"ca-cert-bundle\" not found", + LastTransitionTime: metav1.NewTime(time.Now()), + }, + { + Type: string(conditions.SecretReference), + Reason: string(conditions.FetchingSecretRefFailedReason), + Status: metav1.ConditionFalse, + Message: "secrets \"ca-cert-bundle\" not found", + LastTransitionTime: metav1.NewTime(time.Now()), + }, + }, + }, + }, + runtimeObjects: []runtime.Object{}, + expectGarmRequest: func(_ *mock.MockEndpointClientMockRecorder) {}, + wantErr: true, + }, + { + name: "github-endpoint update - no ca cert bundle secret defined", + object: &garmoperatorv1beta1.GitHubEndpoint{ + ObjectMeta: metav1.ObjectMeta{ + Name: "existing-github-endpoint", + Namespace: "default", + }, + Spec: garmoperatorv1beta1.GitHubEndpointSpec{ + Description: "existing-github-endpoint", + APIBaseURL: "https://api.github.com", + UploadBaseURL: "https://uploads.github.com", + BaseURL: "https://github.com", + }, + }, + expectedObject: &garmoperatorv1beta1.GitHubEndpoint{ + ObjectMeta: metav1.ObjectMeta{ + Name: "existing-github-endpoint", + Namespace: "default", + Finalizers: []string{ + key.GitHubEndpointFinalizerName, + }, + }, + Spec: garmoperatorv1beta1.GitHubEndpointSpec{ + Description: "existing-github-endpoint", + APIBaseURL: "https://api.github.com", + UploadBaseURL: "https://uploads.github.com", + BaseURL: "https://github.com", + }, + Status: garmoperatorv1beta1.GitHubEndpointStatus{ + Conditions: []metav1.Condition{ + { + Type: string(conditions.ReadyCondition), + Reason: string(conditions.SuccessfulReconcileReason), + Status: metav1.ConditionTrue, + Message: "", + LastTransitionTime: metav1.NewTime(time.Now()), + }, + }, + }, + }, + runtimeObjects: []runtime.Object{}, + expectGarmRequest: func(m *mock.MockEndpointClientMockRecorder) { + m.GetEndpoint(endpoints.NewGetGithubEndpointParams(). + WithName("existing-github-endpoint")). + Return(&endpoints.GetGithubEndpointOK{ + Payload: params.GithubEndpoint{ + Name: "existing-github-endpoint", + Description: "existing-github-endpoint", + APIBaseURL: "https://api.github.com", + UploadBaseURL: "https://uploads.github.com", + BaseURL: "https://github.com", + CACertBundle: []byte(""), + }, + }, nil) + m.UpdateEndpoint(endpoints.NewUpdateGithubEndpointParams(). + WithName("existing-github-endpoint"). + WithBody(params.UpdateGithubEndpointParams{ + Description: util.StringPtr("existing-github-endpoint"), + APIBaseURL: util.StringPtr("https://api.github.com"), + UploadBaseURL: util.StringPtr("https://uploads.github.com"), + BaseURL: util.StringPtr("https://github.com"), + CACertBundle: []byte(""), + })).Return(&endpoints.UpdateGithubEndpointOK{ + Payload: params.GithubEndpoint{ + Name: "existing-github-endpoint", + Description: "existing-github-endpoint", + APIBaseURL: "https://api.github.com", + UploadBaseURL: "https://uploads.github.com", + BaseURL: "https://github.com", + CACertBundle: []byte(""), + }, + }, nil) + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -430,7 +640,10 @@ func TestGitHubEndpointReconciler_reconcileDelete(t *testing.T) { APIBaseURL: "https://api.github.com", UploadBaseURL: "https://uploads.github.com", BaseURL: "https://github.com", - CACertBundle: []byte(""), + CACertBundleSecretRef: garmoperatorv1beta1.SecretRef{ + Name: "gh-endpoint-ca-cert-bundle", + Key: "caCertBundle", + }, }, Status: garmoperatorv1beta1.GitHubEndpointStatus{ Conditions: []metav1.Condition{ @@ -441,10 +654,27 @@ func TestGitHubEndpointReconciler_reconcileDelete(t *testing.T) { Message: "", LastTransitionTime: metav1.NewTime(time.Now()), }, + { + Type: string(conditions.SecretReference), + Reason: string(conditions.FetchingSecretRefSuccessReason), + Status: metav1.ConditionTrue, + Message: "", + LastTransitionTime: metav1.NewTime(time.Now()), + }, + }, + }, + }, + runtimeObjects: []runtime.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "gh-endpoint-ca-cert-bundle", + }, + Data: map[string][]byte{ + "caCertBundle": []byte("foobar"), }, }, }, - runtimeObjects: []runtime.Object{}, expectGarmRequest: func(m *mock.MockEndpointClientMockRecorder) { m.DeleteEndpoint( endpoints.NewDeleteGithubEndpointParams().