From e253d1d0afb4af4dd0aa8fe59ed5f127764d9cee Mon Sep 17 00:00:00 2001 From: Jessica He Date: Wed, 9 Apr 2025 16:04:06 -0400 Subject: [PATCH] improve LDAP missing metadata.name error message Signed-off-by: Jessica He --- .changeset/deep-ties-move.md | 5 ++ .../src/ldap/read.test.ts | 60 +++++++++++++++++++ .../src/ldap/read.ts | 15 +++++ 3 files changed, 80 insertions(+) create mode 100644 .changeset/deep-ties-move.md diff --git a/.changeset/deep-ties-move.md b/.changeset/deep-ties-move.md new file mode 100644 index 0000000000..57f6c7772c --- /dev/null +++ b/.changeset/deep-ties-move.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': patch +--- + +Improves error reporting for missing metadata.name in LDAP catalog provider. diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts index 007678c188..4e4f4f7cfd 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -988,6 +988,34 @@ describe('defaultUserTransformer', () => { }, }); }); + + it('throws and includes message when uid (metadata.name) is missing', async () => { + const config: UserConfig = { + dn: 'ddd', + options: {}, + map: { + rdn: 'uid', + name: 'uid', + displayName: 'cn', + email: 'mail', + memberOf: 'memberOf', + }, + set: {}, + }; + + const entry = searchEntry({ + description: ['description-value'], + cn: ['cn-value'], + mail: ['mail-value'], + memberOf: ['x', 'y', 'z'], + }); + + await expect( + defaultUserTransformer(DefaultLdapVendor, config, entry), + ).rejects.toThrow( + "User syncing failed: missing 'uid' attribute, consider applying a user filter to skip processing users with incomplete data.", + ); + }); }); describe('defaultGroupTransformer', () => { @@ -1073,6 +1101,38 @@ describe('defaultGroupTransformer', () => { }, }); }); + + it('throws and includes message when cn (metadata.name) is missing', async () => { + const config: GroupConfig = { + dn: 'ddd', + options: {}, + map: { + rdn: 'cn', + name: 'cn', + displayName: 'cn', + email: 'mail', + description: 'description', + type: 'type', + members: 'members', + memberOf: 'memberOf', + }, + }; + + const entry = searchEntry({ + description: ['description-value'], + mail: ['mail-value'], + avatarUrl: ['avatarUrl-value'], + memberOf: ['x', 'y', 'z'], + entryDN: ['dn-value'], + entryUUID: ['uuid-value'], + }); + + await expect( + defaultGroupTransformer(DefaultLdapVendor, config, entry), + ).rejects.toThrow( + "Group syncing failed: missing 'cn' attribute, consider applying a group filter to skip processing groups with incomplete data.", + ); + }); }); /** diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts index 176d6fca7a..9b9041913d 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -34,6 +34,7 @@ import { LdapVendor } from './vendors'; import { GroupTransformer, UserTransformer } from './types'; import { mapStringAttr } from './util'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { InputError } from '@backstage/errors'; /** * The default implementation of the transformation from an LDAP entry to a @@ -70,6 +71,13 @@ export async function defaultUserTransformer( mapStringAttr(entry, vendor, map.name, v => { entity.metadata.name = v; }); + + if (!entity.metadata.name) { + throw new InputError( + `User syncing failed: missing '${map.name}' attribute, consider applying a user filter to skip processing users with incomplete data.`, + ); + } + mapStringAttr(entry, vendor, map.description, v => { entity.metadata.description = v; }); @@ -180,6 +188,13 @@ export async function defaultGroupTransformer( mapStringAttr(entry, vendor, map.name, v => { entity.metadata.name = v; }); + + if (!entity.metadata.name) { + throw new InputError( + `Group syncing failed: missing '${map.name}' attribute, consider applying a group filter to skip processing groups with incomplete data.`, + ); + } + mapStringAttr(entry, vendor, map.description, v => { entity.metadata.description = v; });