diff --git a/rustfs/src/app/lifecycle_transition_api_test.rs b/rustfs/src/app/lifecycle_transition_api_test.rs index b0326ff54..a4e58667d 100644 --- a/rustfs/src/app/lifecycle_transition_api_test.rs +++ b/rustfs/src/app/lifecycle_transition_api_test.rs @@ -1495,6 +1495,8 @@ async fn cancelled_transition_waiting_for_prepared_reader_cleans_remote() { #[serial] #[ignore = "global-state ILM integration test: runs serialized in the CI ILM Integration (serial) lane, see ci.yml test-ilm-integration-serial and rustfs/backlog#1148 (ilm-1)"] async fn delete_transitioned_object_removes_remote_tier_copy_via_usecase() { + use super::storage_api::test::ReqInfo; + let (_disk_paths, ecstore) = setup_test_env().await; let usecase = DefaultObjectUsecase::from_global(); @@ -1531,6 +1533,11 @@ async fn delete_transitioned_object_removes_remote_tier_copy_via_usecase() { Method::DELETE, ); insert_header(&mut req.headers, SUFFIX_FORCE_DELETE, "true"); + req.extensions.insert(ReqInfo { + cred: Some(rustfs_credentials::Credentials::default()), + is_owner: true, + ..Default::default() + }); Box::pin(usecase.execute_delete_object(req)) .await @@ -1735,6 +1742,8 @@ async fn compensation_driven_complete_multipart_upload_still_transitions() { #[serial] #[ignore = "global-state ILM integration test: runs serialized in the CI ILM Integration (serial) lane, see ci.yml test-ilm-integration-serial and rustfs/backlog#1148 (ilm-1)"] async fn compensation_driven_transition_still_cleans_remote_tier_on_delete() { + use super::storage_api::test::ReqInfo; + let (_disk_paths, ecstore) = setup_test_env().await; let usecase = DefaultObjectUsecase::from_global(); @@ -1771,6 +1780,11 @@ async fn compensation_driven_transition_still_cleans_remote_tier_on_delete() { Method::DELETE, ); insert_header(&mut req.headers, SUFFIX_FORCE_DELETE, "true"); + req.extensions.insert(ReqInfo { + cred: Some(rustfs_credentials::Credentials::default()), + is_owner: true, + ..Default::default() + }); Box::pin(usecase.execute_delete_object(req)) .await diff --git a/rustfs/src/app/object_usecase.rs b/rustfs/src/app/object_usecase.rs index ae773117f..3a2be7dee 100644 --- a/rustfs/src/app/object_usecase.rs +++ b/rustfs/src/app/object_usecase.rs @@ -6615,7 +6615,8 @@ impl DefaultObjectUsecase { )); } - if !recursive_force_delete_is_authorized(&req.headers, req_info_ref(&req)?.is_owner, false) { + let is_owner = req_info_ref(&req).map(|info| info.is_owner).unwrap_or(false); + if !recursive_force_delete_is_authorized(&req.headers, is_owner, false) { return Err(S3Error::with_message( S3ErrorCode::AccessDenied, "Recursive force-delete is restricted to administrative requests", @@ -7081,7 +7082,7 @@ impl DefaultObjectUsecase { authorize_request(&mut req, Action::S3Action(S3Action::ReplicateDeleteAction)).await?; } - let is_owner = req_info_ref(&req)?.is_owner; + let is_owner = req_info_ref(&req).map(|info| info.is_owner).unwrap_or(false); if !recursive_force_delete_is_authorized(&req.headers, is_owner, replica) { return Err(S3Error::with_message( S3ErrorCode::AccessDenied, @@ -13386,6 +13387,23 @@ mod tests { let err = usecase.execute_delete_objects(req).await.unwrap_err(); assert_eq!(err.code(), &S3ErrorCode::InternalError); + assert_eq!(err.message(), Some("Not init")); + } + + #[tokio::test] + async fn execute_delete_object_allows_non_force_request_without_req_info_until_store_lookup() { + let input = DeleteObjectInput::builder() + .bucket("test-bucket".to_string()) + .key("test-key".to_string()) + .build() + .unwrap(); + + let err = DefaultObjectUsecase::without_context() + .execute_delete_object(build_request(input, Method::DELETE)) + .await + .expect_err("an uninitialized store should be reported after non-force admission"); + assert_eq!(err.code(), &S3ErrorCode::InternalError); + assert_eq!(err.message(), Some("Not init")); } #[test]