Skip to content

Commit 6922e3b

Browse files
feat: Implement Enterprise SCIM - Set Groups or Users (#3858)
1 parent bd1caa0 commit 6922e3b

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-0
lines changed

github/enterprise_scim.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,60 @@ func (s *EnterpriseService) ListProvisionedSCIMUsers(ctx context.Context, enterp
214214
return users, resp, nil
215215
}
216216

217+
// SetProvisionedSCIMGroup replaces an existing provisioned group’s information.
218+
//
219+
// You must provide all the information required for the group as if you were provisioning it for the first time. Any
220+
// existing group information that you don't provide will be removed, including group membership. To update only
221+
// specific attributes, refer to the `Enterprise.UpdateSCIMGroupAttribute()` method.
222+
//
223+
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/scim#set-scim-information-for-a-provisioned-enterprise-group
224+
//
225+
//meta:operation PUT /scim/v2/enterprises/{enterprise}/Groups/{scim_group_id}
226+
func (s *EnterpriseService) SetProvisionedSCIMGroup(ctx context.Context, enterprise, scimGroupID string, group SCIMEnterpriseGroupAttributes) (*SCIMEnterpriseGroupAttributes, *Response, error) {
227+
u := fmt.Sprintf("scim/v2/enterprises/%v/Groups/%v", enterprise, scimGroupID)
228+
req, err := s.client.NewRequest("PUT", u, group)
229+
if err != nil {
230+
return nil, nil, err
231+
}
232+
req.Header.Set("Accept", mediaTypeSCIM)
233+
234+
groupNew := new(SCIMEnterpriseGroupAttributes)
235+
resp, err := s.client.Do(ctx, req, groupNew)
236+
if err != nil {
237+
return nil, resp, err
238+
}
239+
240+
return groupNew, resp, nil
241+
}
242+
243+
// SetProvisionedSCIMUser replaces an existing provisioned user's information.
244+
//
245+
// You must supply complete user information, just as you would when provisioning them initially. Any previously
246+
// existing data not provided will be deleted. To update specific attributes only, refer to the
247+
// `Enterprise.UpdateSCIMUserAttribute()` method.
248+
//
249+
// **Warning**: Setting `active: false` will suspend a user, and their handle and email will be obfuscated.
250+
//
251+
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/scim#set-scim-information-for-a-provisioned-enterprise-user
252+
//
253+
//meta:operation PUT /scim/v2/enterprises/{enterprise}/Users/{scim_user_id}
254+
func (s *EnterpriseService) SetProvisionedSCIMUser(ctx context.Context, enterprise, scimUserID string, user SCIMEnterpriseUserAttributes) (*SCIMEnterpriseUserAttributes, *Response, error) {
255+
u := fmt.Sprintf("scim/v2/enterprises/%v/Users/%v", enterprise, scimUserID)
256+
req, err := s.client.NewRequest("PUT", u, user)
257+
if err != nil {
258+
return nil, nil, err
259+
}
260+
req.Header.Set("Accept", mediaTypeSCIM)
261+
262+
userNew := new(SCIMEnterpriseUserAttributes)
263+
resp, err := s.client.Do(ctx, req, userNew)
264+
if err != nil {
265+
return nil, resp, err
266+
}
267+
268+
return userNew, resp, nil
269+
}
270+
217271
// UpdateSCIMGroupAttribute updates a provisioned group’s individual attributes.
218272
//
219273
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/scim#update-an-attribute-for-a-scim-enterprise-group

github/enterprise_scim_test.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,155 @@ func TestEnterpriseService_ListProvisionedSCIMUsers(t *testing.T) {
479479
})
480480
}
481481

