11//
2- // Copyright 2022 Red Hat, Inc.
2+ // Copyright 2023 Red Hat, Inc.
33//
44// Licensed under the Apache License, Version 2.0 (the "License");
55// you may not use this file except in compliance with the License.
@@ -17,12 +17,9 @@ package util
1717
1818import (
1919 "fmt"
20- gitpkg "github.com/go-git/go-git/v5"
21- "github.com/go-git/go-git/v5/plumbing"
22- githttp "github.com/go-git/go-git/v5/plumbing/transport/http"
23- "net/http"
2420 "net/url"
2521 "os"
22+ "os/exec"
2623 "path/filepath"
2724 "strings"
2825)
@@ -39,27 +36,18 @@ const (
3936)
4037
4138type GitUrl struct {
42- Protocol string
43- Host string
44- Owner string
45- Repo string
46- Branch string
47- Path string
48- token string
49- IsFile bool
39+ Protocol string // URL scheme
40+ Host string // URL domain name
41+ Owner string // name of the repo owner
42+ Repo string // name of the repo
43+ Branch string // branch name
44+ Path string // path to a directory or file in the repo
45+ token string // used for authenticating a private repo
46+ IsFile bool // defines if the URL points to a file in the repo
5047}
5148
5249// ParseGitUrl extracts information from a GitHub, GitLab, or Bitbucket url
53- // A client is used to check whether the url is private or public, and sets
54- // the providers personal access token from the environment variable
5550func ParseGitUrl (fullUrl string ) (GitUrl , error ) {
56- var c = http.Client {
57- Timeout : HTTPRequestResponseTimeout ,
58- }
59- return parseGitUrlWithClient (fullUrl , c )
60- }
61-
62- func parseGitUrlWithClient (fullUrl string , c http.Client ) (GitUrl , error ) {
6351 var g GitUrl
6452
6553 err := ValidateURL (fullUrl )
@@ -77,24 +65,25 @@ func parseGitUrlWithClient(fullUrl string, c http.Client) (GitUrl, error) {
7765 }
7866
7967 if parsedUrl .Host == RawGitHubHost || parsedUrl .Host == GitHubHost {
80- g , err = parseGitHubUrl (g , parsedUrl , c )
68+ err = g . parseGitHubUrl (parsedUrl )
8169 } else if parsedUrl .Host == GitLabHost {
82- g , err = parseGitLabUrl (g , parsedUrl , c )
70+ err = g . parseGitLabUrl (parsedUrl )
8371 } else if parsedUrl .Host == BitbucketHost {
84- g , err = parseBitbucketUrl (g , parsedUrl , c )
72+ err = g . parseBitbucketUrl (parsedUrl )
8573 } else {
8674 err = fmt .Errorf ("url host should be a valid GitHub, GitLab, or Bitbucket host; received: %s" , parsedUrl .Host )
8775 }
8876
8977 return g , err
9078}
9179
92- func parseGitHubUrl (g GitUrl , url * url.URL , c http. Client ) ( GitUrl , error ) {
80+ func (g * GitUrl ) parseGitHubUrl ( url * url.URL ) error {
9381 var splitUrl []string
9482 var err error
9583
9684 g .Protocol = url .Scheme
9785 g .Host = url .Host
86+ g .token = os .Getenv (GitHubToken )
9887
9988 if g .Host == RawGitHubHost {
10089 g .IsFile = true
@@ -131,20 +120,17 @@ func parseGitHubUrl(g GitUrl, url *url.URL, c http.Client) (GitUrl, error) {
131120 }
132121 }
133122
134- if ! isGitUrlPublic (g , c ) {
135- g .token = os .Getenv (GitHubToken )
136- }
137-
138- return g , err
123+ return err
139124}
140125
141- func parseGitLabUrl (g GitUrl , url * url.URL , c http. Client ) ( GitUrl , error ) {
126+ func (g * GitUrl ) parseGitLabUrl ( url * url.URL ) error {
142127 var splitFile , splitOrg []string
143128 var err error
144129
145130 g .Protocol = url .Scheme
146131 g .Host = url .Host
147132 g .IsFile = false
133+ g .token = os .Getenv (GitLabToken )
148134
149135 // GitLab urls contain a '-' separating the root of the repo
150136 // and the path to a file or directory
@@ -175,20 +161,17 @@ func parseGitLabUrl(g GitUrl, url *url.URL, c http.Client) (GitUrl, error) {
175161 }
176162 }
177163
178- if ! isGitUrlPublic (g , c ) {
179- g .token = os .Getenv (GitLabToken )
180- }
181-
182- return g , err
164+ return err
183165}
184166
185- func parseBitbucketUrl (g GitUrl , url * url.URL , c http. Client ) ( GitUrl , error ) {
167+ func (g * GitUrl ) parseBitbucketUrl ( url * url.URL ) error {
186168 var splitUrl []string
187169 var err error
188170
189171 g .Protocol = url .Scheme
190172 g .Host = url .Host
191173 g .IsFile = false
174+ g .token = os .Getenv (BitbucketToken )
192175
193176 splitUrl = strings .SplitN (url .Path [1 :], "/" , 5 )
194177 if len (splitUrl ) < 2 {
@@ -215,61 +198,51 @@ func parseBitbucketUrl(g GitUrl, url *url.URL, c http.Client) (GitUrl, error) {
215198 }
216199 }
217200
218- if ! isGitUrlPublic (g , c ) {
219- g .token = os .Getenv (BitbucketToken )
220- }
221-
222- return g , err
201+ return err
223202}
224203
225- func isGitUrlPublic (g GitUrl , c http.Client ) bool {
226- host := g .Host
227- if host == RawGitHubHost {
228- host = GitHubHost
229- }
230-
231- repo := fmt .Sprintf ("%s://%s/%s/%s" , g .Protocol , host , g .Owner , g .Repo )
232-
233- if res , err := c .Get (repo ); err != nil {
234- return false
235- } else if res .StatusCode == http .StatusOK {
236- return true
237- }
238- return false
239- }
240-
241- // CloneGitRepo clones a GitHub Repo to a destination directory
204+ // CloneGitRepo clones a git repo to a destination directory
242205func CloneGitRepo (g GitUrl , destDir string ) error {
243- var cloneOptions * gitpkg.CloneOptions
244-
245206 host := g .Host
246207 if host == RawGitHubHost {
247208 host = GitHubHost
248209 }
249210
211+ isPublic := true
250212 repoUrl := fmt .Sprintf ("%s://%s/%s/%s.git" , g .Protocol , host , g .Owner , g .Repo )
251- branch := fmt .Sprintf ("refs/heads/%s" , g .Branch )
252213
253- cloneOptions = & gitpkg.CloneOptions {
254- URL : repoUrl ,
255- ReferenceName : plumbing .ReferenceName (branch ),
256- SingleBranch : true ,
257- Depth : 1 ,
214+ params := HTTPRequestParams {
215+ URL : repoUrl ,
258216 }
259217
260- if g .token != "" {
261- cloneOptions .Auth = & githttp.BasicAuth {
262- // go-git auth allows username to be anything except
263- // an empty string for GitHub and GitLab, however requires
264- // for Bitbucket to be "x-token-auth"
265- Username : "x-token-auth" ,
266- Password : g .token ,
218+ // check if the git repo is public
219+ _ , err := HTTPGetRequest (params , 0 )
220+ if err != nil {
221+ // private git repo requires authentication
222+ isPublic = false
223+ repoUrl = fmt .Sprintf ("%s://token:%s@%s/%s/%s.git" , g .Protocol , g .token , host , g .Owner , g .Repo )
224+ if g .Host == BitbucketHost {
225+ repoUrl = fmt .Sprintf ("%s://x-token-auth:%s@%s/%s/%s.git" , g .Protocol , g .token , host , g .Owner , g .Repo )
267226 }
268227 }
269228
270- _ , err := gitpkg .PlainClone (destDir , false , cloneOptions )
229+ /* #nosec G204 -- user input is processed into an expected format for the git clone command */
230+ c := exec .Command ("git" , "clone" , repoUrl , destDir )
231+ c .Dir = destDir
232+
233+ // set env to skip authentication prompt and directly error out
234+ c .Env = os .Environ ()
235+ c .Env = append (c .Env , "GIT_TERMINAL_PROMPT=0" , "GIT_ASKPASS=/bin/echo" )
236+
237+ _ , err = c .CombinedOutput ()
271238 if err != nil {
272- return err
239+ if ! isPublic {
240+ if g .token == "" {
241+ return fmt .Errorf ("failed to clone repo without a token, ensure that a token is set if the repo is private. error: %v" , err )
242+ }
243+ return fmt .Errorf ("failed to clone repo with token, ensure that the url and token is correct. error: %v" , err )
244+ }
245+ return fmt .Errorf ("failed to clone repo, ensure that the url is correct. error: %v" , err )
273246 }
274247
275248 return nil
0 commit comments