Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions github/enterprise_scim.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,62 @@ func (s *EnterpriseService) ProvisionSCIMUser(ctx context.Context, enterprise st
return userProvisioned, resp, nil
}

// GetProvisionedSCIMGroup gets information about a SCIM group.
//
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/scim#get-scim-provisioning-information-for-an-enterprise-group
//
//meta:operation GET /scim/v2/enterprises/{enterprise}/Groups/{scim_group_id}
func (s *EnterpriseService) GetProvisionedSCIMGroup(ctx context.Context, enterprise, scimGroupID, excludedAttributes string) (*SCIMEnterpriseGroupAttributes, *Response, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not?

Suggested change
func (s *EnterpriseService) GetProvisionedSCIMGroup(ctx context.Context, enterprise, scimGroupID, excludedAttributes string) (*SCIMEnterpriseGroupAttributes, *Response, error) {
func (s *EnterpriseService) GetProvisionedSCIMGroup(ctx context.Context, enterprise, scimGroupID string, opts *GetProvisionedSCIMGroupOptions) (*SCIMEnterpriseGroupAttributes, *Response, error) {

where:

type GetProvisionedSCIMGroupOptions struct {
	ExcludedAttributes *string `url:"excludedAttributes,omitempty"`
}

Let's not reinvent a wheel and make everything consistent.

Copy link
Contributor Author

@elminster-aom elminster-aom Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not?

Because I felt a bit overkilling to create a structure here but I'll follow your advice.

Copy link
Contributor Author

@elminster-aom elminster-aom Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexandear I followed your advice, commit 7ecf378
It must be ready for merging, let me know

var err error
u := fmt.Sprintf("scim/v2/enterprises/%v/Groups/%v", enterprise, scimGroupID)
if excludedAttributes != "" {
u, err = addOptions(u, &ListProvisionedSCIMGroupsEnterpriseOptions{
ExcludedAttributes: &excludedAttributes,
})
if err != nil {
return nil, nil, err
}
}

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeSCIM)

group := new(SCIMEnterpriseGroupAttributes)
resp, err := s.client.Do(ctx, req, group)
if err != nil {
return nil, resp, err
}

return group, resp, nil
}

// GetProvisionedSCIMUser gets information about a SCIM user.
//
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/scim#get-scim-provisioning-information-for-an-enterprise-user
//
//meta:operation GET /scim/v2/enterprises/{enterprise}/Users/{scim_user_id}
func (s *EnterpriseService) GetProvisionedSCIMUser(ctx context.Context, enterprise, scimUserID string) (*SCIMEnterpriseUserAttributes, *Response, error) {
var err error
u := fmt.Sprintf("scim/v2/enterprises/%v/Users/%v", enterprise, scimUserID)

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
req.Header.Set("Accept", mediaTypeSCIM)

user := new(SCIMEnterpriseUserAttributes)
resp, err := s.client.Do(ctx, req, user)
if err != nil {
return nil, resp, err
}

return user, resp, nil
}

// DeleteSCIMGroup deletes a SCIM group from an enterprise.
//
// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/scim#delete-a-scim-group-from-an-enterprise
Expand Down
181 changes: 181 additions & 0 deletions github/enterprise_scim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,187 @@ func TestEnterpriseService_ProvisionSCIMUser(t *testing.T) {
})
}

func TestEnterpriseService_GetProvisionedSCIMGroup(t *testing.T) {
t.Parallel()
client, mux, _ := setup(t)

// Test 1 without values
mux.HandleFunc("/scim/v2/enterprises/ee/Groups/914a", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeSCIM)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, `{
"schemas": ["`+SCIMSchemasURINamespacesGroups+`"],
"id": "914a",
"externalId": "de88",
"displayName": "gn1",
"meta": {
"resourceType": "Group",
"created": `+referenceTimeStr+`,
"lastModified": `+referenceTimeStr+`,
"location": "https://api.github.com/scim/v2/enterprises/ee/Groups/914a"
},
"members": [{
"value": "e7f9",
"$ref": "https://api.github.com/scim/v2/enterprises/ee/Users/e7f9",
"display": "d1"
}]
}`)
})

ctx := t.Context()
got1, _, err := client.Enterprise.GetProvisionedSCIMGroup(ctx, "ee", "914a", "")
if err != nil {
t.Fatalf("Enterprise.GetProvisionedSCIMGroup returned unexpected error: %v", err)
}

