diff --git a/.changeset/green-worms-report.md b/.changeset/green-worms-report.md new file mode 100644 index 000000000..e30558bc0 --- /dev/null +++ b/.changeset/green-worms-report.md @@ -0,0 +1,5 @@ +--- +'@roadiehq/catalog-backend-module-okta': minor +--- + +Adds option to provide custom user transformer for user and org providers diff --git a/plugins/backend/catalog-backend-module-okta/README.md b/plugins/backend/catalog-backend-module-okta/README.md index fb3e84521..b39754c6d 100644 --- a/plugins/backend/catalog-backend-module-okta/README.md +++ b/plugins/backend/catalog-backend-module-okta/README.md @@ -148,6 +148,83 @@ export default async function createPlugin( } ``` +In case you want to customize the emitted entities, the provider allows to pass custom transformers for users and groups by providing `userTransformer` and `groupTransformer`. + +1. Create a transformer: + +```typescript +import { GroupNamingStrategy } from '@roadiehq/catalog-backend-module-okta'; +import { GroupEntity } from '@backstage/catalog-model'; +import { Group } from '@okta/okta-sdk-nodejs'; + +function myGroupTransformer( + group: Group, + namingStrategy: GroupNamingStrategy, + parentGroup: Group | undefined, + options: { + annotations: Record; + members: string[]; + }, +): GroupEntity { + // Enrich it with your logic + const groupEntity: GroupEntity = { + kind: 'Group', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { + ...options.annotations, + }, + name: namingStrategy(group), + title: group.profile.name, + title: group.profile.description || group.profile.name, + description: group.profile.description || '', + }, + spec: { + members: options.members, + type: 'group', + children: [], + }, + }; + + if (parentGroup) { + groupEntity.spec.parent = namingStrategy(parentGroup); + } + return groupEntity; +} +``` + +2. Configure the provider with the transformer: + +```typescript +import { OktaOrgEntityProvider } from '@roadiehq/catalog-backend-module-okta'; +import { myGroupTransformer } from './myGroupTransformer'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + const orgProvider = OktaOrgEntityProvider.fromConfig(env.config, { + logger: env.logger, + userNamingStrategy: 'strip-domain-email', + groupNamingStrategy: 'kebab-case-name', + groupTransformer: myGroupTransformer, + }); + + builder.addEntityProvider(orgProvider); + + const { processingEngine, router } = await builder.build(); + + orgProvider.run(); + + await processingEngine.start(); + + // ... + + return router; +} +``` + ## Load Users and Groups Separately ### OktaUserEntityProvider @@ -165,6 +242,71 @@ export const customUserNamingStrategy: UserNamingStrategy = user => user.profile.customField; ``` +In case you want to customize the emitted entities, the provider allows to pass custom transformer by providing `userTransformer`. + +1. Create a transformer: + +```typescript +import { UserEntity } from '@backstage/catalog-model'; +import { User } from '@okta/okta-sdk-nodejs'; +import { UserNamingStrategy } from '@roadiehq/catalog-backend-module-okta'; + +function myUserTransformer( + user: User, + namingStrategy: UserNamingStrategy, + options: { annotations: Record }, +): UserEntity { + // Enrich it with your logic + return { + kind: 'User', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { ...options.annotations }, + name: namingStrategy(user), + title: user.profile.email, + }, + spec: { + profile: { + displayName: user.profile.displayName, + email: user.profile.email, + }, + memberOf: [], + }, + }; +} +``` + +2. Configure the provider with the transformer: + +```typescript +import { OktaUserEntityProvider } from '@roadiehq/catalog-backend-module-okta'; +import { myUserTransformer } from './myUserTransformer'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + const userProvider = OktaUserEntityProvider.fromConfig(env.config, { + logger: env.logger, + namingStrategy: 'strip-domain-email', + userTransformer: myUserTransformer, + }); + + builder.addEntityProvider(userProvider); + + const { processingEngine, router } = await builder.build(); + + userProvider.run(); + + await processingEngine.start(); + + // ... + + return router; +} +``` + ### OktaGroupEntityProvider You can configure the provider with different naming strategies. The configured strategy will be used to generate the discovered entities `metadata.name` field. The currently supported strategies are the following: @@ -283,3 +425,80 @@ export default async function createPlugin( return router; } ``` + +In case you want to customize the emitted entities, the provider allows to pass custom transformer by providing `groupTransformer`. + +1. Create a transformer: + +```typescript +import { GroupNamingStrategy } from '@roadiehq/catalog-backend-module-okta'; +import { GroupEntity } from '@backstage/catalog-model'; +import { Group } from '@okta/okta-sdk-nodejs'; + +function myGroupTransformer( + group: Group, + namingStrategy: GroupNamingStrategy, + parentGroup: Group | undefined, + options: { + annotations: Record; + members: string[]; + }, +): GroupEntity { + // Enrich it with your logic + const groupEntity: GroupEntity = { + kind: 'Group', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { + ...options.annotations, + }, + name: namingStrategy(group), + title: group.profile.name, + title: group.profile.description || group.profile.name, + description: group.profile.description || '', + }, + spec: { + members: options.members, + type: 'group', + children: [], + }, + }; + + if (parentGroup) { + groupEntity.spec.parent = namingStrategy(parentGroup); + } + return groupEntity; +} +``` + +2. Configure the provider with the transformer: + +```typescript +import { OktaGroupEntityProvider } from '@roadiehq/catalog-backend-module-okta'; +import { myGroupTransformer } from './myGroupTransformer'; + +export default async function createPlugin( + env: PluginEnvironment, +): Promise { + const builder = await CatalogBuilder.create(env); + + const groupProvider = OktaGroupEntityProvider.fromConfig(env.config, { + logger: env.logger, + userNamingStrategy: 'strip-domain-email', + groupNamingStrategy: 'kebab-case-name', + groupTransformer: myGroupTransformer, + }); + + builder.addEntityProvider(groupProvider); + + const { processingEngine, router } = await builder.build(); + + groupProvider.run(); + + await processingEngine.start(); + + // ... + + return router; +} +``` diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.test.ts b/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.test.ts index 0ec3c5ff3..c33bfb9d3 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.test.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.test.ts @@ -141,6 +141,7 @@ describe('OktaGroupProvider', () => { description: 'Everyone in the company', org_id: '1234', parent_org_id: '1234', + displayName: 'Display name 1', }, listUsers: () => { return new MockOktaCollection([ @@ -160,6 +161,7 @@ describe('OktaGroupProvider', () => { description: null, org_id: '1235', parent_org_id: '1234', + displayName: 'Display name 2', }, listUsers: () => { return new MockOktaCollection([ @@ -452,5 +454,56 @@ describe('OktaGroupProvider', () => { ]), }); }); + + it('uses custom group transformer', async () => { + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = OktaGroupEntityProvider.fromConfig(config, { + logger, + groupTransformer: (group, namingStrategy, options, parentGroup) => ({ + kind: 'Group', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { ...options.annotations }, + name: namingStrategy(group), + title: group.profile.name, + description: group.profile.description || '', + }, + spec: { + profile: { + displayName: group.profile.displayName as string, + }, + members: options.members, + type: 'group', + children: [], + parent: parentGroup ? namingStrategy(parentGroup) : '', + }, + }), + }); + provider.connect(entityProviderConnection); + await provider.run(); + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: expect.arrayContaining([ + expect.objectContaining({ + entity: expect.objectContaining({ + kind: 'Group', + metadata: expect.objectContaining({ + name: 'asdfwefwefwef', + description: 'Everyone in the company', + }), + spec: expect.objectContaining({ + members: ['asdfwefwefwef'], + profile: expect.objectContaining({ + displayName: 'Display name 1', + }), + }), + }), + }), + ]), + }); + }); }); }); diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.ts b/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.ts index 8a3b043f8..f317c6ed0 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/OktaGroupEntityProvider.ts @@ -29,11 +29,12 @@ import { userNamingStrategyFactory, } from './userNamingStrategies'; import { AccountConfig } from '../types'; -import { groupEntityFromOktaGroup } from './groupEntityFromOktaGroup'; +import { groupEntityFromOktaGroup as defaultGroupEntityFromOktaGroup } from './groupEntityFromOktaGroup'; import { getAccountConfig } from './accountConfig'; import { isError } from '@backstage/errors'; import { getOktaGroups } from './getOktaGroups'; import { getParentGroup } from './getParentGroup'; +import { OktaGroupEntityTransformer } from './types'; /** * Provides entities from Okta Group service. @@ -41,6 +42,7 @@ import { getParentGroup } from './getParentGroup'; export class OktaGroupEntityProvider extends OktaEntityProvider { private readonly namingStrategy: GroupNamingStrategy; private readonly userNamingStrategy: UserNamingStrategy; + private readonly groupEntityFromOktaGroup: OktaGroupEntityTransformer; private readonly groupFilter: string | undefined; private readonly orgUrl: string; private readonly customAttributesToAnnotationAllowlist: string[]; @@ -52,6 +54,7 @@ export class OktaGroupEntityProvider extends OktaEntityProvider { logger: winston.Logger; namingStrategy?: GroupNamingStrategies | GroupNamingStrategy; userNamingStrategy?: UserNamingStrategies | UserNamingStrategy; + groupTransformer?: OktaGroupEntityTransformer; customAttributesToAnnotationAllowlist?: string[]; /* * @deprecated, please use hierarchyConfig.parentKey @@ -85,6 +88,7 @@ export class OktaGroupEntityProvider extends OktaEntityProvider { parentKey: string; key?: string; }; + groupTransformer?: OktaGroupEntityTransformer; }, ) { super([accountConfig], options); @@ -92,6 +96,8 @@ export class OktaGroupEntityProvider extends OktaEntityProvider { this.userNamingStrategy = userNamingStrategyFactory( options.userNamingStrategy, ); + this.groupEntityFromOktaGroup = + options?.groupTransformer || defaultGroupEntityFromOktaGroup; this.orgUrl = accountConfig.orgUrl; this.groupFilter = accountConfig.groupFilter; this.customAttributesToAnnotationAllowlist = @@ -160,14 +166,14 @@ export class OktaGroupEntityProvider extends OktaEntityProvider { ...profileAnnotations, }; try { - const groupEntity = groupEntityFromOktaGroup( + const groupEntity = this.groupEntityFromOktaGroup( group, this.namingStrategy, - parentGroup, { annotations, members, }, + parentGroup, ); groupResources.push(groupEntity); } catch (e) { diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.test.ts b/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.test.ts index c8f51d8be..b507a4024 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.test.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.test.ts @@ -671,5 +671,153 @@ describe('OktaOrgEntityProvider', () => { ]), }); }); + + it('uses custom group transformer', async () => { + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + + listGroups = () => { + return new MockOktaCollection([ + { + id: 'asdfwefwefwef', + profile: { + name: 'Everyone@the-company', + description: 'Everyone in the company', + displayName: 'Display name 1', + }, + listUsers: () => { + return new MockOktaCollection([ + { + id: 'user-1', + profile: { + email: 'fname@domain.com', + }, + }, + ]); + }, + }, + ]); + }; + + const provider = OktaOrgEntityProvider.fromConfig(config, { + logger, + groupTransformer: (group, namingStrategy, options, parentGroup) => ({ + kind: 'Group', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { ...options.annotations }, + name: namingStrategy(group), + title: group.profile.name, + description: group.profile.description || '', + }, + spec: { + profile: { + displayName: group.profile.displayName as string, + }, + members: options.members, + type: 'group', + children: [], + parent: parentGroup ? namingStrategy(parentGroup) : '', + }, + }), + }); + await provider.connect(entityProviderConnection); + await provider.run(); + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: expect.arrayContaining([ + expect.objectContaining({ + entity: expect.objectContaining({ + kind: 'Group', + metadata: expect.objectContaining({ + name: 'asdfwefwefwef', + title: 'Everyone@the-company', + }), + spec: expect.objectContaining({ + members: ['user-1'], + profile: expect.objectContaining({ + displayName: 'Display name 1', + }), + }), + }), + }), + ]), + }); + }); + + it('uses custom user transformer', async () => { + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + + listGroups = () => { + return new MockOktaCollection([ + { + id: 'asdfwefwefwef', + profile: { + name: 'Everyone@the-company', + description: 'Everyone in the company', + }, + listUsers: () => { + return new MockOktaCollection([ + { + id: 'user-1', + profile: { + email: 'fname@domain.com', + }, + }, + { + id: 'user-2', + profile: { + email: 'fname2@domain.com', + }, + }, + ]); + }, + }, + ]); + }; + + const provider = OktaOrgEntityProvider.fromConfig(config, { + logger, + userTransformer: (user, namingStrategy, options) => ({ + kind: 'User', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { ...options.annotations }, + name: namingStrategy(user), + title: user.profile.email, + }, + spec: { + profile: { + displayName: user.profile.displayName, + email: user.profile.email, + picture: 'picture.com', + }, + memberOf: [], + }, + }), + }); + await provider.connect(entityProviderConnection); + await provider.run(); + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: expect.arrayContaining([ + expect.objectContaining({ + entity: expect.objectContaining({ + kind: 'User', + spec: expect.objectContaining({ + profile: expect.objectContaining({ + picture: 'picture.com', + }), + }), + }), + }), + ]), + }); + }); }); }); diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.ts b/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.ts index 637d886b0..2a72f2b80 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/OktaOrgEntityProvider.ts @@ -28,14 +28,15 @@ import { UserNamingStrategy, userNamingStrategyFactory, } from './userNamingStrategies'; -import { userEntityFromOktaUser } from './userEntityFromOktaUser'; +import { userEntityFromOktaUser as defaultUserEntityFromOktaUser } from './userEntityFromOktaUser'; import { AccountConfig } from '../types'; -import { groupEntityFromOktaGroup } from './groupEntityFromOktaGroup'; +import { groupEntityFromOktaGroup as defaultGroupEntityFromOktaGroup } from './groupEntityFromOktaGroup'; import { getAccountConfig } from './accountConfig'; import { isError } from '@backstage/errors'; import { getOktaGroups } from './getOktaGroups'; import { getParentGroup } from './getParentGroup'; import { GroupTree } from './GroupTree'; +import { OktaGroupEntityTransformer, OktaUserEntityTransformer } from './types'; /** * Provides entities from Okta Org service. @@ -43,6 +44,8 @@ import { GroupTree } from './GroupTree'; export class OktaOrgEntityProvider extends OktaEntityProvider { private readonly groupNamingStrategy: GroupNamingStrategy; private readonly userNamingStrategy: UserNamingStrategy; + private readonly groupEntityFromOktaGroup: OktaGroupEntityTransformer; + private readonly userEntityFromOktaUser: OktaUserEntityTransformer; private readonly includeEmptyGroups: boolean; private readonly hierarchyConfig: | { parentKey: string; key?: string } @@ -55,6 +58,8 @@ export class OktaOrgEntityProvider extends OktaEntityProvider { logger: winston.Logger; groupNamingStrategy?: GroupNamingStrategies | GroupNamingStrategy; userNamingStrategy?: UserNamingStrategies | UserNamingStrategy; + groupTransformer?: OktaGroupEntityTransformer; + userTransformer?: OktaUserEntityTransformer; includeEmptyGroups?: boolean; /* * @deprecated, please use hierarchyConfig.parentKey @@ -85,6 +90,8 @@ export class OktaOrgEntityProvider extends OktaEntityProvider { logger: winston.Logger; groupNamingStrategy?: GroupNamingStrategies | GroupNamingStrategy; userNamingStrategy?: UserNamingStrategies | UserNamingStrategy; + groupTransformer?: OktaGroupEntityTransformer; + userTransformer?: OktaUserEntityTransformer; includeEmptyGroups?: boolean; hierarchyConfig?: { parentKey: string; @@ -100,6 +107,10 @@ export class OktaOrgEntityProvider extends OktaEntityProvider { this.userNamingStrategy = userNamingStrategyFactory( options.userNamingStrategy, ); + this.groupEntityFromOktaGroup = + options?.groupTransformer || defaultGroupEntityFromOktaGroup; + this.userEntityFromOktaUser = + options.userTransformer || defaultUserEntityFromOktaUser; this.includeEmptyGroups = !!options.includeEmptyGroups; this.hierarchyConfig = options.hierarchyConfig; this.customAttributesToAnnotationAllowlist = @@ -133,7 +144,7 @@ export class OktaOrgEntityProvider extends OktaEntityProvider { await client.listUsers({ search: account.userFilter }).each(user => { try { const userName = this.userNamingStrategy(user); - userResources[userName] = userEntityFromOktaUser( + userResources[userName] = this.userEntityFromOktaUser( user, this.userNamingStrategy, { @@ -191,14 +202,14 @@ export class OktaOrgEntityProvider extends OktaEntityProvider { ...profileAnnotations, }; try { - const groupEntity = groupEntityFromOktaGroup( + const groupEntity = this.groupEntityFromOktaGroup( group, this.groupNamingStrategy, - parentGroup, { annotations, members, }, + parentGroup, ); groupResources.push(groupEntity); } catch (e: unknown) { diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.test.ts b/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.test.ts index 644a47aba..550ba3e5f 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.test.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.test.ts @@ -224,5 +224,49 @@ describe('OktaUserEntityProvider', () => { ], }); }); + + it('uses custom user transformer', async () => { + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + const provider = OktaUserEntityProvider.fromConfig(config, { + logger, + userTransformer: (user, namingStrategy, options) => ({ + kind: 'User', + apiVersion: 'backstage.io/v1alpha1', + metadata: { + annotations: { ...options.annotations }, + name: namingStrategy(user), + title: user.profile.email, + }, + spec: { + profile: { + displayName: user.profile.displayName, + email: user.profile.email, + picture: 'picture.com', + }, + memberOf: [], + }, + }), + }); + provider.connect(entityProviderConnection); + await provider.run(); + expect(entityProviderConnection.applyMutation).toBeCalledWith({ + type: 'full', + entities: [ + expect.objectContaining({ + entity: expect.objectContaining({ + kind: 'User', + spec: expect.objectContaining({ + profile: expect.objectContaining({ + picture: 'picture.com', + }), + }), + }), + }), + ], + }); + }); }); }); diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.ts b/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.ts index e2a1e94bc..dd2a21453 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/OktaUserEntityProvider.ts @@ -24,15 +24,17 @@ import { userNamingStrategyFactory, } from './userNamingStrategies'; import { AccountConfig } from '../types'; -import { userEntityFromOktaUser } from './userEntityFromOktaUser'; +import { userEntityFromOktaUser as defaultUserEntityFromOktaUser } from './userEntityFromOktaUser'; import { getAccountConfig } from './accountConfig'; import { isError } from '@backstage/errors'; +import { OktaUserEntityTransformer } from './types'; /** * Provides entities from Okta User service. */ export class OktaUserEntityProvider extends OktaEntityProvider { private readonly namingStrategy: UserNamingStrategy; + private readonly userEntityFromOktaUser: OktaUserEntityTransformer; private readonly userFilter?: string; private readonly orgUrl: string; private readonly customAttributesToAnnotationAllowlist: string[]; @@ -43,6 +45,7 @@ export class OktaUserEntityProvider extends OktaEntityProvider { logger: winston.Logger; customAttributesToAnnotationAllowlist?: string[]; namingStrategy?: UserNamingStrategies | UserNamingStrategy; + userTransformer?: OktaUserEntityTransformer; }, ) { const accountConfig = getAccountConfig(config); @@ -56,10 +59,13 @@ export class OktaUserEntityProvider extends OktaEntityProvider { logger: winston.Logger; customAttributesToAnnotationAllowlist?: string[]; namingStrategy?: UserNamingStrategies | UserNamingStrategy; + userTransformer?: OktaUserEntityTransformer; }, ) { super([accountConfig], options); this.namingStrategy = userNamingStrategyFactory(options.namingStrategy); + this.userEntityFromOktaUser = + options.userTransformer || defaultUserEntityFromOktaUser; this.userFilter = accountConfig.userFilter; this.orgUrl = accountConfig.orgUrl; this.customAttributesToAnnotationAllowlist = @@ -95,9 +101,11 @@ export class OktaUserEntityProvider extends OktaEntityProvider { ...profileAnnotations, }; try { - const userEntity = userEntityFromOktaUser(user, this.namingStrategy, { - annotations, - }); + const userEntity = this.userEntityFromOktaUser( + user, + this.namingStrategy, + { annotations }, + ); userResources.push(userEntity); } catch (e: unknown) { this.logger.warn( diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.test.ts b/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.test.ts index b07b93cf6..90c6d2502 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.test.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.test.ts @@ -37,8 +37,8 @@ describe('groupEntityFromOktaGroup', () => { groupEntityFromOktaGroup( group as Group, new ProfileFieldGroupNamingStrategy('org_id').nameForGroup, - parentGroup, options, + parentGroup, ), ).toEqual({ apiVersion: 'backstage.io/v1alpha1', @@ -77,8 +77,8 @@ describe('groupEntityFromOktaGroup', () => { groupEntityFromOktaGroup( group as Group, new ProfileFieldGroupNamingStrategy('org_id').nameForGroup, - parentGroup as Group, options, + parentGroup as Group, ), ).toEqual({ apiVersion: 'backstage.io/v1alpha1', diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.ts b/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.ts index fbfb30edf..7a31d8a25 100644 --- a/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.ts +++ b/plugins/backend/catalog-backend-module-okta/src/providers/groupEntityFromOktaGroup.ts @@ -20,11 +20,11 @@ import { GroupNamingStrategy } from './groupNamingStrategies'; export const groupEntityFromOktaGroup = ( group: Group, namingStrategy: GroupNamingStrategy, - parentGroup: Group | undefined, options: { annotations: Record; members: string[]; }, + parentGroup?: Group, ): GroupEntity => { const groupEntity: GroupEntity = { kind: 'Group', diff --git a/plugins/backend/catalog-backend-module-okta/src/providers/types.ts b/plugins/backend/catalog-backend-module-okta/src/providers/types.ts new file mode 100644 index 000000000..0861b2951 --- /dev/null +++ b/plugins/backend/catalog-backend-module-okta/src/providers/types.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2022 Larder Software Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; +import type { + Group as OktaGroup, + User as OktaUser, +} from '@okta/okta-sdk-nodejs'; +import { GroupNamingStrategy } from './groupNamingStrategies'; +import { UserNamingStrategy } from './userNamingStrategies'; + +export type OktaGroupEntityTransformer = ( + group: OktaGroup, + namingStrategy: GroupNamingStrategy, + options: { + annotations: Record; + members: string[]; + }, + parentGroup?: OktaGroup, +) => GroupEntity; + +export type OktaUserEntityTransformer = ( + user: OktaUser, + namingStrategy: UserNamingStrategy, + options: { annotations: Record }, +) => UserEntity;