diff --git a/moto/s3/models.py b/moto/s3/models.py index 79a33340f0bf..ef7f8d23651f 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -2223,11 +2223,22 @@ def put_object_acl( bucket_name: str, key_name: str, acl: Optional[FakeAcl], + disable_notification: Optional[bool] = False, ) -> None: key = self.get_object(bucket_name, key_name) # TODO: Support the XML-based ACL format if key is not None: key.set_acl(acl) + bucket = self.get_bucket(key.bucket_name) # type: ignore + + notify_event_name = ( + notifications.S3NotificationEvent.OBJECT_ACL_UPDATE_EVENT + ) + + if not disable_notification: + notifications.send_event( + self.account_id, notify_event_name, bucket, key + ) else: raise MissingKey(key=key_name) @@ -2574,6 +2585,7 @@ def complete_multipart_upload( bucket_name=bucket_name, key_name=key.name, acl=multipart.acl, + disable_notification=True, # avoid sending ObjectAcl:Put events here ) notifications.send_event( diff --git a/moto/s3/notifications.py b/moto/s3/notifications.py index 6dcae0007bcf..7cbe2753c354 100644 --- a/moto/s3/notifications.py +++ b/moto/s3/notifications.py @@ -41,7 +41,7 @@ class S3NotificationEvent(str, Enum): OBJECT_RESTORE_DELETE_EVENT = "s3:ObjectRestore:Delete" LIFECYCLE_TRANSITION_EVENT = "s3:LifecycleTransition" INTELLIGENT_TIERING_EVENT = "s3:IntelligentTiering" - OBJECT_ACL_EVENT = "s3:ObjectAcl:Put" + OBJECT_ACL_UPDATE_EVENT = "s3:ObjectAcl:Put" LIFECYCLE_EXPIRATION_EVENT = "s3:LifecycleExpiration:*" LIFECYCLEEXPIRATION_DELETE_EVENT = "s3:LifecycleExpiration:Delete" LIFECYCLE_EXPIRATION_DELETE_MARKER_CREATED_EVENT = ( diff --git a/tests/test_s3/test_s3_eventbridge_integration.py b/tests/test_s3/test_s3_eventbridge_integration.py index 5de1e118a355..8fa7ef27704f 100644 --- a/tests/test_s3/test_s3_eventbridge_integration.py +++ b/tests/test_s3/test_s3_eventbridge_integration.py @@ -225,7 +225,7 @@ def test_delete_object_notification(): s3_client.delete_object(Bucket=bucket_name, Key="keyname") events = _get_send_events() - assert len(events) == 3 # [PutObject, ObjectTagging, DeleteObect] + assert len(events) == 3 # [PutObject, ObjectTagging, DeleteObject] event_message = json.loads(events[-1]["message"]) assert event_message["detail-type"] == "Object Deleted" assert event_message["source"] == "aws.s3" @@ -340,3 +340,32 @@ def test_delete_object_tagging_notification(): assert event_message["region"] == REGION_NAME assert event_message["detail"]["bucket"]["name"] == bucket_name assert event_message["detail"]["reason"] == "ObjectTagging" + + +@mock_aws +def test_delete_object_acl_update_notification(): + resource_names = _seteup_bucket_notification_eventbridge() + bucket_name = resource_names["bucket_name"] + s3_client = boto3.client("s3", region_name=REGION_NAME) + + # Put Object + s3_client.put_object(Bucket=bucket_name, Key="keyname", Body="bodyofnewobject") + + # Put Object ACL + s3_client.put_object_acl(Bucket=bucket_name, Key="keyname", ACL="public-read") + + # Delete Object ACL + s3_client.put_object_acl(Bucket=bucket_name, Key="keyname", ACL="private") + + events = _get_send_events() + assert ( + len(events) == 4 + ) # [PutObject, ObjectTagging, CompleteMultipartUpload, ObjectAcl] + event_message = json.loads(events[2]["message"]) + assert event_message["detail-type"] == "Object ACL Updated" + assert event_message["source"] == "aws.s3" + assert event_message["account"] == ACCOUNT_ID + assert event_message["region"] == REGION_NAME + assert event_message["detail"]["bucket"]["name"] == bucket_name + assert event_message["detail"]["object"]["key"] == "keyname" + assert event_message["detail"]["reason"] == "ObjectAcl" diff --git a/tests/test_s3/test_s3_notifications.py b/tests/test_s3/test_s3_notifications.py index 87e45ce0503b..924a2ec6fda4 100644 --- a/tests/test_s3/test_s3_notifications.py +++ b/tests/test_s3/test_s3_notifications.py @@ -51,7 +51,7 @@ "Object Storage Class Changed", ), ([S3NotificationEvent.INTELLIGENT_TIERING_EVENT], "Object Access Tier Changed"), - ([S3NotificationEvent.OBJECT_ACL_EVENT], "Object ACL Updated"), + ([S3NotificationEvent.OBJECT_ACL_UPDATE_EVENT], "Object ACL Updated"), ([S3NotificationEvent.OBJECT_TAGGING_PUT_EVENT], "Object Tags Added"), ([S3NotificationEvent.OBJECT_TAGGING_DELETE_EVENT], "Object Tags Deleted"), ],