Skip to content

Commit 718aed6

Browse files
authored
Merge pull request #88 from ConductorOne/BB763_account_deprovisioning
[BB-763] baton-github: add account deprovisioning
2 parents f80c09e + 10ceb17 commit 718aed6

File tree

4 files changed

+129
-18
lines changed

4 files changed

+129
-18
lines changed

pkg/connector/connector.go

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ func (gh *GitHub) ResourceSyncers(ctx context.Context) []connectorbuilder.Resour
9393
resourceSyncers := []connectorbuilder.ResourceSyncer{
9494
orgBuilder(gh.client, gh.appClient, gh.orgCache, gh.orgs, gh.syncSecrets),
9595
teamBuilder(gh.client, gh.orgCache),
96-
userBuilder(gh.client, gh.hasSAMLEnabled, gh.graphqlClient, gh.orgCache),
96+
userBuilder(gh.client, gh.hasSAMLEnabled, gh.graphqlClient, gh.orgCache, gh.orgs),
9797
repositoryBuilder(gh.client, gh.orgCache),
9898
orgRoleBuilder(gh.client, gh.orgCache),
9999
invitationBuilder(invitationBuilderParams{
100100
client: gh.client,
101101
orgCache: gh.orgCache,
102+
orgs: gh.orgs,
102103
}),
103104
}
104105

@@ -145,28 +146,16 @@ func (gh *GitHub) Validate(ctx context.Context) (annotations.Annotations, error)
145146
return gh.validateAppCredentials(ctx)
146147
}
147148

148-
page := 0
149149
orgLogins := gh.orgs
150150
filterOrgs := true
151151

152152
if len(orgLogins) == 0 {
153153
filterOrgs = false
154-
for {
155-
orgs, resp, err := gh.client.Organizations.List(ctx, "", &github.ListOptions{Page: page})
156-
if err != nil {
157-
return nil, fmt.Errorf("github-connector: failed to retrieve org: %w", err)
158-
}
159-
if resp.StatusCode == http.StatusUnauthorized {
160-
return nil, status.Error(codes.Unauthenticated, "github token is not authorized")
161-
}
162-
for _, o := range orgs {
163-
orgLogins = append(orgLogins, o.GetLogin())
164-
}
165154

166-
if resp.NextPage == 0 {
167-
break
168-
}
169-
page = resp.NextPage
155+
var err error
156+
orgLogins, err = getOrgs(ctx, gh.client, orgLogins)
157+
if err != nil {
158+
return nil, err
170159
}
171160
}
172161

@@ -424,3 +413,32 @@ func (r *appTokenRefresher) Token() (*oauth2.Token, error) {
424413
Expiry: token.GetExpiresAt().Time,
425414
}, nil
426415
}
416+
417+
func getOrgs(ctx context.Context, client *github.Client, orgs []string) ([]string, error) {
418+
if len(orgs) != 0 {
419+
return orgs, nil
420+
}
421+
422+
var (
423+
page = 0
424+
orgLogins []string
425+
)
426+
for {
427+
orgs, resp, err := client.Organizations.List(ctx, "", &github.ListOptions{Page: page})
428+
if err != nil {
429+
return nil, fmt.Errorf("github-connector: failed to retrieve org: %w", err)
430+
}
431+
if resp.StatusCode == http.StatusUnauthorized {
432+
return nil, status.Error(codes.Unauthenticated, "github token is not authorized")
433+
}
434+
for _, o := range orgs {
435+
orgLogins = append(orgLogins, o.GetLogin())
436+
}
437+
438+
if resp.NextPage == 0 {
439+
break
440+
}
441+
page = resp.NextPage
442+
}
443+
return orgLogins, nil
444+
}

