diff --git a/.yarnrc.yml b/.yarnrc.yml index 18069eb1a7..466074db0a 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,17 +1,13 @@ enableGlobalCache: true -httpProxy: "http://sia-lb.telekom.de:8080" - httpTimeout: 300000 -httpsProxy: "http://sia-lb.telekom.de:8080" - nodeLinker: node-modules -npmRegistryServer: "https://registry.npmjs.org/" +npmRegistryServer: 'https://registry.npmjs.org/' plugins: - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs - spec: "@yarnpkg/plugin-workspace-tools" + spec: '@yarnpkg/plugin-workspace-tools' yarnPath: .yarn/releases/yarn-3.8.1.cjs diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index 04a95c4332..e49fb54465 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -19,6 +19,7 @@ import { all_groups_response, all_projects_response, all_saas_users_response, + all_self_hosted_group1_members, subgroup_saas_users_response, all_users_response, apiBaseUrl, @@ -64,6 +65,9 @@ const httpHandlers = [ rest.get(`${apiBaseUrl}/groups/42`, (_, res, ctx) => { return res(ctx.status(500), ctx.json({ error: 'Internal Server Error' })); }), + rest.get(`${apiBaseUrl}/groups/group1/members/all`, (_req, res, ctx) => { + return res(ctx.json(all_self_hosted_group1_members)); + }), rest.get(`${apiBaseUrlSaas}/groups/group1/members/all`, (_req, res, ctx) => { return res(ctx.json(all_saas_users_response)); diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts index b30f80888f..798df32695 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts @@ -596,6 +596,127 @@ export const config_org_double_integration: MockObject = { }, }; +export const config_org_group_saas = { + 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, + }, + }, + }, + }, +}; + +export const config_org_group_restrictUsers_false_saas = { + 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, + }, + }, + }, + }, +}; + +export const config_org_group_restrictUsers_true_saas = { + integrations: { + gitlab: [ + { + host: 'gitlab.com', + apiBaseUrl: 'https://gitlab.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'gitlab.com', + group: 'group1/subgroup1', + restrictUsersToGroup: true, + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, +}; + +export const config_org_group_selfHosted = { + integrations: { + gitlab: [ + { + host: 'example.com', + apiBaseUrl: 'https://example.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'example.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + }, + }, + }, + }, +}; + +export const config_org_group_restrictUsers_true_selfHosted = { + integrations: { + gitlab: [ + { + host: 'example.com', + apiBaseUrl: 'https://example.com/api/v4', + token: '1234', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'example.com', + group: 'group1', + orgEnabled: true, + skipForkedRepos: true, + restrictUsersToGroup: true, + }, + }, + }, + }, +}; /** * GitLab API responses */ @@ -1969,7 +2090,7 @@ export const expected_subgroup_org_scan_entities_saas: MockObject[] = [ ]; // Simulate return of all users but only with membership of the descendants of config.group -export const expected_group_org_scan_entities: MockObject[] = [ +export const expected_full_members_group_org_scan_entities: MockObject[] = [ { entity: { apiVersion: 'backstage.io/v1alpha1', @@ -2093,3 +2214,77 @@ export const expected_group_org_scan_entities: MockObject[] = [ locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, ]; + +export const expected_group_members_group_org_scan_entities: MockObject[] = [ + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://example.com/JohnDoe', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/JohnDoe', + 'example.com/user-login': 'https://gitlab.example/john_doe', + }, + name: 'JohnDoe', + }, + spec: { + memberOf: ['subgroup1'], + profile: { + displayName: 'John Doe', + email: 'john.doe@company.com', + picture: 'https://secure.gravatar.com/', + }, + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + annotations: { + 'backstage.io/managed-by-location': + 'url:https://example.com/group1/subgroup1', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/group1/subgroup1', + 'example.com/team-path': 'group1/subgroup1', + }, + name: 'subgroup1', + description: 'description1', + }, + spec: { + children: [], + profile: { + displayName: 'subgroup1', + }, + type: 'team', + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, +]; + +export const all_self_hosted_group1_members: MockObject[] = [ + { + id: 1, + username: 'JohnDoe', + name: 'John Doe', + state: 'active', + email: 'john.doe@company.com', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.example/john_doe', + }, + // inactive + { + id: 5, + username: 'MarioMario', + name: 'Mario Mario', + state: 'inactive', + email: 'mario.mario-company.com', + avatar_url: 'https://secure.gravatar.com/', + web_url: 'https://gitlab.example/mario_mario', + }, +]; 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 8cf046909d..ddc0d03570 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -175,220 +175,6 @@ describe('GitlabOrgDiscoveryEntityProvider - configuration', () => { }); }); -// This should return all members of the SaaS Root group (group1) -> 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({ - 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, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_full_org_scan_entities_saas, // - }); -}); - -// This should return all members of the SaaS Root group (group1) -> expected_full_org_scan_entities_saas -it('SaaS: should get all saas root group users when restrictUsersToGroup is false', async () => { - const config = new ConfigReader({ - 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, - restrictUsersToGroup: false, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_full_org_scan_entities_saas, // - }); -}); - -// This should return only members of the SaaS subgroup (group1/subgroup1) -> expected_subgroup_org_scan_entities_saas -it('SaaS: should get only subgroup users when restrictUsersToGroup is true', async () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'gitlab.com', - apiBaseUrl: 'https://gitlab.com/api/v4', - token: '1234', - }, - ], - }, - catalog: { - providers: { - gitlab: { - 'test-id': { - host: 'gitlab.com', - group: 'group1/subgroup1', - restrictUsersToGroup: true, - orgEnabled: true, - skipForkedRepos: true, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_subgroup_org_scan_entities_saas, - }); -}); - -// This should return all members of the self-hosted instance regardless of the group set -> expected_full_org_scan_entities -it('Self-hosted: should get all instance users when restrictUsersToGroup is not set', async () => { - const config = new ConfigReader({ - integrations: { - gitlab: [ - { - host: 'example.com', - apiBaseUrl: 'https://example.com/api/v4', - token: '1234', - }, - ], - }, - catalog: { - providers: { - gitlab: { - 'test-id': { - host: 'example.com', - group: 'group1', - orgEnabled: true, - skipForkedRepos: true, - }, - }, - }, - }, - }); - const schedule = new PersistingTaskRunner(); - const entityProviderConnection: EntityProviderConnection = { - applyMutation: jest.fn(), - refresh: jest.fn(), - }; - const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { - logger, - schedule, - })[0]; - expect(provider.getProviderName()).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id', - ); - - await provider.connect(entityProviderConnection); - - const taskDef = schedule.getTasks()[0]; - expect(taskDef.id).toEqual( - 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', - ); - await (taskDef.fn as () => Promise)(); - - expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); - expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ - type: 'full', - entities: mock.expected_group_org_scan_entities, // This should deliver all users but only their membership in subgroups of config.group - }); -}); - describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { it('should apply full update on scheduled execution', async () => { const config = new ConfigReader(mock.config_org_integration); @@ -516,6 +302,168 @@ describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { entities: mock.expected_full_org_scan_entities_saas, }); }); + + // This should return all members of the SaaS Root group (group1) -> 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(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_org_scan_entities_saas, // + }); + }); + + // This should return all members of the SaaS Root group (group1) -> 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, + ); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_org_scan_entities_saas, // + }); + }); + + // This should return only members of the SaaS subgroup (group1/subgroup1) -> expected_subgroup_org_scan_entities_saas + it('SaaS: should get only subgroup users when restrictUsersToGroup is true', async () => { + const config = new ConfigReader( + mock.config_org_group_restrictUsers_true_saas, + ); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_subgroup_org_scan_entities_saas, + }); + }); + + // This should return all members of the self-hosted instance regardless of the group set -> expected_full_members_group_org_scan_entities + // All instance members, but only the group entities below the config.group + it('Self-hosted: should get all instance users when restrictUsersToGroup is not set', async () => { + const config = new ConfigReader(mock.config_org_group_selfHosted); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_full_members_group_org_scan_entities, // This should deliver all users but only their membership in subgroups of config.group + }); + }); + + // This should return all members of the self-hosted config.group and all group entities of config.group -> expected_full_members_group_org_scan_entities + it('Self-hosted: should get only groups users when restrictUsersToGroup is set', async () => { + const config = new ConfigReader( + mock.config_org_group_restrictUsers_true_selfHosted, + ); + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = GitlabOrgDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + expect(provider.getProviderName()).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id', + ); + + await provider.connect(entityProviderConnection); + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + 'GitlabOrgDiscoveryEntityProvider:test-id:refresh', + ); + await (taskDef.fn as () => Promise)(); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1); + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: mock.expected_group_members_group_org_scan_entities, // This should deliver all users but only their membership in subgroups of config.group + }); + }); }); describe('GitlabOrgDiscoveryEntityProvider with events support', () => {