From f3a6c67350cb0ee8d27d8321bd9ab3c282b59e75 Mon Sep 17 00:00:00 2001 From: Travis Fields Date: Fri, 7 Feb 2025 16:33:40 -0800 Subject: [PATCH 1/4] Add ListProvisionedScimGroupsForEnterprise inside SCIM service with test --- github/github-accessors.go | 64 ++++++++++++++++++++++ github/github-accessors_test.go | 85 +++++++++++++++++++++++++++++ github/scim.go | 50 ++++++++++++++++++ github/scim_test.go | 94 +++++++++++++++++++++++++++++++++ 4 files changed, 293 insertions(+) diff --git a/github/github-accessors.go b/github/github-accessors.go index 1685959173c..6270bc1fc6c 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -23894,6 +23894,46 @@ func (s *ScanningAnalysis) GetWarning() string { return *s.Warning } +// GetDisplay returns the Display field if it's non-nil, zero value otherwise. +func (s *SCIMDisplayReference) GetDisplay() string { + if s == nil || s.Display == nil { + return "" + } + return *s.Display +} + +// GetDisplayName returns the DisplayName field if it's non-nil, zero value otherwise. +func (s *SCIMGroupAttributes) GetDisplayName() string { + if s == nil || s.DisplayName == nil { + return "" + } + return *s.DisplayName +} + +// GetExternalID returns the ExternalID field if it's non-nil, zero value otherwise. +func (s *SCIMGroupAttributes) GetExternalID() string { + if s == nil || s.ExternalID == nil { + return "" + } + return *s.ExternalID +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (s *SCIMGroupAttributes) GetID() string { + if s == nil || s.ID == nil { + return "" + } + return *s.ID +} + +// GetMeta returns the Meta field. +func (s *SCIMGroupAttributes) GetMeta() *SCIMMeta { + if s == nil { + return nil + } + return s.Meta +} + // GetCreated returns the Created field if it's non-nil, zero value otherwise. func (s *SCIMMeta) GetCreated() Timestamp { if s == nil || s.Created == nil { @@ -23926,6 +23966,30 @@ func (s *SCIMMeta) GetResourceType() string { return *s.ResourceType } +// GetItemsPerPage returns the ItemsPerPage field if it's non-nil, zero value otherwise. +func (s *SCIMProvisionedGroups) GetItemsPerPage() int { + if s == nil || s.ItemsPerPage == nil { + return 0 + } + return *s.ItemsPerPage +} + +// GetStartIndex returns the StartIndex field if it's non-nil, zero value otherwise. +func (s *SCIMProvisionedGroups) GetStartIndex() int { + if s == nil || s.StartIndex == nil { + return 0 + } + return *s.StartIndex +} + +// GetTotalResults returns the TotalResults field if it's non-nil, zero value otherwise. +func (s *SCIMProvisionedGroups) GetTotalResults() int { + if s == nil || s.TotalResults == nil { + return 0 + } + return *s.TotalResults +} + // GetItemsPerPage returns the ItemsPerPage field if it's non-nil, zero value otherwise. func (s *SCIMProvisionedIdentities) GetItemsPerPage() int { if s == nil || s.ItemsPerPage == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index cee65415517..b3be0c11f27 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -30744,6 +30744,58 @@ func TestScanningAnalysis_GetWarning(tt *testing.T) { s.GetWarning() } +func TestSCIMDisplayReference_GetDisplay(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SCIMDisplayReference{Display: &zeroValue} + s.GetDisplay() + s = &SCIMDisplayReference{} + s.GetDisplay() + s = nil + s.GetDisplay() +} + +func TestSCIMGroupAttributes_GetDisplayName(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SCIMGroupAttributes{DisplayName: &zeroValue} + s.GetDisplayName() + s = &SCIMGroupAttributes{} + s.GetDisplayName() + s = nil + s.GetDisplayName() +} + +func TestSCIMGroupAttributes_GetExternalID(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SCIMGroupAttributes{ExternalID: &zeroValue} + s.GetExternalID() + s = &SCIMGroupAttributes{} + s.GetExternalID() + s = nil + s.GetExternalID() +} + +func TestSCIMGroupAttributes_GetID(tt *testing.T) { + tt.Parallel() + var zeroValue string + s := &SCIMGroupAttributes{ID: &zeroValue} + s.GetID() + s = &SCIMGroupAttributes{} + s.GetID() + s = nil + s.GetID() +} + +func TestSCIMGroupAttributes_GetMeta(tt *testing.T) { + tt.Parallel() + s := &SCIMGroupAttributes{} + s.GetMeta() + s = nil + s.GetMeta() +} + func TestSCIMMeta_GetCreated(tt *testing.T) { tt.Parallel() var zeroValue Timestamp @@ -30788,6 +30840,39 @@ func TestSCIMMeta_GetResourceType(tt *testing.T) { s.GetResourceType() } +func TestSCIMProvisionedGroups_GetItemsPerPage(tt *testing.T) { + tt.Parallel() + var zeroValue int + s := &SCIMProvisionedGroups{ItemsPerPage: &zeroValue} + s.GetItemsPerPage() + s = &SCIMProvisionedGroups{} + s.GetItemsPerPage() + s = nil + s.GetItemsPerPage() +} + +func TestSCIMProvisionedGroups_GetStartIndex(tt *testing.T) { + tt.Parallel() + var zeroValue int + s := &SCIMProvisionedGroups{StartIndex: &zeroValue} + s.GetStartIndex() + s = &SCIMProvisionedGroups{} + s.GetStartIndex() + s = nil + s.GetStartIndex() +} + +func TestSCIMProvisionedGroups_GetTotalResults(tt *testing.T) { + tt.Parallel() + var zeroValue int + s := &SCIMProvisionedGroups{TotalResults: &zeroValue} + s.GetTotalResults() + s = &SCIMProvisionedGroups{} + s.GetTotalResults() + s = nil + s.GetTotalResults() +} + func TestSCIMProvisionedIdentities_GetItemsPerPage(tt *testing.T) { tt.Parallel() var zeroValue int diff --git a/github/scim.go b/github/scim.go index 4b34c1663cd..738141e0a5c 100644 --- a/github/scim.go +++ b/github/scim.go @@ -17,6 +17,25 @@ import ( // GitHub API docs: https://docs.github.com/rest/scim type SCIMService service +// SCIMGroupAttributes represents supported SCIM Group attributes. +// +// GitHub API docs: https://docs.github.com/en/enterprise-cloud@latest/rest/enterprise-admin/scim#list-provisioned-scim-groups-for-an-enterprise +type SCIMGroupAttributes struct { + DisplayName *string `json:"displayName,omitempty"` // The name of the group, suitable for display to end-users. (Optional.) + Members []*SCIMDisplayReference `json:"members,omitempty"` // (Optional.) + Schemas []string `json:"schemas,omitempty"` // (Optional.) + ExternalID *string `json:"externalId,omitempty"` // (Optional.) + // Only populated as a result of calling ListSCIMProvisionedIdentitiesOptions: + ID *string `json:"id,omitempty"` + Meta *SCIMMeta `json:"meta,omitempty"` +} + +type SCIMDisplayReference struct { + Value string `json:"value"` // (Required.) + Ref string `json:"$ref"` // (Required.) + Display *string `json:"display,omitempty"` // (Optional.) +} + // SCIMUserAttributes represents supported SCIM User attributes. // // GitHub API docs: https://docs.github.com/rest/scim#supported-scim-user-attributes @@ -56,6 +75,15 @@ type SCIMMeta struct { Location *string `json:"location,omitempty"` } +// SCIMProvisionedGroups represents the result of calling ListSCIMProvisionedGroupsForEnterprise. +type SCIMProvisionedGroups struct { + Schemas []string `json:"schemas,omitempty"` + TotalResults *int `json:"totalResults,omitempty"` + ItemsPerPage *int `json:"itemsPerPage,omitempty"` + StartIndex *int `json:"startIndex,omitempty"` + Resources []*SCIMGroupAttributes `json:"Resources,omitempty"` +} + // SCIMProvisionedIdentities represents the result of calling ListSCIMProvisionedIdentities. type SCIMProvisionedIdentities struct { Schemas []string `json:"schemas,omitempty"` @@ -217,3 +245,25 @@ func (s *SCIMService) DeleteSCIMUserFromOrg(ctx context.Context, org, scimUserID return s.client.Do(ctx, req, nil) } + +// ListSCIMProvisionedGroupsForEnterprise lists SCIM provisioned groups for an enterprise. +// +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/scim#list-provisioned-scim-groups-for-an-enterprise +// +//meta:operation GET /scim/v2/enterprises/{enterprise}/Groups +func (s *SCIMService) ListSCIMProvisionedGroupsForEnterprise(ctx context.Context, enterprise string, opts *ListSCIMProvisionedIdentitiesOptions) (*SCIMProvisionedGroups, *Response, error) { + u := fmt.Sprintf("scim/v2/enterprises/%v/Groups", enterprise) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + groups := new(SCIMProvisionedGroups) + resp, err := s.client.Do(ctx, req, groups) + if err != nil { + return nil, resp, err + } + + return groups, resp, nil +} diff --git a/github/scim_test.go b/github/scim_test.go index a6c806cb574..42a6f2331ed 100644 --- a/github/scim_test.go +++ b/github/scim_test.go @@ -121,6 +121,100 @@ func TestSCIMService_ListSCIMProvisionedIdentities(t *testing.T) { }) } +func TestSCIMService_ListSCIMProvisionedGroups(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/scim/v2/enterprises/o/Groups", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{ + "schemas": [ + "urn:ietf:params:scim:api:messages:2.0:ListResponse" + ], + "totalResults": 1, + "itemsPerPage": 1, + "startIndex": 1, + "Resources": [ + { + "schemas": [ + "urn:ietf:params:scim:schemas:core:2.0:Group" + ], + "id": "123e4567-e89b-12d3-a456-426614174000", + "externalId": "00u1dhhb1fkIGP7RL1d8", + "displayName": "Mona Octocat", + "meta": { + "resourceType": "Group", + "created": "2018-02-13T15:05:24.000-00:00", + "lastModified": "2018-02-13T15:05:24.000-00:00", + "location": "https://api.github.com/scim/v2/enterprises/octo/Groups/123e4567-e89b-12d3-a456-426614174000" + }, + "members": [ + { + "value": "5fc0c238-1112-11e8-8e45-920c87bdbd75", + "$ref": "https://api.github.com/scim/v2/enterprises/octo/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75", + "display": "Mona Octocat" + } + ] + } + ] + }`)) + }) + + ctx := context.Background() + opts := &ListSCIMProvisionedIdentitiesOptions{} + groups, _, err := client.SCIM.ListSCIMProvisionedGroupsForEnterprise(ctx, "o", opts) + if err != nil { + t.Errorf("SCIM.ListSCIMProvisionedIdentities returned error: %v", err) + } + + date := Timestamp{time.Date(2018, time.February, 13, 15, 5, 24, 0, time.UTC)} + want := SCIMProvisionedGroups{ + Schemas: []string{"urn:ietf:params:scim:api:messages:2.0:ListResponse"}, + TotalResults: Ptr(1), + ItemsPerPage: Ptr(1), + StartIndex: Ptr(1), + Resources: []*SCIMGroupAttributes{ + { + ID: Ptr("123e4567-e89b-12d3-a456-426614174000"), + Meta: &SCIMMeta{ + ResourceType: Ptr("Group"), + Created: &date, + LastModified: &date, + Location: Ptr("https://api.github.com/scim/v2/enterprises/octo/Groups/123e4567-e89b-12d3-a456-426614174000"), + }, + + DisplayName: Ptr("Mona Octocat"), + Schemas: []string{"urn:ietf:params:scim:schemas:core:2.0:Group"}, + ExternalID: Ptr("00u1dhhb1fkIGP7RL1d8"), + Members: []*SCIMDisplayReference{ + { + Value: "5fc0c238-1112-11e8-8e45-920c87bdbd75", + Ref: "https://api.github.com/scim/v2/enterprises/octo/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75", + Display: Ptr("Mona Octocat"), + }, + }, + }, + }, + } + + if !cmp.Equal(groups, &want) { + diff := cmp.Diff(groups, want) + t.Errorf("SCIM.ListSCIMProvisionedGroupsForEnterprise returned %+v, want %+v: diff %+v", groups, want, diff) + } + + const methodName = "ListSCIMProvisionedGroupsForEnterprise" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.SCIM.ListSCIMProvisionedGroupsForEnterprise(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + _, r, err := client.SCIM.ListSCIMProvisionedGroupsForEnterprise(ctx, "o", opts) + return r, err + }) +} + func TestSCIMService_ProvisionAndInviteSCIMUser(t *testing.T) { t.Parallel() client, mux, _ := setup(t) From 10b8e26d637584a6d1529abc8fce4a070679d648 Mon Sep 17 00:00:00 2001 From: Travis Fields <1703710+cyberious@users.noreply.github.com> Date: Sun, 9 Feb 2025 14:09:56 -0800 Subject: [PATCH 2/4] Add doc for SCIMDisplayReference struct --- github/scim.go | 1 + 1 file changed, 1 insertion(+) diff --git a/github/scim.go b/github/scim.go index 738141e0a5c..0f766db0cb8 100644 --- a/github/scim.go +++ b/github/scim.go @@ -30,6 +30,7 @@ type SCIMGroupAttributes struct { Meta *SCIMMeta `json:"meta,omitempty"` } +// SCIMDisplayReference represents a JSON SCIM resource comprising of a value, $ref, and display. type SCIMDisplayReference struct { Value string `json:"value"` // (Required.) Ref string `json:"$ref"` // (Required.) From 52c871dbe689c9481d2015296ad9015ad65b5a71 Mon Sep 17 00:00:00 2001 From: Travis Fields <1703710+cyberious@users.noreply.github.com> Date: Mon, 10 Feb 2025 07:28:56 -0800 Subject: [PATCH 3/4] Remove from doc string and simplify to ref --- github/scim.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/scim.go b/github/scim.go index 0f766db0cb8..656b06c8a5a 100644 --- a/github/scim.go +++ b/github/scim.go @@ -30,7 +30,7 @@ type SCIMGroupAttributes struct { Meta *SCIMMeta `json:"meta,omitempty"` } -// SCIMDisplayReference represents a JSON SCIM resource comprising of a value, $ref, and display. +// SCIMDisplayReference represents a JSON SCIM resource comprising of a value, ref, and display. type SCIMDisplayReference struct { Value string `json:"value"` // (Required.) Ref string `json:"$ref"` // (Required.) From 60695bbe8158163606106ddd0002435dc44f498f Mon Sep 17 00:00:00 2001 From: Travis Fields <1703710+cyberious@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:25:18 -0800 Subject: [PATCH 4/4] Update github/scim.go Co-authored-by: Glenn Lewis <6598971+gmlewis@users.noreply.github.com> --- github/scim.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/scim.go b/github/scim.go index 656b06c8a5a..70f063caa9b 100644 --- a/github/scim.go +++ b/github/scim.go @@ -30,7 +30,7 @@ type SCIMGroupAttributes struct { Meta *SCIMMeta `json:"meta,omitempty"` } -// SCIMDisplayReference represents a JSON SCIM resource comprising of a value, ref, and display. +// SCIMDisplayReference represents a JSON SCIM (System for Cross-domain Identity Management) resource. type SCIMDisplayReference struct { Value string `json:"value"` // (Required.) Ref string `json:"$ref"` // (Required.)