@@ -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
247270func (o * orgRoleResourceType ) Grant (ctx context.Context , principal * v2.Resource , entitlement * v2.Entitlement ) (annotations.Annotations , error ) {
0 commit comments