github.com/jenkins-x/jx/v2@v2.1.155/pkg/cmd/step/git/credentials/step_git_credentials.go (about) 1 package credentials 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 10 "github.com/jenkins-x/jx/v2/pkg/auth" 11 "github.com/jenkins-x/jx/v2/pkg/cmd/opts/step" 12 "github.com/jenkins-x/jx/v2/pkg/gits/credentialhelper" 13 "github.com/pkg/errors" 14 15 "github.com/jenkins-x/jx/v2/pkg/cmd/helper" 16 17 "github.com/jenkins-x/jx-logging/pkg/log" 18 "github.com/jenkins-x/jx/v2/pkg/cmd/opts" 19 "github.com/jenkins-x/jx/v2/pkg/cmd/templates" 20 "github.com/jenkins-x/jx/v2/pkg/util" 21 "github.com/spf13/cobra" 22 23 apierrors "k8s.io/apimachinery/pkg/api/errors" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 ) 26 27 const ( 28 optionOutputFile = "output" 29 // Deprecated 30 optionGitHubAppOwner = "github-app-owner" 31 optionRepoOwner = "repo-owner" 32 ) 33 34 // StepGitCredentialsOptions contains the command line flags 35 type StepGitCredentialsOptions struct { 36 step.StepOptions 37 38 OutputFile string 39 // Deprecated 40 GitHubAppOwner string 41 RepoOwner string 42 GitKind string 43 CredentialsSecret string 44 CredentialHelper bool 45 } 46 47 var ( 48 StepGitCredentialsLong = templates.LongDesc(` 49 This pipeline step generates a Git credentials file for the current Git provider secrets 50 51 `) 52 53 StepGitCredentialsExample = templates.Examples(` 54 # generate the Git credentials file in the canonical location 55 jx step git credentials 56 57 # generate the Git credentials to a output file 58 jx step git credentials -o /tmp/mycreds 59 60 # respond to a gitcredentials request 61 jx step git credentials --credential-helper 62 `) 63 ) 64 65 func NewCmdStepGitCredentials(commonOpts *opts.CommonOptions) *cobra.Command { 66 options := StepGitCredentialsOptions{ 67 StepOptions: step.StepOptions{ 68 CommonOptions: commonOpts, 69 }, 70 } 71 cmd := &cobra.Command{ 72 Use: "credentials", 73 Short: "Creates the Git credentials file for the current pipeline", 74 Long: StepGitCredentialsLong, 75 Example: StepGitCredentialsExample, 76 Run: func(cmd *cobra.Command, args []string) { 77 options.Cmd = cmd 78 options.Args = args 79 err := options.Run() 80 helper.CheckErr(err) 81 }, 82 } 83 cmd.Flags().StringVarP(&options.OutputFile, optionOutputFile, "o", "", "The output file name") 84 cmd.Flags().StringVarP(&options.GitHubAppOwner, optionGitHubAppOwner, "g", "", "Deprecated - The owner (organisation or user name) if using GitHub App based tokens") 85 cmd.Flags().StringVarP(&options.RepoOwner, optionRepoOwner, "r", "", "The owner (organisation or user name) if using GitHub App based tokens") 86 87 cmd.Flags().StringVarP(&options.CredentialsSecret, "credentials-secret", "s", "", "The secret name to read the credentials from") 88 cmd.Flags().StringVarP(&options.GitKind, "git-kind", "", "", "The git kind. e.g. github, bitbucketserver etc") 89 cmd.Flags().BoolVar(&options.CredentialHelper, "credential-helper", false, "respond to a gitcredentials request") 90 91 return cmd 92 } 93 94 func (o *StepGitCredentialsOptions) Run() error { 95 if os.Getenv("JX_CREDENTIALS_FROM_SECRET") != "" { 96 log.Logger().Infof("Overriding CredentialsSecret from env var JX_CREDENTIALS_FROM_SECRET") 97 o.CredentialsSecret = os.Getenv("JX_CREDENTIALS_FROM_SECRET") 98 } 99 100 outFile, err := o.determineOutputFile() 101 if err != nil { 102 return err 103 } 104 105 if o.CredentialsSecret != "" { 106 // get secret 107 kubeClient, ns, err := o.KubeClientAndDevNamespace() 108 if err != nil { 109 return err 110 } 111 112 secret, err := kubeClient.CoreV1().Secrets(ns).Get(o.CredentialsSecret, metav1.GetOptions{}) 113 if err != nil { 114 if apierrors.IsNotFound(err) { 115 return errors.Wrapf(err, "failed to find secret '%s' in namespace '%s'", o.CredentialsSecret, ns) 116 } 117 return errors.Wrapf(err, "failed to read secret '%s' in namespace '%s'", o.CredentialsSecret, ns) 118 } 119 120 creds, err := credentialhelper.CreateGitCredentialFromURL(string(secret.Data["url"]), string(secret.Data["token"]), string(secret.Data["user"])) 121 if err != nil { 122 return errors.Wrap(err, "failed to create git credentials") 123 } 124 125 return o.createGitCredentialsFile(outFile, []credentialhelper.GitCredential{creds}) 126 } 127 128 gha, err := o.IsGitHubAppMode() 129 if err != nil { 130 return err 131 } 132 133 if o.RepoOwner == "" && o.GitHubAppOwner != "" { 134 log.Logger().Warnf("The flag --%s is deprecated, use --%s instead", optionGitHubAppOwner, optionRepoOwner) 135 o.RepoOwner = o.GitHubAppOwner 136 } 137 138 if gha && o.RepoOwner == "" { 139 log.Logger().Infof("this command does nothing if using github app mode and no %s option specified", optionRepoOwner) 140 return nil 141 } 142 143 var authConfigSvc auth.ConfigService 144 if gha { 145 authConfigSvc, err = o.GitAuthConfigServiceGitHubAppMode(o.GitKind) 146 if err != nil { 147 return errors.Wrap(err, "when creating auth config service using GitAuthConfigServiceGitHubAppMode") 148 } 149 } else { 150 authConfigSvc, err = o.GitAuthConfigService() 151 if err != nil { 152 return errors.Wrap(err, "when creating auth config service using GitAuthConfigService") 153 } 154 } 155 156 credentials, err := o.CreateGitCredentialsFromAuthService(authConfigSvc, gha) 157 if err != nil { 158 return errors.Wrap(err, "creating git credentials") 159 } 160 161 if o.CredentialHelper { 162 helper, err := credentialhelper.CreateGitCredentialsHelper(os.Stdin, os.Stdout, credentials) 163 if err != nil { 164 return errors.Wrap(err, "unable to create git credential helper") 165 } 166 // the credential helper operation (get|store|remove) is passed as last argument to the helper 167 err = helper.Run(os.Args[len(os.Args)-1]) 168 if err != nil { 169 return err 170 } 171 return nil 172 } 173 174 outFile, err = o.determineOutputFile() 175 if err != nil { 176 return errors.Wrap(err, "unable to determine for git credentials") 177 } 178 179 return o.createGitCredentialsFile(outFile, credentials) 180 } 181 182 // GitCredentialsFileData takes the given git credentials and writes them into a byte array. 183 func (o *StepGitCredentialsOptions) GitCredentialsFileData(credentials []credentialhelper.GitCredential) ([]byte, error) { 184 var buffer bytes.Buffer 185 for _, gitCredential := range credentials { 186 u, err := gitCredential.URL() 187 if err != nil { 188 log.Logger().Warnf("Ignoring incomplete git credentials %q", gitCredential) 189 continue 190 } 191 192 buffer.WriteString(u.String() + "\n") 193 // Write the https protocol in case only https is set for completeness 194 if u.Scheme == "http" { 195 u.Scheme = "https" 196 buffer.WriteString(u.String() + "\n") 197 } 198 } 199 200 return buffer.Bytes(), nil 201 } 202 203 func (o *StepGitCredentialsOptions) determineOutputFile() (string, error) { 204 outFile := o.OutputFile 205 if outFile == "" { 206 outFile = util.GitCredentialsFile() 207 } 208 209 dir, _ := filepath.Split(outFile) 210 if dir != "" { 211 err := os.MkdirAll(dir, util.DefaultWritePermissions) 212 if err != nil { 213 return "", err 214 } 215 } 216 return outFile, nil 217 } 218 219 // CreateGitCredentialsFileFromUsernameAndToken creates the git credentials into file using the provided username, token & url 220 func (o *StepGitCredentialsOptions) createGitCredentialsFile(fileName string, credentials []credentialhelper.GitCredential) error { 221 data, err := o.GitCredentialsFileData(credentials) 222 if err != nil { 223 return errors.Wrap(err, "creating git credentials") 224 } 225 226 if err := ioutil.WriteFile(fileName, data, util.DefaultWritePermissions); err != nil { 227 return fmt.Errorf("failed to write to %s: %s", fileName, err) 228 } 229 log.Logger().Infof("Generated Git credentials file %s", util.ColorInfo(fileName)) 230 return nil 231 } 232 233 // CreateGitCredentialsFromAuthService creates the git credentials using the auth config service 234 func (o *StepGitCredentialsOptions) CreateGitCredentialsFromAuthService(authConfigSvc auth.ConfigService, githubAppEnabled bool) ([]credentialhelper.GitCredential, error) { 235 var credentialList []credentialhelper.GitCredential 236 237 cfg := authConfigSvc.Config() 238 if cfg == nil { 239 return nil, errors.New("no git auth config found") 240 } 241 242 for _, server := range cfg.Servers { 243 var auths []*auth.UserAuth 244 if githubAppEnabled && o.RepoOwner != "" { 245 auths = server.Users 246 } else { 247 gitAuth := server.CurrentAuth() 248 if gitAuth == nil { 249 continue 250 } else { 251 auths = append(auths, gitAuth) 252 } 253 } 254 for _, gitAuth := range auths { 255 if githubAppEnabled && o.RepoOwner != "" && gitAuth.GithubAppOwner != o.RepoOwner { 256 continue 257 } 258 username := gitAuth.Username 259 password := gitAuth.ApiToken 260 if password == "" { 261 password = gitAuth.BearerToken 262 } 263 if password == "" { 264 password = gitAuth.Password 265 } 266 if username == "" || password == "" { 267 log.Logger().Warnf("Empty auth config for git service URL %q", server.URL) 268 continue 269 } 270 271 credential, err := credentialhelper.CreateGitCredentialFromURL(server.URL, username, password) 272 if err != nil { 273 return nil, errors.Wrapf(err, "invalid git auth information") 274 } 275 276 credentialList = append(credentialList, credential) 277 } 278 } 279 return credentialList, nil 280 }