want1 := &SCIMEnterpriseGroupAttributes{
ID: Ptr("914a"),
Meta: &SCIMEnterpriseMeta{
ResourceType: "Group",
Created: &Timestamp{referenceTime},
LastModified: &Timestamp{referenceTime},
Location: Ptr("https://api.github.com/scim/v2/enterprises/ee/Groups/914a"),
},
DisplayName: Ptr("gn1"),
Schemas: []string{SCIMSchemasURINamespacesGroups},
ExternalID: Ptr("de88"),
Members: []*SCIMEnterpriseDisplayReference{{
Value: "e7f9",
Ref: Ptr("https://api.github.com/scim/v2/enterprises/ee/Users/e7f9"),
Display: Ptr("d1"),
}},
}

if diff := cmp.Diff(want1, got1); diff != "" {
t.Fatalf("Enterprise.GetProvisionedSCIMGroup diff mismatch (-want +got):\n%v", diff)
}

// Test 2 with values
mux.HandleFunc("/scim/v2/enterprises/ee/Groups/78ba", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeSCIM)
testFormValues(t, r, values{"excludedAttributes": "externalId,members,schemas,meta"})
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, `{
"id": "78ba",
"displayName": "gn2"
}`)
})

got2, _, err := client.Enterprise.GetProvisionedSCIMGroup(ctx, "ee", "78ba", "externalId,members,schemas,meta")
if err != nil {
t.Fatalf("Enterprise.GetProvisionedSCIMGroup returned unexpected error: %v", err)
}

want2 := &SCIMEnterpriseGroupAttributes{
ID: Ptr("78ba"),
DisplayName: Ptr("gn2"),
}

if diff := cmp.Diff(want2, got2); diff != "" {
t.Fatalf("Enterprise.GetProvisionedSCIMGroup diff mismatch (-want +got):\n%v", diff)
}

const methodName = "GetProvisionedSCIMGroup"
testBadOptions(t, methodName, func() (err error) {
_, _, err = client.Enterprise.GetProvisionedSCIMGroup(ctx, "ee", "\n", "")
return err
})

testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
got, resp, err := client.Enterprise.GetProvisionedSCIMGroup(ctx, "ee", "914a", "meta")
if got != nil {
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
}
return resp, err
})
}

func TestEnterpriseService_GetProvisionedSCIMUser(t *testing.T) {
t.Parallel()
client, mux, _ := setup(t)

mux.HandleFunc("/scim/v2/enterprises/ee/Users/5fc0", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeSCIM)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, `{
"schemas": ["`+SCIMSchemasURINamespacesUser+`"],
"id": "5fc0",
"externalId": "00u1",
"userName": "[email protected]",
"displayName": "Mona Octocat",
"name": {
"givenName": "Mona",
"familyName": "Octocat",
"formatted": "Mona Octocat"
},
"emails": [
{
"value": "[email protected]",
"primary": true
}
],
"active": true,
"meta": {
"resourceType": "User",
"created": `+referenceTimeStr+`,
"lastModified": `+referenceTimeStr+`,
"location": "https://api.github.com/scim/v2/enterprises/ee/Users/5fc0"
}
}`)
})

ctx := t.Context()
got, _, err := client.Enterprise.GetProvisionedSCIMUser(ctx, "ee", "5fc0")
if err != nil {
t.Fatalf("Enterprise.GetProvisionedSCIMUser returned unexpected error: %v", err)
}

want := &SCIMEnterpriseUserAttributes{
Schemas: []string{SCIMSchemasURINamespacesUser},
ID: Ptr("5fc0"),
ExternalID: "00u1",
UserName: "[email protected]",
DisplayName: "Mona Octocat",
Name: &SCIMEnterpriseUserName{
GivenName: "Mona",
FamilyName: "Octocat",
Formatted: Ptr("Mona Octocat"),
},
Emails: []*SCIMEnterpriseUserEmail{{
Value: "[email protected]",
Primary: true,
}},
Active: true,
Meta: &SCIMEnterpriseMeta{
ResourceType: "User",
Created: &Timestamp{referenceTime},
LastModified: &Timestamp{referenceTime},
Location: Ptr("https://api.github.com/scim/v2/enterprises/ee/Users/5fc0"),
},
}

if diff := cmp.Diff(want, got); diff != "" {
t.Fatalf("Enterprise.GetProvisionedSCIMUser diff mismatch (-want +got):\n%v", diff)
}

const methodName = "GetProvisionedSCIMUser"
testBadOptions(t, methodName, func() (err error) {
_, _, err = client.Enterprise.GetProvisionedSCIMUser(ctx, "\n", "\n")
return err
})

testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
got, resp, err := client.Enterprise.GetProvisionedSCIMUser(ctx, "ee", "5fc0")
if got != nil {
t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
}
return resp, err
})
}

func TestEnterpriseService_DeleteSCIMGroup(t *testing.T) {
t.Parallel()
client, mux, _ := setup(t)
Expand Down
Loading