diff --git a/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts b/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts index aaf33ae0ee..dd3285565c 100644 --- a/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts +++ b/packages/shared/common/__tests__/internal/events/EventProcessor.test.ts @@ -468,6 +468,54 @@ describe('given an event processor', () => { ]); }); + it('redacts all attributes from anonymous context for migration op events', async () => { + const userObj = { key: 'user-key', kind: 'user', name: 'Example user', anonymous: true }; + const context = Context.fromLDContext(userObj); + + Date.now = jest.fn(() => 1000); + eventProcessor.sendEvent({ + kind: 'migration_op', + operation: 'read', + creationDate: 1000, + context, + evaluation: { + key: 'flagkey', + value: 'live', + default: 'off', + reason: { kind: 'FALLTHROUGH' }, + }, + measurements: [], + samplingRatio: 1, + }); + + await eventProcessor.flush(); + + const redactedContext = { + kind: 'user', + key: 'user-key', + anonymous: true, + _meta: { + redactedAttributes: ['name'], + }, + }; + + expect(mockSendEventData).toBeCalledWith(LDEventType.AnalyticsEvents, [ + { + kind: 'migration_op', + operation: 'read', + creationDate: 1000, + context: redactedContext, + evaluation: { + key: 'flagkey', + value: 'live', + default: 'off', + reason: { kind: 'FALLTHROUGH' }, + }, + measurements: [], + }, + ]); + }); + it('expires debug mode based on client time if client time is later than server time', async () => { Date.now = jest.fn(() => 2000); @@ -689,6 +737,15 @@ describe('given an event processor', () => { await eventProcessor.flush(); + // The custom event inlines the context, so an anonymous context's attributes are redacted. + // The index event is not subject to anonymous redaction and keeps the full context. + const redactedAnonUser = { + key: 'anon-user', + kind: 'user', + anonymous: true, + _meta: { redactedAttributes: ['name'] }, + }; + expect(mockSendEventData).toBeCalledWith(LDEventType.AnalyticsEvents, [ { kind: 'index', @@ -700,7 +757,7 @@ describe('given an event processor', () => { key: 'eventkey', data: { thing: 'stuff' }, creationDate: 1000, - context: { ...anonUser, kind: 'user' }, + context: redactedAnonUser, }, ]); }); diff --git a/packages/shared/common/src/internal/events/EventProcessor.ts b/packages/shared/common/src/internal/events/EventProcessor.ts index 401d2fc4b6..354533cc09 100644 --- a/packages/shared/common/src/internal/events/EventProcessor.ts +++ b/packages/shared/common/src/internal/events/EventProcessor.ts @@ -263,7 +263,9 @@ export default class EventProcessor implements LDEventProcessor { if (shouldSample(inputEvent.samplingRatio)) { const migrationEvent: MigrationOutputEvent = { ...inputEvent, - context: inputEvent.context ? this._contextFilter.filter(inputEvent.context) : undefined, + context: inputEvent.context + ? this._contextFilter.filter(inputEvent.context, true) + : undefined, }; if (migrationEvent.samplingRatio === 1) { delete migrationEvent.samplingRatio; @@ -359,7 +361,7 @@ export default class EventProcessor implements LDEventProcessor { kind: 'custom', creationDate: event.creationDate, key: event.key, - context: this._contextFilter.filter(event.context), + context: this._contextFilter.filter(event.context, true), }; if (event.samplingRatio !== 1) {