maintner: add TrackGitHub method variant taking an oauth2.TokenSource
Replace the plain string token with an oauth2.TokenSource throughout
the GitHub tracking and polling code. This allows callers to provide
token sources that can refresh credentials, rather than being limited
to static tokens. (e.g. GitHub Apps credentials)
diff --git a/maintner/github.go b/maintner/github.go
index 772408f..ad05a8f 100644
--- a/maintner/github.go
+++ b/maintner/github.go
@@ -782,6 +782,13 @@
// watch and append to the mutation log. Only valid in leader mode.
// The token is the auth token to use to make API calls.
func (c *Corpus) TrackGitHub(owner, repo, token string) {
+ c.TrackGitHubWithTokenSource(owner, repo, oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}))
+}
+
+// TrackGitHubWithTokenSource registers the named GitHub repo as a repo to
+// watch and append to the mutation log. Only valid in leader mode.
+// The tokenSource is used to obtain auth tokens for GitHub API calls.
+func (c *Corpus) TrackGitHubWithTokenSource(owner, repo string, tokenSource oauth2.TokenSource) {
if c.mutationLogger == nil {
panic("can't TrackGitHub in non-leader mode")
}
@@ -794,14 +801,14 @@
log.Fatalf("invalid github owner/repo %q/%q", owner, repo)
}
c.watchedGithubRepos = append(c.watchedGithubRepos, watchedGithubRepo{
- gr: gr,
- token: token,
+ gr: gr,
+ tokenSource: tokenSource,
})
}
type watchedGithubRepo struct {
- gr *GitHubRepo
- token string
+ gr *GitHubRepo
+ tokenSource oauth2.TokenSource
}
// g.c.mu must be held
@@ -1450,9 +1457,8 @@
// sync checks for new changes on a single GitHub repository and
// updates the Corpus with any changes. If loop is true, it runs
// forever.
-func (gr *GitHubRepo) sync(ctx context.Context, token string, loop bool) error {
- ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
- hc := oauth2.NewClient(ctx, ts)
+func (gr *GitHubRepo) sync(ctx context.Context, tokenSource oauth2.TokenSource, loop bool) error {
+ hc := oauth2.NewClient(ctx, tokenSource)
if tr, ok := hc.Transport.(*http.Transport); ok {
defer tr.CloseIdleConnections()
}
@@ -1468,7 +1474,7 @@
p := &githubRepoPoller{
c: gr.github.c,
- token: token,
+ tokenSource: tokenSource,
gr: gr,
githubDirect: github.NewClient(&http.Client{Transport: directTransport}),
githubCaching: github.NewClient(&http.Client{Transport: cachingTransport}),
@@ -1529,7 +1535,7 @@
type githubRepoPoller struct {
c *Corpus // shortcut for gr.github.c
gr *GitHubRepo
- token string
+ tokenSource oauth2.TokenSource
lastUpdate time.Time // modified by sync
githubCaching *github.Client
githubDirect *github.Client // not caching
@@ -2048,7 +2054,11 @@
p.Owner(), p.Repo(), issueNum, perPage, page)
req, _ := http.NewRequest("GET", u, nil)
- req.Header.Set("Authorization", "Bearer "+p.token)
+ tok, err := p.tokenSource.Token()
+ if err != nil {
+ return nil, nil, fmt.Errorf("getting token: %v", err)
+ }
+ req.Header.Set("Authorization", "Bearer "+tok.AccessToken)
req.Header.Set("User-Agent", "golang-x-build-maintner/1.0")
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
@@ -2292,7 +2302,11 @@
p.Owner(), p.Repo(), issueNum, perPage, page)
req, _ := http.NewRequest("GET", u, nil)
- req.Header.Set("Authorization", "Bearer "+p.token)
+ tok, err := p.tokenSource.Token()
+ if err != nil {
+ return nil, nil, fmt.Errorf("getting token: %v", err)
+ }
+ req.Header.Set("Authorization", "Bearer "+tok.AccessToken)
req.Header.Set("User-Agent", "golang-x-build-maintner/1.0")
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
diff --git a/maintner/github_test.go b/maintner/github_test.go
index b9d9b9c..374c474 100644
--- a/maintner/github_test.go
+++ b/maintner/github_test.go
@@ -21,6 +21,7 @@
"github.com/google/go-github/v74/github"
"golang.org/x/build/maintner/maintpb"
+ "golang.org/x/oauth2"
"google.golang.org/protobuf/types/known/timestamppb"
)
@@ -669,7 +670,7 @@
defer server.Close()
p := &githubRepoPoller{
c: &c,
- token: "foobar",
+ tokenSource: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: "foobar"}),
gr: gr,
githubDirect: github.NewClient(server.Client()),
githubCaching: github.NewClient(server.Client()),
@@ -745,7 +746,7 @@
defer server.Close()
p := &githubRepoPoller{
c: &c,
- token: "foobar",
+ tokenSource: oauth2.StaticTokenSource(&oauth2.Token{AccessToken: "foobar"}),
gr: gr,
githubDirect: github.NewClient(server.Client()),
githubCaching: github.NewClient(server.Client()),
diff --git a/maintner/maintner.go b/maintner/maintner.go
index d78802b..c8ad3ca 100644
--- a/maintner/maintner.go
+++ b/maintner/maintner.go
@@ -371,11 +371,11 @@
group, ctx := errgroup.WithContext(ctx)
for _, w := range c.watchedGithubRepos {
- gr, token := w.gr, w.token
+ gr, ts := w.gr, w.tokenSource
group.Go(func() error {
log.Printf("Polling %v ...", gr.id)
for {
- err := gr.sync(ctx, token, loop)
+ err := gr.sync(ctx, ts, loop)
if loop && isTempErr(err) {
log.Printf("Temporary error from github %v: %v", gr.ID(), err)
time.Sleep(30 * time.Second)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
c.TrackGitHubWithTokenSource(owner, repo, oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}))// The token is the auth token to use to make API calls.
now that we have a new method, worth editing the last doc line to read "The token is a static auth token; for dynamic OAuth try the WithTokenSource variant" or something?
tok, err := p.tokenSource.Token()Don't like that this is a new source of latency with uncontrollable timeout when the token refreshes, but don't think it makes sense to change here - if people care they can have the TokenSource refresh in the background.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
req.Header.Set("Authorization", "Bearer "+tok.AccessToken)I think we could start using `tok.SetAuthHeader(req)` here now that there's an `oauth2.Token`, if you want. But this should be equivalent at least for today's needs, so either way is fine. (Similarly on line 2309.)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
tok, err := p.tokenSource.Token()Don't like that this is a new source of latency with uncontrollable timeout when the token refreshes, but don't think it makes sense to change here - if people care they can have the TokenSource refresh in the background.
Can the potential latency be dealt with by wrapping with something like [oauth2.ReuseTokenSource](https://pkg.go.dev/golang.org/x/oauth2#ReuseTokenSource)?
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
req.Header.Set("Authorization", "Bearer "+tok.AccessToken)I think we could start using `tok.SetAuthHeader(req)` here now that there's an `oauth2.Token`, if you want. But this should be equivalent at least for today's needs, so either way is fine. (Similarly on line 2309.)
This CL was my minimally-sized trial balloon to see if this code had somebody around to still review these things. If so (seems like it!) then I can send more changes. ;)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
req.Header.Set("Authorization", "Bearer "+tok.AccessToken)Brad FitzpatrickI think we could start using `tok.SetAuthHeader(req)` here now that there's an `oauth2.Token`, if you want. But this should be equivalent at least for today's needs, so either way is fine. (Similarly on line 2309.)
This CL was my minimally-sized trial balloon to see if this code had somebody around to still review these things. If so (seems like it!) then I can send more changes. ;)
Makes sense.
seems like it!
To an extent. :) Issue #37603 is still applicable today. For instance, it's taken me a while to find time to review CL 726080 partly because managing risk of applying comparatively larger changes to maintner is still quite high cost.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |