From 1425af70ce29446c80acf4c4e33c46f6f9c090a5 Mon Sep 17 00:00:00 2001 From: Richard Neidermyer Date: Tue, 14 Nov 2023 12:37:40 -0500 Subject: [PATCH 1/4] feat!: add obfuscate logging option --- README.md | 22 ++++++-- src/dynamo-streams.test.ts | 108 ++++++++++++++++++++++++++++++++++--- src/dynamo-streams.ts | 77 ++++++++++++++++++++++---- 3 files changed, 185 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 14a75bc..a2c76c0 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ import { DynamoStreamHandler } from '@lifeomic/delta'; const stream = new DynamoStreamHandler({ logger, + // Optionally specify a list of image keys to obfuscate the values of + loggerObfuscateImageKeys: ['api-secret'], parse: (item) => { // parse the item using your custom logic, e.g. using zod or ajv. return { id: item.id }; @@ -165,12 +167,22 @@ test('something', async () => { ### Parallel Processing + Ordering -By default, the abstractions in `@lifeomic/delta` (`DynamoStreamHandler` and `SQSMessageHandler`) will process events in parallel. To control the parallelization, specify a `concurrency` value when creating the handler. +By default, the abstractions in `@lifeomic/delta` (`DynamoStreamHandler` and +`SQSMessageHandler`) will process events in parallel. To control the +parallelization, specify a `concurrency` value when creating the handler. -These abstractions also ensure that within a batch of events correct _ordering_ of events is maintained according to the ordering semantics of the upstream event source, even when processing in parallel. +These abstractions also ensure that within a batch of events correct _ordering_ +of events is maintained according to the ordering semantics of the upstream +event source, even when processing in parallel. -In `DynamoStreamHandler`, events for the same _key_ will always be processed serially -- events from different keys will be processed in parallel. +In `DynamoStreamHandler`, events for the same _key_ will always be processed +serially -- events from different keys will be processed in parallel. -In `SQSMessageHandler`, events with the same `MessageGroupId` will always processed serially -- events with different `MessageGroupId` values will be processed in parallel. +In `SQSMessageHandler`, events with the same `MessageGroupId` will always +processed serially -- events with different `MessageGroupId` values will be +processed in parallel. -**Note**: while the ordering semantics above will always be preserved, events that do _not_ need to be ordered will not necessarily be processed in the same order they were received in the batch (even when using a `concurrency` value of `1`). +**Note**: while the ordering semantics above will always be preserved, events +that do _not_ need to be ordered will not necessarily be processed in the same +order they were received in the batch (even when using a `concurrency` value of +`1`). diff --git a/src/dynamo-streams.test.ts b/src/dynamo-streams.test.ts index 80abfbf..83d8399 100644 --- a/src/dynamo-streams.test.ts +++ b/src/dynamo-streams.test.ts @@ -2,6 +2,7 @@ import { LoggerInterface } from '@lifeomic/logging'; import { v4 as uuid } from 'uuid'; import { DynamoStreamHandler } from './dynamo-streams'; import { marshall } from '@aws-sdk/util-dynamodb'; +import { DynamoDBStreamEvent } from 'aws-lambda'; import { z } from 'zod'; const TestSchema = z.object({ @@ -223,7 +224,6 @@ describe('DynamoStreamHandler', () => { ); expect(dataSources.doSomething).toHaveBeenCalledTimes(5); - expect(dataSources.doSomething).toHaveBeenNthCalledWith(1, 'insert 1', { id: 'test-id-1', }); @@ -443,7 +443,6 @@ describe('DynamoStreamHandler', () => { ); expect(logger.error).toHaveBeenCalledWith( - expect.anything(), 'The dynamodb property was not present on event', ); }); @@ -456,7 +455,6 @@ describe('DynamoStreamHandler', () => { ); expect(logger.error).toHaveBeenCalledWith( - expect.anything(), 'No NewImage was defined for an INSERT event', ); }); @@ -476,7 +474,6 @@ describe('DynamoStreamHandler', () => { ); expect(logger.error).toHaveBeenCalledWith( - expect.anything(), 'No NewImage was defined for a MODIFY event', ); }); @@ -496,7 +493,6 @@ describe('DynamoStreamHandler', () => { ); expect(logger.error).toHaveBeenCalledWith( - expect.anything(), 'No OldImage was defined for a MODIFY event', ); }); @@ -509,7 +505,6 @@ describe('DynamoStreamHandler', () => { ); expect(logger.error).toHaveBeenCalledWith( - expect.anything(), 'No OldImage was defined for a REMOVE event', ); }); @@ -737,4 +732,105 @@ describe('DynamoStreamHandler', () => { expect(end - start).toBeGreaterThanOrEqual(400); }); }); + + describe('logger obfuscation', () => { + const baseEvent = { + Records: [ + { + eventName: 'MODIFY', + dynamodb: { + NewImage: { + id: { S: 'test-id' }, + secret: { S: 'abcdefg' } + }, + OldImage: { + id: { S: 'test-id' }, + not_secret: { S: 'abcdefg' } + } + }, + }, + ], + } as DynamoDBStreamEvent; + + test('no obfuscation without configuration', async () => { + const testValue = uuid(); + + const overrideLogger = { + info: jest.fn(), + error: jest.fn(), + child: jest.fn(), + }; + overrideLogger.child.mockImplementation(() => overrideLogger); + const { obfuscateEvent } = new DynamoStreamHandler({ + logger, + parse: testSerializer.parse, + createRunContext: () => ({ dataSources }), + }) + .harness({ + logger: overrideLogger as any, + createRunContext: () => ({ dataSources, testValue }), + }); + + const result = obfuscateEvent(baseEvent); + expect(result).toEqual(baseEvent); + }); + + test('obfuscate with a configuration', async () => { + const testValue = uuid(); + + const overrideLogger = { + info: jest.fn(), + error: jest.fn(), + child: jest.fn(), + }; + overrideLogger.child.mockImplementation(() => overrideLogger); + const { obfuscateEvent } = new DynamoStreamHandler({ + logger, + loggerObfuscateImageKeys: ['secret'], + parse: testSerializer.parse, + createRunContext: () => ({ dataSources }), + }) + .harness({ + logger: overrideLogger as any, + createRunContext: () => ({ dataSources, testValue }), + }); + + const result = obfuscateEvent(baseEvent); + expect(result).toEqual({ + Records: [ + { + eventName: 'MODIFY', + dynamodb: { + NewImage: { + id: { S: 'test-id' }, + secret: { S: 'obfuscated' } + }, + OldImage: { + id: { S: 'test-id' }, + not_secret: { S: 'abcdefg' } + } + }, + }, + ], + }); + + const missingImageEvent = baseEvent; + delete missingImageEvent.Records[0].dynamodb!.OldImage; + const result2 = obfuscateEvent(missingImageEvent); + expect(result2).toEqual({ + Records: [ + { + eventName: 'MODIFY', + dynamodb: { + NewImage: { + id: { S: 'test-id' }, + secret: { S: 'obfuscated' } + }, + }, + }, + ], + }); + }); + }); + }); diff --git a/src/dynamo-streams.ts b/src/dynamo-streams.ts index a7acee1..4f19148 100644 --- a/src/dynamo-streams.ts +++ b/src/dynamo-streams.ts @@ -1,6 +1,10 @@ import { LoggerInterface } from '@lifeomic/logging'; import { v4 as uuid } from 'uuid'; -import { DynamoDBStreamEvent, DynamoDBStreamHandler } from 'aws-lambda'; +import { + DynamoDBStreamEvent, + DynamoDBStreamHandler, + DynamoDBRecord +} from 'aws-lambda'; import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'; import { BaseContext, @@ -13,6 +17,11 @@ export type DynamoStreamHandlerConfig = { * A logger to use in the context. */ logger: LoggerInterface; + /** + * A listing of keys within a dynamo record's images to obfuscate in logging + * output. + */ + loggerObfuscateImageKeys?: string[]; /** * A function for parsing images from the stream into your custom type. * @@ -60,7 +69,6 @@ export type DynamoStreamHandlerHarnessConfig = { * An optional override for the logger. */ logger?: LoggerInterface; - /** * An optional override for creating the run context. */ @@ -69,6 +77,7 @@ export type DynamoStreamHandlerHarnessConfig = { export type DynamoStreamHandlerHarnessContext = { sendEvent: (event: TestEvent) => Promise; + obfuscateEvent: (event: DynamoDBStreamEvent) => DynamoDBStreamEvent; }; export type TestRecord = @@ -127,6 +136,50 @@ export class DynamoStreamHandler { return copy; } + private obfuscate( + blob: any, + keys: string[], + ): any { + if (blob === undefined) return undefined; + const obfuscated = blob; + keys.forEach(k => { + if (obfuscated[k]) { + obfuscated[k] = { S: 'obfuscated' }; + } + }); + return obfuscated; + } + + private obfuscateRecord( + dynamoRecord: DynamoDBRecord + ): DynamoDBRecord { + if (this.config.loggerObfuscateImageKeys && dynamoRecord.dynamodb) { + return { + ...dynamoRecord, + dynamodb: { + ...dynamoRecord.dynamodb, + NewImage: this.obfuscate( + dynamoRecord.dynamodb.NewImage, + this.config.loggerObfuscateImageKeys + ), + OldImage: this.obfuscate( + dynamoRecord.dynamodb.OldImage, + this.config.loggerObfuscateImageKeys + ), + }, + } + } + return dynamoRecord; + } + + private obfuscateEvent( + dynamoEvent: DynamoDBStreamEvent + ): DynamoDBStreamEvent { + return { + Records: dynamoEvent.Records.map(r => this.obfuscateRecord(r)), + } + } + /** * Adds an "INSERT" event handler. */ @@ -178,7 +231,10 @@ export class DynamoStreamHandler { ...base, }; - context.logger.info({ event }, 'Processing DynamoDB stream event'); + context.logger.info( + { event: this.obfuscateEvent(event) }, + 'Processing DynamoDB stream event' + ); await processWithOrdering( { @@ -194,7 +250,7 @@ export class DynamoStreamHandler { // We need to order by key -- so, just stringify the key. // // But, add custom logic to ensure that the key object is stringified - // determinstically, regardless of the order of its keys. (e.g. we + // deterministically, regardless of the order of its keys. (e.g. we // should stringify { a: 1, b: 2 } and { b: 2, a: 1 } to the same string) // // It's possible that AWS already ensures that the keys are deterministically @@ -210,10 +266,11 @@ export class DynamoStreamHandler { stopOnError: false, }, async (record) => { - const recordLogger = this.config.logger.child({ record }); + const recordLogger = this.config.logger.child({ + record: this.obfuscateRecord(record) + }); if (!record.dynamodb) { recordLogger.error( - { record }, 'The dynamodb property was not present on event', ); return; @@ -234,7 +291,6 @@ export class DynamoStreamHandler { if (record.eventName === 'INSERT') { if (!newEntity) { recordLogger.error( - { record }, 'No NewImage was defined for an INSERT event', ); return; @@ -248,14 +304,12 @@ export class DynamoStreamHandler { else if (record.eventName === 'MODIFY') { if (!oldEntity) { recordLogger.error( - { record }, 'No OldImage was defined for a MODIFY event', ); return; } if (!newEntity) { recordLogger.error( - { record }, 'No NewImage was defined for a MODIFY event', ); return; @@ -273,7 +327,6 @@ export class DynamoStreamHandler { else if (record.eventName === 'REMOVE') { if (!oldEntity) { recordLogger.error( - { record }, 'No OldImage was defined for a REMOVE event', ); return; @@ -290,7 +343,7 @@ export class DynamoStreamHandler { /** * Returns a test harness for exercising the handler, with an optional - * overriden context. + * overridden context. */ harness( options?: DynamoStreamHandlerHarnessConfig, @@ -333,6 +386,8 @@ export class DynamoStreamHandler { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument await lambda(dynamoEvent, {} as any, null as any); }, + obfuscateEvent: (event: DynamoDBStreamEvent) => + this.obfuscateEvent(event), }; } } From e3648d0b27ce975b3b3958bc97c17599a1e95162 Mon Sep 17 00:00:00 2001 From: Richard Neidermyer Date: Tue, 14 Nov 2023 13:31:14 -0500 Subject: [PATCH 2/4] fix linter errors --- src/dynamo-streams.test.ts | 37 ++++++++++++++----------------- src/dynamo-streams.ts | 45 ++++++++++++++------------------------ 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/src/dynamo-streams.test.ts b/src/dynamo-streams.test.ts index 83d8399..cf5462b 100644 --- a/src/dynamo-streams.test.ts +++ b/src/dynamo-streams.test.ts @@ -741,18 +741,18 @@ describe('DynamoStreamHandler', () => { dynamodb: { NewImage: { id: { S: 'test-id' }, - secret: { S: 'abcdefg' } + secret: { S: 'abcdefg' }, }, OldImage: { id: { S: 'test-id' }, - not_secret: { S: 'abcdefg' } - } + not_secret: { S: 'abcdefg' }, + }, }, }, ], } as DynamoDBStreamEvent; - test('no obfuscation without configuration', async () => { + test('no obfuscation without configuration', () => { const testValue = uuid(); const overrideLogger = { @@ -765,17 +765,16 @@ describe('DynamoStreamHandler', () => { logger, parse: testSerializer.parse, createRunContext: () => ({ dataSources }), - }) - .harness({ - logger: overrideLogger as any, - createRunContext: () => ({ dataSources, testValue }), - }); + }).harness({ + logger: overrideLogger as any, + createRunContext: () => ({ dataSources, testValue }), + }); const result = obfuscateEvent(baseEvent); expect(result).toEqual(baseEvent); }); - test('obfuscate with a configuration', async () => { + test('obfuscate with a configuration', () => { const testValue = uuid(); const overrideLogger = { @@ -789,11 +788,10 @@ describe('DynamoStreamHandler', () => { loggerObfuscateImageKeys: ['secret'], parse: testSerializer.parse, createRunContext: () => ({ dataSources }), - }) - .harness({ - logger: overrideLogger as any, - createRunContext: () => ({ dataSources, testValue }), - }); + }).harness({ + logger: overrideLogger as any, + createRunContext: () => ({ dataSources, testValue }), + }); const result = obfuscateEvent(baseEvent); expect(result).toEqual({ @@ -803,12 +801,12 @@ describe('DynamoStreamHandler', () => { dynamodb: { NewImage: { id: { S: 'test-id' }, - secret: { S: 'obfuscated' } + secret: { S: 'obfuscated' }, }, OldImage: { id: { S: 'test-id' }, - not_secret: { S: 'abcdefg' } - } + not_secret: { S: 'abcdefg' }, + }, }, }, ], @@ -824,7 +822,7 @@ describe('DynamoStreamHandler', () => { dynamodb: { NewImage: { id: { S: 'test-id' }, - secret: { S: 'obfuscated' } + secret: { S: 'obfuscated' }, }, }, }, @@ -832,5 +830,4 @@ describe('DynamoStreamHandler', () => { }); }); }); - }); diff --git a/src/dynamo-streams.ts b/src/dynamo-streams.ts index 4f19148..b1abead 100644 --- a/src/dynamo-streams.ts +++ b/src/dynamo-streams.ts @@ -3,7 +3,7 @@ import { v4 as uuid } from 'uuid'; import { DynamoDBStreamEvent, DynamoDBStreamHandler, - DynamoDBRecord + DynamoDBRecord, } from 'aws-lambda'; import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'; import { @@ -136,13 +136,10 @@ export class DynamoStreamHandler { return copy; } - private obfuscate( - blob: any, - keys: string[], - ): any { + private obfuscate(blob: any, keys: string[]): any { if (blob === undefined) return undefined; const obfuscated = blob; - keys.forEach(k => { + keys.forEach((k) => { if (obfuscated[k]) { obfuscated[k] = { S: 'obfuscated' }; } @@ -150,9 +147,7 @@ export class DynamoStreamHandler { return obfuscated; } - private obfuscateRecord( - dynamoRecord: DynamoDBRecord - ): DynamoDBRecord { + private obfuscateRecord(dynamoRecord: DynamoDBRecord): DynamoDBRecord { if (this.config.loggerObfuscateImageKeys && dynamoRecord.dynamodb) { return { ...dynamoRecord, @@ -160,24 +155,24 @@ export class DynamoStreamHandler { ...dynamoRecord.dynamodb, NewImage: this.obfuscate( dynamoRecord.dynamodb.NewImage, - this.config.loggerObfuscateImageKeys + this.config.loggerObfuscateImageKeys, ), OldImage: this.obfuscate( dynamoRecord.dynamodb.OldImage, - this.config.loggerObfuscateImageKeys + this.config.loggerObfuscateImageKeys, ), }, - } + }; } return dynamoRecord; } private obfuscateEvent( - dynamoEvent: DynamoDBStreamEvent + dynamoEvent: DynamoDBStreamEvent, ): DynamoDBStreamEvent { return { - Records: dynamoEvent.Records.map(r => this.obfuscateRecord(r)), - } + Records: dynamoEvent.Records.map((r) => this.obfuscateRecord(r)), + }; } /** @@ -233,7 +228,7 @@ export class DynamoStreamHandler { context.logger.info( { event: this.obfuscateEvent(event) }, - 'Processing DynamoDB stream event' + 'Processing DynamoDB stream event', ); await processWithOrdering( @@ -267,7 +262,7 @@ export class DynamoStreamHandler { }, async (record) => { const recordLogger = this.config.logger.child({ - record: this.obfuscateRecord(record) + record: this.obfuscateRecord(record), }); if (!record.dynamodb) { recordLogger.error( @@ -290,9 +285,7 @@ export class DynamoStreamHandler { // Handle INSERT events -- invoke the INSERT actions in order. if (record.eventName === 'INSERT') { if (!newEntity) { - recordLogger.error( - 'No NewImage was defined for an INSERT event', - ); + recordLogger.error('No NewImage was defined for an INSERT event'); return; } @@ -303,15 +296,11 @@ export class DynamoStreamHandler { // Handle MODIFY events -- invoke the MODIFY actions in order. else if (record.eventName === 'MODIFY') { if (!oldEntity) { - recordLogger.error( - 'No OldImage was defined for a MODIFY event', - ); + recordLogger.error('No OldImage was defined for a MODIFY event'); return; } if (!newEntity) { - recordLogger.error( - 'No NewImage was defined for a MODIFY event', - ); + recordLogger.error('No NewImage was defined for a MODIFY event'); return; } @@ -326,9 +315,7 @@ export class DynamoStreamHandler { // Handle REMOVE events -- invoke the REMOVE actions in order. else if (record.eventName === 'REMOVE') { if (!oldEntity) { - recordLogger.error( - 'No OldImage was defined for a REMOVE event', - ); + recordLogger.error('No OldImage was defined for a REMOVE event'); return; } From ef751032949e04e97545a4b28cb677186cbd539c Mon Sep 17 00:00:00 2001 From: Richard Neidermyer Date: Tue, 14 Nov 2023 13:55:44 -0500 Subject: [PATCH 3/4] Remove Incorrect Test Abstraction --- src/dynamo-streams.test.ts | 119 ++++++------------------------------- src/dynamo-streams.ts | 3 - 2 files changed, 19 insertions(+), 103 deletions(-) diff --git a/src/dynamo-streams.test.ts b/src/dynamo-streams.test.ts index cf5462b..294150e 100644 --- a/src/dynamo-streams.test.ts +++ b/src/dynamo-streams.test.ts @@ -2,7 +2,7 @@ import { LoggerInterface } from '@lifeomic/logging'; import { v4 as uuid } from 'uuid'; import { DynamoStreamHandler } from './dynamo-streams'; import { marshall } from '@aws-sdk/util-dynamodb'; -import { DynamoDBStreamEvent } from 'aws-lambda'; +// import { DynamoDBStreamEvent } from 'aws-lambda'; import { z } from 'zod'; const TestSchema = z.object({ @@ -431,6 +431,7 @@ describe('DynamoStreamHandler', () => { describe('error scenarios', () => { const lambda = new DynamoStreamHandler({ logger, + loggerObfuscateImageKeys: ['secret'], parse: testSerializer.parse, createRunContext: () => ({ logger, dataSources }), }).lambda(); @@ -476,6 +477,12 @@ describe('DynamoStreamHandler', () => { expect(logger.error).toHaveBeenCalledWith( 'No NewImage was defined for a MODIFY event', ); + expect(logger.child).toHaveBeenCalledWith({ + record: { + eventName: 'MODIFY', + dynamodb: { OldImage: { id: { S: 'test-id' } } }, + }, + }); }); test('MODIFY with no OldImage', async () => { @@ -484,7 +491,9 @@ describe('DynamoStreamHandler', () => { Records: [ { eventName: 'MODIFY', - dynamodb: { NewImage: { id: { S: 'test-id' } } }, + dynamodb: { + NewImage: { id: { S: 'test-id' }, secret: { S: 'test-id' } }, + }, }, ], }, @@ -495,6 +504,14 @@ describe('DynamoStreamHandler', () => { 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' }, secret: { S: 'obfuscated' } }, + }, + }, + }); }); test('REMOVE with no OldImage', async () => { @@ -732,102 +749,4 @@ describe('DynamoStreamHandler', () => { expect(end - start).toBeGreaterThanOrEqual(400); }); }); - - describe('logger obfuscation', () => { - const baseEvent = { - Records: [ - { - eventName: 'MODIFY', - dynamodb: { - NewImage: { - id: { S: 'test-id' }, - secret: { S: 'abcdefg' }, - }, - OldImage: { - id: { S: 'test-id' }, - not_secret: { S: 'abcdefg' }, - }, - }, - }, - ], - } as DynamoDBStreamEvent; - - test('no obfuscation without configuration', () => { - const testValue = uuid(); - - const overrideLogger = { - info: jest.fn(), - error: jest.fn(), - child: jest.fn(), - }; - overrideLogger.child.mockImplementation(() => overrideLogger); - const { obfuscateEvent } = new DynamoStreamHandler({ - logger, - parse: testSerializer.parse, - createRunContext: () => ({ dataSources }), - }).harness({ - logger: overrideLogger as any, - createRunContext: () => ({ dataSources, testValue }), - }); - - const result = obfuscateEvent(baseEvent); - expect(result).toEqual(baseEvent); - }); - - test('obfuscate with a configuration', () => { - const testValue = uuid(); - - const overrideLogger = { - info: jest.fn(), - error: jest.fn(), - child: jest.fn(), - }; - overrideLogger.child.mockImplementation(() => overrideLogger); - const { obfuscateEvent } = new DynamoStreamHandler({ - logger, - loggerObfuscateImageKeys: ['secret'], - parse: testSerializer.parse, - createRunContext: () => ({ dataSources }), - }).harness({ - logger: overrideLogger as any, - createRunContext: () => ({ dataSources, testValue }), - }); - - const result = obfuscateEvent(baseEvent); - expect(result).toEqual({ - Records: [ - { - eventName: 'MODIFY', - dynamodb: { - NewImage: { - id: { S: 'test-id' }, - secret: { S: 'obfuscated' }, - }, - OldImage: { - id: { S: 'test-id' }, - not_secret: { S: 'abcdefg' }, - }, - }, - }, - ], - }); - - const missingImageEvent = baseEvent; - delete missingImageEvent.Records[0].dynamodb!.OldImage; - const result2 = obfuscateEvent(missingImageEvent); - expect(result2).toEqual({ - Records: [ - { - eventName: 'MODIFY', - dynamodb: { - NewImage: { - id: { S: 'test-id' }, - secret: { S: 'obfuscated' }, - }, - }, - }, - ], - }); - }); - }); }); diff --git a/src/dynamo-streams.ts b/src/dynamo-streams.ts index b1abead..279dfdf 100644 --- a/src/dynamo-streams.ts +++ b/src/dynamo-streams.ts @@ -77,7 +77,6 @@ export type DynamoStreamHandlerHarnessConfig = { export type DynamoStreamHandlerHarnessContext = { sendEvent: (event: TestEvent) => Promise; - obfuscateEvent: (event: DynamoDBStreamEvent) => DynamoDBStreamEvent; }; export type TestRecord = @@ -373,8 +372,6 @@ export class DynamoStreamHandler { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument await lambda(dynamoEvent, {} as any, null as any); }, - obfuscateEvent: (event: DynamoDBStreamEvent) => - this.obfuscateEvent(event), }; } } From 8e0e3b2ed1810203d60c03f2c5e779226b2f0840 Mon Sep 17 00:00:00 2001 From: Richard Neidermyer Date: Tue, 14 Nov 2023 14:28:40 -0500 Subject: [PATCH 4/4] remove comment --- src/dynamo-streams.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dynamo-streams.test.ts b/src/dynamo-streams.test.ts index 294150e..0709fc9 100644 --- a/src/dynamo-streams.test.ts +++ b/src/dynamo-streams.test.ts @@ -2,7 +2,6 @@ import { LoggerInterface } from '@lifeomic/logging'; import { v4 as uuid } from 'uuid'; import { DynamoStreamHandler } from './dynamo-streams'; import { marshall } from '@aws-sdk/util-dynamodb'; -// import { DynamoDBStreamEvent } from 'aws-lambda'; import { z } from 'zod'; const TestSchema = z.object({