diff --git a/pkg/connector/org.go b/pkg/connector/org.go index dd98a988..c3614b10 100644 --- a/pkg/connector/org.go +++ b/pkg/connector/org.go @@ -187,72 +187,78 @@ func (o *orgResourceType) Grants( return nil, "", nil, err } - opts := github.ListMembersOptions{ - ListOptions: github.ListOptions{ - Page: page, - PerPage: maxPageSize, - }, - } + var ( + reqAnnos annotations.Annotations + pageToken string + rv = []*v2.Grant{} + ) - orgName, err := o.orgCache.GetOrgName(ctx, resource.Id) - if err != nil { - return nil, "", nil, err - } + switch rId := bag.ResourceTypeID(); rId { + case resourceTypeOrg.Id: + bag.Pop() + bag.Push(pagination.PageState{ + ResourceTypeID: orgRoleAdmin, + }) + bag.Push(pagination.PageState{ + ResourceTypeID: orgRoleMember, + }) + case orgRoleAdmin, orgRoleMember: - users, resp, err := o.client.Organizations.ListMembers(ctx, orgName, &opts) - if err != nil { - if isNotFoundError(resp) { - return nil, "", nil, uhttp.WrapErrors(codes.NotFound, fmt.Sprintf("org: %s not found", orgName)) + orgName, err := o.orgCache.GetOrgName(ctx, resource.Id) + if err != nil { + return nil, "", nil, err } - errMsg := "github-connectorv2: failed to list org members" - if isRatelimited(resp) { - return nil, "", nil, uhttp.WrapErrors(codes.Unavailable, "too many requests", err) + opts := github.ListMembersOptions{ + Role: rId, + ListOptions: github.ListOptions{ + Page: page, + PerPage: maxPageSize, + }, } - return nil, "", nil, fmt.Errorf("%s: %w", errMsg, err) - } - - nextPage, reqAnnos, err := parseResp(resp) - if err != nil { - return nil, "", nil, fmt.Errorf("github-connectorv2: failed to parse response: %w", err) - } - - pageToken, err := bag.NextToken(nextPage) - if err != nil { - return nil, "", nil, err - } - - var rv []*v2.Grant - for _, user := range users { - membership, _, err := o.client.Organizations.GetOrgMembership(ctx, user.GetLogin(), orgName) + users, resp, err := o.client.Organizations.ListMembers(ctx, orgName, &opts) if err != nil { - return nil, "", nil, fmt.Errorf("github-connectorv2: failed to get org memberships for user: %w", err) + if isNotFoundError(resp) { + return nil, "", nil, uhttp.WrapErrors(codes.NotFound, fmt.Sprintf("org: %s not found", orgName)) + } + errMsg := "github-connectorv2: failed to list org members" + if isRatelimited(resp) { + return nil, "", nil, uhttp.WrapErrors(codes.Unavailable, "too many requests", err) + } + return nil, "", nil, fmt.Errorf("%s: %w", errMsg, err) } - if membership.GetState() == "pending" { - continue + + var nextPage string + nextPage, reqAnnos, err = parseResp(resp) + if err != nil { + return nil, "", nil, fmt.Errorf("github-connectorv2: failed to parse response: %w", err) } - ur, err := userResource(ctx, user, user.GetEmail(), nil) + err = bag.Next(nextPage) if err != nil { return nil, "", nil, err } - roleName := strings.ToLower(membership.GetRole()) - switch roleName { - case orgRoleAdmin: - rv = append(rv, o.orgRoleGrant(orgRoleAdmin, resource, ur.Id, user.GetID())) - rv = append(rv, o.orgRoleGrant(orgRoleMember, resource, ur.Id, user.GetID())) - - case orgRoleMember: - rv = append(rv, o.orgRoleGrant(orgRoleMember, resource, ur.Id, user.GetID())) + for _, user := range users { + ur, err := userResource(ctx, user, user.GetEmail(), nil) + if err != nil { + return nil, "", nil, err + } - default: - ctxzap.Extract(ctx).Warn("Unknown GitHub Role Name", - zap.String("role_name", roleName), - zap.String("github_username", user.GetLogin()), - ) + if rId == orgRoleAdmin { + rv = append(rv, o.orgRoleGrant(orgRoleMember, resource, ur.Id, user.GetID())) + } + rv = append(rv, o.orgRoleGrant(rId, resource, ur.Id, user.GetID())) } + default: + ctxzap.Extract(ctx).Warn("Unknown GitHub Role Name", + zap.String("role_name", rId), + ) } + pageToken, err = bag.Marshal() + if err != nil { + return nil, "", nil, err + } return rv, pageToken, reqAnnos, nil } diff --git a/pkg/connector/org_test.go b/pkg/connector/org_test.go index b3de4b5f..bb1a27da 100644 --- a/pkg/connector/org_test.go +++ b/pkg/connector/org_test.go @@ -37,11 +37,10 @@ func TestOrganization(t *testing.T) { require.Nil(t, err) require.Empty(t, grantAnnotations) - grants, nextToken, grantsAnnotations, err := client.Grants(ctx, organization, &pagination.Token{}) + _, nextToken, grantsAnnotations, err := client.Grants(ctx, organization, &pagination.Token{}) require.Nil(t, err) test.AssertHasRatelimitAnnotations(t, grantsAnnotations) - require.Equal(t, "", nextToken) - require.Len(t, grants, 2) + require.Equal(t, "{\"states\":[{\"type\":\"admin\"}],\"current_state\":{\"type\":\"member\"}}", nextToken) grant := v2.Grant{ Entitlement: &entitlement, diff --git a/pkg/connector/team.go b/pkg/connector/team.go index 4806e0dc..6775bae6 100644 --- a/pkg/connector/team.go +++ b/pkg/connector/team.go @@ -174,56 +174,72 @@ func (o *teamResourceType) Grants(ctx context.Context, resource *v2.Resource, pT return nil, "", nil, err } - opts := github.TeamListTeamMembersOptions{ - ListOptions: github.ListOptions{ - Page: page, - PerPage: maxPageSize, - }, - } - - users, resp, err := o.client.Teams.ListTeamMembersByID(ctx, org.GetID(), githubID, &opts) - if err != nil { - if isNotFoundError(resp) { - return nil, "", nil, uhttp.WrapErrors(codes.NotFound, fmt.Sprintf("org: %d not found", org.GetID())) - } - if isRatelimited(resp) { - return nil, "", nil, uhttp.WrapErrors(codes.Unavailable, "too many requests", err) + var ( + reqAnnos annotations.Annotations + pageToken string + rv = []*v2.Grant{} + ) + switch rId := bag.ResourceTypeID(); rId { + case resourceTypeTeam.Id: + bag.Pop() + bag.Push(pagination.PageState{ + ResourceTypeID: teamRoleMember, + }) + bag.Push(pagination.PageState{ + ResourceTypeID: teamRoleMaintainer, + }) + case teamRoleMember, teamRoleMaintainer: + opts := github.TeamListTeamMembersOptions{ + ListOptions: github.ListOptions{ + Page: page, + PerPage: maxPageSize, + }, + Role: rId, } - return nil, "", nil, fmt.Errorf("github-connectorv2: failed to fetch team members: %w", err) - } - - nextPage, reqAnnos, err := parseResp(resp) - if err != nil { - return nil, "", nil, fmt.Errorf("github-connectorv2: failed to parse response: %w", err) - } - - pageToken, err := bag.NextToken(nextPage) - if err != nil { - return nil, "", nil, err - } - var rv []*v2.Grant - for _, user := range users { - membership, _, err := o.client.Teams.GetTeamMembershipByID(ctx, org.GetID(), githubID, user.GetLogin()) + users, resp, err := o.client.Teams.ListTeamMembersByID(ctx, org.GetID(), githubID, &opts) if err != nil { if isNotFoundError(resp) { - return nil, "", nil, uhttp.WrapErrors(codes.NotFound, fmt.Sprintf("user: %s not found", user.GetLogin())) + return nil, "", nil, uhttp.WrapErrors(codes.NotFound, fmt.Sprintf("org: %d not found", org.GetID())) + } + if isRatelimited(resp) { + return nil, "", nil, uhttp.WrapErrors(codes.Unavailable, "too many requests", err) } - return nil, "", nil, fmt.Errorf("github-connectorv2: failed to get team membership for user: %w", err) + return nil, "", nil, fmt.Errorf("github-connectorv2: failed to fetch team members: %w", err) + } + + var nextPage string + nextPage, reqAnnos, err = parseResp(resp) + if err != nil { + return nil, "", nil, fmt.Errorf("github-connectorv2: failed to parse response: %w", err) } - ur, err := userResource(ctx, user, user.GetEmail(), nil) + err = bag.Next(nextPage) if err != nil { return nil, "", nil, err } - rv = append(rv, grant.NewGrant(resource, membership.GetRole(), ur.Id, - grant.WithAnnotation(&v2.V1Identifier{ - Id: fmt.Sprintf("team-grant:%s:%d:%s", resource.Id.Resource, user.GetID(), membership.GetRole()), - }), - )) + for _, user := range users { + ur, err := userResource(ctx, user, user.GetEmail(), nil) + if err != nil { + return nil, "", nil, err + } + rv = append(rv, grant.NewGrant(resource, rId, ur.Id, + grant.WithAnnotation(&v2.V1Identifier{ + Id: fmt.Sprintf("team-grant:%s:%d:%s", resource.Id.Resource, user.GetID(), rId), + }), + )) + } + default: + ctxzap.Extract(ctx).Warn("Unknown GitHub Role Name", + zap.String("role_name", rId), + ) } + pageToken, err = bag.Marshal() + if err != nil { + return nil, "", nil, err + } return rv, pageToken, reqAnnos, nil } diff --git a/pkg/connector/team_test.go b/pkg/connector/team_test.go index 69110271..d739b529 100644 --- a/pkg/connector/team_test.go +++ b/pkg/connector/team_test.go @@ -39,11 +39,10 @@ func TestTeam(t *testing.T) { require.Nil(t, err) require.Empty(t, grantAnnotations) - grants, nextToken, grantsAnnotations, err := client.Grants(ctx, team, &pagination.Token{}) + _, nextToken, grantsAnnotations, err := client.Grants(ctx, team, &pagination.Token{}) require.Nil(t, err) test.AssertHasRatelimitAnnotations(t, grantsAnnotations) - require.Equal(t, "", nextToken) - require.Len(t, grants, 1) + require.Equal(t, "{\"states\":[{\"type\":\"member\"}],\"current_state\":{\"type\":\"maintainer\"}}", nextToken) grant := v2.Grant{ Entitlement: &entitlement,