From d784c0a841f2804ec7ad9be10d54463dcea2256d Mon Sep 17 00:00:00 2001 From: niksis02 Date: Thu, 21 Aug 2025 20:40:18 +0400 Subject: [PATCH] feat: adds not implemented routes for bucket notification configuration actions Closes #1453 Adds `NotImplemented` routes for bucket notification configuration S3 actions: - `PutBucketNotificationConfiguration` - `GetBucketNotificationConfiguration` --- auth/bucket_policy_actions.go | 4 ++++ metrics/actions.go | 10 ++++++++++ s3api/router.go | 28 ++++++++++++++++++++++++++++ tests/integration/group-tests.go | 5 +++++ tests/integration/tests.go | 31 +++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+) diff --git a/auth/bucket_policy_actions.go b/auth/bucket_policy_actions.go index 13a8eec..67b834d 100644 --- a/auth/bucket_policy_actions.go +++ b/auth/bucket_policy_actions.go @@ -80,6 +80,8 @@ const ( GetReplicationConfigurationAction Action = "s3:GetReplicationConfiguration" PutBucketPublicAccessBlockAction Action = "s3:PutBucketPublicAccessBlock" GetBucketPublicAccessBlockAction Action = "s3:GetBucketPublicAccessBlock" + PutBucketNotificationAction Action = "s3:PutBucketNotification" + GetBucketNotificationAction Action = "s3:GetBucketNotification" AllActions Action = "s3:*" ) @@ -143,6 +145,8 @@ var supportedActionList = map[Action]struct{}{ GetReplicationConfigurationAction: {}, PutBucketPublicAccessBlockAction: {}, GetBucketPublicAccessBlockAction: {}, + PutBucketNotificationAction: {}, + GetBucketNotificationAction: {}, AllActions: {}, } diff --git a/metrics/actions.go b/metrics/actions.go index 20f7ab1..93661f0 100644 --- a/metrics/actions.go +++ b/metrics/actions.go @@ -108,6 +108,8 @@ var ( ActionPutPublicAccessBlock = "s3_PutPublicAccessBlock" ActionGetPublicAccessBlock = "s3_GetPublicAccessBlock" ActionDeletePublicAccessBlock = "s3_DeletePublicAccessBlock" + ActionPutBucketNotificationConfiguration = "s3_PutBucketNotificationConfiguration" + ActionGetBucketNotificationConfiguration = "s3_GetBucketNotificationConfiguration" // Admin actions ActionAdminCreateUser = "admin_CreateUser" @@ -458,4 +460,12 @@ func init() { Name: "DeletePublicAccessBlock", Service: "s3", } + ActionMap[ActionPutBucketNotificationConfiguration] = Action{ + Name: "PutBucketNotificationConfiguration", + Service: "s3", + } + ActionMap[ActionGetBucketNotificationConfiguration] = Action{ + Name: "GetBucketNotificationConfiguration", + Service: "s3", + } } diff --git a/s3api/router.go b/s3api/router.go index d01fa44..9441e88 100644 --- a/s3api/router.go +++ b/s3api/router.go @@ -342,6 +342,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Put("", + middlewares.MatchQueryArgs("notification"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionPutBucketNotificationConfiguration, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionPutBucketNotificationConfiguration, auth.PutBucketNotificationAction, auth.PermissionWrite), + middlewares.VerifyPresignedV4Signature(root, iam, region, debug), + middlewares.VerifyV4Signature(root, iam, region, debug), + middlewares.VerifyMD5Body(), + middlewares.ParseAcl(be), + ), + ) bucketRouter.Put("", controllers.ProcessHandlers( ctrl.CreateBucket, @@ -877,6 +891,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Get("", + middlewares.MatchQueryArgs("notification"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionGetBucketNotificationConfiguration, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionGetBucketNotificationConfiguration, auth.GetBucketNotificationAction, auth.PermissionRead), + middlewares.VerifyPresignedV4Signature(root, iam, region, debug), + middlewares.VerifyV4Signature(root, iam, region, debug), + middlewares.VerifyMD5Body(), + middlewares.ParseAcl(be), + ), + ) bucketRouter.Get("", middlewares.MatchQueryArgWithValue("list-type", "2"), controllers.ProcessHandlers( diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index eee9e4d..9f43526 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -663,6 +663,9 @@ func TestNotImplementedActions(s *S3Conf) { PutPublicAccessBlock_not_implemented(s) GetPublicAccessBlock_not_implemented(s) DeletePublicAccessBlock_not_implemented(s) + // bucket notification actions + PutBucketNotificationConfiguratio_not_implemented(s) + GetBucketNotificationConfiguratio_not_implemented(s) } func TestWORMProtection(s *S3Conf) { @@ -1428,6 +1431,8 @@ func GetIntTests() IntTests { "PutPublicAccessBlock_not_implemented": PutPublicAccessBlock_not_implemented, "GetPublicAccessBlock_not_implemented": GetPublicAccessBlock_not_implemented, "DeletePublicAccessBlock_not_implemented": DeletePublicAccessBlock_not_implemented, + "PutBucketNotificationConfiguratio_not_implemented": PutBucketNotificationConfiguratio_not_implemented, + "GetBucketNotificationConfiguratio_not_implemented": GetBucketNotificationConfiguratio_not_implemented, "WORMProtection_bucket_object_lock_configuration_compliance_mode": WORMProtection_bucket_object_lock_configuration_compliance_mode, "WORMProtection_bucket_object_lock_configuration_governance_mode": WORMProtection_bucket_object_lock_configuration_governance_mode, "WORMProtection_bucket_object_lock_governance_bypass_delete": WORMProtection_bucket_object_lock_governance_bypass_delete, diff --git a/tests/integration/tests.go b/tests/integration/tests.go index df9e46e..ef10192 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -15934,6 +15934,37 @@ func DeletePublicAccessBlock_not_implemented(s *S3Conf) error { }) } +func PutBucketNotificationConfiguratio_not_implemented(s *S3Conf) error { + testName := "PutBucketNotificationConfiguratio_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.PutBucketNotificationConfiguration(ctx, + &s3.PutBucketNotificationConfigurationInput{ + Bucket: &bucket, + NotificationConfiguration: &types.NotificationConfiguration{ + EventBridgeConfiguration: &types.EventBridgeConfiguration{}, + }, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func GetBucketNotificationConfiguratio_not_implemented(s *S3Conf) error { + testName := "GetBucketNotificationConfiguratio_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.GetBucketNotificationConfiguration(ctx, + &s3.GetBucketNotificationConfigurationInput{ + Bucket: &bucket, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + func WORMProtection_bucket_object_lock_configuration_compliance_mode(s *S3Conf) error { testName := "WORMProtection_bucket_object_lock_configuration_compliance_mode" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {