github.com/argoproj/argo-cd/v3@v3.2.1/util/db/repository_secrets.go (about)

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	log "github.com/sirupsen/logrus"
     9  	"google.golang.org/grpc/codes"
    10  	"google.golang.org/grpc/status"
    11  	corev1 "k8s.io/api/core/v1"
    12  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  
    15  	"github.com/argoproj/argo-cd/v3/common"
    16  	appsv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    17  	"github.com/argoproj/argo-cd/v3/util/git"
    18  )
    19  
    20  var _ repositoryBackend = &secretsRepositoryBackend{}
    21  
    22  type secretsRepositoryBackend struct {
    23  	db *db
    24  	// If true, the backend will manage write only credentials. If false, it will manage only read credentials.
    25  	writeCreds bool
    26  }
    27  
    28  func (s *secretsRepositoryBackend) CreateRepository(ctx context.Context, repository *appsv1.Repository) (*appsv1.Repository, error) {
    29  	secName := RepoURLToSecretName(repoSecretPrefix, repository.Repo, repository.Project)
    30  
    31  	repositorySecret := &corev1.Secret{
    32  		ObjectMeta: metav1.ObjectMeta{
    33  			Name: secName,
    34  		},
    35  	}
    36  
    37  	updatedSecret := s.repositoryToSecret(repository, repositorySecret)
    38  
    39  	_, err := s.db.createSecret(ctx, updatedSecret)
    40  	if err != nil {
    41  		if apierrors.IsAlreadyExists(err) {
    42  			hasLabel, err := s.hasRepoTypeLabel(secName)
    43  			if err != nil {
    44  				return nil, status.Error(codes.Internal, err.Error())
    45  			}
    46  			if !hasLabel {
    47  				msg := fmt.Sprintf("secret %q doesn't have the proper %q label: please fix the secret or delete it", secName, common.LabelKeySecretType)
    48  				return nil, status.Error(codes.InvalidArgument, msg)
    49  			}
    50  			return nil, status.Errorf(codes.AlreadyExists, "repository %q already exists", repository.Repo)
    51  		}
    52  		return nil, err
    53  	}
    54  
    55  	return repository, s.db.settingsMgr.ResyncInformers()
    56  }
    57  
    58  // hasRepoTypeLabel will verify if a secret with the given name exists. If so it will check if
    59  // the secret has the proper label argocd.argoproj.io/secret-type defined. Will return true if
    60  // the label is found and false otherwise. Will return false if no secret is found with the given
    61  // name.
    62  func (s *secretsRepositoryBackend) hasRepoTypeLabel(secretName string) (bool, error) {
    63  	noCache := make(map[string]*corev1.Secret)
    64  	sec, err := s.db.getSecret(secretName, noCache)
    65  	if err != nil {
    66  		if apierrors.IsNotFound(err) {
    67  			return false, nil
    68  		}
    69  		return false, err
    70  	}
    71  	_, ok := sec.GetLabels()[common.LabelKeySecretType]
    72  	if ok {
    73  		return true, nil
    74  	}
    75  	return false, nil
    76  }
    77  
    78  func (s *secretsRepositoryBackend) GetRepoCredsBySecretName(_ context.Context, name string) (*appsv1.RepoCreds, error) {
    79  	secret, err := s.db.getSecret(name, map[string]*corev1.Secret{})
    80  	if err != nil {
    81  		return nil, fmt.Errorf("failed to get secret %s: %w", name, err)
    82  	}
    83  	return s.secretToRepoCred(secret)
    84  }
    85  
    86  func (s *secretsRepositoryBackend) GetRepository(_ context.Context, repoURL, project string) (*appsv1.Repository, error) {
    87  	secret, err := s.getRepositorySecret(repoURL, project, true)
    88  	if err != nil {
    89  		if status.Code(err) == codes.NotFound {
    90  			return &appsv1.Repository{Repo: repoURL}, nil
    91  		}
    92  
    93  		return nil, err
    94  	}
    95  
    96  	repository, err := secretToRepository(secret)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	return repository, err
   102  }
   103  
   104  func (s *secretsRepositoryBackend) ListRepositories(_ context.Context, repoType *string) ([]*appsv1.Repository, error) {
   105  	var repos []*appsv1.Repository
   106  
   107  	secrets, err := s.db.listSecretsByType(s.getSecretType())
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	for _, secret := range secrets {
   113  		r, err := secretToRepository(secret)
   114  		if err != nil {
   115  			if r == nil {
   116  				return nil, err
   117  			}
   118  			modifiedTime := metav1.Now()
   119  			r.ConnectionState = appsv1.ConnectionState{
   120  				Status:     appsv1.ConnectionStatusFailed,
   121  				Message:    "Configuration error - please check the server logs",
   122  				ModifiedAt: &modifiedTime,
   123  			}
   124  
   125  			log.Warnf("Error while parsing repository secret '%s': %v", secret.Name, err)
   126  		}
   127  
   128  		if repoType == nil || *repoType == r.Type {
   129  			repos = append(repos, r)
   130  		}
   131  	}
   132  
   133  	return repos, nil
   134  }
   135  
   136  func (s *secretsRepositoryBackend) UpdateRepository(ctx context.Context, repository *appsv1.Repository) (*appsv1.Repository, error) {
   137  	repositorySecret, err := s.getRepositorySecret(repository.Repo, repository.Project, false)
   138  	if err != nil {
   139  		if status.Code(err) == codes.NotFound {
   140  			return s.CreateRepository(ctx, repository)
   141  		}
   142  		return nil, err
   143  	}
   144  
   145  	updatedSecret := s.repositoryToSecret(repository, repositorySecret)
   146  
   147  	_, err = s.db.kubeclientset.CoreV1().Secrets(s.db.ns).Update(ctx, updatedSecret, metav1.UpdateOptions{})
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	return repository, s.db.settingsMgr.ResyncInformers()
   153  }
   154  
   155  func (s *secretsRepositoryBackend) DeleteRepository(ctx context.Context, repoURL, project string) error {
   156  	secret, err := s.getRepositorySecret(repoURL, project, false)
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	if err := s.db.deleteSecret(ctx, secret); err != nil {
   162  		return err
   163  	}
   164  
   165  	return s.db.settingsMgr.ResyncInformers()
   166  }
   167  
   168  func (s *secretsRepositoryBackend) RepositoryExists(_ context.Context, repoURL, project string, allowFallback bool) (bool, error) {
   169  	secret, err := s.getRepositorySecret(repoURL, project, allowFallback)
   170  	if err != nil {
   171  		if status.Code(err) == codes.NotFound {
   172  			return false, nil
   173  		}
   174  
   175  		return false, fmt.Errorf("failed to get repository secret for %q: %w", repoURL, err)
   176  	}
   177  
   178  	return secret != nil, nil
   179  }
   180  
   181  func (s *secretsRepositoryBackend) CreateRepoCreds(ctx context.Context, repoCreds *appsv1.RepoCreds) (*appsv1.RepoCreds, error) {
   182  	secName := RepoURLToSecretName(credSecretPrefix, repoCreds.URL, "")
   183  
   184  	repoCredsSecret := &corev1.Secret{
   185  		ObjectMeta: metav1.ObjectMeta{
   186  			Name: secName,
   187  		},
   188  	}
   189  
   190  	updatedSecret := s.repoCredsToSecret(repoCreds, repoCredsSecret)
   191  
   192  	_, err := s.db.createSecret(ctx, updatedSecret)
   193  	if err != nil {
   194  		if apierrors.IsAlreadyExists(err) {
   195  			return nil, status.Errorf(codes.AlreadyExists, "repository credentials %q already exists", repoCreds.URL)
   196  		}
   197  		return nil, err
   198  	}
   199  
   200  	return repoCreds, s.db.settingsMgr.ResyncInformers()
   201  }
   202  
   203  func (s *secretsRepositoryBackend) GetRepoCreds(_ context.Context, repoURL string) (*appsv1.RepoCreds, error) {
   204  	secret, err := s.getRepoCredsSecret(repoURL)
   205  	if err != nil {
   206  		if status.Code(err) == codes.NotFound {
   207  			return nil, nil
   208  		}
   209  
   210  		return nil, err
   211  	}
   212  
   213  	return s.secretToRepoCred(secret)
   214  }
   215  
   216  func (s *secretsRepositoryBackend) ListRepoCreds(_ context.Context) ([]string, error) {
   217  	var repoURLs []string
   218  
   219  	secrets, err := s.db.listSecretsByType(common.LabelValueSecretTypeRepoCreds)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	for _, secret := range secrets {
   225  		repoURLs = append(repoURLs, string(secret.Data["url"]))
   226  	}
   227  
   228  	return repoURLs, nil
   229  }
   230  
   231  func (s *secretsRepositoryBackend) UpdateRepoCreds(ctx context.Context, repoCreds *appsv1.RepoCreds) (*appsv1.RepoCreds, error) {
   232  	repoCredsSecret, err := s.getRepoCredsSecret(repoCreds.URL)
   233  	if err != nil {
   234  		if status.Code(err) == codes.NotFound {
   235  			return s.CreateRepoCreds(ctx, repoCreds)
   236  		}
   237  		return nil, err
   238  	}
   239  
   240  	updatedSecret := s.repoCredsToSecret(repoCreds, repoCredsSecret)
   241  
   242  	repoCredsSecret, err = s.db.kubeclientset.CoreV1().Secrets(s.db.ns).Update(ctx, updatedSecret, metav1.UpdateOptions{})
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  
   247  	updatedRepoCreds, err := s.secretToRepoCred(repoCredsSecret)
   248  	if err != nil {
   249  		return nil, err
   250  	}
   251  
   252  	return updatedRepoCreds, s.db.settingsMgr.ResyncInformers()
   253  }
   254  
   255  func (s *secretsRepositoryBackend) DeleteRepoCreds(ctx context.Context, name string) error {
   256  	secret, err := s.getRepoCredsSecret(name)
   257  	if err != nil {
   258  		return err
   259  	}
   260  
   261  	if err := s.db.deleteSecret(ctx, secret); err != nil {
   262  		return err
   263  	}
   264  
   265  	return s.db.settingsMgr.ResyncInformers()
   266  }
   267  
   268  func (s *secretsRepositoryBackend) RepoCredsExists(_ context.Context, repoURL string) (bool, error) {
   269  	_, err := s.getRepoCredsSecret(repoURL)
   270  	if err != nil {
   271  		if status.Code(err) == codes.NotFound {
   272  			return false, nil
   273  		}
   274  
   275  		return false, err
   276  	}
   277  
   278  	return true, nil
   279  }
   280  
   281  func (s *secretsRepositoryBackend) GetAllHelmRepoCreds(_ context.Context) ([]*appsv1.RepoCreds, error) {
   282  	var helmRepoCreds []*appsv1.RepoCreds
   283  
   284  	secrets, err := s.db.listSecretsByType(common.LabelValueSecretTypeRepoCreds)
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  
   289  	for _, secret := range secrets {
   290  		if strings.EqualFold(string(secret.Data["type"]), "helm") {
   291  			repoCreds, err := s.secretToRepoCred(secret)
   292  			if err != nil {
   293  				return nil, err
   294  			}
   295  
   296  			helmRepoCreds = append(helmRepoCreds, repoCreds)
   297  		}
   298  	}
   299  
   300  	return helmRepoCreds, nil
   301  }
   302  
   303  func (s *secretsRepositoryBackend) GetAllOCIRepoCreds(_ context.Context) ([]*appsv1.RepoCreds, error) {
   304  	var ociRepoCreds []*appsv1.RepoCreds
   305  
   306  	secrets, err := s.db.listSecretsByType(common.LabelValueSecretTypeRepoCreds)
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  
   311  	for _, secret := range secrets {
   312  		if strings.EqualFold(string(secret.Data["type"]), "oci") {
   313  			repoCreds, err := s.secretToRepoCred(secret)
   314  			if err != nil {
   315  				return nil, err
   316  			}
   317  
   318  			ociRepoCreds = append(ociRepoCreds, repoCreds)
   319  		}
   320  	}
   321  
   322  	return ociRepoCreds, nil
   323  }
   324  
   325  func secretToRepository(secret *corev1.Secret) (*appsv1.Repository, error) {
   326  	secretCopy := secret.DeepCopy()
   327  
   328  	repository := &appsv1.Repository{
   329  		Name:                       string(secretCopy.Data["name"]),
   330  		Repo:                       string(secretCopy.Data["url"]),
   331  		Username:                   string(secretCopy.Data["username"]),
   332  		Password:                   string(secretCopy.Data["password"]),
   333  		BearerToken:                string(secretCopy.Data["bearerToken"]),
   334  		SSHPrivateKey:              string(secretCopy.Data["sshPrivateKey"]),
   335  		TLSClientCertData:          string(secretCopy.Data["tlsClientCertData"]),
   336  		TLSClientCertKey:           string(secretCopy.Data["tlsClientCertKey"]),
   337  		Type:                       string(secretCopy.Data["type"]),
   338  		GithubAppPrivateKey:        string(secretCopy.Data["githubAppPrivateKey"]),
   339  		GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
   340  		Proxy:                      string(secretCopy.Data["proxy"]),
   341  		NoProxy:                    string(secretCopy.Data["noProxy"]),
   342  		Project:                    string(secretCopy.Data["project"]),
   343  		GCPServiceAccountKey:       string(secretCopy.Data["gcpServiceAccountKey"]),
   344  	}
   345  
   346  	insecureIgnoreHostKey, err := boolOrFalse(secretCopy, "insecureIgnoreHostKey")
   347  	if err != nil {
   348  		return repository, err
   349  	}
   350  	repository.InsecureIgnoreHostKey = insecureIgnoreHostKey
   351  
   352  	insecure, err := boolOrFalse(secretCopy, "insecure")
   353  	if err != nil {
   354  		return repository, err
   355  	}
   356  	repository.Insecure = insecure
   357  
   358  	enableLfs, err := boolOrFalse(secretCopy, "enableLfs")
   359  	if err != nil {
   360  		return repository, err
   361  	}
   362  	repository.EnableLFS = enableLfs
   363  
   364  	enableOCI, err := boolOrFalse(secretCopy, "enableOCI")
   365  	if err != nil {
   366  		return repository, err
   367  	}
   368  	repository.EnableOCI = enableOCI
   369  
   370  	insecureOCIForceHTTP, err := boolOrFalse(secretCopy, "insecureOCIForceHttp")
   371  	if err != nil {
   372  		return repository, err
   373  	}
   374  	repository.InsecureOCIForceHttp = insecureOCIForceHTTP
   375  
   376  	githubAppID, err := intOrZero(secretCopy, "githubAppID")
   377  	if err != nil {
   378  		return repository, err
   379  	}
   380  	repository.GithubAppId = githubAppID
   381  
   382  	githubAppInstallationID, err := intOrZero(secretCopy, "githubAppInstallationID")
   383  	if err != nil {
   384  		return repository, err
   385  	}
   386  	repository.GithubAppInstallationId = githubAppInstallationID
   387  
   388  	forceBasicAuth, err := boolOrFalse(secretCopy, "forceHttpBasicAuth")
   389  	if err != nil {
   390  		return repository, err
   391  	}
   392  	repository.ForceHttpBasicAuth = forceBasicAuth
   393  
   394  	useAzureWorkloadIdentity, err := boolOrFalse(secretCopy, "useAzureWorkloadIdentity")
   395  	if err != nil {
   396  		return repository, err
   397  	}
   398  	repository.UseAzureWorkloadIdentity = useAzureWorkloadIdentity
   399  
   400  	return repository, nil
   401  }
   402  
   403  func (s *secretsRepositoryBackend) repositoryToSecret(repository *appsv1.Repository, secret *corev1.Secret) *corev1.Secret {
   404  	secretCopy := secret.DeepCopy()
   405  
   406  	if secretCopy.Data == nil {
   407  		secretCopy.Data = make(map[string][]byte)
   408  	}
   409  
   410  	updateSecretString(secretCopy, "name", repository.Name)
   411  	updateSecretString(secretCopy, "project", repository.Project)
   412  	updateSecretString(secretCopy, "url", repository.Repo)
   413  	updateSecretString(secretCopy, "username", repository.Username)
   414  	updateSecretString(secretCopy, "password", repository.Password)
   415  	updateSecretString(secretCopy, "bearerToken", repository.BearerToken)
   416  	updateSecretString(secretCopy, "sshPrivateKey", repository.SSHPrivateKey)
   417  	updateSecretBool(secretCopy, "enableOCI", repository.EnableOCI)
   418  	updateSecretBool(secretCopy, "insecureOCIForceHttp", repository.InsecureOCIForceHttp)
   419  	updateSecretString(secretCopy, "tlsClientCertData", repository.TLSClientCertData)
   420  	updateSecretString(secretCopy, "tlsClientCertKey", repository.TLSClientCertKey)
   421  	updateSecretString(secretCopy, "type", repository.Type)
   422  	updateSecretString(secretCopy, "githubAppPrivateKey", repository.GithubAppPrivateKey)
   423  	updateSecretInt(secretCopy, "githubAppID", repository.GithubAppId)
   424  	updateSecretInt(secretCopy, "githubAppInstallationID", repository.GithubAppInstallationId)
   425  	updateSecretString(secretCopy, "githubAppEnterpriseBaseUrl", repository.GitHubAppEnterpriseBaseURL)
   426  	updateSecretBool(secretCopy, "insecureIgnoreHostKey", repository.InsecureIgnoreHostKey)
   427  	updateSecretBool(secretCopy, "insecure", repository.Insecure)
   428  	updateSecretBool(secretCopy, "enableLfs", repository.EnableLFS)
   429  	updateSecretString(secretCopy, "proxy", repository.Proxy)
   430  	updateSecretString(secretCopy, "noProxy", repository.NoProxy)
   431  	updateSecretString(secretCopy, "gcpServiceAccountKey", repository.GCPServiceAccountKey)
   432  	updateSecretBool(secretCopy, "forceHttpBasicAuth", repository.ForceHttpBasicAuth)
   433  	updateSecretBool(secretCopy, "useAzureWorkloadIdentity", repository.UseAzureWorkloadIdentity)
   434  	addSecretMetadata(secretCopy, s.getSecretType())
   435  
   436  	return secretCopy
   437  }
   438  
   439  func (s *secretsRepositoryBackend) secretToRepoCred(secret *corev1.Secret) (*appsv1.RepoCreds, error) {
   440  	secretCopy := secret.DeepCopy()
   441  
   442  	repository := &appsv1.RepoCreds{
   443  		URL:                        string(secretCopy.Data["url"]),
   444  		Username:                   string(secretCopy.Data["username"]),
   445  		Password:                   string(secretCopy.Data["password"]),
   446  		BearerToken:                string(secretCopy.Data["bearerToken"]),
   447  		SSHPrivateKey:              string(secretCopy.Data["sshPrivateKey"]),
   448  		TLSClientCertData:          string(secretCopy.Data["tlsClientCertData"]),
   449  		TLSClientCertKey:           string(secretCopy.Data["tlsClientCertKey"]),
   450  		Type:                       string(secretCopy.Data["type"]),
   451  		GithubAppPrivateKey:        string(secretCopy.Data["githubAppPrivateKey"]),
   452  		GitHubAppEnterpriseBaseURL: string(secretCopy.Data["githubAppEnterpriseBaseUrl"]),
   453  		GCPServiceAccountKey:       string(secretCopy.Data["gcpServiceAccountKey"]),
   454  		Proxy:                      string(secretCopy.Data["proxy"]),
   455  		NoProxy:                    string(secretCopy.Data["noProxy"]),
   456  	}
   457  
   458  	enableOCI, err := boolOrFalse(secretCopy, "enableOCI")
   459  	if err != nil {
   460  		return repository, err
   461  	}
   462  	repository.EnableOCI = enableOCI
   463  
   464  	insecureOCIForceHTTP, err := boolOrFalse(secretCopy, "insecureOCIForceHttp")
   465  	if err != nil {
   466  		return repository, err
   467  	}
   468  	repository.InsecureOCIForceHttp = insecureOCIForceHTTP
   469  
   470  	githubAppID, err := intOrZero(secretCopy, "githubAppID")
   471  	if err != nil {
   472  		return repository, err
   473  	}
   474  	repository.GithubAppId = githubAppID
   475  
   476  	githubAppInstallationID, err := intOrZero(secretCopy, "githubAppInstallationID")
   477  	if err != nil {
   478  		return repository, err
   479  	}
   480  	repository.GithubAppInstallationId = githubAppInstallationID
   481  
   482  	forceBasicAuth, err := boolOrFalse(secretCopy, "forceHttpBasicAuth")
   483  	if err != nil {
   484  		return repository, err
   485  	}
   486  	repository.ForceHttpBasicAuth = forceBasicAuth
   487  
   488  	useAzureWorkloadIdentity, err := boolOrFalse(secretCopy, "useAzureWorkloadIdentity")
   489  	if err != nil {
   490  		return repository, err
   491  	}
   492  	repository.UseAzureWorkloadIdentity = useAzureWorkloadIdentity
   493  
   494  	return repository, nil
   495  }
   496  
   497  func (s *secretsRepositoryBackend) repoCredsToSecret(repoCreds *appsv1.RepoCreds, secret *corev1.Secret) *corev1.Secret {
   498  	secretCopy := secret.DeepCopy()
   499  
   500  	if secretCopy.Data == nil {
   501  		secretCopy.Data = make(map[string][]byte)
   502  	}
   503  
   504  	updateSecretString(secretCopy, "url", repoCreds.URL)
   505  	updateSecretString(secretCopy, "username", repoCreds.Username)
   506  	updateSecretString(secretCopy, "password", repoCreds.Password)
   507  	updateSecretString(secretCopy, "bearerToken", repoCreds.BearerToken)
   508  	updateSecretString(secretCopy, "sshPrivateKey", repoCreds.SSHPrivateKey)
   509  	updateSecretBool(secretCopy, "enableOCI", repoCreds.EnableOCI)
   510  	updateSecretBool(secretCopy, "insecureOCIForceHttp", repoCreds.InsecureOCIForceHttp)
   511  	updateSecretString(secretCopy, "tlsClientCertData", repoCreds.TLSClientCertData)
   512  	updateSecretString(secretCopy, "tlsClientCertKey", repoCreds.TLSClientCertKey)
   513  	updateSecretString(secretCopy, "type", repoCreds.Type)
   514  	updateSecretString(secretCopy, "githubAppPrivateKey", repoCreds.GithubAppPrivateKey)
   515  	updateSecretInt(secretCopy, "githubAppID", repoCreds.GithubAppId)
   516  	updateSecretInt(secretCopy, "githubAppInstallationID", repoCreds.GithubAppInstallationId)
   517  	updateSecretString(secretCopy, "githubAppEnterpriseBaseUrl", repoCreds.GitHubAppEnterpriseBaseURL)
   518  	updateSecretString(secretCopy, "gcpServiceAccountKey", repoCreds.GCPServiceAccountKey)
   519  	updateSecretString(secretCopy, "proxy", repoCreds.Proxy)
   520  	updateSecretString(secretCopy, "noProxy", repoCreds.NoProxy)
   521  	updateSecretBool(secretCopy, "forceHttpBasicAuth", repoCreds.ForceHttpBasicAuth)
   522  	updateSecretBool(secretCopy, "useAzureWorkloadIdentity", repoCreds.UseAzureWorkloadIdentity)
   523  	addSecretMetadata(secretCopy, s.getRepoCredSecretType())
   524  
   525  	return secretCopy
   526  }
   527  
   528  func (s *secretsRepositoryBackend) getRepositorySecret(repoURL, project string, allowFallback bool) (*corev1.Secret, error) {
   529  	secrets, err := s.db.listSecretsByType(s.getSecretType())
   530  	if err != nil {
   531  		return nil, fmt.Errorf("failed to list repository secrets: %w", err)
   532  	}
   533  
   534  	var foundSecret *corev1.Secret
   535  	for _, secret := range secrets {
   536  		if git.SameURL(string(secret.Data["url"]), repoURL) {
   537  			projectSecret := string(secret.Data["project"])
   538  			if project == projectSecret {
   539  				if foundSecret != nil {
   540  					log.Warnf("Found multiple credentials for repoURL: %s", repoURL)
   541  				}
   542  
   543  				return secret, nil
   544  			}
   545  
   546  			if projectSecret == "" && allowFallback {
   547  				if foundSecret != nil {
   548  					log.Warnf("Found multiple credentials for repoURL: %s", repoURL)
   549  				}
   550  
   551  				foundSecret = secret
   552  			}
   553  		}
   554  	}
   555  
   556  	if foundSecret != nil {
   557  		return foundSecret, nil
   558  	}
   559  
   560  	return nil, status.Errorf(codes.NotFound, "repository %q not found", repoURL)
   561  }
   562  
   563  func (s *secretsRepositoryBackend) getRepoCredsSecret(repoURL string) (*corev1.Secret, error) {
   564  	secrets, err := s.db.listSecretsByType(s.getRepoCredSecretType())
   565  	if err != nil {
   566  		return nil, err
   567  	}
   568  
   569  	index := s.getRepositoryCredentialIndex(secrets, repoURL)
   570  	if index < 0 {
   571  		return nil, status.Errorf(codes.NotFound, "repository credentials %q not found", repoURL)
   572  	}
   573  
   574  	return secrets[index], nil
   575  }
   576  
   577  func (s *secretsRepositoryBackend) getRepositoryCredentialIndex(repoCredentials []*corev1.Secret, repoURL string) int {
   578  	maxLen, idx := 0, -1
   579  	repoURL = git.NormalizeGitURL(repoURL)
   580  	for i, cred := range repoCredentials {
   581  		credURL := git.NormalizeGitURL(string(cred.Data["url"]))
   582  		if strings.HasPrefix(repoURL, credURL) {
   583  			if len(credURL) == maxLen {
   584  				log.Warnf("Found multiple credentials for repoURL: %s", repoURL)
   585  			}
   586  			if len(credURL) > maxLen {
   587  				maxLen = len(credURL)
   588  				idx = i
   589  			}
   590  		}
   591  	}
   592  	return idx
   593  }
   594  
   595  func (s *secretsRepositoryBackend) getSecretType() string {
   596  	if s.writeCreds {
   597  		return common.LabelValueSecretTypeRepositoryWrite
   598  	}
   599  	return common.LabelValueSecretTypeRepository
   600  }
   601  
   602  func (s *secretsRepositoryBackend) getRepoCredSecretType() string {
   603  	if s.writeCreds {
   604  		return common.LabelValueSecretTypeRepoCredsWrite
   605  	}
   606  	return common.LabelValueSecretTypeRepoCreds
   607  }