Fix bug in GitHub token access (#490)

Co-authored-by: Azeem Shaikh <azeems@google.com>
This commit is contained in:
Azeem Shaikh 2021-05-22 11:24:53 -07:00 committed by GitHub
parent 26d17907a6
commit 0c636b0f5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 24 deletions

1
go.mod
View File

@ -28,7 +28,6 @@ require (
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
google.golang.org/api v0.46.0 // indirect
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384 // indirect

View File

@ -15,35 +15,36 @@
package roundtripper
import (
"context"
"fmt"
"net/http"
"sync"
"sync/atomic"
"golang.org/x/oauth2"
)
func MakeOAuthTransport(ctx context.Context, accessTokens []string) http.RoundTripper {
tokenSource := &tokenPool{
tokens: makeTokenAccessor(accessTokens),
func MakeGitHubTransport(innerTransport http.RoundTripper, accessTokens []string) http.RoundTripper {
return &githubTransport{
innerTransport: innerTransport,
tokens: makeTokenAccessor(accessTokens),
}
return oauth2.NewClient(ctx, tokenSource).Transport
}
// githubTransport handles authorization using GitHub personal access tokens (PATs) during HTTP requests.
type githubTransport struct {
innerTransport http.RoundTripper
tokens tokenAccessor
}
type tokenAccessor interface {
next() (*oauth2.Token, error)
next() string
}
type tokenPool struct {
tokens tokenAccessor
}
func (pool *tokenPool) Token() (*oauth2.Token, error) {
token, err := pool.tokens.next()
func (gt *githubTransport) RoundTrip(r *http.Request) (*http.Response, error) {
r.Header.Add("Authorization", fmt.Sprintf("Bearer %s", gt.tokens.next()))
resp, err := gt.innerTransport.RoundTrip(r)
if err != nil {
return token, fmt.Errorf("error during Next(): %w", err)
return nil, fmt.Errorf("error in HTTP: %w", err)
}
return token, nil
return resp, nil
}
func makeTokenAccessor(accessTokens []string) tokenAccessor {
@ -55,14 +56,15 @@ func makeTokenAccessor(accessTokens []string) tokenAccessor {
type roundRobinAccessor struct {
accessTokens []string
counter int64
mu sync.Mutex
}
func (roundRobin *roundRobinAccessor) next() (*oauth2.Token, error) {
func (roundRobin *roundRobinAccessor) next() string {
roundRobin.mu.Lock()
defer roundRobin.mu.Unlock()
c := atomic.AddInt64(&roundRobin.counter, 1)
// not locking it because it is never modified
l := len(roundRobin.accessTokens)
index := c % int64(l)
return &oauth2.Token{
AccessToken: roundRobin.accessTokens[index],
}, nil
return roundRobin.accessTokens[index]
}

View File

@ -42,9 +42,9 @@ const (
func NewTransport(ctx context.Context, logger *zap.SugaredLogger) http.RoundTripper {
transport := http.DefaultTransport
// Start with oauth
if token := os.Getenv(GithubAuthToken); token != "" {
transport = MakeOAuthTransport(ctx, strings.Split(token, ","))
// Use GitHub PAT
transport = MakeGitHubTransport(transport, strings.Split(token, ","))
} else if keyPath := os.Getenv(GithubAppKeyPath); keyPath != "" { // Also try a GITHUB_APP
appID, err := strconv.Atoi(os.Getenv(GithubAppID))
if err != nil {