Make github org comparison case-insensitive, but return original case

Co-authored-by: Joshua Casey <joshuatcasey@gmail.com>
This commit is contained in:
Ryan Richard
2024-05-21 11:57:55 -07:00
committed by Joshua Casey
parent 8923704f3c
commit 8f8db3f542
14 changed files with 240 additions and 73 deletions

View File

@@ -16,6 +16,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/setutil"
)
const (
@@ -36,8 +37,8 @@ type TeamInfo struct {
type GitHubInterface interface {
GetUserInfo(ctx context.Context) (*UserInfo, error)
GetOrgMembership(ctx context.Context) (sets.Set[string], error)
GetTeamMembership(ctx context.Context, allowedOrganizations sets.Set[string]) ([]TeamInfo, error)
GetOrgMembership(ctx context.Context) ([]string, error)
GetTeamMembership(ctx context.Context, allowedOrganizations *setutil.CaseInsensitiveSet) ([]TeamInfo, error)
}
type githubClient struct {
@@ -107,7 +108,7 @@ func (g *githubClient) GetUserInfo(ctx context.Context) (*UserInfo, error) {
}
// GetOrgMembership returns an array of the "Login" attributes for all organizations to which the authenticated user belongs.
func (g *githubClient) GetOrgMembership(ctx context.Context) (sets.Set[string], error) {
func (g *githubClient) GetOrgMembership(ctx context.Context) ([]string, error) {
const errorPrefix = "error fetching organizations for authenticated user"
organizationLogins := sets.New[string]()
@@ -135,11 +136,11 @@ func (g *githubClient) GetOrgMembership(ctx context.Context) (sets.Set[string],
}
plog.Trace("calculated response from GitHub org membership endpoint", "orgs", organizationLogins.UnsortedList())
return organizationLogins, nil
return organizationLogins.UnsortedList(), nil
}
func isOrgAllowed(allowedOrganizations sets.Set[string], login string) bool {
return len(allowedOrganizations) == 0 || allowedOrganizations.Has(login)
func isOrgAllowed(allowedOrganizations *setutil.CaseInsensitiveSet, login string) bool {
return allowedOrganizations.Empty() || allowedOrganizations.ContainsIgnoringCase(login)
}
func buildAndValidateParentTeam(githubTeam *github.Team, organizationLogin string) (*TeamInfo, error) {
@@ -176,7 +177,7 @@ func buildTeam(githubTeam *github.Team, organizationLogin string) (*TeamInfo, er
// GetTeamMembership returns a description of each team to which the authenticated user belongs.
// If allowedOrganizations is not empty, will filter the results to only those teams which belong to the allowed organizations.
// Parent teams will also be returned.
func (g *githubClient) GetTeamMembership(ctx context.Context, allowedOrganizations sets.Set[string]) ([]TeamInfo, error) {
func (g *githubClient) GetTeamMembership(ctx context.Context, allowedOrganizations *setutil.CaseInsensitiveSet) ([]TeamInfo, error) {
const errorPrefix = "error fetching team membership for authenticated user"
teamInfos := sets.New[TeamInfo]()

View File

@@ -12,10 +12,10 @@ import (
"github.com/google/go-github/v62/github"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/util/cert"
"go.pinniped.dev/internal/net/phttp"
"go.pinniped.dev/internal/setutil"
"go.pinniped.dev/internal/testutil/tlsserver"
)
@@ -380,8 +380,7 @@ func TestGetOrgMembership(t *testing.T) {
}
require.NotNil(t, actual)
require.Equal(t, len(actual), len(test.wantOrgs))
require.True(t, actual.HasAll(test.wantOrgs...))
require.ElementsMatch(t, test.wantOrgs, actual)
})
}
}
@@ -394,7 +393,7 @@ func TestGetTeamMembership(t *testing.T) {
httpClient *http.Client
token string
ctx context.Context
allowedOrganizations []string
allowedOrganizations *setutil.CaseInsensitiveSet
wantErr string
wantTeams []TeamInfo
}{
@@ -436,7 +435,7 @@ func TestGetTeamMembership(t *testing.T) {
),
),
token: "some-token",
allowedOrganizations: []string{"alpha", "beta"},
allowedOrganizations: setutil.NewCaseInsensitiveSet("alpha", "beta"),
wantTeams: []TeamInfo{
{
Name: "orgAlpha-team1-name",
@@ -461,7 +460,7 @@ func TestGetTeamMembership(t *testing.T) {
},
},
{
name: "filters by allowedOrganizations",
name: "filters by allowedOrganizations in a case-insensitive way, but preserves case as returned by GitHub API in the result",
httpClient: mock.NewMockedHTTPClient(
mock.WithRequestMatch(
mock.GetUserTeams,
@@ -470,38 +469,38 @@ func TestGetTeamMembership(t *testing.T) {
Name: github.String("team1-name"),
Slug: github.String("team1-slug"),
Organization: &github.Organization{
Login: github.String("alpha"),
Login: github.String("alPhA"),
},
},
{
Name: github.String("team2-name"),
Slug: github.String("team2-slug"),
Organization: &github.Organization{
Login: github.String("beta"),
Login: github.String("bEtA"),
},
},
{
Name: github.String("team3-name"),
Slug: github.String("team3-slug"),
Organization: &github.Organization{
Login: github.String("gamma"),
Login: github.String("gAmmA"),
},
},
},
),
),
token: "some-token",
allowedOrganizations: []string{"alpha", "gamma"},
allowedOrganizations: setutil.NewCaseInsensitiveSet("ALPHA", "gamma"),
wantTeams: []TeamInfo{
{
Name: "team1-name",
Slug: "team1-slug",
Org: "alpha",
Org: "alPhA",
},
{
Name: "team3-name",
Slug: "team3-slug",
Org: "gamma",
Org: "gAmmA",
},
},
},
@@ -623,11 +622,8 @@ func TestGetTeamMembership(t *testing.T) {
},
),
),
token: "some-token",
allowedOrganizations: []string{
"org-with-nested-teams",
"beta",
},
token: "some-token",
allowedOrganizations: setutil.NewCaseInsensitiveSet("org-with-nested-teams", "beta"),
wantTeams: []TeamInfo{
{
Name: "team-name-without-parent",
@@ -677,7 +673,7 @@ func TestGetTeamMembership(t *testing.T) {
),
),
token: "some-token",
allowedOrganizations: []string{"page1-org-name", "page2-org-name"},
allowedOrganizations: setutil.NewCaseInsensitiveSet("page1-org-name", "page2-org-name"),
wantTeams: []TeamInfo{
{
Name: "page1-team-name",
@@ -770,7 +766,7 @@ func TestGetTeamMembership(t *testing.T) {
),
),
token: "does-this-token-work",
allowedOrganizations: []string{"org-login"},
allowedOrganizations: setutil.NewCaseInsensitiveSet("org-login"),
wantTeams: []TeamInfo{
{
Name: "team1-name",
@@ -821,7 +817,7 @@ func TestGetTeamMembership(t *testing.T) {
ctx = test.ctx
}
actual, err := githubClient.GetTeamMembership(ctx, sets.New[string](test.allowedOrganizations...))
actual, err := githubClient.GetTeamMembership(ctx, test.allowedOrganizations)
if test.wantErr != "" {
rt, ok := test.httpClient.Transport.(*mock.EnforceHostRoundTripper)
require.True(t, ok)