From 154222e89fa56a4f9ca26acec092cd8c11661522 Mon Sep 17 00:00:00 2001 From: sundaresanr Date: Thu, 5 Nov 2026 11:53:53 -0800 Subject: [PATCH] fix(aws_s3 source): keep EventBridge S3 object keys as sent EventBridge does not URL-encode the object key, unlike native S3 notifications. Decoding it changed keys that contain "+" or "%", so GetObject requested an object that does not exist. Give the EventBridge detail its own object type with a plain key, and copy the key unchanged into the S3 event record. Native notifications still decode their keys. --- src/sources/aws_s3/sqs.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/sources/aws_s3/sqs.rs b/src/sources/aws_s3/sqs.rs index 6ba95c779db52..f164d1ad076eb 100644 --- a/src/sources/aws_s3/sqs.rs +++ b/src/sources/aws_s3/sqs.rs @@ -1064,11 +1064,17 @@ pub struct EventBridgeS3Event { pub struct EventBridgeS3Detail { pub event_version: S3EventVersion, pub bucket: S3Bucket, - pub object: S3Object, + pub object: EventBridgeS3Object, #[serde(default)] pub reason: String, } +// Unlike native S3 notifications, EventBridge does not URL-encode the object key. +#[derive(Clone, Debug, Deserialize)] +pub struct EventBridgeS3Object { + pub key: String, +} + impl From for S3EventRecord { fn from(event: EventBridgeS3Event) -> Self { // "Object Created" -> "ObjectCreated", matching the native event-name kinds. @@ -1084,7 +1090,9 @@ impl From for S3EventRecord { event_time: event.time, s3: S3Message { bucket: event.detail.bucket, - object: event.detail.object, + object: S3Object { + key: event.detail.object.key, + }, }, } } @@ -1487,12 +1495,13 @@ fn test_eventbridge_restore_without_reason() { } #[test] -fn test_eventbridge_key_is_url_decoded() { - let body = eventbridge_body("Object Created", "a+b%2Bc%25d", "PutObject"); +fn test_eventbridge_key_is_not_url_decoded() { + let body = eventbridge_body("Object Created", "eb test/a b+c%d.txt", "PutObject"); let SqsEvent::EventBridge(event) = serde_json::from_str::(&body).unwrap() else { panic!("expected an EventBridge event"); }; - assert_eq!(event.detail.object.key, "a b+c%d"); + let record: S3EventRecord = event.into(); + assert_eq!(record.s3.object.key, "eb test/a b+c%d.txt"); } #[test]