From 0fb7b59f1983d436a98b4393e7c6bd1be69d1fd9 Mon Sep 17 00:00:00 2001 From: Matous Jobanek Date: Fri, 26 Apr 2019 07:35:37 +0200 Subject: [PATCH] feat(ODC-64): modify GS controller to validate credentials,repository and branch --- .../gitsource/gitsource_controller.go | 18 ++- .../gitsource/gitsource_controller_test.go | 128 +++++++++++++++++- 2 files changed, 141 insertions(+), 5 deletions(-) diff --git a/pkg/controller/gitsource/gitsource_controller.go b/pkg/controller/gitsource/gitsource_controller.go index a22229d..5a987f9 100644 --- a/pkg/controller/gitsource/gitsource_controller.go +++ b/pkg/controller/gitsource/gitsource_controller.go @@ -3,6 +3,7 @@ package gitsource import ( "context" "github.com/redhat-developer/devconsole-api/pkg/apis/devconsole/v1alpha1" + "github.com/redhat-developer/devconsole-git/pkg/git" "github.com/redhat-developer/devconsole-git/pkg/git/connection" gslog "github.com/redhat-developer/devconsole-git/pkg/log" "k8s.io/apimachinery/pkg/api/errors" @@ -81,7 +82,7 @@ func (r *ReconcileGitSource) Reconcile(request reconcile.Request) (reconcile.Res } gitSourceLogger := gslog.LogWithGSValues(reqLogger, gitSource) - isDirty := updateStatus(gitSourceLogger, gitSource) + isDirty := updateStatus(gitSourceLogger, r.client, request.Namespace, gitSource) if isDirty { err = r.client.Update(context.TODO(), gitSource) @@ -100,7 +101,7 @@ func (r *ReconcileGitSource) Reconcile(request reconcile.Request) (reconcile.Res return reconcile.Result{}, nil } -func updateStatus(log *gslog.GitSourceLogger, gitSource *v1alpha1.GitSource) (isDirty bool) { +func updateStatus(log *gslog.GitSourceLogger, client client.Client, namespace string, gitSource *v1alpha1.GitSource) (isDirty bool) { if gitSource.Status.Connection.State != "" { return false @@ -109,15 +110,24 @@ func updateStatus(log *gslog.GitSourceLogger, gitSource *v1alpha1.GitSource) (is gitSource.Status.State = v1alpha1.Initializing } - gitSource.Status.Connection = getConnectionStatus(log, gitSource) + gitSource.Status.Connection = getConnectionStatus(log, client, namespace, gitSource) return true } -func getConnectionStatus(log *gslog.GitSourceLogger, gitSource *v1alpha1.GitSource) v1alpha1.Connection { +func getConnectionStatus(log *gslog.GitSourceLogger, client client.Client, namespace string, gitSource *v1alpha1.GitSource) v1alpha1.Connection { if gitSource.Spec.SecretRef == nil { if validationError := connection.ValidateGitSource(log, gitSource); validationError != nil { return NewFailedConnection(validationError) } + return NewConnection("", "", v1alpha1.OK) + } + secret, err := git.NewGitSecret(client, namespace, gitSource) + if err != nil { + return NewConnection(err.Error(), v1alpha1.BadCredentials, v1alpha1.Failed) + } + validationError := connection.ValidateGitSourceWithSecret(log, gitSource, secret) + if validationError != nil { + return NewFailedConnection(validationError) } return NewConnection("", "", v1alpha1.OK) } diff --git a/pkg/controller/gitsource/gitsource_controller_test.go b/pkg/controller/gitsource/gitsource_controller_test.go index 5f9b945..babbc39 100644 --- a/pkg/controller/gitsource/gitsource_controller_test.go +++ b/pkg/controller/gitsource/gitsource_controller_test.go @@ -2,11 +2,14 @@ package gitsource import ( "context" + "fmt" "github.com/redhat-developer/devconsole-api/pkg/apis/devconsole/v1alpha1" + "github.com/redhat-developer/devconsole-git/pkg/git/repository" "github.com/redhat-developer/devconsole-git/pkg/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/h2non/gock.v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -73,6 +76,129 @@ func TestReconcileGitSourceConnectionSkip(t *testing.T) { assertGitSource(t, client, "", v1alpha1.OK, v1alpha1.ConnectionInternalFailure) } +func TestValidateGitHubInvalidSecret(t *testing.T) { + // given + defer gock.OffAll() + gock.New("https://api.github.com"). + Get("/user"). + Reply(401) + + secret := test.NewSecret(corev1.SecretTypeOpaque, map[string][]byte{"password": []byte("some-token")}) + gs := test.NewGitSource(test.WithURL(repoGitHubURL)) + gs.Spec.SecretRef = &v1alpha1.SecretRef{Name: test.SecretName} + reconciler, request, client := PrepareClient(test.GitSourceName, + test.RegisterGvkObject(v1alpha1.SchemeGroupVersion, gs), + test.RegisterGvkObject(corev1.SchemeGroupVersion, secret)) + + //when + _, err := reconciler.Reconcile(request) + + // then + require.NoError(t, err) + assertGitSource(t, client, v1alpha1.Initializing, v1alpha1.Failed, v1alpha1.BadCredentials) +} + +func TestValidateGitLabSecretAndUnavailableRepo(t *testing.T) { + // given + defer gock.OffAll() + gock.New("https://gitlab.com/"). + Get("/api/v4/user"). + Reply(200). + BodyString("{}") + gock.New("https://gitlab.com/"). + Get(fmt.Sprintf("/api/v4/projects/%s", repoIdentifier)). + Reply(404) + + secret := test.NewSecret(corev1.SecretTypeOpaque, map[string][]byte{"password": []byte("some-token")}) + gs := test.NewGitSource(test.WithURL("https://gitlab.com/" + repoIdentifier)) + gs.Spec.SecretRef = &v1alpha1.SecretRef{Name: test.SecretName} + reconciler, request, client := PrepareClient(test.GitSourceName, + test.RegisterGvkObject(v1alpha1.SchemeGroupVersion, gs), + test.RegisterGvkObject(corev1.SchemeGroupVersion, secret)) + + //when + _, err := reconciler.Reconcile(request) + + // then + require.NoError(t, err) + assertGitSource(t, client, v1alpha1.Initializing, v1alpha1.Failed, v1alpha1.RepoNotReachable) +} + +func TestValidateGitHubSecretAndAvailableRepoWithWrongBranch(t *testing.T) { + // given + defer gock.OffAll() + gock.New("https://api.github.com"). + Get("/user"). + Reply(200) + gock.New("https://api.github.com"). + Get(fmt.Sprintf("repos/%s", repoIdentifier)). + Reply(200) + gock.New("https://api.github.com"). + Get(fmt.Sprintf("repos/%s/branches/any", repoIdentifier)). + Reply(404) + + secret := test.NewSecret(corev1.SecretTypeOpaque, map[string][]byte{ + "username": []byte("username"), + "password": []byte("password")}) + gs := test.NewGitSource(test.WithURL(repoGitHubURL), test.WithRef("any")) + gs.Spec.SecretRef = &v1alpha1.SecretRef{Name: test.SecretName} + reconciler, request, client := PrepareClient(test.GitSourceName, + test.RegisterGvkObject(v1alpha1.SchemeGroupVersion, gs), + test.RegisterGvkObject(corev1.SchemeGroupVersion, secret)) + + //when + _, err := reconciler.Reconcile(request) + + // then + require.NoError(t, err) + assertGitSource(t, client, v1alpha1.Initializing, v1alpha1.Failed, v1alpha1.BranchNotFound) +} + +func TestValidateBitBucketWithCorrectData(t *testing.T) { + // given + defer gock.OffAll() + gock.New("https://api.bitbucket.org/"). + Get("/2.0/.*"). + Times(3). + Reply(200) + + secret := test.NewSecret(corev1.SecretTypeOpaque, map[string][]byte{"password": []byte("some-token")}) + gs := test.NewGitSource(test.WithURL("https://bitbucket.org/" + repoIdentifier)) + gs.Spec.SecretRef = &v1alpha1.SecretRef{Name: test.SecretName} + reconciler, request, client := PrepareClient(test.GitSourceName, + test.RegisterGvkObject(v1alpha1.SchemeGroupVersion, gs), + test.RegisterGvkObject(corev1.SchemeGroupVersion, secret)) + + // when + _, err := reconciler.Reconcile(request) + + // then + require.NoError(t, err) + assertGitSource(t, client, v1alpha1.Initializing, v1alpha1.OK, "") +} + +func TestValidateGenericGit(t *testing.T) { + //given + reset := test.RunBasicSshServer(t, "super-secret") + defer reset() + + dummyRepo := test.NewDummyGitRepo(t, repository.Master) + dummyRepo.Commit("main.go") + secret := test.NewSecret(corev1.SecretTypeOpaque, map[string][]byte{"password": []byte("super-secret")}) + gs := test.NewGitSource(test.WithURL("ssh://git@localhost:2222" + dummyRepo.Path)) + gs.Spec.SecretRef = &v1alpha1.SecretRef{Name: test.SecretName} + reconciler, request, client := PrepareClient(test.GitSourceName, + test.RegisterGvkObject(v1alpha1.SchemeGroupVersion, gs), + test.RegisterGvkObject(corev1.SchemeGroupVersion, secret)) + + // when + _, err := reconciler.Reconcile(request) + + // then + require.NoError(t, err) + assertGitSource(t, client, v1alpha1.Initializing, v1alpha1.OK, "") +} + func PrepareClient(name string, gvkObjects ...test.GvkObject) (*ReconcileGitSource, reconcile.Request, client.Client) { // Create a fake client to mock API calls. cl, s := test.PrepareClient(gvkObjects...) @@ -93,7 +219,7 @@ func assertGitSource(t *testing.T, client client.Client, gsState v1alpha1.State, require.NotNil(t, gitSource.Status.Connection) if reason != "" { - assert.Contains(t, gitSource.Status.Connection.Reason, reason) + assert.Equal(t, gitSource.Status.Connection.Reason, reason) assert.NotEmpty(t, gitSource.Status.Connection.Error) } else { assert.Empty(t, gitSource.Status.Connection.Error)