github.com/argoproj/argo-cd/v2@v2.10.5/util/db/repository_secrets_test.go (about)

     1  package db
     2  
     3  import (
     4  	"strconv"
     5  	"testing"
     6  
     7  	"context"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"google.golang.org/grpc/codes"
    11  	"google.golang.org/grpc/status"
    12  	corev1 "k8s.io/api/core/v1"
    13  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/apimachinery/pkg/runtime"
    16  	"k8s.io/apimachinery/pkg/runtime/schema"
    17  	"k8s.io/apimachinery/pkg/watch"
    18  	"k8s.io/client-go/kubernetes/fake"
    19  	k8stesting "k8s.io/client-go/testing"
    20  
    21  	"github.com/argoproj/argo-cd/v2/common"
    22  	appsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
    23  	"github.com/argoproj/argo-cd/v2/util/settings"
    24  )
    25  
    26  func TestSecretsRepositoryBackend_CreateRepository(t *testing.T) {
    27  	type fixture struct {
    28  		clientSet   *fake.Clientset
    29  		repoBackend *secretsRepositoryBackend
    30  	}
    31  	repo := &appsv1.Repository{
    32  		Name:                  "ArgoCD",
    33  		Repo:                  "git@github.com:argoproj/argo-cd.git",
    34  		Username:              "someUsername",
    35  		Password:              "somePassword",
    36  		InsecureIgnoreHostKey: false,
    37  		EnableLFS:             true,
    38  	}
    39  	setupWithK8sObjects := func(objects ...runtime.Object) *fixture {
    40  
    41  		clientset := getClientset(map[string]string{}, objects...)
    42  		settingsMgr := settings.NewSettingsManager(context.Background(), clientset, testNamespace)
    43  		repoBackend := &secretsRepositoryBackend{db: &db{
    44  			ns:            testNamespace,
    45  			kubeclientset: clientset,
    46  			settingsMgr:   settingsMgr,
    47  		}}
    48  		return &fixture{
    49  			clientSet:   clientset,
    50  			repoBackend: repoBackend,
    51  		}
    52  	}
    53  	t.Run("will create repository successfully", func(t *testing.T) {
    54  		// given
    55  		t.Parallel()
    56  		f := setupWithK8sObjects()
    57  
    58  		// when
    59  		output, err := f.repoBackend.CreateRepository(context.Background(), repo)
    60  
    61  		// then
    62  		assert.NoError(t, err)
    63  		assert.Same(t, repo, output)
    64  
    65  		secret, err := f.clientSet.CoreV1().Secrets(testNamespace).Get(
    66  			context.TODO(),
    67  			RepoURLToSecretName(repoSecretPrefix, repo.Repo),
    68  			metav1.GetOptions{},
    69  		)
    70  		assert.NotNil(t, secret)
    71  		assert.NoError(t, err)
    72  
    73  		assert.Equal(t, common.AnnotationValueManagedByArgoCD, secret.Annotations[common.AnnotationKeyManagedBy])
    74  		assert.Equal(t, common.LabelValueSecretTypeRepository, secret.Labels[common.LabelKeySecretType])
    75  
    76  		assert.Equal(t, repo.Name, string(secret.Data["name"]))
    77  		assert.Equal(t, repo.Repo, string(secret.Data["url"]))
    78  		assert.Equal(t, repo.Username, string(secret.Data["username"]))
    79  		assert.Equal(t, repo.Password, string(secret.Data["password"]))
    80  		assert.Equal(t, "", string(secret.Data["insecureIgnoreHostKey"]))
    81  		assert.Equal(t, strconv.FormatBool(repo.EnableLFS), string(secret.Data["enableLfs"]))
    82  	})
    83  	t.Run("will return proper error if secret does not have expected label", func(t *testing.T) {
    84  		// given
    85  		t.Parallel()
    86  		secret := &corev1.Secret{}
    87  		repositoryToSecret(repo, secret)
    88  		delete(secret.Labels, common.LabelKeySecretType)
    89  		f := setupWithK8sObjects(secret)
    90  		f.clientSet.ReactionChain = nil
    91  		f.clientSet.AddReactor("create", "secrets", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
    92  			gr := schema.GroupResource{
    93  				Group:    "v1",
    94  				Resource: "secrets",
    95  			}
    96  			return true, nil, k8serrors.NewAlreadyExists(gr, "already exists")
    97  		})
    98  
    99  		// when
   100  		output, err := f.repoBackend.CreateRepository(context.Background(), repo)
   101  
   102  		// then
   103  		assert.Error(t, err)
   104  		assert.Nil(t, output)
   105  		status, ok := status.FromError(err)
   106  		assert.True(t, ok)
   107  		assert.Equal(t, codes.InvalidArgument, status.Code())
   108  	})
   109  	t.Run("will return proper error if secret already exists", func(t *testing.T) {
   110  		// given
   111  		t.Parallel()
   112  		secName := RepoURLToSecretName(repoSecretPrefix, repo.Repo)
   113  		secret := &corev1.Secret{
   114  			TypeMeta: metav1.TypeMeta{
   115  				Kind:       "Secret",
   116  				APIVersion: "v1",
   117  			},
   118  			ObjectMeta: metav1.ObjectMeta{
   119  				Name:      secName,
   120  				Namespace: "default",
   121  			},
   122  		}
   123  		repositoryToSecret(repo, secret)
   124  		f := setupWithK8sObjects(secret)
   125  		f.clientSet.ReactionChain = nil
   126  		f.clientSet.WatchReactionChain = nil
   127  		f.clientSet.AddReactor("create", "secrets", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
   128  			gr := schema.GroupResource{
   129  				Group:    "v1",
   130  				Resource: "secrets",
   131  			}
   132  			return true, nil, k8serrors.NewAlreadyExists(gr, "already exists")
   133  		})
   134  		watcher := watch.NewFakeWithChanSize(1, true)
   135  		watcher.Add(secret)
   136  		f.clientSet.AddWatchReactor("secrets", func(action k8stesting.Action) (handled bool, ret watch.Interface, err error) {
   137  			return true, watcher, nil
   138  		})
   139  
   140  		// when
   141  		output, err := f.repoBackend.CreateRepository(context.Background(), repo)
   142  
   143  		// then
   144  		assert.Error(t, err)
   145  		assert.Nil(t, output)
   146  		status, ok := status.FromError(err)
   147  		assert.True(t, ok)
   148  		assert.Equal(t, codes.AlreadyExists, status.Code())
   149  	})
   150  }
   151  
   152  func TestSecretsRepositoryBackend_GetRepository(t *testing.T) {
   153  	repoSecrets := []runtime.Object{
   154  		&corev1.Secret{
   155  			ObjectMeta: metav1.ObjectMeta{
   156  				Namespace:   testNamespace,
   157  				Name:        RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj/argo-cd.git"),
   158  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   159  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   160  			},
   161  			Data: map[string][]byte{
   162  				"name":     []byte("ArgoCD"),
   163  				"url":      []byte("git@github.com:argoproj/argo-cd.git"),
   164  				"username": []byte("someUsername"),
   165  				"password": []byte("somePassword"),
   166  			},
   167  		},
   168  		&corev1.Secret{
   169  			ObjectMeta: metav1.ObjectMeta{
   170  				Namespace: testNamespace,
   171  				Name:      "user-managed",
   172  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   173  			},
   174  			Data: map[string][]byte{
   175  				"name":     []byte("UserManagedRepo"),
   176  				"url":      []byte("git@github.com:argoproj/argoproj.git"),
   177  				"username": []byte("someOtherUsername"),
   178  				"password": []byte("someOtherPassword"),
   179  			},
   180  		},
   181  	}
   182  
   183  	clientset := getClientset(map[string]string{}, repoSecrets...)
   184  	testee := &secretsRepositoryBackend{db: &db{
   185  		ns:            testNamespace,
   186  		kubeclientset: clientset,
   187  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   188  	}}
   189  
   190  	repository, err := testee.GetRepository(context.TODO(), "git@github.com:argoproj/argo-cd.git")
   191  	assert.NoError(t, err)
   192  	assert.NotNil(t, repository)
   193  	assert.Equal(t, "ArgoCD", repository.Name)
   194  	assert.Equal(t, "git@github.com:argoproj/argo-cd.git", repository.Repo)
   195  	assert.Equal(t, "someUsername", repository.Username)
   196  	assert.Equal(t, "somePassword", repository.Password)
   197  
   198  	repository, err = testee.GetRepository(context.TODO(), "git@github.com:argoproj/argoproj.git")
   199  	assert.NoError(t, err)
   200  	assert.NotNil(t, repository)
   201  	assert.Equal(t, "UserManagedRepo", repository.Name)
   202  	assert.Equal(t, "git@github.com:argoproj/argoproj.git", repository.Repo)
   203  	assert.Equal(t, "someOtherUsername", repository.Username)
   204  	assert.Equal(t, "someOtherPassword", repository.Password)
   205  }
   206  
   207  func TestSecretsRepositoryBackend_ListRepositories(t *testing.T) {
   208  	repoSecrets := []runtime.Object{
   209  		&corev1.Secret{
   210  			ObjectMeta: metav1.ObjectMeta{
   211  				Namespace:   testNamespace,
   212  				Name:        RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj/argo-cd.git"),
   213  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   214  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   215  			},
   216  			Data: map[string][]byte{
   217  				"name":     []byte("ArgoCD"),
   218  				"url":      []byte("git@github.com:argoproj/argo-cd.git"),
   219  				"username": []byte("someUsername"),
   220  				"password": []byte("somePassword"),
   221  			},
   222  		},
   223  		&corev1.Secret{
   224  			ObjectMeta: metav1.ObjectMeta{
   225  				Namespace: testNamespace,
   226  				Name:      "user-managed",
   227  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   228  			},
   229  			Data: map[string][]byte{
   230  				"name":     []byte("UserManagedRepo"),
   231  				"url":      []byte("git@github.com:argoproj/argoproj.git"),
   232  				"username": []byte("someOtherUsername"),
   233  				"password": []byte("someOtherPassword"),
   234  			},
   235  		},
   236  	}
   237  
   238  	clientset := getClientset(map[string]string{}, repoSecrets...)
   239  	testee := &secretsRepositoryBackend{db: &db{
   240  		ns:            testNamespace,
   241  		kubeclientset: clientset,
   242  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   243  	}}
   244  
   245  	repositories, err := testee.ListRepositories(context.TODO(), nil)
   246  	assert.NoError(t, err)
   247  	assert.Len(t, repositories, 2)
   248  
   249  	for _, repository := range repositories {
   250  		if repository.Name == "ArgoCD" {
   251  			assert.Equal(t, "git@github.com:argoproj/argo-cd.git", repository.Repo)
   252  			assert.Equal(t, "someUsername", repository.Username)
   253  			assert.Equal(t, "somePassword", repository.Password)
   254  		} else if repository.Name == "UserManagedRepo" {
   255  			assert.Equal(t, "git@github.com:argoproj/argoproj.git", repository.Repo)
   256  			assert.Equal(t, "someOtherUsername", repository.Username)
   257  			assert.Equal(t, "someOtherPassword", repository.Password)
   258  		} else {
   259  			assert.Fail(t, "unexpected repository found in list")
   260  		}
   261  	}
   262  }
   263  
   264  func TestSecretsRepositoryBackend_UpdateRepository(t *testing.T) {
   265  	managedRepository := &appsv1.Repository{
   266  		Name:     "Managed",
   267  		Repo:     "git@github.com:argoproj/argo-cd.git",
   268  		Username: "someUsername",
   269  		Password: "somePassword",
   270  	}
   271  	userProvidedRepository := &appsv1.Repository{
   272  		Name:     "User Provided",
   273  		Repo:     "git@github.com:argoproj/argoproj.git",
   274  		Username: "someOtherUsername",
   275  		Password: "someOtherPassword",
   276  	}
   277  	newRepository := &appsv1.Repository{
   278  		Name:     "New",
   279  		Repo:     "git@github.com:argoproj/argo-events.git",
   280  		Username: "foo",
   281  		Password: "bar",
   282  	}
   283  
   284  	managedSecretName := RepoURLToSecretName(repoSecretPrefix, managedRepository.Repo)
   285  	newSecretName := RepoURLToSecretName(repoSecretPrefix, newRepository.Repo)
   286  	repoSecrets := []runtime.Object{
   287  		&corev1.Secret{
   288  			ObjectMeta: metav1.ObjectMeta{
   289  				Namespace:   testNamespace,
   290  				Name:        managedSecretName,
   291  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   292  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   293  			},
   294  			Data: map[string][]byte{
   295  				"name":     []byte(managedRepository.Name),
   296  				"url":      []byte(managedRepository.Repo),
   297  				"username": []byte(managedRepository.Username),
   298  				"password": []byte(managedRepository.Password),
   299  			},
   300  		},
   301  		&corev1.Secret{
   302  			ObjectMeta: metav1.ObjectMeta{
   303  				Namespace: testNamespace,
   304  				Name:      "user-managed",
   305  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   306  			},
   307  			Data: map[string][]byte{
   308  				"name":     []byte(userProvidedRepository.Name),
   309  				"url":      []byte(userProvidedRepository.Repo),
   310  				"username": []byte(userProvidedRepository.Username),
   311  				"password": []byte(userProvidedRepository.Password),
   312  			},
   313  		},
   314  	}
   315  
   316  	clientset := getClientset(map[string]string{}, repoSecrets...)
   317  	testee := &secretsRepositoryBackend{db: &db{
   318  		ns:            testNamespace,
   319  		kubeclientset: clientset,
   320  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   321  	}}
   322  
   323  	managedRepository.Username = "newUsername"
   324  	updateRepository, err := testee.UpdateRepository(context.TODO(), managedRepository)
   325  	assert.NoError(t, err)
   326  	assert.Same(t, managedRepository, updateRepository)
   327  	assert.Equal(t, managedRepository.Username, updateRepository.Username)
   328  
   329  	secret, err := clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), managedSecretName, metav1.GetOptions{})
   330  	assert.NoError(t, err)
   331  	assert.NotNil(t, secret)
   332  	assert.Equal(t, "newUsername", string(secret.Data["username"]))
   333  
   334  	userProvidedRepository.Username = "newOtherUsername"
   335  	updateRepository, err = testee.UpdateRepository(context.TODO(), userProvidedRepository)
   336  	assert.NoError(t, err)
   337  	assert.Same(t, userProvidedRepository, updateRepository)
   338  	assert.Equal(t, userProvidedRepository.Username, updateRepository.Username)
   339  
   340  	secret, err = clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), "user-managed", metav1.GetOptions{})
   341  	assert.NoError(t, err)
   342  	assert.NotNil(t, secret)
   343  	assert.Equal(t, "newOtherUsername", string(secret.Data["username"]))
   344  
   345  	updateRepository, err = testee.UpdateRepository(context.TODO(), newRepository)
   346  	assert.NoError(t, err)
   347  	assert.Same(t, newRepository, updateRepository)
   348  
   349  	secret, err = clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), newSecretName, metav1.GetOptions{})
   350  	assert.NoError(t, err)
   351  	assert.NotNil(t, secret)
   352  	assert.Equal(t, "foo", string(secret.Data["username"]))
   353  }
   354  
   355  func TestSecretsRepositoryBackend_DeleteRepository(t *testing.T) {
   356  	managedSecretName := RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj/argo-cd.git")
   357  	repoSecrets := []runtime.Object{
   358  		&corev1.Secret{
   359  			ObjectMeta: metav1.ObjectMeta{
   360  				Namespace:   testNamespace,
   361  				Name:        managedSecretName,
   362  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   363  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   364  			},
   365  			Data: map[string][]byte{
   366  				"name":     []byte("ArgoCD"),
   367  				"url":      []byte("git@github.com:argoproj/argo-cd.git"),
   368  				"username": []byte("someUsername"),
   369  				"password": []byte("somePassword"),
   370  			},
   371  		},
   372  		&corev1.Secret{
   373  			ObjectMeta: metav1.ObjectMeta{
   374  				Namespace: testNamespace,
   375  				Name:      "user-managed",
   376  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository},
   377  			},
   378  			Data: map[string][]byte{
   379  				"name":     []byte("UserManagedRepo"),
   380  				"url":      []byte("git@github.com:argoproj/argoproj.git"),
   381  				"username": []byte("someOtherUsername"),
   382  				"password": []byte("someOtherPassword"),
   383  			},
   384  		},
   385  	}
   386  
   387  	clientset := getClientset(map[string]string{}, repoSecrets...)
   388  	testee := &secretsRepositoryBackend{db: &db{
   389  		ns:            testNamespace,
   390  		kubeclientset: clientset,
   391  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   392  	}}
   393  
   394  	err := testee.DeleteRepository(context.TODO(), "git@github.com:argoproj/argo-cd.git")
   395  	assert.NoError(t, err)
   396  
   397  	_, err = clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), managedSecretName, metav1.GetOptions{})
   398  	assert.Error(t, err)
   399  
   400  	err = testee.DeleteRepository(context.TODO(), "git@github.com:argoproj/argoproj.git")
   401  	assert.NoError(t, err)
   402  
   403  	secret, err := clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), "user-managed", metav1.GetOptions{})
   404  	assert.NoError(t, err)
   405  	assert.NotNil(t, secret)
   406  	assert.Empty(t, secret.Labels[common.LabelValueSecretTypeRepository])
   407  }
   408  
   409  func TestSecretsRepositoryBackend_CreateRepoCreds(t *testing.T) {
   410  
   411  	clientset := getClientset(map[string]string{})
   412  	testee := &secretsRepositoryBackend{db: &db{
   413  		ns:            testNamespace,
   414  		kubeclientset: clientset,
   415  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   416  	}}
   417  
   418  	testCases := []struct {
   419  		name      string
   420  		repoCreds appsv1.RepoCreds
   421  		// Note: URL needs to be a different one for every testCase
   422  		// otherwise we would need to use the DeleteRepoCreds method to clean up the secret after each test
   423  		// which results in an unwanted dependency in a unit test
   424  	}{
   425  		{
   426  			name: "minimal_https_fields",
   427  			repoCreds: appsv1.RepoCreds{
   428  				URL:       "git@github.com:argoproj",
   429  				Username:  "someUsername",
   430  				Password:  "somePassword",
   431  				EnableOCI: true,
   432  			},
   433  		},
   434  		{
   435  			name: "with_proxy",
   436  			repoCreds: appsv1.RepoCreds{
   437  				URL:      "git@github.com:kubernetes",
   438  				Username: "anotherUsername",
   439  				Password: "anotherPassword",
   440  				Proxy:    "https://proxy.argoproj.io:3128",
   441  			},
   442  		},
   443  	}
   444  
   445  	for _, testCase := range testCases {
   446  		t.Run(testCase.name, func(t *testing.T) {
   447  			output, err := testee.CreateRepoCreds(context.TODO(), &testCase.repoCreds)
   448  			assert.NoError(t, err)
   449  			assert.Same(t, &testCase.repoCreds, output)
   450  
   451  			secret, err := clientset.CoreV1().Secrets(testNamespace).Get(
   452  				context.TODO(),
   453  				RepoURLToSecretName(credSecretPrefix, testCase.repoCreds.URL),
   454  				metav1.GetOptions{},
   455  			)
   456  			assert.NotNil(t, secret)
   457  			assert.NoError(t, err)
   458  
   459  			assert.Equal(t, common.AnnotationValueManagedByArgoCD, secret.Annotations[common.AnnotationKeyManagedBy])
   460  			assert.Equal(t, common.LabelValueSecretTypeRepoCreds, secret.Labels[common.LabelKeySecretType])
   461  
   462  			// check every possible field of the secret if it has the same (default) value as the repoCred struct
   463  			// non-string fields must be parsed so that their default value matches the one of the corresponding type
   464  			assert.Equal(t, testCase.repoCreds.URL, string(secret.Data["url"]))
   465  			assert.Equal(t, testCase.repoCreds.Username, string(secret.Data["username"]))
   466  			assert.Equal(t, testCase.repoCreds.Password, string(secret.Data["password"]))
   467  			if enableOCI, err := strconv.ParseBool(string(secret.Data["githubAppPrivateKey"])); err == nil {
   468  				assert.Equal(t, strconv.FormatBool(testCase.repoCreds.EnableOCI), enableOCI)
   469  			}
   470  			assert.Equal(t, testCase.repoCreds.SSHPrivateKey, string(secret.Data["sshPrivateKey"]))
   471  			assert.Equal(t, testCase.repoCreds.TLSClientCertData, string(secret.Data["tlsClientCertData"]))
   472  			assert.Equal(t, testCase.repoCreds.TLSClientCertKey, string(secret.Data["tlsClientCertKey"]))
   473  			assert.Equal(t, testCase.repoCreds.Type, string(secret.Data["type"]))
   474  			assert.Equal(t, testCase.repoCreds.GithubAppPrivateKey, string(secret.Data["githubAppPrivateKey"]))
   475  			if githubAppPrivateKey, err := strconv.ParseInt(string(secret.Data["githubAppPrivateKey"]), 10, 64); err == nil {
   476  				assert.Equal(t, testCase.repoCreds.GithubAppId, githubAppPrivateKey)
   477  			}
   478  			if githubAppID, err := strconv.ParseInt(string(secret.Data["githubAppId"]), 10, 64); err == nil {
   479  				assert.Equal(t, testCase.repoCreds.GithubAppInstallationId, githubAppID)
   480  			}
   481  			assert.Equal(t, testCase.repoCreds.GitHubAppEnterpriseBaseURL, string(secret.Data["githubAppEnterpriseUrl"]))
   482  			assert.Equal(t, testCase.repoCreds.Proxy, string(secret.Data["proxy"]))
   483  
   484  		})
   485  	}
   486  }
   487  
   488  func TestSecretsRepositoryBackend_GetRepoCreds(t *testing.T) {
   489  	repoCredSecrets := []runtime.Object{
   490  		&corev1.Secret{
   491  			ObjectMeta: metav1.ObjectMeta{
   492  				Namespace:   testNamespace,
   493  				Name:        RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj"),
   494  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   495  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   496  			},
   497  			Data: map[string][]byte{
   498  				"url":      []byte("git@github.com:argoproj"),
   499  				"username": []byte("someUsername"),
   500  				"password": []byte("somePassword"),
   501  			},
   502  		},
   503  		&corev1.Secret{
   504  			ObjectMeta: metav1.ObjectMeta{
   505  				Namespace: testNamespace,
   506  				Name:      "user-managed",
   507  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   508  			},
   509  			Data: map[string][]byte{
   510  				"url":      []byte("git@gitlab.com"),
   511  				"username": []byte("someOtherUsername"),
   512  				"password": []byte("someOtherPassword"),
   513  			},
   514  		},
   515  	}
   516  
   517  	clientset := getClientset(map[string]string{}, repoCredSecrets...)
   518  	testee := &secretsRepositoryBackend{db: &db{
   519  		ns:            testNamespace,
   520  		kubeclientset: clientset,
   521  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   522  	}}
   523  
   524  	repoCred, err := testee.GetRepoCreds(context.TODO(), "git@github.com:argoproj")
   525  	assert.NoError(t, err)
   526  	assert.NotNil(t, repoCred)
   527  	assert.Equal(t, "git@github.com:argoproj", repoCred.URL)
   528  	assert.Equal(t, "someUsername", repoCred.Username)
   529  	assert.Equal(t, "somePassword", repoCred.Password)
   530  
   531  	repoCred, err = testee.GetRepoCreds(context.TODO(), "git@gitlab.com")
   532  	assert.NoError(t, err)
   533  	assert.NotNil(t, repoCred)
   534  	assert.Equal(t, "git@gitlab.com", repoCred.URL)
   535  	assert.Equal(t, "someOtherUsername", repoCred.Username)
   536  	assert.Equal(t, "someOtherPassword", repoCred.Password)
   537  }
   538  
   539  func TestSecretsRepositoryBackend_ListRepoCreds(t *testing.T) {
   540  	repoCredSecrets := []runtime.Object{
   541  		&corev1.Secret{
   542  			ObjectMeta: metav1.ObjectMeta{
   543  				Namespace:   testNamespace,
   544  				Name:        RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj"),
   545  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   546  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   547  			},
   548  			Data: map[string][]byte{
   549  				"url":      []byte("git@github.com:argoproj"),
   550  				"username": []byte("someUsername"),
   551  				"password": []byte("somePassword"),
   552  			},
   553  		},
   554  		&corev1.Secret{
   555  			ObjectMeta: metav1.ObjectMeta{
   556  				Namespace: testNamespace,
   557  				Name:      "user-managed",
   558  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   559  			},
   560  			Data: map[string][]byte{
   561  				"url":      []byte("git@gitlab.com"),
   562  				"username": []byte("someOtherUsername"),
   563  				"password": []byte("someOtherPassword"),
   564  			},
   565  		},
   566  	}
   567  
   568  	clientset := getClientset(map[string]string{}, repoCredSecrets...)
   569  	testee := &secretsRepositoryBackend{db: &db{
   570  		ns:            testNamespace,
   571  		kubeclientset: clientset,
   572  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   573  	}}
   574  
   575  	repoCreds, err := testee.ListRepoCreds(context.TODO())
   576  	assert.NoError(t, err)
   577  	assert.Len(t, repoCreds, 2)
   578  	assert.Contains(t, repoCreds, "git@github.com:argoproj")
   579  	assert.Contains(t, repoCreds, "git@gitlab.com")
   580  }
   581  
   582  func TestSecretsRepositoryBackend_UpdateRepoCreds(t *testing.T) {
   583  	managedCreds := &appsv1.RepoCreds{
   584  		URL:      "git@github.com:argoproj",
   585  		Username: "someUsername",
   586  		Password: "somePassword",
   587  	}
   588  	userProvidedCreds := &appsv1.RepoCreds{
   589  		URL:      "git@gitlab.com",
   590  		Username: "someOtherUsername",
   591  		Password: "someOtherPassword",
   592  	}
   593  	newCreds := &appsv1.RepoCreds{
   594  		URL:      "git@github.com:foobar",
   595  		Username: "foo",
   596  		Password: "bar",
   597  	}
   598  
   599  	managedCredsName := RepoURLToSecretName(credSecretPrefix, managedCreds.URL)
   600  	newCredsName := RepoURLToSecretName(credSecretPrefix, newCreds.URL)
   601  	repoCredSecrets := []runtime.Object{
   602  		&corev1.Secret{
   603  			ObjectMeta: metav1.ObjectMeta{
   604  				Namespace:   testNamespace,
   605  				Name:        managedCredsName,
   606  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   607  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   608  			},
   609  			Data: map[string][]byte{
   610  				"url":      []byte(managedCreds.URL),
   611  				"username": []byte(managedCreds.Username),
   612  				"password": []byte(managedCreds.Password),
   613  			},
   614  		},
   615  		&corev1.Secret{
   616  			ObjectMeta: metav1.ObjectMeta{
   617  				Namespace: testNamespace,
   618  				Name:      "user-managed",
   619  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   620  			},
   621  			Data: map[string][]byte{
   622  				"url":      []byte(userProvidedCreds.URL),
   623  				"username": []byte(userProvidedCreds.Username),
   624  				"password": []byte(userProvidedCreds.Password),
   625  			},
   626  		},
   627  	}
   628  
   629  	clientset := getClientset(map[string]string{}, repoCredSecrets...)
   630  	testee := &secretsRepositoryBackend{db: &db{
   631  		ns:            testNamespace,
   632  		kubeclientset: clientset,
   633  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   634  	}}
   635  
   636  	managedCreds.Username = "newUsername"
   637  	updateRepoCreds, err := testee.UpdateRepoCreds(context.TODO(), managedCreds)
   638  	assert.NoError(t, err)
   639  	assert.NotSame(t, managedCreds, updateRepoCreds)
   640  	assert.Equal(t, managedCreds.Username, updateRepoCreds.Username)
   641  
   642  	secret, err := clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), managedCredsName, metav1.GetOptions{})
   643  	assert.NoError(t, err)
   644  	assert.NotNil(t, secret)
   645  	assert.Equal(t, "newUsername", string(secret.Data["username"]))
   646  
   647  	userProvidedCreds.Username = "newOtherUsername"
   648  	updateRepoCreds, err = testee.UpdateRepoCreds(context.TODO(), userProvidedCreds)
   649  	assert.NoError(t, err)
   650  	assert.NotSame(t, userProvidedCreds, updateRepoCreds)
   651  	assert.Equal(t, userProvidedCreds.Username, updateRepoCreds.Username)
   652  
   653  	secret, err = clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), "user-managed", metav1.GetOptions{})
   654  	assert.NoError(t, err)
   655  	assert.NotNil(t, secret)
   656  	assert.Equal(t, "newOtherUsername", string(secret.Data["username"]))
   657  
   658  	updateRepoCreds, err = testee.UpdateRepoCreds(context.TODO(), newCreds)
   659  	assert.NoError(t, err)
   660  	assert.Same(t, newCreds, updateRepoCreds)
   661  
   662  	secret, err = clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), newCredsName, metav1.GetOptions{})
   663  	assert.NoError(t, err)
   664  	assert.NotNil(t, secret)
   665  	assert.Equal(t, "foo", string(secret.Data["username"]))
   666  }
   667  
   668  func TestSecretsRepositoryBackend_DeleteRepoCreds(t *testing.T) {
   669  	managedSecretName := RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj/argo-cd.git")
   670  	repoSecrets := []runtime.Object{
   671  		&corev1.Secret{
   672  			ObjectMeta: metav1.ObjectMeta{
   673  				Namespace:   testNamespace,
   674  				Name:        managedSecretName,
   675  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   676  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   677  			},
   678  			Data: map[string][]byte{
   679  				"url":      []byte("git@github.com:argoproj"),
   680  				"username": []byte("someUsername"),
   681  				"password": []byte("somePassword"),
   682  			},
   683  		},
   684  		&corev1.Secret{
   685  			ObjectMeta: metav1.ObjectMeta{
   686  				Namespace: testNamespace,
   687  				Name:      "user-managed",
   688  				Labels:    map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   689  			},
   690  			Data: map[string][]byte{
   691  				"url":      []byte("git@gitlab.com"),
   692  				"username": []byte("someOtherUsername"),
   693  				"password": []byte("someOtherPassword"),
   694  			},
   695  		},
   696  	}
   697  
   698  	clientset := getClientset(map[string]string{}, repoSecrets...)
   699  	testee := &secretsRepositoryBackend{db: &db{
   700  		ns:            testNamespace,
   701  		kubeclientset: clientset,
   702  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   703  	}}
   704  
   705  	err := testee.DeleteRepoCreds(context.TODO(), "git@github.com:argoproj")
   706  	assert.NoError(t, err)
   707  
   708  	_, err = clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), managedSecretName, metav1.GetOptions{})
   709  	assert.Error(t, err)
   710  
   711  	err = testee.DeleteRepoCreds(context.TODO(), "git@gitlab.com")
   712  	assert.NoError(t, err)
   713  
   714  	secret, err := clientset.CoreV1().Secrets(testNamespace).Get(context.TODO(), "user-managed", metav1.GetOptions{})
   715  	assert.NoError(t, err)
   716  	assert.NotNil(t, secret)
   717  	assert.Empty(t, secret.Labels[common.LabelValueSecretTypeRepoCreds])
   718  }
   719  
   720  func TestSecretsRepositoryBackend_GetAllHelmRepoCreds(t *testing.T) {
   721  	repoCredSecrets := []runtime.Object{
   722  		&corev1.Secret{
   723  			ObjectMeta: metav1.ObjectMeta{
   724  				Namespace:   testNamespace,
   725  				Name:        RepoURLToSecretName(repoSecretPrefix, "git@github.com:argoproj"),
   726  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   727  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   728  			},
   729  			Data: map[string][]byte{
   730  				"url":      []byte("git@github.com:argoproj"),
   731  				"username": []byte("someUsername"),
   732  				"password": []byte("somePassword"),
   733  				"type":     []byte("helm"),
   734  			},
   735  		},
   736  		&corev1.Secret{
   737  			ObjectMeta: metav1.ObjectMeta{
   738  				Namespace:   testNamespace,
   739  				Name:        RepoURLToSecretName(repoSecretPrefix, "git@gitlab.com"),
   740  				Annotations: map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD},
   741  				Labels:      map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds},
   742  			},
   743  			Data: map[string][]byte{
   744  				"url":      []byte("git@gitlab.com"),
   745  				"username": []byte("someOtherUsername"),
   746  				"password": []byte("someOtherPassword"),
   747  				"type":     []byte("git"),
   748  			},
   749  		},
   750  	}
   751  
   752  	clientset := getClientset(map[string]string{}, repoCredSecrets...)
   753  	testee := &secretsRepositoryBackend{db: &db{
   754  		ns:            testNamespace,
   755  		kubeclientset: clientset,
   756  		settingsMgr:   settings.NewSettingsManager(context.TODO(), clientset, testNamespace),
   757  	}}
   758  
   759  	repoCreds, err := testee.GetAllHelmRepoCreds(context.TODO())
   760  	assert.NoError(t, err)
   761  	assert.Len(t, repoCreds, 1)
   762  }
   763  
   764  func TestRepoCredsToSecret(t *testing.T) {
   765  	s := &corev1.Secret{}
   766  	creds := &appsv1.RepoCreds{
   767  		URL:                        "URL",
   768  		Username:                   "Username",
   769  		Password:                   "Password",
   770  		SSHPrivateKey:              "SSHPrivateKey",
   771  		EnableOCI:                  true,
   772  		TLSClientCertData:          "TLSClientCertData",
   773  		TLSClientCertKey:           "TLSClientCertKey",
   774  		Type:                       "Type",
   775  		GithubAppPrivateKey:        "GithubAppPrivateKey",
   776  		GithubAppId:                123,
   777  		GithubAppInstallationId:    456,
   778  		GitHubAppEnterpriseBaseURL: "GitHubAppEnterpriseBaseURL",
   779  	}
   780  	repoCredsToSecret(creds, s)
   781  	assert.Equal(t, []byte(creds.URL), s.Data["url"])
   782  	assert.Equal(t, []byte(creds.Username), s.Data["username"])
   783  	assert.Equal(t, []byte(creds.Password), s.Data["password"])
   784  	assert.Equal(t, []byte(creds.SSHPrivateKey), s.Data["sshPrivateKey"])
   785  	assert.Equal(t, []byte(strconv.FormatBool(creds.EnableOCI)), s.Data["enableOCI"])
   786  	assert.Equal(t, []byte(creds.TLSClientCertData), s.Data["tlsClientCertData"])
   787  	assert.Equal(t, []byte(creds.TLSClientCertKey), s.Data["tlsClientCertKey"])
   788  	assert.Equal(t, []byte(creds.Type), s.Data["type"])
   789  	assert.Equal(t, []byte(creds.GithubAppPrivateKey), s.Data["githubAppPrivateKey"])
   790  	assert.Equal(t, []byte(strconv.FormatInt(creds.GithubAppId, 10)), s.Data["githubAppID"])
   791  	assert.Equal(t, []byte(strconv.FormatInt(creds.GithubAppInstallationId, 10)), s.Data["githubAppInstallationID"])
   792  	assert.Equal(t, []byte(creds.GitHubAppEnterpriseBaseURL), s.Data["githubAppEnterpriseBaseUrl"])
   793  	assert.Equal(t, map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD}, s.Annotations)
   794  	assert.Equal(t, map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepoCreds}, s.Labels)
   795  }