From 70649aeb93537ee2285456d9af16cf76b508c5f1 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Thu, 29 May 2025 15:56:04 +0100 Subject: [PATCH 1/9] wip: Ingest sub group users from gitlab Signed-off-by: Jack Palmer --- .../GitlabOrgDiscoveryEntityProvider.ts | 90 +++++++++++-------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index 1fbd2a2a13..aef8914723 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -359,7 +359,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { } let groups; - let users; + const allUsers = []; // Self-hosted: Fetch the users either from the defined group (restrictUsersToGroup) or fetch all users from the GitLab instance // SaaS: Fetch the users from the defined group (restrictUsersToGroup) or fetch all users from the root group. @@ -367,13 +367,15 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) .items; groups.push(await this.gitLabClient.getGroupByPath(this.config.group)); // adds the parent group for #26554 - users = paginated( - options => - this.gitLabClient.listGroupMembers(this.config.group, options), // calls /groups//members - { - page: 1, - per_page: 100, - }, + allUsers.push( + paginated( + options => + this.gitLabClient.listGroupMembers(this.config.group, options), // calls /groups//members + { + page: 1, + per_page: 100, + }, + ), ); } else if ( this.gitLabClient.isSelfManaged() && @@ -387,35 +389,46 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { all_available: true, }, ); - users = paginated( - options => this.gitLabClient.listUsers(options), // calls /users? - { page: 1, per_page: 100, active: true }, + allUsers.push( + paginated( + options => this.gitLabClient.listUsers(options), // calls /users? + { page: 1, per_page: 100, active: true }, + ), ); } // SaaS: Fetch the users from the defined group (restrictUsersToGroup) or fetch all users from the root group. else { - groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) - .items; + const descendantGroups = ( + await this.gitLabClient.listDescendantGroups(this.config.group) + ).items; + groups = descendantGroups; groups.push(await this.gitLabClient.getGroupByPath(this.config.group)); // adds the parent group for #26554 const rootGroupSplit = this.config.group.split('/'); - const groupPath = this.config.restrictUsersToGroup - ? this.config.group - : rootGroupSplit[0]; - users = paginated( - options => - this.gitLabClient.listSaaSUsers( - groupPath, - options, - this.config.includeUsersWithoutSeat, + const groupPaths = this.config.restrictUsersToGroup + ? [this.config.group] + : [rootGroupSplit[0], ...descendantGroups.map(g => g.id)]; + + // Fetch users group and descendant groups + for (const group of groupPaths) { + logger.debug(`Fetching users for group: ${group}`); + allUsers.push( + paginated( + options => + this.gitLabClient.listSaaSUsers( + String(group), + options, + this.config.includeUsersWithoutSeat, + ), + { + page: 1, + per_page: 100, + }, ), - { - page: 1, - per_page: 100, - }, - ); + ); + } } const idMappedUser: { [userId: number]: GitLabUser } = {}; @@ -430,16 +443,23 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { matches: [], }; - for await (const user of users) { - userRes.scanned++; + for (const users of allUsers) { + // Iterate through paginated users + for await (const user of users) { + // Skip if user already processed and do not count it as scanned + if (user.id in idMappedUser) { + continue; // Skip if user already processed + } + userRes.scanned++; - if (!this.shouldProcessUser(user)) { - logger.debug(`Skipped user: ${user.username}`); - continue; + if (!this.shouldProcessUser(user)) { + logger.debug(`Skipped user: ${user.username}`); + continue; + } + + idMappedUser[user.id] = user; + userRes.matches.push(user); } - - idMappedUser[user.id] = user; - userRes.matches.push(user); } for await (const group of groups) { From f5f7541170a7c74e5ce21db74eac3f82337091f8 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Mon, 2 Jun 2025 11:03:44 +0100 Subject: [PATCH 2/9] fix: tests Signed-off-by: Jack Palmer --- .../src/__testUtils__/handlers.ts | 8 ++++++++ .../src/__testUtils__/mocks.ts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index 9ffb43a53d..77efa87878 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -89,6 +89,14 @@ const httpHandlers = [ }, ), + rest.get(`${apiBaseUrlSaas}/groups/456/members/all`, (_req, res, ctx) => { + return res(ctx.json(all_saas_users_response)); + }), + + rest.get(`${apiBaseUrlSaas}/groups/1/members/all`, (_req, res, ctx) => { + return res(ctx.json(all_saas_users_response)); + }), + /** * Users REST endpoint mocks */ diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts index d9914c0d0c..43187031a2 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts @@ -1020,7 +1020,7 @@ export const all_saas_users_response: MockObject[] = [ access_level: 30, created_at: '2023-07-19T08:58:34.984Z', expires_at: null, - id: 34, + id: 36, username: 'testuser3', name: 'Test User 3', state: 'active', From 1f4d9779f68e188f378a9aba4aea6facf7497203 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Mon, 2 Jun 2025 11:30:48 +0100 Subject: [PATCH 3/9] chore: Add tests Signed-off-by: Jack Palmer --- .../src/__testUtils__/handlers.ts | 63 ++++- .../src/__testUtils__/mocks.ts | 252 +++++++++++++++++- .../GitlabOrgDiscoveryEntityProvider.test.ts | 4 +- 3 files changed, 315 insertions(+), 4 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index 77efa87878..3616ed1f47 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -30,6 +30,10 @@ import { some_endpoint, unhealthy_endpoint, userID, + all_saas_group_with_subgroups_members, + all_saas_subgroup_1_members, + all_saas_subgroup_2_members, + group_with_subgroups_response, } from './mocks'; const httpHandlers = [ @@ -71,6 +75,13 @@ const httpHandlers = [ return res(ctx.set('x-next-page', ''), ctx.json(all_groups_response)); }), + rest.get(`${apiBaseUrl}/groups/group-with-subgroup`, (_, res, ctx) => { + return res( + ctx.set('x-next-page', ''), + ctx.json(group_with_subgroups_response), + ); + }), + rest.get(`${apiBaseUrl}/groups/42`, (_, res, ctx) => { return res(ctx.status(500), ctx.json({ error: 'Internal Server Error' })); }), @@ -97,6 +108,16 @@ const httpHandlers = [ return res(ctx.json(all_saas_users_response)); }), + // Subgroup 1 members id=6 + rest.get(`${apiBaseUrlSaas}/groups/6/members/all`, (_req, res, ctx) => { + return res(ctx.json(all_saas_subgroup_1_members)); + }), + + // Subgroup 2 members id=7 + rest.get(`${apiBaseUrlSaas}/groups/7/members/all`, (_req, res, ctx) => { + return res(ctx.json(all_saas_subgroup_2_members)); + }), + /** * Users REST endpoint mocks */ @@ -616,7 +637,47 @@ const graphqlHandlers = [ graphql .link(saasGraphQlBaseUrl) - .query('listDescendantGroups', async (_, res, ctx) => { + .query('listDescendantGroups', async (req, res, ctx) => { + const { group } = req.variables; + + if (group === 'group1') { + return res( + ctx.data({ + group: { + descendantGroups: { + nodes: req.variables.endCursor + ? [ + { + id: 'gid://gitlab/Group/6', + name: 'subgroup1', + description: 'description1', + fullPath: 'path/subgroup1', + parent: { + id: '1', + }, + }, + ] + : [ + { + id: 'gid://gitlab/Group/7', + name: 'subgroup2', + description: 'description2', + fullPath: 'path/subgroup2', + parent: { + id: '1', + }, + }, + ], + pageInfo: { + endCursor: req.variables.endCursor ? 'end' : 'next', + hasNextPage: !req.variables.endCursor, + }, + }, + }, + }), + ); + } + return res( ctx.data({ group: { diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts index 43187031a2..2e74be66cc 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts @@ -796,6 +796,30 @@ export const config_org_group_restrictUsers_true_selfHosted = { }, }, }; + +export const config_org_group_with_subgroups_sass = { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, +}; /** * GitLab API responses */ @@ -1021,6 +1045,71 @@ export const all_saas_users_response: MockObject[] = [ created_at: '2023-07-19T08:58:34.984Z', expires_at: null, id: 36, + username: 'testusernoseat1', + name: 'Test User No Seat 1', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.com/testusernoseat1', + email: 'testusernoseat1@example.com', + group_saml_identity: { + provider: 'group_saml', + extern_uid: '60', + saml_provider_id: 1, + }, + is_using_seat: false, + membership_state: 'active', + }, +]; + +// Only test user 1 +export const all_saas_group_with_subgroups_members: MockObject[] = [ + { + 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: '50', + saml_provider_id: 1, + }, + is_using_seat: true, + membership_state: 'active', + }, +]; + +// Only test user 1 +export const all_saas_subgroup_1_members: MockObject[] = [ + { + 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-17T08:58:34.984Z', + expires_at: null, + id: 33, username: 'testuser3', name: 'Test User 3', state: 'active', @@ -1032,7 +1121,49 @@ export const all_saas_users_response: MockObject[] = [ extern_uid: '53', saml_provider_id: 1, }, - is_using_seat: false, + is_using_seat: true, + membership_state: 'active', + }, +]; + +// Only test user 2 +export const all_saas_subgroup_2_members: MockObject[] = [ + { + 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: 30, + created_at: '2023-07-17T08:58:34.984Z', + expires_at: null, + id: 44, + username: 'testuser4', + name: 'Test User 4', + state: 'active', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.com/testuser4', + email: 'testuser4@example.com', + group_saml_identity: { + provider: 'group_saml', + extern_uid: '54', + saml_provider_id: 1, + }, + is_using_seat: true, membership_state: 'active', }, ]; @@ -1074,6 +1205,21 @@ export const all_groups_response: GitLabGroup[] = [ description: '', full_path: 'group1/subgroup1', }, + { + id: 7, + name: 'subgroup2', + description: '', + full_path: 'group1/subgroup2', + }, +]; + +export const group_with_subgroups_response: GitLabGroup[] = [ + { + id: 1, + name: 'group1', + description: 'description1', + full_path: 'group1', + }, ]; export const group_with_parent: MockObject[] = [ @@ -2183,6 +2329,58 @@ export const expected_full_org_scan_entities_saas: MockObject[] = [ }, locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://gitlab.com/testuser4', + 'backstage.io/managed-by-origin-location': + 'url:https://gitlab.com/testuser4', + 'gitlab.com/user-login': 'https://gitlab.com/testuser4', + 'gitlab.com/saml-external-uid': '54', + }, + name: 'testuser4', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Test User 4', + email: 'testuser4@example.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://gitlab.com/testuser3', + 'backstage.io/managed-by-origin-location': + 'url:https://gitlab.com/testuser3', + 'gitlab.com/user-login': 'https://gitlab.com/testuser3', + 'gitlab.com/saml-external-uid': '53', + }, + name: 'testuser3', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Test User 3', + email: 'testuser3@example.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, ]; export const expected_full_org_scan_entities_includeUsersWithoutSeat_saas: MockObject[] = @@ -2239,6 +2437,58 @@ export const expected_full_org_scan_entities_includeUsersWithoutSeat_saas: MockO }, locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://gitlab.com/testusernoseat1', + 'backstage.io/managed-by-origin-location': + 'url:https://gitlab.com/testusernoseat1', + 'gitlab.com/user-login': 'https://gitlab.com/testusernoseat1', + 'gitlab.com/saml-external-uid': '60', + }, + name: 'testusernoseat1', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Test User No Seat 1', + email: 'testusernoseat1@example.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://gitlab.com/testuser4', + 'backstage.io/managed-by-origin-location': + 'url:https://gitlab.com/testuser4', + 'gitlab.com/user-login': 'https://gitlab.com/testuser4', + 'gitlab.com/saml-external-uid': '54', + }, + name: 'testuser4', + }, + spec: { + memberOf: [], + profile: { + displayName: 'Test User 4', + email: 'testuser4@example.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, { entity: { apiVersion: 'backstage.io/v1alpha1', 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 5f62cedb71..047488166a 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -303,7 +303,7 @@ describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { }); }); - // This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas + // This should return all members of the SaaS Root group (group1) and any subgroups -> expected_full_org_scan_entities_saas it('SaaS: should get all saas root group users when restrictUsersToGroup is not set', async () => { const config = new ConfigReader(mock.config_org_group_saas); const schedule = new PersistingTaskRunner(); @@ -334,7 +334,7 @@ describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { }); }); - // This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas + // This should return all members of the SaaS Root group (group1) and any subgroups -> expected_full_org_scan_entities_saas it('SaaS: should get all saas root group users when restrictUsersToGroup is false', async () => { const config = new ConfigReader( mock.config_org_group_restrictUsers_false_saas, From 42bb3b86df30b1870a4901aecceb758b8f511633 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Mon, 2 Jun 2025 11:56:42 +0100 Subject: [PATCH 4/9] chore: changeset Signed-off-by: Jack Palmer --- .changeset/major-heads-scream.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/major-heads-scream.md diff --git a/.changeset/major-heads-scream.md b/.changeset/major-heads-scream.md new file mode 100644 index 0000000000..f57c6a0d99 --- /dev/null +++ b/.changeset/major-heads-scream.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': minor +--- + +Changing default saas discovery to include members from subgroups of the root group From 15c160465b184a037c4784e498542a0f83fed4d4 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Mon, 2 Jun 2025 13:03:31 +0100 Subject: [PATCH 5/9] fix: types Signed-off-by: Jack Palmer --- .../catalog-backend-module-gitlab/src/__testUtils__/handlers.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index 3616ed1f47..0732bbc4cd 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -30,7 +30,6 @@ import { some_endpoint, unhealthy_endpoint, userID, - all_saas_group_with_subgroups_members, all_saas_subgroup_1_members, all_saas_subgroup_2_members, group_with_subgroups_response, From 54db2a497ca84a9f1464ff7f455f38fd25a13142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 3 Jun 2025 10:55:36 +0200 Subject: [PATCH 6/9] Update .changeset/major-heads-scream.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/major-heads-scream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/major-heads-scream.md b/.changeset/major-heads-scream.md index f57c6a0d99..458331debf 100644 --- a/.changeset/major-heads-scream.md +++ b/.changeset/major-heads-scream.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend-module-gitlab': minor --- -Changing default saas discovery to include members from subgroups of the root group +Changing default SAAS discovery to include members from subgroups of the root group From 27a00a5c2abdbbd9f9a3b59d0253aca3b4b63f71 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Tue, 3 Jun 2025 10:36:27 +0100 Subject: [PATCH 7/9] fix: Replace string casting with string literal Signed-off-by: Jack Palmer --- .../src/providers/GitlabOrgDiscoveryEntityProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index aef8914723..3eec377e73 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -409,7 +409,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { const groupPaths = this.config.restrictUsersToGroup ? [this.config.group] - : [rootGroupSplit[0], ...descendantGroups.map(g => g.id)]; + : [rootGroupSplit[0], ...descendantGroups.map(g => `${g.id}`)]; // Fetch users group and descendant groups for (const group of groupPaths) { @@ -418,7 +418,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { paginated( options => this.gitLabClient.listSaaSUsers( - String(group), + group, options, this.config.includeUsersWithoutSeat, ), From f5d10a4ab5b08e0a77fb51d5e59d9fbf5e25af08 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Tue, 3 Jun 2025 15:22:17 +0100 Subject: [PATCH 8/9] chore: update changeset Signed-off-by: Jack Palmer --- .changeset/major-heads-scream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/major-heads-scream.md b/.changeset/major-heads-scream.md index 458331debf..ee95942328 100644 --- a/.changeset/major-heads-scream.md +++ b/.changeset/major-heads-scream.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend-module-gitlab': minor --- -Changing default SAAS discovery to include members from subgroups of the root group +Breaking: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable setting config `restrictUsersToGroup: true`. From 588b7f0ce6fc852dc9f5266ddf10f9ab968eaab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 4 Jun 2025 12:05:55 +0200 Subject: [PATCH 9/9] Update .changeset/major-heads-scream.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/major-heads-scream.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/major-heads-scream.md b/.changeset/major-heads-scream.md index ee95942328..24caa6e4bb 100644 --- a/.changeset/major-heads-scream.md +++ b/.changeset/major-heads-scream.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend-module-gitlab': minor --- -Breaking: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable setting config `restrictUsersToGroup: true`. +**BREAKING CHANGE**: User and Group discovery will default to ingesting all users in sub groups that belong to the specified root group in config. Disable by setting `restrictUsersToGroup: true` in app-config under your module settings.