diff --git a/.changeset/flat-rules-rush.md b/.changeset/flat-rules-rush.md index f57e800d91..c68a4e5756 100644 --- a/.changeset/flat-rules-rush.md +++ b/.changeset/flat-rules-rush.md @@ -8,6 +8,11 @@ This API is the only one that shows `email` field for enterprise users and allows to filter out bot users not using a license using the `is_using_seat` field. +We also added the annotation `gitlab.com/saml-external-uid` taking the value +of `group_saml_identity.extern_uid` of the forementioned endpoint response. +This is useful in case you want to backreference the user with the id of your +identity provider (e.g. OneLogin). + ref: https://docs.gitlab.com/ee/user/enterprise_user/#get-users-email-addresses-through-the-api diff --git a/plugins/catalog-backend-module-gitlab/src/lib/types.ts b/plugins/catalog-backend-module-gitlab/src/lib/types.ts index 5a4082eec3..946317a11a 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/types.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/types.ts @@ -39,12 +39,17 @@ export type GitLabProject = { export type GitLabUser = { id: number; username: string; - email: string; + email?: string; name: string; state: string; web_url: string; avatar_url: string; groups?: GitLabGroup[]; + group_saml_identity?: GitLabGroupSamlIdentity; +}; + +export type GitLabGroupSamlIdentity = { + extern_uid: string; }; export type GitLabGroup = { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts index 1b1357c1bf..ad930ea23d 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -548,46 +548,6 @@ describe('GitlabOrgDiscoveryEntityProvider', () => { }), ), ), - graphql - .link('https://gitlab.com/api/graphql') - .query('getGroupMembers', async (_, res, ctx) => - res( - ctx.data({ - group: { - groupMembers: { - nodes: [ - { - user: { - id: 'gid://gitlab/User/12', - username: 'testuser1', - publicEmail: 'testuser1@example.com', - state: 'active', - name: 'Test User 1', - webUrl: 'https://gitlab.com/testuser1', - avatarUrl: 'https://secure.gravatar.com/', - }, - }, - { - user: { - id: 'gid://gitlab/User/34', - username: 'testuser2', - publicEmail: 'testuser2@example.com', - state: 'active', - name: 'Test User 2', - webUrl: 'https://gitlab.com/testuser2', - avatarUrl: 'https://secure.gravatar.com/', - }, - }, - ], - pageInfo: { - endCursor: 'end', - hasNextPage: false, - }, - }, - }, - }), - ), - ), graphql .link('https://gitlab.com/api/graphql') .query('getGroupMembers', async (req, res, ctx) => @@ -608,6 +568,67 @@ describe('GitlabOrgDiscoveryEntityProvider', () => { }), ), ), + rest.get( + `https://gitlab.com/api/v4/groups/group1/members`, + (_req, res, ctx) => { + const response = [ + { + access_level: 30, + created_at: '2023-07-17T08:58:34.984Z', + expires_at: null, + id: 12, + username: 'testuser1', + name: 'Test User 1', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.com/testuser1', + email: 'testuser1@example.com', + group_saml_identity: { + provider: 'group_saml', + extern_uid: '51', + saml_provider_id: 1, + }, + is_using_seat: true, + membership_state: 'active', + }, + { + access_level: 30, + created_at: '2023-07-19T08:58:34.984Z', + expires_at: null, + id: 34, + username: 'testuser2', + name: 'Test User 2', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.com/testuser2', + email: 'testuser2@example.com', + group_saml_identity: { + provider: 'group_saml', + extern_uid: '52', + saml_provider_id: 1, + }, + is_using_seat: true, + membership_state: 'active', + }, + { + access_level: 50, + created_at: '2023-07-15T08:58:34.984Z', + expires_at: '2023-10-26', + id: 54, + username: 'group_100_bot_23dc8057bef66e05181f39be4652577c', + name: 'Token Bot', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: + 'https://gitlab.com/group_100_bot_23dc8057bef66e05181f39be4652577c', + group_saml_identity: null, + is_using_seat: false, + membership_state: 'active', + }, + ]; + return res(ctx.json(response)); + }, + ), ); await provider.connect(entityProviderConnection); @@ -630,11 +651,12 @@ describe('GitlabOrgDiscoveryEntityProvider', () => { 'backstage.io/managed-by-origin-location': 'url:https://gitlab.com/testuser1', 'gitlab.com/user-login': 'https://gitlab.com/testuser1', + 'gitlab.com/saml-external-uid': '51', }, name: 'testuser1', }, spec: { - memberOf: ['group2', 'group3'], + memberOf: ['group2'], profile: { displayName: 'Test User 1', email: 'testuser1@example.com', @@ -655,11 +677,12 @@ describe('GitlabOrgDiscoveryEntityProvider', () => { 'backstage.io/managed-by-origin-location': 'url:https://gitlab.com/testuser2', 'gitlab.com/user-login': 'https://gitlab.com/testuser2', + 'gitlab.com/saml-external-uid': '52', }, name: 'testuser2', }, spec: { - memberOf: ['group2', 'group3'], + memberOf: ['group3'], profile: { displayName: 'Test User 2', email: 'testuser2@example.com', diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index b98b8ab7c3..b73874c401 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -331,6 +331,10 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { const annotations: { [annotationName: string]: string } = {}; annotations[`${host}/user-login`] = user.web_url; + if (user?.group_saml_identity?.extern_uid) { + annotations[`${host}/saml-external-uid`] = + user.group_saml_identity.extern_uid; + } const entity: UserEntity = { apiVersion: 'backstage.io/v1alpha1',