@@ -176,17 +176,14 @@ func (gh *GitHub) validateAppCredentials(ctx context.Context) (annotations.Annot
176176}
177177
178178// newGitHubClient returns a new GitHub API client authenticated with an access token via oauth2.
179- func newGitHubClient (ctx context.Context , instanceURL string , accessToken string ) (* github.Client , error ) {
179+ func newGitHubClient (ctx context.Context , instanceURL string , ts oauth2. TokenSource ) (* github.Client , error ) {
180180 httpClient , err := uhttp .NewClient (ctx , uhttp .WithLogger (true , ctxzap .Extract (ctx )))
181181 if err != nil {
182182 return nil , err
183183 }
184184
185185 ctx = context .WithValue (ctx , oauth2 .HTTPClient , httpClient )
186186
187- ts := oauth2 .StaticTokenSource (
188- & oauth2.Token {AccessToken : accessToken },
189- )
190187 tc := oauth2 .NewClient (ctx , ts )
191188 gc := github .NewClient (tc )
192189
@@ -205,13 +202,23 @@ func New(ctx context.Context, ghc *cfg.Github, appKey string) (*GitHub, error) {
205202 return nil , err
206203 }
207204
208- var appClient * github.Client
205+ var (
206+ appClient * github.Client
207+ ts = oauth2 .StaticTokenSource (
208+ & oauth2.Token {AccessToken : patToken },
209+ )
210+ )
209211 if jwttoken != "" {
210212 if len (ghc .Orgs ) != 1 {
211213 return nil , fmt .Errorf ("github-connector: only one org should be specified" )
212214 }
213215
214- appClient , err = newGitHubClient (ctx , ghc .InstanceUrl , jwttoken )
216+ appClient , err = newGitHubClient (ctx ,
217+ ghc .InstanceUrl ,
218+ oauth2 .StaticTokenSource (
219+ & oauth2.Token {AccessToken : jwttoken },
220+ ),
221+ )
215222 if err != nil {
216223 return nil , err
217224 }
@@ -224,14 +231,26 @@ func New(ctx context.Context, ghc *cfg.Github, appKey string) (*GitHub, error) {
224231 if err != nil {
225232 return nil , err
226233 }
227- patToken = token
234+
235+ ts = oauth2 .ReuseTokenSource (
236+ & oauth2.Token {
237+ AccessToken : token .GetToken (),
238+ Expiry : token .GetExpiresAt ().Time ,
239+ },
240+ & appTokenRefresher {
241+ ctx : ctx ,
242+ instanceURL : ghc .InstanceUrl ,
243+ installationID : installation .GetID (),
244+ jwttoken : jwttoken ,
245+ },
246+ )
228247 }
229248
230- client , err := newGitHubClient (ctx , ghc .InstanceUrl , patToken )
249+ client , err := newGitHubClient (ctx , ghc .InstanceUrl , ts )
231250 if err != nil {
232251 return nil , err
233252 }
234- graphqlClient , err := newGitHubGraphqlClient (ctx , ghc .InstanceUrl , patToken )
253+ graphqlClient , err := newGitHubGraphqlClient (ctx , ghc .InstanceUrl , ts )
235254 if err != nil {
236255 return nil , err
237256 }
@@ -248,17 +267,14 @@ func New(ctx context.Context, ghc *cfg.Github, appKey string) (*GitHub, error) {
248267 return gh , nil
249268}
250269
251- func newGitHubGraphqlClient (ctx context.Context , instanceURL string , accessToken string ) (* githubv4.Client , error ) {
270+ func newGitHubGraphqlClient (ctx context.Context , instanceURL string , ts oauth2. TokenSource ) (* githubv4.Client , error ) {
252271 httpClient , err := uhttp .NewClient (ctx , uhttp .WithLogger (true , ctxzap .Extract (ctx )))
253272 if err != nil {
254273 return nil , err
255274 }
256275
257276 ctx = context .WithValue (ctx , oauth2 .HTTPClient , httpClient )
258277
259- ts := oauth2 .StaticTokenSource (
260- & oauth2.Token {AccessToken : accessToken },
261- )
262278 tc := oauth2 .NewClient (ctx , ts )
263279
264280 instanceURL = strings .TrimSuffix (instanceURL , "/" )
@@ -331,16 +347,44 @@ func findInstallation(ctx context.Context, c *github.Client, orgName string) (*g
331347 return installation , resp , nil
332348}
333349
334- func getInstallationToken (ctx context.Context , c * github.Client , id int64 ) (string , error ) {
350+ func getInstallationToken (ctx context.Context , c * github.Client , id int64 ) (* github. InstallationToken , error ) {
335351 token , resp , err := c .Apps .CreateInstallationToken (ctx , id , & github.InstallationTokenOptions {})
336352 if err != nil {
337- return "" , err
353+ return nil , err
338354 }
339355
340356 if resp .StatusCode != http .StatusCreated {
341357 body , _ := io .ReadAll (resp .Body )
342- return "" , fmt .Errorf ("GitHub API error: %s" , body )
358+ return nil , fmt .Errorf ("GitHub API error: %s" , body )
343359 }
344360
345- return token .GetToken (), nil
361+ return token , nil
362+ }
363+
364+ type appTokenRefresher struct {
365+ ctx context.Context
366+ jwttoken string
367+ instanceURL string
368+ installationID int64
369+ }
370+
371+ func (r * appTokenRefresher ) Token () (* oauth2.Token , error ) {
372+ appClient , err := newGitHubClient (r .ctx ,
373+ r .instanceURL ,
374+ oauth2 .StaticTokenSource (
375+ & oauth2.Token {AccessToken : r .jwttoken },
376+ ),
377+ )
378+ if err != nil {
379+ return nil , err
380+ }
381+
382+ token , err := getInstallationToken (r .ctx , appClient , r .installationID )
383+ if err != nil {
384+ return nil , err
385+ }
386+ return & oauth2.Token {
387+ AccessToken : token .GetToken (),
388+ Expiry : token .GetExpiresAt ().Time ,
389+ }, nil
346390}
0 commit comments