github.com/kubeshop/testkube@v1.17.23/internal/app/api/v1/repository.go (about)

     1  package v1
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/gofiber/fiber/v2"
    11  
    12  	"github.com/kubeshop/testkube/pkg/api/v1/testkube"
    13  	"github.com/kubeshop/testkube/pkg/executor/content"
    14  	"github.com/kubeshop/testkube/pkg/secret"
    15  )
    16  
    17  var (
    18  	// errWrongRepositoryType is wrong repository type error
    19  	errWrongRepositoryType = errors.New("type: Invalid repository type. Only 'git' supported")
    20  	// errAuthFailed is auth failed error
    21  	errAuthFailed = errors.New("username or token: Authentication failed. The provided credentials are not valid")
    22  	// errWrongAuthType is wrong auth type error
    23  	errWrongAuthType = errors.New("auth type: Invalid auth type. Only 'basic' or 'header' supported")
    24  	// errRepositoryNotFound is repository not found error
    25  	errRepositoryNotFound = errors.New("uri: The repository could not be found")
    26  	// errBranchNotFound is branch not found error
    27  	errBranchNotFound = errors.New("branch: The specified branch could not be found")
    28  	// errCommitNotFound is commit not found error
    29  	errCommitNotFound = errors.New("commit: The specified commit could not be found")
    30  	// errPathNotFound is path not found error
    31  	errPathNotFound = errors.New("path: The specified path could not be found")
    32  )
    33  
    34  func (s TestkubeAPI) ValidateRepositoryHandler() fiber.Handler {
    35  	return func(c *fiber.Ctx) error {
    36  		errPrefix := "failed to validate repository"
    37  		var request testkube.Repository
    38  		err := c.BodyParser(&request)
    39  		if err != nil {
    40  			return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: Unable to parse request: %w", errPrefix, err))
    41  		}
    42  
    43  		if request.Type_ != "git" {
    44  			return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: %w", errPrefix, errWrongRepositoryType))
    45  		}
    46  
    47  		switch testkube.GitAuthType(request.AuthType) {
    48  		case testkube.GitAuthTypeBasic, testkube.GitAuthTypeHeader, testkube.GitAuthTypeEmpty:
    49  		default:
    50  			return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: %w", errPrefix, errWrongAuthType))
    51  		}
    52  
    53  		if request.Username == "" && request.Token == "" {
    54  			var items = []struct {
    55  				secretRef *testkube.SecretRef
    56  				field     *string
    57  				name      string
    58  			}{
    59  				{
    60  					request.UsernameSecret,
    61  					&request.Username,
    62  					"username secret",
    63  				},
    64  				{
    65  					request.TokenSecret,
    66  					&request.Token,
    67  					"token secret",
    68  				},
    69  			}
    70  
    71  			for _, item := range items {
    72  				if item.secretRef != nil {
    73  					secretClient, err := secret.NewClient(item.secretRef.Namespace)
    74  					if err != nil {
    75  						return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: %s: Unable to get secret client: %w", errPrefix, item.name, err))
    76  					}
    77  
    78  					data, err := secretClient.Get(item.secretRef.Name)
    79  					if err != nil {
    80  						return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: %s: Unable to get secret from secret client: %w", errPrefix, item.name, err))
    81  					}
    82  
    83  					if value, ok := data[item.secretRef.Key]; !ok {
    84  						return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: %s: Missed key %s in secret %s/%s", errPrefix, item.name,
    85  							item.secretRef.Key, item.secretRef.Namespace, item.secretRef.Name))
    86  					} else {
    87  						*item.field = value
    88  					}
    89  				}
    90  			}
    91  		}
    92  
    93  		if request.CertificateSecret == "" {
    94  			dir, err := os.MkdirTemp("", "checkout")
    95  			if err != nil {
    96  				return s.Error(c, http.StatusInternalServerError, fmt.Errorf("%s: Could not create folder for git: %w", errPrefix, err))
    97  			}
    98  			defer os.RemoveAll(dir) // clean up
    99  
   100  			if request.Path != "" {
   101  				request.WorkingDir = "." // skip partial checkout for path validation
   102  			}
   103  
   104  			fetcher := content.NewFetcher(dir)
   105  			if _, err = fetcher.FetchGit(&request); err != nil {
   106  				message := strings.ToLower(err.Error())
   107  				switch {
   108  				case strings.Contains(message, "remote: not found"):
   109  					err = errRepositoryNotFound
   110  				case strings.Contains(message, "could not find remote branch"):
   111  					err = errBranchNotFound
   112  				case strings.Contains(message, "did not match any file") ||
   113  					strings.Contains(message, "couldn't find remote"):
   114  					err = errCommitNotFound
   115  				case strings.Contains(message, "authentication failed") ||
   116  					strings.Contains(message, "could not read username"):
   117  					err = errAuthFailed
   118  				case strings.Contains(message, "no such file or directory"):
   119  					err = errPathNotFound
   120  				}
   121  
   122  				return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: %w", errPrefix, err))
   123  			}
   124  		}
   125  
   126  		return c.SendStatus(http.StatusNoContent)
   127  	}
   128  }