From 0b6e94a8ff675b1104a20b749ec81dc1c0c04c12 Mon Sep 17 00:00:00 2001 From: Ellie Kelsch Date: Wed, 13 May 2026 09:09:27 +0100 Subject: [PATCH 1/4] fix: org detection failure on ghec-dr endpoints --- github/config.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/github/config.go b/github/config.go index b205b5e505..0adbcfac3d 100644 --- a/github/config.go +++ b/github/config.go @@ -3,6 +3,7 @@ package github import ( "context" "fmt" + "log" "net/http" "net/url" "regexp" @@ -129,9 +130,16 @@ func (c *Config) ConfigureOwner(owner *Owner) (*Owner, error) { owner.name = user.GetLogin() } else { remoteOrg, _, err := owner.v3client.Organizations.Get(ctx, owner.name) - if err == nil { - if remoteOrg != nil { - owner.id = remoteOrg.GetID() + if err == nil && remoteOrg != nil { + owner.id = remoteOrg.GetID() + owner.IsOrganization = true + } else { + if err != nil { + log.Printf("[WARN] Unable to detect organization via Organizations.Get for %q: %s. Falling back to Users.Get.", owner.name, err) + } + user, _, userErr := owner.v3client.Users.Get(ctx, owner.name) + if userErr == nil && user != nil && user.GetType() == "Organization" { + owner.id = user.GetID() owner.IsOrganization = true } } From f71d2c82f412b8040a8b24003def41b23bedb739 Mon Sep 17 00:00:00 2001 From: Ellie Kelsch Date: Wed, 13 May 2026 09:15:08 +0100 Subject: [PATCH 2/4] test: org detection failure on ghec-dr endpoints --- github/config_test.go | 98 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/github/config_test.go b/github/config_test.go index 1d88e231bc..634eb51b3b 100644 --- a/github/config_test.go +++ b/github/config_test.go @@ -2,10 +2,13 @@ package github import ( "context" + "encoding/json" "net/http" "net/http/httptest" + "net/url" "testing" + gogithub "github.com/google/go-github/v86/github" "github.com/shurcooL/githubv4" ) @@ -514,3 +517,98 @@ func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) } return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody}, nil } + +func TestConfigureOwner_OrgDetectionFallback(t *testing.T) { + testCases := []struct { + name string + ownerName string + orgStatus int + userResp map[string]any + userStatus int + wantIsOrg bool + wantID int64 + }{ + { + name: "org detected via Organizations.Get", + ownerName: "my-org", + orgStatus: http.StatusOK, + wantIsOrg: true, + wantID: 100, + }, + { + name: "org detected via Users.Get fallback", + ownerName: "my-org", + orgStatus: http.StatusNotFound, + userResp: map[string]any{"login": "my-org", "id": 200, "type": "Organization"}, + userStatus: http.StatusOK, + wantIsOrg: true, + wantID: 200, + }, + { + name: "user detected via Users.Get fallback", + ownerName: "some-user", + orgStatus: http.StatusNotFound, + userResp: map[string]any{"login": "some-user", "id": 300, "type": "User"}, + userStatus: http.StatusOK, + wantIsOrg: false, + wantID: 0, + }, + { + name: "both endpoints fail", + ownerName: "unknown", + orgStatus: http.StatusNotFound, + userStatus: http.StatusNotFound, + wantIsOrg: false, + wantID: 0, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + mux := http.NewServeMux() + mux.HandleFunc("/orgs/"+tc.ownerName, func(w http.ResponseWriter, r *http.Request) { + if tc.orgStatus != http.StatusOK { + http.Error(w, `{"message":"Not Found"}`, tc.orgStatus) + return + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]any{ + "login": tc.ownerName, + "id": 100, + "type": "Organization", + }) + }) + mux.HandleFunc("/users/"+tc.ownerName, func(w http.ResponseWriter, r *http.Request) { + if tc.userStatus != http.StatusOK || tc.userResp == nil { + http.Error(w, `{"message":"Not Found"}`, http.StatusNotFound) + return + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(tc.userResp) + }) + server := httptest.NewServer(mux) + t.Cleanup(server.Close) + + serverURL, _ := url.Parse(server.URL + "/") + v3client := gogithub.NewClient(nil) + v3client.BaseURL = serverURL + + owner := &Owner{v3client: v3client} + config := &Config{Owner: tc.ownerName} + + result, err := config.ConfigureOwner(owner) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if result.IsOrganization != tc.wantIsOrg { + t.Errorf("IsOrganization = %v, want %v", result.IsOrganization, tc.wantIsOrg) + } + if result.id != tc.wantID { + t.Errorf("id = %d, want %d", result.id, tc.wantID) + } + }) + } +} From dcb731d7f1106a38039d690f66cbfa906fed8980 Mon Sep 17 00:00:00 2001 From: Ellie Kelsch Date: Wed, 13 May 2026 09:24:54 +0100 Subject: [PATCH 3/4] fix: log warning and clean up --- github/config.go | 2 ++ github/config_test.go | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/github/config.go b/github/config.go index 0adbcfac3d..93191c10bd 100644 --- a/github/config.go +++ b/github/config.go @@ -141,6 +141,8 @@ func (c *Config) ConfigureOwner(owner *Owner) (*Owner, error) { if userErr == nil && user != nil && user.GetType() == "Organization" { owner.id = user.GetID() owner.IsOrganization = true + } else if userErr != nil { + log.Printf("[WARN] Unable to detect owner type via Users.Get for %q: %s", owner.name, userErr) } } } diff --git a/github/config_test.go b/github/config_test.go index 634eb51b3b..04ca068184 100644 --- a/github/config_test.go +++ b/github/config_test.go @@ -529,11 +529,12 @@ func TestConfigureOwner_OrgDetectionFallback(t *testing.T) { wantID int64 }{ { - name: "org detected via Organizations.Get", - ownerName: "my-org", - orgStatus: http.StatusOK, - wantIsOrg: true, - wantID: 100, + name: "org detected via Organizations.Get", + ownerName: "my-org", + orgStatus: http.StatusOK, + userStatus: http.StatusNotFound, + wantIsOrg: true, + wantID: 100, }, { name: "org detected via Users.Get fallback", @@ -582,7 +583,7 @@ func TestConfigureOwner_OrgDetectionFallback(t *testing.T) { }) mux.HandleFunc("/users/"+tc.ownerName, func(w http.ResponseWriter, r *http.Request) { if tc.userStatus != http.StatusOK || tc.userResp == nil { - http.Error(w, `{"message":"Not Found"}`, http.StatusNotFound) + http.Error(w, `{"message":"Not Found"}`, tc.userStatus) return } w.Header().Set("Content-Type", "application/json") From ae0051783f8825a9f78c81ea51a5bf7685bd8b05 Mon Sep 17 00:00:00 2001 From: Ellie Kelsch Date: Wed, 13 May 2026 09:28:21 +0100 Subject: [PATCH 4/4] fix: add defensive log for safety --- github/config.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/github/config.go b/github/config.go index 93191c10bd..195d755f1d 100644 --- a/github/config.go +++ b/github/config.go @@ -136,6 +136,8 @@ func (c *Config) ConfigureOwner(owner *Owner) (*Owner, error) { } else { if err != nil { log.Printf("[WARN] Unable to detect organization via Organizations.Get for %q: %s. Falling back to Users.Get.", owner.name, err) + } else { + log.Printf("[WARN] Organizations.Get for %q returned empty response. Falling back to Users.Get.", owner.name) } user, _, userErr := owner.v3client.Users.Get(ctx, owner.name) if userErr == nil && user != nil && user.GetType() == "Organization" {