This is an automated email from the ASF dual-hosted git repository.

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new f72868cd3 fix: disable API client caching for GitHub App connections 
(#8850)
f72868cd3 is described below

commit f72868cd3423bdab0416f8611d85bb1d98699772
Author: fxgagnon <[email protected]>
AuthorDate: Sat Apr 25 09:00:34 2026 -0400

    fix: disable API client caching for GitHub App connections (#8850)
    
    GitHub App installation tokens expire after ~1 hour, causing admin APIs
    (remote-scopes, test-connection) to fail silently after token expiry.
    
    This fix overrides GetHash() to return empty string for GitHub App 
connections,
    disabling client caching and ensuring fresh tokens are fetched for each 
admin request.
    
    PAT connections continue to use default caching behavior.
    
    Fixes #8847
---
 backend/plugins/github/models/connection.go      | 10 ++++++
 backend/plugins/github/models/connection_test.go | 42 ++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/backend/plugins/github/models/connection.go 
b/backend/plugins/github/models/connection.go
index 51034f67c..4489b70cb 100644
--- a/backend/plugins/github/models/connection.go
+++ b/backend/plugins/github/models/connection.go
@@ -134,6 +134,16 @@ func (connection GithubConnection) TableName() string {
        return "_tool_github_connections"
 }
 
+func (connection GithubConnection) GetHash() string {
+       if connection.AuthMethod == AppKey {
+               // GitHub App installation tokens expire after ~1 hour, disable 
API client caching
+               // to ensure fresh tokens are fetched for admin APIs 
(remote-scopes, test-connection)
+               return ""
+       }
+       // Use default caching for PAT connections (they don't expire)
+       return connection.BaseConnection.GetHash()
+}
+
 func (connection *GithubConnection) MergeFromRequest(target *GithubConnection, 
body map[string]interface{}) error {
        modifiedConnection := GithubConnection{}
        if err := helper.DecodeMapStruct(body, &modifiedConnection, true); err 
!= nil {
diff --git a/backend/plugins/github/models/connection_test.go 
b/backend/plugins/github/models/connection_test.go
index 41323b9b5..7d4c74673 100644
--- a/backend/plugins/github/models/connection_test.go
+++ b/backend/plugins/github/models/connection_test.go
@@ -18,6 +18,7 @@ limitations under the License.
 package models
 
 import (
+       "github.com/apache/incubator-devlake/core/models/common"
        "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
        "testing"
 
@@ -238,3 +239,44 @@ func TestTokenTypeClassification(t *testing.T) {
        assert.Equal(t, GithubTokenTypeFineGrained, 
conn.typeIs("github_pat_123"))
        assert.Equal(t, GithubTokenTypeUnknown, conn.typeIs("some_other_token"))
 }
+
+func TestGithubConnection_GetHash(t *testing.T) {
+       tests := []struct {
+               name       string
+               connection GithubConnection
+               want       string
+       }{
+               {
+                       name: "GitHub App connection should return empty hash 
to disable caching",
+                       connection: GithubConnection{
+                               GithubConn: GithubConn{
+                                       MultiAuth: api.MultiAuth{
+                                               AuthMethod: AppKey,
+                                       },
+                               },
+                       },
+                       want: "",
+               },
+               {
+                       name: "PAT connection should use default hash",
+                       connection: GithubConnection{
+                               BaseConnection: api.BaseConnection{
+                                       Model: common.Model{
+                                               ID: 123,
+                                       },
+                               },
+                               GithubConn: GithubConn{
+                                       MultiAuth: api.MultiAuth{
+                                               AuthMethod: AccessToken,
+                                       },
+                               },
+                       },
+                       want: "1230001-01-01 00:00:00 +0000 UTC", // ID + zero 
UpdatedAt
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       assert.Equalf(t, tt.want, tt.connection.GetHash(), 
"GetHash()")
+               })
+       }
+}

Reply via email to