pkg/connector/invitation.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package connector
33
import (
44
"context"
55
"fmt"
6+
"strconv"
67

78
v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
89
"github.com/conductorone/baton-sdk/pkg/annotations"
@@ -41,6 +42,7 @@ func invitationToUserResource(invitation *github.Invitation) (*v2.Resource, erro
4142
type invitationResourceType struct {
4243
client *github.Client
4344
orgCache *orgNameCache
45+
orgs []string
4446
}
4547

4648
func (i *invitationResourceType) ResourceType(_ context.Context) *v2.ResourceType {
@@ -153,6 +155,47 @@ func (i *invitationResourceType) CreateAccount(
153155
}, nil, nil, nil
154156
}
155157

158+
func (i *invitationResourceType) Delete(ctx context.Context, resourceId *v2.ResourceId) (annotations.Annotations, error) {
159+
if resourceId.ResourceType != resourceTypeInvitation.Id {
160+
return nil, fmt.Errorf("baton-github: non-invitation resource passed to invitation delete")
161+
}
162+
163+
orgs, err := getOrgs(ctx, i.client, i.orgs)
164+
if err != nil {
165+
return nil, err
166+
}
167+
168+
invitationID, err := strconv.ParseInt(resourceId.GetResource(), 10, 64)
169+
if err != nil {
170+
return nil, fmt.Errorf("baton-github: invalid invitation id")
171+
}
172+
173+
var (
174+
isRemoved = false
175+
resp *github.Response
176+
)
177+
178+
for _, org := range orgs {
179+
resp, err = i.client.Organizations.CancelInvite(ctx, org, invitationID)
180+
if err == nil {
181+
isRemoved = true
182+
}
183+
}
184+
185+
if !isRemoved {
186+
return nil, fmt.Errorf("baton-github: failed to cancel invite")
187+
}
188+
189+
restApiRateLimit, err := extractRateLimitData(resp)
190+
if err != nil {
191+
return nil, err
192+
}
193+
194+
var annotations annotations.Annotations
195+
annotations.WithRateLimiting(restApiRateLimit)
196+
return annotations, nil
197+
}
198+
156199
type createUserParams struct {
157200
org string
158201
email *string
@@ -179,11 +222,13 @@ func getCreateUserParams(accountInfo *v2.AccountInfo) (*createUserParams, error)
179222
type invitationBuilderParams struct {
180223
client *github.Client
181224
orgCache *orgNameCache
225+
orgs []string
182226
}
183227

184228
func invitationBuilder(p invitationBuilderParams) *invitationResourceType {
185229
return &invitationResourceType{
186230
client: p.client,
187231
orgCache: p.orgCache,
232+
orgs: p.orgs,
188233
}
189234
}

pkg/connector/user.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ type userResourceType struct {
9292
graphqlClient *githubv4.Client
9393
hasSAMLEnabled *bool
9494
orgCache *orgNameCache
95+
orgs []string
9596
}
9697

9798
func (o *userResourceType) ResourceType(_ context.Context) *v2.ResourceType {
@@ -224,13 +225,59 @@ func (o *userResourceType) Grants(_ context.Context, _ *v2.Resource, _ *paginati
224225
return nil, "", nil, nil
225226
}
226227

227-
func userBuilder(client *github.Client, hasSAMLEnabled *bool, graphqlClient *githubv4.Client, orgCache *orgNameCache) *userResourceType {
228+
func (o *userResourceType) Delete(ctx context.Context, resourceId *v2.ResourceId) (annotations.Annotations, error) {
229+
if resourceId.ResourceType != resourceTypeUser.Id {
230+
return nil, fmt.Errorf("baton-github: non-user resource passed to user delete")
231+
}
232+
233+
orgs, err := getOrgs(ctx, o.client, o.orgs)
234+
if err != nil {
235+
return nil, err
236+
}
237+
238+
userID, err := strconv.ParseInt(resourceId.GetResource(), 10, 64)
239+
if err != nil {
240+
return nil, fmt.Errorf("baton-github: invalid invitation id")
241+
}
242+
243+
u, _, err := o.client.Users.GetByID(ctx, userID)
244+
if err != nil {
245+
return nil, fmt.Errorf("baton-github: invalid userID")
246+
}
247+
248+
var (
249+
isRemoved = false
250+
resp *github.Response
251+
)
252+
for _, org := range orgs {
253+
resp, err = o.client.Organizations.RemoveOrgMembership(ctx, u.GetLogin(), org)
254+
if err == nil {
255+
isRemoved = true
256+
}
257+
}
258+
259+
if !isRemoved {
260+
return nil, fmt.Errorf("baton-github: failed to cancel user")
261+
}
262+
263+
restApiRateLimit, err := extractRateLimitData(resp)
264+
if err != nil {
265+
return nil, err
266+
}
267+
268+
var annotations annotations.Annotations
269+
annotations.WithRateLimiting(restApiRateLimit)
270+
return annotations, nil
271+
}
272+
273+
func userBuilder(client *github.Client, hasSAMLEnabled *bool, graphqlClient *githubv4.Client, orgCache *orgNameCache, orgs []string) *userResourceType {
228274
return &userResourceType{
229275
resourceType: resourceTypeUser,
230276
client: client,
231277
graphqlClient: graphqlClient,
232278
hasSAMLEnabled: hasSAMLEnabled,
233279
orgCache: orgCache,
280+
orgs: orgs,
234281
}
235282
}
236283

pkg/connector/user_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func TestUsersList(t *testing.T) {
4949
testCase.hasSamlEnabled,
5050
graphQLClient,
5151
cache,
52+
[]string{organization.DisplayName},
5253
)
5354

5455
users, nextToken, annotations, err := client.List(

0 commit comments

Comments
 (0)