From 29c559893c16c77c36e97b9bc4bf5a9ced6c9a99 Mon Sep 17 00:00:00 2001 From: Huw Griffiths Date: Tue, 2 Jul 2019 15:12:20 +1000 Subject: [PATCH 1/5] Extend events.SimpleEmailReceiptAction fields The action object contains different data depending on the type. Previously only the fields relevant to the Lambda type were included, preventing use of the SimpleEmailReceiptAction for other types. --- events/ses.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/events/ses.go b/events/ses.go index 793b448e..2af898af 100644 --- a/events/ses.go +++ b/events/ses.go @@ -56,9 +56,17 @@ type SimpleEmailCommonHeaders struct { } type SimpleEmailReceiptAction struct { - Type string `json:"type"` - InvocationType string `json:"invocationType"` - FunctionArn string `json:"functionArn"` + Type string `json:"type"` + TopicARN string `json:"topicArn"` + BucketName string `json:"bucketName"` + ObjectKey string `json:"objectKey"` + SMTPReplyCode string `json:"smtpReplayCode"` + StatusCode string `json:"statusCode"` + Message string `json:"message"` + Sender string `json:"sender"` + InvocationType string `json:"invocationType"` + FunctionArn string `json:"functionArn"` + OrganizationARN string `json:"organizationArn"` } type SimpleEmailVerdict struct { From 380843756851cfb992d15aaf2844f843653b3d2c Mon Sep 17 00:00:00 2001 From: Bryan Moffatt Date: Tue, 2 Jul 2019 15:31:49 +0100 Subject: [PATCH 2/5] Update ses.go * ReceiptAction FunctionArn -> FunctionARN * ReceiptAction json:"smtpReplayCode" -> json:"smtpReplyCode" --- events/ses.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/events/ses.go b/events/ses.go index 2af898af..f51a5d09 100644 --- a/events/ses.go +++ b/events/ses.go @@ -60,12 +60,12 @@ type SimpleEmailReceiptAction struct { TopicARN string `json:"topicArn"` BucketName string `json:"bucketName"` ObjectKey string `json:"objectKey"` - SMTPReplyCode string `json:"smtpReplayCode"` + SMTPReplyCode string `json:"smtpReplyCode"` StatusCode string `json:"statusCode"` Message string `json:"message"` Sender string `json:"sender"` InvocationType string `json:"invocationType"` - FunctionArn string `json:"functionArn"` + FunctionARN string `json:"functionArn"` OrganizationARN string `json:"organizationArn"` } From a32f7788a375e5683b23d3bc91906926e37c3c4e Mon Sep 17 00:00:00 2001 From: Huw Griffiths Date: Wed, 3 Jul 2019 08:54:35 +1000 Subject: [PATCH 3/5] Resolve TestSESEventMarshaling failure Using omitempty like this will prevent the inclusion of fields with empty strings. There are possibly scenarios where adding omitempty to the existing FunctionARN and InvocationType fields would change the behaviour of systems that expect the fields to be present and assigned an empty string. I've decided that the consistency of the fields when Unmarshaling is a bigger priority here though, as the chances of real world applications depending on this behaviour seems pretty remote to me. --- events/ses.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/events/ses.go b/events/ses.go index f51a5d09..1e5489c0 100644 --- a/events/ses.go +++ b/events/ses.go @@ -57,16 +57,16 @@ type SimpleEmailCommonHeaders struct { type SimpleEmailReceiptAction struct { Type string `json:"type"` - TopicARN string `json:"topicArn"` - BucketName string `json:"bucketName"` - ObjectKey string `json:"objectKey"` - SMTPReplyCode string `json:"smtpReplyCode"` - StatusCode string `json:"statusCode"` - Message string `json:"message"` - Sender string `json:"sender"` - InvocationType string `json:"invocationType"` - FunctionARN string `json:"functionArn"` - OrganizationARN string `json:"organizationArn"` + TopicARN string `json:"topicArn,omitempty"` + BucketName string `json:"bucketName,omitempty"` + ObjectKey string `json:"objectKey,omitempty"` + SMTPReplyCode string `json:"smtpReplyCode,omitempty"` + StatusCode string `json:"statusCode,omitempty"` + Message string `json:"message,omitempty"` + Sender string `json:"sender,omitempty"` + InvocationType string `json:"invocationType,omitempty"` + FunctionARN string `json:"functionArn,omitempty"` + OrganizationARN string `json:"organizationArn,omitempty"` } type SimpleEmailVerdict struct { From e8ce2d5bb2737c33fc00b62b0f5e9c7369b282d9 Mon Sep 17 00:00:00 2001 From: Huw Griffiths Date: Wed, 3 Jul 2019 09:14:03 +1000 Subject: [PATCH 4/5] Extend TestSESEventMarshaling This test only covered an SES lambda event, and did not cover other types of SES events. Adding SES-S3 and SES-SNS events here is improving the test coverage. --- events/ses_test.go | 31 +++-- .../{ses-event.json => ses-lambda-event.json} | 0 events/testdata/ses-s3-event.json | 114 ++++++++++++++++++ events/testdata/ses-sns-event.json | 112 +++++++++++++++++ 4 files changed, 248 insertions(+), 9 deletions(-) rename events/testdata/{ses-event.json => ses-lambda-event.json} (100%) create mode 100644 events/testdata/ses-s3-event.json create mode 100644 events/testdata/ses-sns-event.json diff --git a/events/ses_test.go b/events/ses_test.go index 0c83dcbc..41f9a523 100644 --- a/events/ses_test.go +++ b/events/ses_test.go @@ -9,19 +9,32 @@ import ( ) func TestSESEventMarshaling(t *testing.T) { - inputJSON := test.ReadJSONFromFile(t, "./testdata/ses-event.json") - var inputEvent SimpleEmailEvent - if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { - t.Errorf("could not unmarshal event. details: %v", err) + tests := []struct { + file string + }{ + {"./testdata/ses-lambda-event.json"}, + {"./testdata/ses-s3-event.json"}, + {"./testdata/ses-sns-event.json"}, } - outputJSON, err := json.Marshal(inputEvent) - if err != nil { - t.Errorf("could not marshal event. details: %v", err) - } + for _, tc := range tests { + t.Run(tc.file, func(t *testing.T) { + inputJSON := test.ReadJSONFromFile(t, tc.file) + + var inputEvent SimpleEmailEvent + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } - assert.JSONEq(t, string(inputJSON), string(outputJSON)) + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) + }) + } } func TestSESMarshalingMalformedJson(t *testing.T) { diff --git a/events/testdata/ses-event.json b/events/testdata/ses-lambda-event.json similarity index 100% rename from events/testdata/ses-event.json rename to events/testdata/ses-lambda-event.json diff --git a/events/testdata/ses-s3-event.json b/events/testdata/ses-s3-event.json new file mode 100644 index 00000000..16827d86 --- /dev/null +++ b/events/testdata/ses-s3-event.json @@ -0,0 +1,114 @@ +{ + "Records": [ + { + "eventVersion": "1.0", + "ses": { + "receipt": { + "timestamp": "2015-09-11T20:32:33.936Z", + "processingTimeMillis": 406, + "recipients": [ + "recipient@example.com" + ], + "spamVerdict": { + "status": "PASS" + }, + "virusVerdict": { + "status": "PASS" + }, + "spfVerdict": { + "status": "PASS" + }, + "dkimVerdict": { + "status": "PASS" + }, + "dmarcVerdict": { + "status": "PASS" + }, + "dmarcPolicy": "reject", + "action": { + "type": "S3", + "topicArn": "arn:aws:sns:us-east-1:012345678912:example-topic", + "bucketName": "my-S3-bucket", + "objectKey": "email" + } + }, + "mail": { + "timestamp": "2015-09-11T20:32:33.936Z", + "source": "0000014fbe1c09cf-7cb9f704-7531-4e53-89a1-5fa9744f5eb6-000000@amazonses.com", + "messageId": "d6iitobk75ur44p8kdnnp7g2n800", + "destination": [ + "recipient@example.com" + ], + "headersTruncated": false, + "headers": [ + { + "name": "Return-Path", + "value": "<0000014fbe1c09cf-7cb9f704-7531-4e53-89a1-5fa9744f5eb6-000000@amazonses.com>" + }, + { + "name": "Received", + "value": "from a9-183.smtp-out.amazonses.com (a9-183.smtp-out.amazonses.com [54.240.9.183]) by inbound-smtp.us-east-1.amazonaws.com with SMTP id d6iitobk75ur44p8kdnnp7g2n800 for recipient@example.com; Fri, 11 Sep 2015 20:32:33 +0000 (UTC)" + }, + { + "name": "DKIM-Signature", + "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug; d=amazonses.com; t=1442003552; h=From:To:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Date:Message-ID:Feedback-ID; bh=DWr3IOmYWoXCA9ARqGC/UaODfghffiwFNRIb2Mckyt4=; b=p4ukUDSFqhqiub+zPR0DW1kp7oJZakrzupr6LBe6sUuvqpBkig56UzUwc29rFbJF hlX3Ov7DeYVNoN38stqwsF8ivcajXpQsXRC1cW9z8x875J041rClAjV7EGbLmudVpPX 4hHst1XPyX5wmgdHIhmUuh8oZKpVqGi6bHGzzf7g=" + }, + { + "name": "From", + "value": "sender@example.com" + }, + { + "name": "To", + "value": "recipient@example.com" + }, + { + "name": "Subject", + "value": "Example subject" + }, + { + "name": "MIME-Version", + "value": "1.0" + }, + { + "name": "Content-Type", + "value": "text/plain; charset=UTF-8" + }, + { + "name": "Content-Transfer-Encoding", + "value": "7bit" + }, + { + "name": "Date", + "value": "Fri, 11 Sep 2015 20:32:32 +0000" + }, + { + "name": "Message-ID", + "value": "<61967230-7A45-4A9D-BEC9-87CBCF2211C9@example.com>" + }, + { + "name": "X-SES-Outgoing", + "value": "2015.09.11-54.240.9.183" + }, + { + "name": "Feedback-ID", + "value": "1.us-east-1.Krv2FKpFdWV+KUYw3Qd6wcpPJ4Sv/pOPpEPSHn2u2o4=:AmazonSES" + } + ], + "commonHeaders": { + "returnPath": "0000014fbe1c09cf-7cb9f704-7531-4e53-89a1-5fa9744f5eb6-000000@amazonses.com", + "from": [ + "sender@example.com" + ], + "date": "Fri, 11 Sep 2015 20:32:32 +0000", + "to": [ + "recipient@example.com" + ], + "messageId": "<61967230-7A45-4A9D-BEC9-87CBCF2211C9@example.com>", + "subject": "Example subject" + } + } + }, + "eventSource": "aws:ses" + } + ] +} diff --git a/events/testdata/ses-sns-event.json b/events/testdata/ses-sns-event.json new file mode 100644 index 00000000..771d5006 --- /dev/null +++ b/events/testdata/ses-sns-event.json @@ -0,0 +1,112 @@ +{ + "Records": [ + { + "eventVersion": "1.0", + "ses": { + "receipt": { + "timestamp": "2015-09-11T20:32:33.936Z", + "processingTimeMillis": 222, + "recipients": [ + "recipient@example.com" + ], + "spamVerdict": { + "status": "PASS" + }, + "virusVerdict": { + "status": "PASS" + }, + "spfVerdict": { + "status": "PASS" + }, + "dkimVerdict": { + "status": "PASS" + }, + "dmarcVerdict": { + "status": "PASS" + }, + "dmarcPolicy": "reject", + "action": { + "type": "SNS", + "topicArn": "arn:aws:sns:us-east-1:012345678912:example-topic" + } + }, + "mail": { + "timestamp": "2015-09-11T20:32:33.936Z", + "source": "61967230-7A45-4A9D-BEC9-87CBCF2211C9@example.com", + "messageId": "d6iitobk75ur44p8kdnnp7g2n800", + "destination": [ + "recipient@example.com" + ], + "headersTruncated": false, + "headers": [ + { + "name": "Return-Path", + "value": "<0000014fbe1c09cf-7cb9f704-7531-4e53-89a1-5fa9744f5eb6-000000@amazonses.com>" + }, + { + "name": "Received", + "value": "from a9-183.smtp-out.amazonses.com (a9-183.smtp-out.amazonses.com [54.240.9.183]) by inbound-smtp.us-east-1.amazonaws.com with SMTP id d6iitobk75ur44p8kdnnp7g2n800 for recipient@example.com; Fri, 11 Sep 2015 20:32:33 +0000 (UTC)" + }, + { + "name": "DKIM-Signature", + "value": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=ug7nbtf4gccmlpwj322ax3p6ow6yfsug; d=amazonses.com; t=1442003552; h=From:To:Subject:MIME-Version:Content-Type:Content-Transfer-Encoding:Date:Message-ID:Feedback-ID; bh=DWr3IOmYWoXCA9ARqGC/UaODfghffiwFNRIb2Mckyt4=; b=p4ukUDSFqhqiub+zPR0DW1kp7oJZakrzupr6LBe6sUuvqpBkig56UzUwc29rFbJF hlX3Ov7DeYVNoN38stqwsF8ivcajXpQsXRC1cW9z8x875J041rClAjV7EGbLmudVpPX 4hHst1XPyX5wmgdHIhmUuh8oZKpVqGi6bHGzzf7g=" + }, + { + "name": "From", + "value": "sender@example.com" + }, + { + "name": "To", + "value": "recipient@example.com" + }, + { + "name": "Subject", + "value": "Example subject" + }, + { + "name": "MIME-Version", + "value": "1.0" + }, + { + "name": "Content-Type", + "value": "text/plain; charset=UTF-8" + }, + { + "name": "Content-Transfer-Encoding", + "value": "7bit" + }, + { + "name": "Date", + "value": "Fri, 11 Sep 2015 20:32:32 +0000" + }, + { + "name": "Message-ID", + "value": "<61967230-7A45-4A9D-BEC9-87CBCF2211C9@example.com>" + }, + { + "name": "X-SES-Outgoing", + "value": "2015.09.11-54.240.9.183" + }, + { + "name": "Feedback-ID", + "value": "1.us-east-1.Krv2FKpFdWV+KUYw3Qd6wcpPJ4Sv/pOPpEPSHn2u2o4=:AmazonSES" + } + ], + "commonHeaders": { + "returnPath": "0000014fbe1c09cf-7cb9f704-7531-4e53-89a1-5fa9744f5eb6-000000@amazonses.com", + "from": [ + "sender@example.com" + ], + "date": "Fri, 11 Sep 2015 20:32:32 +0000", + "to": [ + "recipient@example.com" + ], + "messageId": "<61967230-7A45-4A9D-BEC9-87CBCF2211C9@example.com>", + "subject": "Example subject" + } + } + }, + "eventSource": "aws:ses" + } + ] +} From 0748fe5f002778f89832450001f8f98b8051b449 Mon Sep 17 00:00:00 2001 From: Huw Griffiths Date: Wed, 3 Jul 2019 09:50:50 +1000 Subject: [PATCH 5/5] Document events.SimpleEmailReceiptAction --- events/ses.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/events/ses.go b/events/ses.go index 1e5489c0..ff899856 100644 --- a/events/ses.go +++ b/events/ses.go @@ -55,6 +55,10 @@ type SimpleEmailCommonHeaders struct { Subject string `json:"subject"` } +// SimpleEmailReceiptAction is a logical union of fields present in all action +// Types. For example, the FunctionARN and InvocationType fields are only +// present for the Lambda Type, and the BucketName and ObjectKey fields are only +// present for the S3 Type. type SimpleEmailReceiptAction struct { Type string `json:"type"` TopicARN string `json:"topicArn,omitempty"`