fix: Fetch GitHub teams by name for performance (#2955)

In large organizations with thousands of teams, looping took >5s.
This fetches organizations by team name, which should be very fast!
This commit is contained in:
Kyle Carberry
2022-07-12 19:45:43 -05:00
committed by GitHub
parent 7e9819f2a8
commit 8b76e40629
4 changed files with 20 additions and 55 deletions

View File

@ -29,7 +29,7 @@ type GithubOAuth2Config struct {
AuthenticatedUser func(ctx context.Context, client *http.Client) (*github.User, error)
ListEmails func(ctx context.Context, client *http.Client) ([]*github.UserEmail, error)
ListOrganizationMemberships func(ctx context.Context, client *http.Client) ([]*github.Membership, error)
ListTeams func(ctx context.Context, client *http.Client, org string) ([]*github.Team, error)
Team func(ctx context.Context, client *http.Client, org, team string) (*github.Team, error)
AllowSignups bool
AllowOrganizations []string
@ -74,31 +74,20 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
// The default if no teams are specified is to allow all.
if len(api.GithubOAuth2Config.AllowTeams) > 0 {
teams, err := api.GithubOAuth2Config.ListTeams(r.Context(), oauthClient, *selectedMembership.Organization.Login)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to fetch teams from GitHub.",
Detail: err.Error(),
})
return
}
var allowedTeam *github.Team
for _, team := range teams {
for _, allowTeam := range api.GithubOAuth2Config.AllowTeams {
if allowTeam.Organization != *selectedMembership.Organization.Login {
// This needs to continue because multiple organizations
// could exist in the allow/team listings.
continue
}
if allowTeam.Slug != *team.Slug {
continue
}
allowedTeam = team
break
for _, allowTeam := range api.GithubOAuth2Config.AllowTeams {
if allowTeam.Organization != *selectedMembership.Organization.Login {
// This needs to continue because multiple organizations
// could exist in the allow/team listings.
continue
}
allowedTeam, err = api.GithubOAuth2Config.Team(r.Context(), oauthClient, allowTeam.Organization, allowTeam.Slug)
// The calling user may not have permission to the requested team!
if err != nil {
continue
}
}
if allowedTeam == nil {
httpapi.Write(rw, http.StatusUnauthorized, codersdk.Response{
Message: fmt.Sprintf("You aren't a member of an authorized team in the %s Github organization!", *selectedMembership.Organization.Login),

View File

@ -9,6 +9,7 @@ import (
"github.com/google/go-github/v43/github"
"github.com/stretchr/testify/require"
"golang.org/x/oauth2"
"golang.org/x/xerrors"
"github.com/coder/coder/coderd"
"github.com/coder/coder/coderd/coderdtest"
@ -87,10 +88,8 @@ func TestUserOAuth2Github(t *testing.T) {
},
}}, nil
},
ListTeams: func(ctx context.Context, client *http.Client, org string) ([]*github.Team, error) {
return []*github.Team{{
Slug: github.String("nope"),
}}, nil
Team: func(ctx context.Context, client *http.Client, org, team string) (*github.Team, error) {
return nil, xerrors.New("no perms")
},
},
})
@ -223,10 +222,8 @@ func TestUserOAuth2Github(t *testing.T) {
},
}}, nil
},
ListTeams: func(ctx context.Context, client *http.Client, org string) ([]*github.Team, error) {
return []*github.Team{{
Slug: github.String("frontend"),
}}, nil
Team: func(ctx context.Context, client *http.Client, org, team string) (*github.Team, error) {
return &github.Team{}, nil
},
AuthenticatedUser: func(ctx context.Context, client *http.Client) (*github.User, error) {
return &github.User{