From 025b0ee3c8db01b443ee7a44a76cb1a02bfc74a8 Mon Sep 17 00:00:00 2001 From: niksis02 Date: Wed, 20 Aug 2025 20:48:58 +0400 Subject: [PATCH] feat: adds not implemented routes for bucket lifecycle configuration actions Closes #1443 Adds `NotImplemented` routes for bucket lifecycle configuration S3 actions. - `PutBucketLifecycleConfiguration` - `GetBucketLifecycleConfiguration` - `DeleteBucketLifecycle` --- auth/bucket_policy_actions.go | 2 ++ metrics/actions.go | 3 ++ s3api/router.go | 42 +++++++++++++++++++++++ tests/integration/group-tests.go | 7 ++++ tests/integration/tests.go | 57 ++++++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+) diff --git a/auth/bucket_policy_actions.go b/auth/bucket_policy_actions.go index 8721c93..ec0b763 100644 --- a/auth/bucket_policy_actions.go +++ b/auth/bucket_policy_actions.go @@ -68,6 +68,8 @@ const ( GetIntelligentTieringConfigurationAction Action = "s3:GetIntelligentTieringConfiguration" PutInventoryConfigurationAction Action = "s3:PutInventoryConfiguration" GetInventoryConfigurationAction Action = "s3:GetInventoryConfiguration" + PutLifecycleConfigurationAction Action = "s3:PutLifecycleConfiguration" + GetLifecycleConfigurationAction Action = "s3:GetLifecycleConfiguration" AllActions Action = "s3:*" ) diff --git a/metrics/actions.go b/metrics/actions.go index a207e10..579767c 100644 --- a/metrics/actions.go +++ b/metrics/actions.go @@ -90,6 +90,9 @@ var ( ActionGetBucketInventoryConfiguration = "s3_GetBucketInventoryConfiguration" ActionListBucketInventoryConfigurations = "s3_ListBucketInventoryConfigurations" ActionDeleteBucketInventoryConfiguration = "s3_DeleteBucketInventoryConfiguration" + ActionPutBucketLifecycleConfiguration = "s3_PutBucketLifecycleConfiguration" + ActionGetBucketLifecycleConfiguration = "s3_GetBucketLifecycleConfiguration" + ActionDeleteBucketLifecycle = "s3_DeleteBucketLifecycle" // Admin actions ActionAdminCreateUser = "admin_CreateUser" diff --git a/s3api/router.go b/s3api/router.go index 28be6af..967f225 100644 --- a/s3api/router.go +++ b/s3api/router.go @@ -251,6 +251,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Put("", + middlewares.MatchQueryArgs("lifecycle"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionPutBucketLifecycleConfiguration, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionPutBucketLifecycleConfiguration, auth.PutLifecycleConfigurationAction, 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, @@ -386,6 +400,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Delete("", + middlewares.MatchQueryArgs("lifecycle"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionDeleteBucketLifecycle, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionDeleteBucketLifecycle, auth.PutLifecycleConfigurationAction, auth.PermissionWrite), + middlewares.VerifyPresignedV4Signature(root, iam, region, debug), + middlewares.VerifyV4Signature(root, iam, region, debug), + middlewares.VerifyMD5Body(), + middlewares.ParseAcl(be), + ), + ) bucketRouter.Delete("", controllers.ProcessHandlers( ctrl.DeleteBucket, @@ -615,6 +643,20 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ middlewares.ParseAcl(be), ), ) + bucketRouter.Get("", + middlewares.MatchQueryArgs("lifecycle"), + controllers.ProcessHandlers( + ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrNotImplemented)), + metrics.ActionGetBucketLifecycleConfiguration, + services, + middlewares.BucketObjectNameValidator(), + middlewares.AuthorizePublicBucketAccess(be, metrics.ActionGetBucketLifecycleConfiguration, auth.GetLifecycleConfigurationAction, 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 19fbd85..ae0f79c 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -603,6 +603,10 @@ func TestNotImplementedActions(s *S3Conf) { GetBucketInventoryConfiguration_not_implemented(s) ListBucketInventoryConfiguration_not_implemented(s) DeleteBucketInventoryConfiguration_not_implemented(s) + // bucket lifecycle configuration actions + PutBucketLifecycleConfiguration_not_implemented(s) + GetBucketLifecycleConfiguration_not_implemented(s) + DeleteBucketLifecycle_not_implemented(s) } func TestWORMProtection(s *S3Conf) { @@ -1325,6 +1329,9 @@ func GetIntTests() IntTests { "GetBucketInventoryConfiguration_not_implemented": GetBucketInventoryConfiguration_not_implemented, "ListBucketInventoryConfiguration_not_implemented": ListBucketInventoryConfiguration_not_implemented, "DeleteBucketInventoryConfiguration_not_implemented": DeleteBucketInventoryConfiguration_not_implemented, + "PutBucketLifecycleConfiguration_not_implemented": PutBucketLifecycleConfiguration_not_implemented, + "GetBucketLifecycleConfiguration_not_implemented": GetBucketLifecycleConfiguration_not_implemented, + "DeleteBucketLifecycle_not_implemented": DeleteBucketLifecycle_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 c70b3b1..5828688 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -14867,6 +14867,63 @@ func DeleteBucketInventoryConfiguration_not_implemented(s *S3Conf) error { }) } +func PutBucketLifecycleConfiguration_not_implemented(s *S3Conf) error { + testName := "PutBucketLifecycleConfiguration_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.PutBucketAnalyticsConfiguration(ctx, + &s3.PutBucketAnalyticsConfigurationInput{ + Bucket: &bucket, + Id: getPtr("unique_id"), + AnalyticsConfiguration: &types.AnalyticsConfiguration{ + Id: getPtr("my-id"), + StorageClassAnalysis: &types.StorageClassAnalysis{ + DataExport: &types.StorageClassAnalysisDataExport{ + Destination: &types.AnalyticsExportDestination{ + S3BucketDestination: &types.AnalyticsS3BucketDestination{ + Bucket: &bucket, + Format: types.AnalyticsS3ExportFileFormatCsv, + }, + }, + OutputSchemaVersion: types.StorageClassAnalysisSchemaVersionV1, + }, + }, + }, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func GetBucketLifecycleConfiguration_not_implemented(s *S3Conf) error { + testName := "GetBucketLifecycleConfiguration_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.GetBucketLifecycleConfiguration(ctx, + &s3.GetBucketLifecycleConfigurationInput{ + Bucket: &bucket, + }) + cancel() + + return checkApiErr(err, s3err.GetAPIError(s3err.ErrNotImplemented)) + }) +} + +func DeleteBucketLifecycle_not_implemented(s *S3Conf) error { + testName := "DeleteBucketLifecycle_not_implemented" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + _, err := s3client.DeleteBucketLifecycle(ctx, + &s3.DeleteBucketLifecycleInput{ + 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 {