482+
func TestEnterpriseService_SetProvisionedSCIMGroup(t *testing.T) {
483+
t.Parallel()
484+
client, mux, _ := setup(t)
485+
486+
mux.HandleFunc("/scim/v2/enterprises/ee/Groups/abcd", func(w http.ResponseWriter, r *http.Request) {
487+
testMethod(t, r, "PUT")
488+
testHeader(t, r, "Accept", mediaTypeSCIM)
489+
testBody(t, r, `{"displayName":"dn","externalId":"8aa1","schemas":["`+SCIMSchemasURINamespacesGroups+`"]}`+"\n")
490+
w.WriteHeader(http.StatusOK)
491+
fmt.Fprint(w, `{
492+
"schemas": ["`+SCIMSchemasURINamespacesGroups+`"],
493+
"id": "abcd",
494+
"externalId": "8aa1",
495+
"displayName": "dn",
496+
"meta": {
497+
"resourceType": "Group",
498+
"created": `+referenceTimeStr+`,
499+
"lastModified": `+referenceTimeStr+`,
500+
"location": "https://api.github.localhost/scim/v2/enterprises/ee/Groups/abcd"
501+
}
502+
}`)
503+
})
504+
want := &SCIMEnterpriseGroupAttributes{
505+
Schemas: []string{SCIMSchemasURINamespacesGroups},
506+
ID: Ptr("abcd"),
507+
ExternalID: Ptr("8aa1"),
508+
DisplayName: Ptr("dn"),
509+
Meta: &SCIMEnterpriseMeta{
510+
ResourceType: "Group",
511+
Created: &Timestamp{referenceTime},
512+
LastModified: &Timestamp{referenceTime},
513+
Location: Ptr("https://api.github.localhost/scim/v2/enterprises/ee/Groups/abcd"),
514+
},
515+
}
516+
517+
ctx := t.Context()
518+
input := SCIMEnterpriseGroupAttributes{
519+
Schemas: []string{SCIMSchemasURINamespacesGroups},
520+
ExternalID: Ptr("8aa1"),
521+
DisplayName: Ptr("dn"),
522+
}
523+
got, _, err := client.Enterprise.SetProvisionedSCIMGroup(ctx, "ee", "abcd", input)
524+
if err != nil {
525+
t.Fatalf("Enterprise.SetProvisionedSCIMGroup returned unexpected error: %v", err)
526+
}
527+
if diff := cmp.Diff(want, got); diff != "" {
528+
t.Fatalf("Enterprise.SetProvisionedSCIMGroup diff mismatch (-want +got):\n%v", diff)
529+
}
530+
531+
const methodName = "SetProvisionedSCIMGroup"
532+
testBadOptions(t, methodName, func() (err error) {
533+
_, _, err = client.Enterprise.SetProvisionedSCIMGroup(ctx, "\n", "\n", SCIMEnterpriseGroupAttributes{})
534+
return err
535+
})
536+
537+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
538+
got, resp, err := client.Enterprise.SetProvisionedSCIMGroup(ctx, "ee", "abcd", input)
539+
if got != nil {
540+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
541+
}
542+
return resp, err
543+
})
544+
}
545+
546+
func TestEnterpriseService_SetProvisionedSCIMUser(t *testing.T) {
547+
t.Parallel()
548+
client, mux, _ := setup(t)
549+
550+
mux.HandleFunc("/scim/v2/enterprises/ee/Users/7fce", func(w http.ResponseWriter, r *http.Request) {
551+
testMethod(t, r, "PUT")
552+
testHeader(t, r, "Accept", mediaTypeSCIM)
553+
testBody(t, r, `{"displayName":"John Doe","userName":"e123","emails":[{"value":"john@email.com","primary":true,"type":"work"}],"externalId":"e123","active":true,"schemas":["`+SCIMSchemasURINamespacesUser+`"]}`+"\n")
554+
w.WriteHeader(http.StatusOK)
555+
fmt.Fprint(w, `{
556+
"schemas": ["`+SCIMSchemasURINamespacesUser+`"],
557+
"id": "7fce",
558+
"externalId": "e123",
559+
"active": true,
560+
"userName": "e123",
561+
"displayName": "John Doe",
562+
"emails": [{
563+
"value": "john@email.com",
564+
"type": "work",
565+
"primary": true
566+
}],
567+
"meta": {
568+
"resourceType": "User",
569+
"created": `+referenceTimeStr+`,
570+
"lastModified": `+referenceTimeStr+`,
571+
"location": "https://api.github.localhost/scim/v2/enterprises/ee/Users/7fce"
572+
}
573+
}`)
574+
})
575+
want := &SCIMEnterpriseUserAttributes{
576+
Schemas: []string{SCIMSchemasURINamespacesUser},
577+
ID: Ptr("7fce"),
578+
ExternalID: "e123",
579+
Active: true,
580+
UserName: "e123",
581+
DisplayName: "John Doe",
582+
Emails: []*SCIMEnterpriseUserEmail{{
583+
Value: "john@email.com",
584+
Type: "work",
585+
Primary: true,
586+
}},
587+
Meta: &SCIMEnterpriseMeta{
588+
ResourceType: "User",
589+
Created: &Timestamp{referenceTime},
590+
LastModified: &Timestamp{referenceTime},
591+
Location: Ptr("https://api.github.localhost/scim/v2/enterprises/ee/Users/7fce"),
592+
},
593+
}
594+
595+
ctx := t.Context()
596+
input := SCIMEnterpriseUserAttributes{
597+
Schemas: []string{SCIMSchemasURINamespacesUser},
598+
ExternalID: "e123",
599+
Active: true,
600+
UserName: "e123",
601+
DisplayName: "John Doe",
602+
Emails: []*SCIMEnterpriseUserEmail{{
603+
Value: "john@email.com",
604+
Type: "work",
605+
Primary: true,
606+
}},
607+
}
608+
got, _, err := client.Enterprise.SetProvisionedSCIMUser(ctx, "ee", "7fce", input)
609+
if err != nil {
610+
t.Fatalf("Enterprise.SetProvisionedSCIMUser returned unexpected error: %v", err)
611+
}
612+
if diff := cmp.Diff(want, got); diff != "" {
613+
t.Fatalf("Enterprise.SetProvisionedSCIMUser diff mismatch (-want +got):\n%v", diff)
614+
}
615+
616+
const methodName = "SetProvisionedSCIMUser"
617+
testBadOptions(t, methodName, func() (err error) {
618+
_, _, err = client.Enterprise.SetProvisionedSCIMUser(ctx, "\n", "\n", SCIMEnterpriseUserAttributes{})
619+
return err
620+
})
621+
622+
testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
623+
got, resp, err := client.Enterprise.SetProvisionedSCIMUser(ctx, "ee", "7fce", input)
624+
if got != nil {
625+
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
626+
}
627+
return resp, err
628+
})
629+
}
630+
482631
func TestEnterpriseService_UpdateSCIMGroupAttribute(t *testing.T) {
483632
t.Parallel()
484633
client, mux, _ := setup(t)

0 commit comments

Comments
 (0)