Skip to content

Commit f9d0764

Browse files
committed
Refactor Grants method in orgRole to improve pagination and error handling. Streamlined resource type checks and enhanced grant creation for users and teams, ensuring proper handling of permission errors and returning accurate annotations.
1 parent a76b437 commit f9d0764

File tree

1 file changed

+92
-69
lines changed

1 file changed

+92
-69
lines changed

pkg/connector/org_role.go

Lines changed: 92 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ func (o *orgRoleResourceType) Grants(
133133
return nil, "", nil, nil
134134
}
135135

136-
bag, page, err := parsePageToken(pToken.Token, &v2.ResourceId{ResourceType: resourceTypeOrgRole.Id})
136+
bag, page, err := parsePageToken(pToken.Token, resource.Id)
137137
if err != nil {
138138
return nil, "", nil, err
139139
}
@@ -143,105 +143,128 @@ func (o *orgRoleResourceType) Grants(
143143
return nil, "", nil, err
144144
}
145145

146+
var rv []*v2.Grant
147+
var reqAnnos annotations.Annotations
148+
146149
roleID, err := strconv.ParseInt(resource.Id.Resource, 10, 64)
147150
if err != nil {
148151
return nil, "", nil, fmt.Errorf("invalid role ID: %w", err)
149152
}
150153

