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 }