diff --git a/packages/shared/openfeature-server-common/__tests__/translateContext.test.ts b/packages/shared/openfeature-server-common/__tests__/translateContext.test.ts index c8cf2ce834..cce7a70ef3 100644 --- a/packages/shared/openfeature-server-common/__tests__/translateContext.test.ts +++ b/packages/shared/openfeature-server-common/__tests__/translateContext.test.ts @@ -172,6 +172,48 @@ it('can handle privateAttributes in a single context', () => { expect(logger.logs.length).toEqual(0); }); +it('logs an error when privateAttributes is not an array', () => { + const logger = new TestLogger(); + expect( + translateContext(logger, { + targetingKey: 'my-key', + myCustomAttribute: 'myCustomValue', + privateAttributes: 'myCustomAttribute' as unknown as string[], + }), + ).toEqual({ + kind: 'user', + key: 'my-key', + myCustomAttribute: 'myCustomValue', + }); + expect(logger.logs).toEqual(["The attribute 'privateAttributes' must be an array"]); +}); + +it('omits non-string privateAttributes entries and logs an error', () => { + const logger = new TestLogger(); + expect( + translateContext(logger, { + targetingKey: 'my-key', + privateAttributes: ['myCustomAttribute', 17 as unknown as string], + }), + ).toEqual({ + kind: 'user', + key: 'my-key', + _meta: { + privateAttributes: ['myCustomAttribute'], + }, + }); + expect(logger.logs).toEqual(["'privateAttributes' must be an array of only string values"]); +}); + +it('does not set metadata when privateAttributes is empty', () => { + const logger = new TestLogger(); + expect(translateContext(logger, { targetingKey: 'my-key', privateAttributes: [] })).toEqual({ + kind: 'user', + key: 'my-key', + }); + expect(logger.logs.length).toEqual(0); +}); + it('detects a cycle and logs an error', () => { const a: any = { b: { c: {} }, diff --git a/packages/shared/openfeature-server-common/src/translateContext.ts b/packages/shared/openfeature-server-common/src/translateContext.ts index b2a0f29fea..406ca28d0e 100644 --- a/packages/shared/openfeature-server-common/src/translateContext.ts +++ b/packages/shared/openfeature-server-common/src/translateContext.ts @@ -84,10 +84,20 @@ function translateContextCommon( return; } if (key === 'privateAttributes') { - // eslint-disable-next-line no-underscore-dangle - convertedContext._meta = { - privateAttributes: value as string[], - }; + if (!Array.isArray(value)) { + logger.error("The attribute 'privateAttributes' must be an array"); + return; + } + + const privateAttributes = value.filter((item): item is string => typeof item === 'string'); + if (privateAttributes.length !== value.length) { + logger.error("'privateAttributes' must be an array of only string values"); + } + + if (privateAttributes.length) { + // eslint-disable-next-line no-underscore-dangle + convertedContext._meta = { privateAttributes }; + } } else if (key in LDContextBuiltIns) { if (typeof value === LDContextBuiltIns[key]) { (convertedContext as any)[key] = value;