From 49c287083c38820921407bc1476d6c32405add7d Mon Sep 17 00:00:00 2001 From: Richard Neidermyer Date: Thu, 16 Nov 2023 09:51:52 -0500 Subject: [PATCH] fix: copy member for obfuscation --- src/dynamo-streams.test.ts | 95 ++++++++++++++++++++++++++++++++++++-- src/dynamo-streams.ts | 11 +++-- 2 files changed, 98 insertions(+), 8 deletions(-) diff --git a/src/dynamo-streams.test.ts b/src/dynamo-streams.test.ts index 0709fc9..e9389b7 100644 --- a/src/dynamo-streams.test.ts +++ b/src/dynamo-streams.test.ts @@ -8,6 +8,12 @@ const TestSchema = z.object({ id: z.string(), name: z.string().optional(), otherValue: z.string().optional(), + otherMap: z + .object({ + name: z.string(), + age: z.number(), + }) + .optional(), }); const testSerializer = { @@ -430,7 +436,6 @@ describe('DynamoStreamHandler', () => { describe('error scenarios', () => { const lambda = new DynamoStreamHandler({ logger, - loggerObfuscateImageKeys: ['secret'], parse: testSerializer.parse, createRunContext: () => ({ logger, dataSources }), }).lambda(); @@ -491,7 +496,7 @@ describe('DynamoStreamHandler', () => { { eventName: 'MODIFY', dynamodb: { - NewImage: { id: { S: 'test-id' }, secret: { S: 'test-id' } }, + NewImage: { id: { S: 'test-id' } }, }, }, ], @@ -507,7 +512,7 @@ describe('DynamoStreamHandler', () => { record: { eventName: 'MODIFY', dynamodb: { - NewImage: { id: { S: 'test-id' }, secret: { S: 'obfuscated' } }, + NewImage: { id: { S: 'test-id' } }, }, }, }); @@ -748,4 +753,88 @@ describe('DynamoStreamHandler', () => { expect(end - start).toBeGreaterThanOrEqual(400); }); }); + + describe('logging obfuscation', () => { + test('MODIFY with no OldImage and obfuscated secret', async () => { + const lambda = new DynamoStreamHandler({ + logger, + loggerObfuscateImageKeys: ['otherValue'], + parse: testSerializer.parse, + createRunContext: () => ({ logger, dataSources }), + }).lambda(); + + await lambda( + { + Records: [ + { + eventName: 'MODIFY', + dynamodb: { + NewImage: { + id: { S: 'test-id' }, + otherValue: { S: 'secret data' }, + }, + }, + }, + ], + }, + {} as any, + {} as any, + ); + + expect(logger.error).toHaveBeenCalledWith( + 'No OldImage was defined for a MODIFY event', + ); + expect(logger.child).toHaveBeenCalledWith({ + record: { + eventName: 'MODIFY', + dynamodb: { + NewImage: { id: { S: 'test-id' }, otherValue: { S: 'obfuscated' } }, + }, + }, + }); + }); + + test('event not modified during obfuscation', async () => { + const lambda = new DynamoStreamHandler({ + logger, + loggerObfuscateImageKeys: ['otherMap', 'otherValue'], + parse: testSerializer.parse, + createRunContext: () => ({ logger, dataSources }), + }) + .onModify((ctx, oldEntity, newEntity) => { + ctx.dataSources.doSomething(oldEntity, newEntity); + }) + .lambda(); + + await lambda( + { + Records: [ + { + eventName: 'MODIFY', + dynamodb: { + OldImage: { + id: { S: 'old-modify' }, + otherValue: { S: 'secret data' }, + }, + NewImage: { + id: { S: 'new-modify' }, + otherMap: { + M: { name: { S: 'secret data' }, age: { N: '35' } }, + }, + }, + }, + }, + ], + }, + {} as any, + {} as any, + ); + + expect(dataSources.doSomething).toHaveBeenCalledTimes(1); + expect(dataSources.doSomething).toHaveBeenCalledWith( + { id: 'old-modify', otherValue: 'secret data' }, + { id: 'new-modify', otherMap: { name: 'secret data', age: 35 } }, + ); + }); + }); }); diff --git a/src/dynamo-streams.ts b/src/dynamo-streams.ts index 279dfdf..627072e 100644 --- a/src/dynamo-streams.ts +++ b/src/dynamo-streams.ts @@ -19,7 +19,8 @@ export type DynamoStreamHandlerConfig = { logger: LoggerInterface; /** * A listing of keys within a dynamo record's images to obfuscate in logging - * output. + * output. This will not perform a deep obfuscation of 'M' AttributeValue + * types and instead will simply obfuscate the entire value. */ loggerObfuscateImageKeys?: string[]; /** @@ -137,13 +138,13 @@ export class DynamoStreamHandler { private obfuscate(blob: any, keys: string[]): any { if (blob === undefined) return undefined; - const obfuscated = blob; + const copy: any = { ...blob }; keys.forEach((k) => { - if (obfuscated[k]) { - obfuscated[k] = { S: 'obfuscated' }; + if (copy[k]) { + copy[k] = { S: 'obfuscated' }; } }); - return obfuscated; + return copy; } private obfuscateRecord(dynamoRecord: DynamoDBRecord): DynamoDBRecord {