From f0c55a11bb9692552c724f9009eae83453cd801d Mon Sep 17 00:00:00 2001 From: Connor Kirkpatrick Date: Thu, 27 Feb 2025 11:17:01 +0000 Subject: [PATCH 1/3] Update sourceIPAddress field The sourceIPAddress field can be either an IP address or a fixed string ("s3.amazonaws.com"). --- packages/parser/src/schemas/s3.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/parser/src/schemas/s3.ts b/packages/parser/src/schemas/s3.ts index 0505f635be..911dd546c5 100644 --- a/packages/parser/src/schemas/s3.ts +++ b/packages/parser/src/schemas/s3.ts @@ -8,7 +8,7 @@ const S3Identity = z.object({ }); const S3RequestParameters = z.object({ - sourceIPAddress: z.string().ip(), + sourceIPAddress: z.union([z.string().ip(), z.literal('s3.amazonaws.com')]), }); const S3ResponseElements = z.object({ From ae38d6219f801f1bdf92739fecc7813bf6fc3241 Mon Sep 17 00:00:00 2001 From: Connor Kirkpatrick Date: Thu, 27 Feb 2025 11:25:08 +0000 Subject: [PATCH 2/3] Make sequencer field optional The sequencer field is only present in PUT and DELETE events. --- packages/parser/src/schemas/s3.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/parser/src/schemas/s3.ts b/packages/parser/src/schemas/s3.ts index 911dd546c5..c7d0b78541 100644 --- a/packages/parser/src/schemas/s3.ts +++ b/packages/parser/src/schemas/s3.ts @@ -24,7 +24,7 @@ const S3Message = z.object({ size: z.number().optional(), urlDecodedKey: z.string().optional(), eTag: z.string().optional(), - sequencer: z.string(), + sequencer: z.string().optional(), // Only present in PUT and DELETE events versionId: z.optional(z.string()), }), bucket: z.object({ From d692f787745b70ad9d0b879422c06a8b9fac09ab Mon Sep 17 00:00:00 2001 From: Connor Kirkpatrick Date: Thu, 27 Feb 2025 11:45:48 +0000 Subject: [PATCH 3/3] Add test --- .../tests/events/s3/s3-lifecycle-event.json | 36 +++++++++++++++++++ packages/parser/tests/unit/schema/s3.test.ts | 14 ++++++++ 2 files changed, 50 insertions(+) create mode 100644 packages/parser/tests/events/s3/s3-lifecycle-event.json diff --git a/packages/parser/tests/events/s3/s3-lifecycle-event.json b/packages/parser/tests/events/s3/s3-lifecycle-event.json new file mode 100644 index 0000000000..6fb7d482dd --- /dev/null +++ b/packages/parser/tests/events/s3/s3-lifecycle-event.json @@ -0,0 +1,36 @@ +{ + "Records": [ + { + "eventVersion": "2.3", + "eventSource": "aws:s3", + "awsRegion": "us-west-2", + "eventTime": "1970-01-01T00:00:00.000Z", + "eventName": "LifecycleExpiration:Delete", + "userIdentity": { + "principalId": "s3.amazonaws.com" + }, + "requestParameters": { + "sourceIPAddress": "s3.amazonaws.com" + }, + "responseElements": { + "x-amz-request-id": "C3D13FE58DE4C810", + "x-amz-id-2": "FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD" + }, + "s3": { + "s3SchemaVersion": "1.0", + "configurationId": "testConfigRule", + "bucket": { + "name": "amzn-s3-demo-bucket", + "ownerIdentity": { + "principalId": "A3NL1KOZZKExample" + }, + "arn": "arn:aws:s3:::amzn-s3-demo-bucket" + }, + "object": { + "key": "expiration/delete", + "sequencer": "0055AED6DCD90281E5" + } + } + } + ] +} diff --git a/packages/parser/tests/unit/schema/s3.test.ts b/packages/parser/tests/unit/schema/s3.test.ts index 2335934d03..c59a799280 100644 --- a/packages/parser/tests/unit/schema/s3.test.ts +++ b/packages/parser/tests/unit/schema/s3.test.ts @@ -97,6 +97,20 @@ describe('Schema: S3', () => { expect(result).toStrictEqual(event); }); + it('parses an S3 LifeCycle event with a deleted object', () => { + // Prepare + const event = getTestEvent({ + eventsPath, + filename: 's3-lifecycle-event', + }); + + // Act + const result = S3Schema.parse(event); + + // Assess + expect(result).toStrictEqual(event); + }); + it('parses an S3 Object Lambda with an IAM user', () => { // Prepare const event = structuredClone(baseLambdaEvent);