151-
var ret []*v2.Grant
152-
153-
// First, get teams with this role
154-
opts := &github.ListOptions{
155-
Page: page,
156-
PerPage: pToken.Size,
157-
}
158-
teams, resp, err := o.client.Organizations.ListTeamsAssignedToOrgRole(ctx, orgName, roleID, opts)
159-
if err != nil {
160-
// Handle permission errors without erroring out. Some customers may not want to give us permissions to get org roles and members.
161-
if resp != nil && (resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusNotFound) {
162-
// Return empty list with no error to indicate we skipped this resource
163-
pageToken, err := bag.NextToken("")
164-
if err != nil {
165-
return nil, "", nil, err
154+
switch bag.ResourceTypeID() {
155+
case resourceTypeOrgRole.Id:
156+
bag.Pop()
157+
bag.Push(pagination.PageState{
158+
ResourceTypeID: resourceTypeUser.Id,
159+
})
160+
bag.Push(pagination.PageState{
161+
ResourceTypeID: resourceTypeTeam.Id,
162+
})
163+
case resourceTypeUser.Id:
164+
opts := &github.ListOptions{
165+
Page: page,
166+
}
167+
users, resp, err := o.client.Organizations.ListUsersAssignedToOrgRole(ctx, orgName, roleID, opts)
168+
if err != nil {
169+
if resp != nil && (resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusNotFound) {
170+
pageToken, err := bag.NextToken("")
171+
if err != nil {
172+
return nil, "", nil, err
173+
}
174+
return rv, pageToken, nil, nil
166175
}
167-
return nil, pageToken, nil, nil
176+
return nil, "", nil, fmt.Errorf("failed to list role users: %w", err)
168177
}
169-
return nil, "", nil, fmt.Errorf("failed to list role teams: %w", err)
170-
}
171-
172-
// Create expandable grants for teams. To show inherited roles, we need to show the teams that have the role.
173-
for _, team := range teams {
174-
teamResource, err := teamResource(team, resource.ParentResourceId)
178+
nextPage, respAnnos, err := parseResp(resp)
175179
if err != nil {
176180
return nil, "", nil, err
177181
}
182+
reqAnnos = respAnnos
178183

179-
grant := grant.NewGrant(
180-
resource,
181-
"assigned",
182-
teamResource.Id,
183-
grant.WithAnnotation(&v2.GrantExpandable{
184-
EntitlementIds: []string{fmt.Sprintf("team:%d:member", team.GetID())},
185-
Shallow: true,
186-
}),
187-
)
188-
ret = append(ret, grant)
189-
}
190-
191-
// If we got a full page of teams, return them and let the next page handle users
192-
if len(teams) == pToken.Size {
193-
pageToken, err := bag.NextToken(fmt.Sprintf("%d", page+1))
184+
err = bag.Next(nextPage)
194185
if err != nil {
195186
return nil, "", nil, err
196187
}
197-
return ret, pageToken, nil, nil
198-
}
199188

200-
// Then, get direct user assignments
201-
users, resp, err := o.client.Organizations.ListUsersAssignedToOrgRole(ctx, orgName, roleID, opts)
202-
if err != nil {
203-
// Handle permission errors without erroring out. Some customers may not want to give us permissions to get org roles and members.
204-
if resp != nil && (resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusNotFound) {
205-
// Return empty list with no error to indicate we skipped this resource
206-
pageToken, err := bag.NextToken("")
189+
// Create regular grants for direct user assignments.
190+
for _, user := range users {
191+
userResource, err := userResource(ctx, user, user.GetEmail(), nil)
207192
if err != nil {
208193
return nil, "", nil, err
209194
}
210-
return nil, pageToken, nil, nil
195+
196+
grant := grant.NewGrant(
197+
resource,
198+
"assigned",
199+
userResource.Id,
200+
grant.WithAnnotation(&v2.V1Identifier{
201+
Id: fmt.Sprintf("org-role:%s:%d:%d", resource.Id.Resource, user.GetID(), roleID),
202+
}),
203+
)
204+
grant.Principal = userResource
205+
rv = append(rv, grant)
206+
}
207+
case resourceTypeTeam.Id:
208+
opts := &github.ListOptions{
209+
Page: page,
210+
}
211+
teams, resp, err := o.client.Organizations.ListTeamsAssignedToOrgRole(ctx, orgName, roleID, opts)
212+
if err != nil {
213+
// Handle permission errors without erroring out. Some customers may not want to give us permissions to get org roles and members.
214+
if resp != nil && (resp.StatusCode == http.StatusForbidden || resp.StatusCode == http.StatusNotFound) {
215+
// Return empty list with no error to indicate we skipped this resource
216+
pageToken, err := bag.NextToken("")
217+
if err != nil {
218+
return nil, "", nil, err
219+
}
220+
return nil, pageToken, nil, nil
221+
}
222+
return nil, "", nil, fmt.Errorf("failed to list role teams: %w", err)
211223
}
212-
return nil, "", nil, fmt.Errorf("failed to list role users: %w", err)
213-
}
214224

215-
// Create grants for users
216-
for _, user := range users {
217-
userResource, err := userResource(ctx, user, *user.Email, nil)
225+
nextPage, respAnnos, err := parseResp(resp)
218226
if err != nil {
219227
return nil, "", nil, err
220228
}
229+
reqAnnos = respAnnos
221230

222-
grant := grant.NewGrant(
223-
resource,
224-
"assigned",
225-
userResource.Id,
226-
)
227-
ret = append(ret, grant)
228-
}
229-
230-
// If we got a full page of users, return them and let the next page handle more users
231-
if len(users) == pToken.Size {
232-
pageToken, err := bag.NextToken(fmt.Sprintf("%d", page+1))
231+
err = bag.Next(nextPage)
233232
if err != nil {
234233
return nil, "", nil, err
235234
}
236-
return ret, pageToken, nil, nil
237-
}
238235

239-
// No more pages
240-
pageToken, err := bag.NextToken("")
236+
// Create expandable grants for teams. To show inherited roles, we need to show the teams that have the role.
237+
for _, team := range teams {
238+
teamResource, err := teamResource(team, resource.ParentResourceId)
239+
if err != nil {
240+
return nil, "", nil, err
241+
}
242+
rv = append(rv, grant.NewGrant(
243+
resource,
244+
"assigned",
245+
teamResource.Id,
246+
grant.WithAnnotation(&v2.V1Identifier{
247+
Id: fmt.Sprintf("org-role-grant:%s:%d:%s", resource.Id.Resource, team.GetID(), "assigned"),
248+
},
249+
&v2.GrantExpandable{
250+
EntitlementIds: []string{
251+
entitlement.NewEntitlementID(teamResource, teamRoleMaintainer),
252+
entitlement.NewEntitlementID(teamResource, teamRoleMember),
253+
},
254+
Shallow: true,
255+
},
256+
),
257+
))
258+
}
259+
default:
260+
return nil, "", nil, fmt.Errorf("unexpected resource type while fetching grants for org role")
261+
}
262+
pageToken, err := bag.Marshal()
241263
if err != nil {
242264
return nil, "", nil, err
243265
}
244-
return ret, pageToken, nil, nil
266+
267+
return rv, pageToken, reqAnnos, nil
245268
}
246269

247270
func (o *orgRoleResourceType) Grant(ctx context.Context, principal *v2.Resource, entitlement *v2.Entitlement) (annotations.Annotations, error) {

0 commit comments

Comments
 (0)