From 3d25f206c83e893d6dc5ea419a8702f0f44655e0 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Wed, 15 Oct 2025 11:27:39 -0700 Subject: [PATCH] S3: Signature verification should not check permissions (#7335) * Signature verification should not check permissions - that's done later in authRequest * test permissions during signature verfication * fix s3 test path * s3tests_boto3 => s3tests * remove extra lines --- .github/workflows/s3tests.yml | 726 +++++++++++------------ test/s3/fix_s3_tests_bucket_conflicts.py | 2 +- weed/s3api/auth_credentials_test.go | 56 ++ weed/s3api/auth_signature_v2.go | 10 - weed/s3api/auth_signature_v4.go | 12 - 5 files changed, 420 insertions(+), 386 deletions(-) diff --git a/.github/workflows/s3tests.yml b/.github/workflows/s3tests.yml index 6da1afd30..540247a34 100644 --- a/.github/workflows/s3tests.yml +++ b/.github/workflows/s3tests.yml @@ -107,7 +107,7 @@ jobs: echo "All SeaweedFS components are ready!" cd ../s3-tests - sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests_boto3/functional/test_s3.py + sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests/functional/test_s3.py # Debug: Show the config file contents echo "=== S3 Config File Contents ===" @@ -132,183 +132,183 @@ jobs: echo "✅ S3 server is responding, starting tests..." tox -- \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_distinct \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_many \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_many \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_encoding_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_encoding_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_prefix \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_prefix \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_ends_with_delimiter \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_prefix_ends_with_delimiter \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_underscore \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_prefix_underscore \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_percentage \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_percentage \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_whitespace \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_whitespace \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_dot \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_dot \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_not_skip_special \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_fetchowner_notempty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_fetchowner_defaultempty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_fetchowner_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_one \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_maxkeys_one \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_zero \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_maxkeys_zero \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_maxkeys_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_unordered \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_unordered \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_invalid \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_continuationtoken_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_continuationtoken \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_both_continuationtoken_startafter \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_startafter_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_not_in_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_startafter_not_in_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_after_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_startafter_after_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_return_data \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_objects_anonymous \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_objects_anonymous \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_objects_anonymous_fail \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_objects_anonymous_fail \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_long_name \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_special_prefix \ - s3tests_boto3/functional/test_s3.py::test_bucket_delete_notexist \ - s3tests_boto3/functional/test_s3.py::test_bucket_create_delete \ - s3tests_boto3/functional/test_s3.py::test_object_read_not_exist \ - s3tests_boto3/functional/test_s3.py::test_multi_object_delete \ - s3tests_boto3/functional/test_s3.py::test_multi_objectv2_delete \ - s3tests_boto3/functional/test_s3.py::test_object_head_zero_bytes \ - s3tests_boto3/functional/test_s3.py::test_object_write_check_etag \ - s3tests_boto3/functional/test_s3.py::test_object_write_cache_control \ - s3tests_boto3/functional/test_s3.py::test_object_write_expires \ - s3tests_boto3/functional/test_s3.py::test_object_write_read_update_read_delete \ - s3tests_boto3/functional/test_s3.py::test_object_metadata_replaced_on_put \ - s3tests_boto3/functional/test_s3.py::test_object_write_file \ - s3tests_boto3/functional/test_s3.py::test_post_object_invalid_date_format \ - s3tests_boto3/functional/test_s3.py::test_post_object_no_key_specified \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_signature \ - s3tests_boto3/functional/test_s3.py::test_post_object_condition_is_case_sensitive \ - s3tests_boto3/functional/test_s3.py::test_post_object_expires_is_case_sensitive \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_expires_condition \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_conditions_list \ - s3tests_boto3/functional/test_s3.py::test_post_object_upload_size_limit_exceeded \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_content_length_argument \ - s3tests_boto3/functional/test_s3.py::test_post_object_invalid_content_length_argument \ - s3tests_boto3/functional/test_s3.py::test_post_object_upload_size_below_minimum \ - s3tests_boto3/functional/test_s3.py::test_post_object_empty_conditions \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmatch_good \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifnonematch_good \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmatch_failed \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifnonematch_failed \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmodifiedsince_good \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmodifiedsince_failed \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifunmodifiedsince_failed \ - s3tests_boto3/functional/test_s3.py::test_bucket_head \ - s3tests_boto3/functional/test_s3.py::test_bucket_head_notexist \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated_bucket_acl \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated_object_acl \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated_object_gone \ - s3tests_boto3/functional/test_s3.py::test_object_raw_get_x_amz_expires_out_range_zero \ - s3tests_boto3/functional/test_s3.py::test_object_anon_put \ - s3tests_boto3/functional/test_s3.py::test_object_put_authenticated \ - s3tests_boto3/functional/test_s3.py::test_bucket_recreate_overwrite_acl \ - s3tests_boto3/functional/test_s3.py::test_bucket_recreate_new_acl \ - s3tests_boto3/functional/test_s3.py::test_buckets_create_then_list \ - s3tests_boto3/functional/test_s3.py::test_buckets_list_ctime \ - s3tests_boto3/functional/test_s3.py::test_list_buckets_invalid_auth \ - s3tests_boto3/functional/test_s3.py::test_list_buckets_bad_auth \ - s3tests_boto3/functional/test_s3.py::test_bucket_create_naming_good_contains_period \ - s3tests_boto3/functional/test_s3.py::test_bucket_create_naming_good_contains_hyphen \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_special_prefix \ - s3tests_boto3/functional/test_s3.py::test_object_copy_zero_size \ - s3tests_boto3/functional/test_s3.py::test_object_copy_same_bucket \ - s3tests_boto3/functional/test_s3.py::test_object_copy_to_itself \ - s3tests_boto3/functional/test_s3.py::test_object_copy_diff_bucket \ - s3tests_boto3/functional/test_s3.py::test_object_copy_canned_acl \ - s3tests_boto3/functional/test_s3.py::test_object_copy_bucket_not_found \ - s3tests_boto3/functional/test_s3.py::test_object_copy_key_not_found \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_small \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_without_range \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_special_names \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_multiple_sizes \ - s3tests_boto3/functional/test_s3.py::test_multipart_get_part \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_empty \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_multiple_sizes \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_contents \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_overwrite_existing_object \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_size_too_small \ - s3tests_boto3/functional/test_s3.py::test_multipart_resend_first_finishes_last \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_resend_part \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_missing_part \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_incorrect_etag \ - s3tests_boto3/functional/test_s3.py::test_abort_multipart_upload \ - s3tests_boto3/functional/test_s3.py::test_list_multipart_upload \ - s3tests_boto3/functional/test_s3.py::test_atomic_read_1mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_read_4mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_read_8mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_write_1mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_write_4mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_write_8mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_1mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_4mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_8mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_multipart_upload_write \ - s3tests_boto3/functional/test_s3.py::test_ranged_request_response_code \ - s3tests_boto3/functional/test_s3.py::test_ranged_big_request_response_code \ - s3tests_boto3/functional/test_s3.py::test_ranged_request_skip_leading_bytes_response_code \ - s3tests_boto3/functional/test_s3.py::test_ranged_request_return_trailing_bytes_response_code \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifmatch_good \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifnonematch_failed \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifmatch_failed \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifnonematch_good \ - s3tests_boto3/functional/test_s3.py::test_lifecycle_set \ - s3tests_boto3/functional/test_s3.py::test_lifecycle_get \ - s3tests_boto3/functional/test_s3.py::test_lifecycle_set_filter + s3tests/functional/test_s3.py::test_bucket_list_empty \ + s3tests/functional/test_s3.py::test_bucket_list_distinct \ + s3tests/functional/test_s3.py::test_bucket_list_many \ + s3tests/functional/test_s3.py::test_bucket_listv2_many \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_encoding_basic \ + s3tests/functional/test_s3.py::test_bucket_list_encoding_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_prefix \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_prefix \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_ends_with_delimiter \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_prefix_ends_with_delimiter \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_underscore \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_prefix_underscore \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_percentage \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_percentage \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_whitespace \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_whitespace \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_dot \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_dot \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_unreadable \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_unreadable \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_empty \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_none \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_none \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_not_skip_special \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_fetchowner_notempty \ + s3tests/functional/test_s3.py::test_bucket_listv2_fetchowner_defaultempty \ + s3tests/functional/test_s3.py::test_bucket_listv2_fetchowner_empty \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_basic \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_alt \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_alt \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_empty \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_none \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_none \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_unreadable \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_unreadable \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_one \ + s3tests/functional/test_s3.py::test_bucket_listv2_maxkeys_one \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_zero \ + s3tests/functional/test_s3.py::test_bucket_listv2_maxkeys_zero \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_none \ + s3tests/functional/test_s3.py::test_bucket_listv2_maxkeys_none \ + s3tests/functional/test_s3.py::test_bucket_list_unordered \ + s3tests/functional/test_s3.py::test_bucket_listv2_unordered \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_invalid \ + s3tests/functional/test_s3.py::test_bucket_list_marker_none \ + s3tests/functional/test_s3.py::test_bucket_list_marker_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_continuationtoken_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_continuationtoken \ + s3tests/functional/test_s3.py::test_bucket_listv2_both_continuationtoken_startafter \ + s3tests/functional/test_s3.py::test_bucket_list_marker_unreadable \ + s3tests/functional/test_s3.py::test_bucket_listv2_startafter_unreadable \ + s3tests/functional/test_s3.py::test_bucket_list_marker_not_in_list \ + s3tests/functional/test_s3.py::test_bucket_listv2_startafter_not_in_list \ + s3tests/functional/test_s3.py::test_bucket_list_marker_after_list \ + s3tests/functional/test_s3.py::test_bucket_listv2_startafter_after_list \ + s3tests/functional/test_s3.py::test_bucket_list_return_data \ + s3tests/functional/test_s3.py::test_bucket_list_objects_anonymous \ + s3tests/functional/test_s3.py::test_bucket_listv2_objects_anonymous \ + s3tests/functional/test_s3.py::test_bucket_list_objects_anonymous_fail \ + s3tests/functional/test_s3.py::test_bucket_listv2_objects_anonymous_fail \ + s3tests/functional/test_s3.py::test_bucket_list_long_name \ + s3tests/functional/test_s3.py::test_bucket_list_special_prefix \ + s3tests/functional/test_s3.py::test_bucket_delete_notexist \ + s3tests/functional/test_s3.py::test_bucket_create_delete \ + s3tests/functional/test_s3.py::test_object_read_not_exist \ + s3tests/functional/test_s3.py::test_multi_object_delete \ + s3tests/functional/test_s3.py::test_multi_objectv2_delete \ + s3tests/functional/test_s3.py::test_object_head_zero_bytes \ + s3tests/functional/test_s3.py::test_object_write_check_etag \ + s3tests/functional/test_s3.py::test_object_write_cache_control \ + s3tests/functional/test_s3.py::test_object_write_expires \ + s3tests/functional/test_s3.py::test_object_write_read_update_read_delete \ + s3tests/functional/test_s3.py::test_object_metadata_replaced_on_put \ + s3tests/functional/test_s3.py::test_object_write_file \ + s3tests/functional/test_s3.py::test_post_object_invalid_date_format \ + s3tests/functional/test_s3.py::test_post_object_no_key_specified \ + s3tests/functional/test_s3.py::test_post_object_missing_signature \ + s3tests/functional/test_s3.py::test_post_object_condition_is_case_sensitive \ + s3tests/functional/test_s3.py::test_post_object_expires_is_case_sensitive \ + s3tests/functional/test_s3.py::test_post_object_missing_expires_condition \ + s3tests/functional/test_s3.py::test_post_object_missing_conditions_list \ + s3tests/functional/test_s3.py::test_post_object_upload_size_limit_exceeded \ + s3tests/functional/test_s3.py::test_post_object_missing_content_length_argument \ + s3tests/functional/test_s3.py::test_post_object_invalid_content_length_argument \ + s3tests/functional/test_s3.py::test_post_object_upload_size_below_minimum \ + s3tests/functional/test_s3.py::test_post_object_empty_conditions \ + s3tests/functional/test_s3.py::test_get_object_ifmatch_good \ + s3tests/functional/test_s3.py::test_get_object_ifnonematch_good \ + s3tests/functional/test_s3.py::test_get_object_ifmatch_failed \ + s3tests/functional/test_s3.py::test_get_object_ifnonematch_failed \ + s3tests/functional/test_s3.py::test_get_object_ifmodifiedsince_good \ + s3tests/functional/test_s3.py::test_get_object_ifmodifiedsince_failed \ + s3tests/functional/test_s3.py::test_get_object_ifunmodifiedsince_failed \ + s3tests/functional/test_s3.py::test_bucket_head \ + s3tests/functional/test_s3.py::test_bucket_head_notexist \ + s3tests/functional/test_s3.py::test_object_raw_authenticated \ + s3tests/functional/test_s3.py::test_object_raw_authenticated_bucket_acl \ + s3tests/functional/test_s3.py::test_object_raw_authenticated_object_acl \ + s3tests/functional/test_s3.py::test_object_raw_authenticated_object_gone \ + s3tests/functional/test_s3.py::test_object_raw_get_x_amz_expires_out_range_zero \ + s3tests/functional/test_s3.py::test_object_anon_put \ + s3tests/functional/test_s3.py::test_object_put_authenticated \ + s3tests/functional/test_s3.py::test_bucket_recreate_overwrite_acl \ + s3tests/functional/test_s3.py::test_bucket_recreate_new_acl \ + s3tests/functional/test_s3.py::test_buckets_create_then_list \ + s3tests/functional/test_s3.py::test_buckets_list_ctime \ + s3tests/functional/test_s3.py::test_list_buckets_invalid_auth \ + s3tests/functional/test_s3.py::test_list_buckets_bad_auth \ + s3tests/functional/test_s3.py::test_bucket_create_naming_good_contains_period \ + s3tests/functional/test_s3.py::test_bucket_create_naming_good_contains_hyphen \ + s3tests/functional/test_s3.py::test_bucket_list_special_prefix \ + s3tests/functional/test_s3.py::test_object_copy_zero_size \ + s3tests/functional/test_s3.py::test_object_copy_same_bucket \ + s3tests/functional/test_s3.py::test_object_copy_to_itself \ + s3tests/functional/test_s3.py::test_object_copy_diff_bucket \ + s3tests/functional/test_s3.py::test_object_copy_canned_acl \ + s3tests/functional/test_s3.py::test_object_copy_bucket_not_found \ + s3tests/functional/test_s3.py::test_object_copy_key_not_found \ + s3tests/functional/test_s3.py::test_multipart_copy_small \ + s3tests/functional/test_s3.py::test_multipart_copy_without_range \ + s3tests/functional/test_s3.py::test_multipart_copy_special_names \ + s3tests/functional/test_s3.py::test_multipart_copy_multiple_sizes \ + s3tests/functional/test_s3.py::test_multipart_get_part \ + s3tests/functional/test_s3.py::test_multipart_upload \ + s3tests/functional/test_s3.py::test_multipart_upload_empty \ + s3tests/functional/test_s3.py::test_multipart_upload_multiple_sizes \ + s3tests/functional/test_s3.py::test_multipart_upload_contents \ + s3tests/functional/test_s3.py::test_multipart_upload_overwrite_existing_object \ + s3tests/functional/test_s3.py::test_multipart_upload_size_too_small \ + s3tests/functional/test_s3.py::test_multipart_resend_first_finishes_last \ + s3tests/functional/test_s3.py::test_multipart_upload_resend_part \ + s3tests/functional/test_s3.py::test_multipart_upload_missing_part \ + s3tests/functional/test_s3.py::test_multipart_upload_incorrect_etag \ + s3tests/functional/test_s3.py::test_abort_multipart_upload \ + s3tests/functional/test_s3.py::test_list_multipart_upload \ + s3tests/functional/test_s3.py::test_atomic_read_1mb \ + s3tests/functional/test_s3.py::test_atomic_read_4mb \ + s3tests/functional/test_s3.py::test_atomic_read_8mb \ + s3tests/functional/test_s3.py::test_atomic_write_1mb \ + s3tests/functional/test_s3.py::test_atomic_write_4mb \ + s3tests/functional/test_s3.py::test_atomic_write_8mb \ + s3tests/functional/test_s3.py::test_atomic_dual_write_1mb \ + s3tests/functional/test_s3.py::test_atomic_dual_write_4mb \ + s3tests/functional/test_s3.py::test_atomic_dual_write_8mb \ + s3tests/functional/test_s3.py::test_atomic_multipart_upload_write \ + s3tests/functional/test_s3.py::test_ranged_request_response_code \ + s3tests/functional/test_s3.py::test_ranged_big_request_response_code \ + s3tests/functional/test_s3.py::test_ranged_request_skip_leading_bytes_response_code \ + s3tests/functional/test_s3.py::test_ranged_request_return_trailing_bytes_response_code \ + s3tests/functional/test_s3.py::test_copy_object_ifmatch_good \ + s3tests/functional/test_s3.py::test_copy_object_ifnonematch_failed \ + s3tests/functional/test_s3.py::test_copy_object_ifmatch_failed \ + s3tests/functional/test_s3.py::test_copy_object_ifnonematch_good \ + s3tests/functional/test_s3.py::test_lifecycle_set \ + s3tests/functional/test_s3.py::test_lifecycle_get \ + s3tests/functional/test_s3.py::test_lifecycle_set_filter kill -9 $pid || true # Clean up data directory rm -rf "$WEED_DATA_DIR" || true @@ -408,7 +408,7 @@ jobs: echo "All SeaweedFS components are ready!" cd ../s3-tests - sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests_boto3/functional/test_s3.py + sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests/functional/test_s3.py # Create and update s3tests.conf to use port 8001 cp ../docker/compose/s3tests.conf ../docker/compose/s3tests-versioning.conf sed -i 's/port = 8000/port = 8001/g' ../docker/compose/s3tests-versioning.conf @@ -476,7 +476,7 @@ jobs: " || echo "Cleanup completed with some errors (expected)" # Run versioning and object lock tests once (avoid duplicates) - tox -- s3tests_boto3/functional/test_s3.py -k "object_lock or versioning" --tb=short + tox -- s3tests/functional/test_s3.py -k "object_lock or versioning" --tb=short kill -9 $pid || true # Clean up data directory rm -rf "$WEED_DATA_DIR" || true @@ -566,7 +566,7 @@ jobs: echo "All SeaweedFS components are ready!" cd ../s3-tests - sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests_boto3/functional/test_s3.py + sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests/functional/test_s3.py # Create and update s3tests.conf to use port 8002 cp ../docker/compose/s3tests.conf ../docker/compose/s3tests-cors.conf sed -i 's/port = 8000/port = 8002/g' ../docker/compose/s3tests-cors.conf @@ -595,11 +595,11 @@ jobs: sleep 2 done # Run CORS-specific tests from s3-tests suite - tox -- s3tests_boto3/functional/test_s3.py -k "cors" --tb=short || echo "No CORS tests found in s3-tests suite" + tox -- s3tests/functional/test_s3.py -k "cors" --tb=short || echo "No CORS tests found in s3-tests suite" # If no specific CORS tests exist, run bucket configuration tests that include CORS - tox -- s3tests_boto3/functional/test_s3.py::test_put_bucket_cors || echo "No put_bucket_cors test found" - tox -- s3tests_boto3/functional/test_s3.py::test_get_bucket_cors || echo "No get_bucket_cors test found" - tox -- s3tests_boto3/functional/test_s3.py::test_delete_bucket_cors || echo "No delete_bucket_cors test found" + tox -- s3tests/functional/test_s3.py::test_put_bucket_cors || echo "No put_bucket_cors test found" + tox -- s3tests/functional/test_s3.py::test_get_bucket_cors || echo "No get_bucket_cors test found" + tox -- s3tests/functional/test_s3.py::test_delete_bucket_cors || echo "No delete_bucket_cors test found" kill -9 $pid || true # Clean up data directory rm -rf "$WEED_DATA_DIR" || true @@ -896,7 +896,7 @@ jobs: echo "All SeaweedFS components are ready!" cd ../s3-tests - sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests_boto3/functional/test_s3.py + sed -i "s/assert prefixes == \['foo%2B1\/', 'foo\/', 'quux%20ab\/'\]/assert prefixes == \['foo\/', 'foo%2B1\/', 'quux%20ab\/'\]/" s3tests/functional/test_s3.py # Create and update s3tests.conf to use port 8004 cp ../docker/compose/s3tests.conf ../docker/compose/s3tests-sql.conf sed -i 's/port = 8000/port = 8004/g' ../docker/compose/s3tests-sql.conf @@ -947,183 +947,183 @@ jobs: sleep 2 done tox -- \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_distinct \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_many \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_many \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_encoding_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_encoding_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_prefix \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_prefix \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_ends_with_delimiter \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_prefix_ends_with_delimiter \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_underscore \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_prefix_underscore \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_percentage \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_percentage \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_whitespace \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_whitespace \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_dot \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_dot \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_delimiter_not_skip_special \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_delimiter_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_fetchowner_notempty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_fetchowner_defaultempty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_fetchowner_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_basic \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_alt \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_not_exist \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_prefix_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_prefix_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_one \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_maxkeys_one \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_zero \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_maxkeys_zero \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_maxkeys_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_unordered \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_unordered \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_maxkeys_invalid \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_none \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_continuationtoken_empty \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_continuationtoken \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_both_continuationtoken_startafter \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_startafter_unreadable \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_not_in_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_startafter_not_in_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_marker_after_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_startafter_after_list \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_return_data \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_objects_anonymous \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_objects_anonymous \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_objects_anonymous_fail \ - s3tests_boto3/functional/test_s3.py::test_bucket_listv2_objects_anonymous_fail \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_long_name \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_special_prefix \ - s3tests_boto3/functional/test_s3.py::test_bucket_delete_notexist \ - s3tests_boto3/functional/test_s3.py::test_bucket_create_delete \ - s3tests_boto3/functional/test_s3.py::test_object_read_not_exist \ - s3tests_boto3/functional/test_s3.py::test_multi_object_delete \ - s3tests_boto3/functional/test_s3.py::test_multi_objectv2_delete \ - s3tests_boto3/functional/test_s3.py::test_object_head_zero_bytes \ - s3tests_boto3/functional/test_s3.py::test_object_write_check_etag \ - s3tests_boto3/functional/test_s3.py::test_object_write_cache_control \ - s3tests_boto3/functional/test_s3.py::test_object_write_expires \ - s3tests_boto3/functional/test_s3.py::test_object_write_read_update_read_delete \ - s3tests_boto3/functional/test_s3.py::test_object_metadata_replaced_on_put \ - s3tests_boto3/functional/test_s3.py::test_object_write_file \ - s3tests_boto3/functional/test_s3.py::test_post_object_invalid_date_format \ - s3tests_boto3/functional/test_s3.py::test_post_object_no_key_specified \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_signature \ - s3tests_boto3/functional/test_s3.py::test_post_object_condition_is_case_sensitive \ - s3tests_boto3/functional/test_s3.py::test_post_object_expires_is_case_sensitive \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_expires_condition \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_conditions_list \ - s3tests_boto3/functional/test_s3.py::test_post_object_upload_size_limit_exceeded \ - s3tests_boto3/functional/test_s3.py::test_post_object_missing_content_length_argument \ - s3tests_boto3/functional/test_s3.py::test_post_object_invalid_content_length_argument \ - s3tests_boto3/functional/test_s3.py::test_post_object_upload_size_below_minimum \ - s3tests_boto3/functional/test_s3.py::test_post_object_empty_conditions \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmatch_good \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifnonematch_good \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmatch_failed \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifnonematch_failed \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmodifiedsince_good \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifmodifiedsince_failed \ - s3tests_boto3/functional/test_s3.py::test_get_object_ifunmodifiedsince_failed \ - s3tests_boto3/functional/test_s3.py::test_bucket_head \ - s3tests_boto3/functional/test_s3.py::test_bucket_head_notexist \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated_bucket_acl \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated_object_acl \ - s3tests_boto3/functional/test_s3.py::test_object_raw_authenticated_object_gone \ - s3tests_boto3/functional/test_s3.py::test_object_raw_get_x_amz_expires_out_range_zero \ - s3tests_boto3/functional/test_s3.py::test_object_anon_put \ - s3tests_boto3/functional/test_s3.py::test_object_put_authenticated \ - s3tests_boto3/functional/test_s3.py::test_bucket_recreate_overwrite_acl \ - s3tests_boto3/functional/test_s3.py::test_bucket_recreate_new_acl \ - s3tests_boto3/functional/test_s3.py::test_buckets_create_then_list \ - s3tests_boto3/functional/test_s3.py::test_buckets_list_ctime \ - s3tests_boto3/functional/test_s3.py::test_list_buckets_invalid_auth \ - s3tests_boto3/functional/test_s3.py::test_list_buckets_bad_auth \ - s3tests_boto3/functional/test_s3.py::test_bucket_create_naming_good_contains_period \ - s3tests_boto3/functional/test_s3.py::test_bucket_create_naming_good_contains_hyphen \ - s3tests_boto3/functional/test_s3.py::test_bucket_list_special_prefix \ - s3tests_boto3/functional/test_s3.py::test_object_copy_zero_size \ - s3tests_boto3/functional/test_s3.py::test_object_copy_same_bucket \ - s3tests_boto3/functional/test_s3.py::test_object_copy_to_itself \ - s3tests_boto3/functional/test_s3.py::test_object_copy_diff_bucket \ - s3tests_boto3/functional/test_s3.py::test_object_copy_canned_acl \ - s3tests_boto3/functional/test_s3.py::test_object_copy_bucket_not_found \ - s3tests_boto3/functional/test_s3.py::test_object_copy_key_not_found \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_small \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_without_range \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_special_names \ - s3tests_boto3/functional/test_s3.py::test_multipart_copy_multiple_sizes \ - s3tests_boto3/functional/test_s3.py::test_multipart_get_part \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_empty \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_multiple_sizes \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_contents \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_overwrite_existing_object \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_size_too_small \ - s3tests_boto3/functional/test_s3.py::test_multipart_resend_first_finishes_last \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_resend_part \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_missing_part \ - s3tests_boto3/functional/test_s3.py::test_multipart_upload_incorrect_etag \ - s3tests_boto3/functional/test_s3.py::test_abort_multipart_upload \ - s3tests_boto3/functional/test_s3.py::test_list_multipart_upload \ - s3tests_boto3/functional/test_s3.py::test_atomic_read_1mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_read_4mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_read_8mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_write_1mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_write_4mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_write_8mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_1mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_4mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_8mb \ - s3tests_boto3/functional/test_s3.py::test_atomic_multipart_upload_write \ - s3tests_boto3/functional/test_s3.py::test_ranged_request_response_code \ - s3tests_boto3/functional/test_s3.py::test_ranged_big_request_response_code \ - s3tests_boto3/functional/test_s3.py::test_ranged_request_skip_leading_bytes_response_code \ - s3tests_boto3/functional/test_s3.py::test_ranged_request_return_trailing_bytes_response_code \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifmatch_good \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifnonematch_failed \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifmatch_failed \ - s3tests_boto3/functional/test_s3.py::test_copy_object_ifnonematch_good \ - s3tests_boto3/functional/test_s3.py::test_lifecycle_set \ - s3tests_boto3/functional/test_s3.py::test_lifecycle_get \ - s3tests_boto3/functional/test_s3.py::test_lifecycle_set_filter + s3tests/functional/test_s3.py::test_bucket_list_empty \ + s3tests/functional/test_s3.py::test_bucket_list_distinct \ + s3tests/functional/test_s3.py::test_bucket_list_many \ + s3tests/functional/test_s3.py::test_bucket_listv2_many \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_encoding_basic \ + s3tests/functional/test_s3.py::test_bucket_list_encoding_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_prefix \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_prefix \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_ends_with_delimiter \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_prefix_ends_with_delimiter \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_prefix_underscore \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_prefix_underscore \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_percentage \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_percentage \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_whitespace \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_whitespace \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_dot \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_dot \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_unreadable \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_unreadable \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_empty \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_none \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_none \ + s3tests/functional/test_s3.py::test_bucket_listv2_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_delimiter_not_skip_special \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_basic \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_alt \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_delimiter_prefix_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_delimiter_prefix_delimiter_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_fetchowner_notempty \ + s3tests/functional/test_s3.py::test_bucket_listv2_fetchowner_defaultempty \ + s3tests/functional/test_s3.py::test_bucket_listv2_fetchowner_empty \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_basic \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_basic \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_alt \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_alt \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_empty \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_none \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_none \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_not_exist \ + s3tests/functional/test_s3.py::test_bucket_list_prefix_unreadable \ + s3tests/functional/test_s3.py::test_bucket_listv2_prefix_unreadable \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_one \ + s3tests/functional/test_s3.py::test_bucket_listv2_maxkeys_one \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_zero \ + s3tests/functional/test_s3.py::test_bucket_listv2_maxkeys_zero \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_none \ + s3tests/functional/test_s3.py::test_bucket_listv2_maxkeys_none \ + s3tests/functional/test_s3.py::test_bucket_list_unordered \ + s3tests/functional/test_s3.py::test_bucket_listv2_unordered \ + s3tests/functional/test_s3.py::test_bucket_list_maxkeys_invalid \ + s3tests/functional/test_s3.py::test_bucket_list_marker_none \ + s3tests/functional/test_s3.py::test_bucket_list_marker_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_continuationtoken_empty \ + s3tests/functional/test_s3.py::test_bucket_listv2_continuationtoken \ + s3tests/functional/test_s3.py::test_bucket_listv2_both_continuationtoken_startafter \ + s3tests/functional/test_s3.py::test_bucket_list_marker_unreadable \ + s3tests/functional/test_s3.py::test_bucket_listv2_startafter_unreadable \ + s3tests/functional/test_s3.py::test_bucket_list_marker_not_in_list \ + s3tests/functional/test_s3.py::test_bucket_listv2_startafter_not_in_list \ + s3tests/functional/test_s3.py::test_bucket_list_marker_after_list \ + s3tests/functional/test_s3.py::test_bucket_listv2_startafter_after_list \ + s3tests/functional/test_s3.py::test_bucket_list_return_data \ + s3tests/functional/test_s3.py::test_bucket_list_objects_anonymous \ + s3tests/functional/test_s3.py::test_bucket_listv2_objects_anonymous \ + s3tests/functional/test_s3.py::test_bucket_list_objects_anonymous_fail \ + s3tests/functional/test_s3.py::test_bucket_listv2_objects_anonymous_fail \ + s3tests/functional/test_s3.py::test_bucket_list_long_name \ + s3tests/functional/test_s3.py::test_bucket_list_special_prefix \ + s3tests/functional/test_s3.py::test_bucket_delete_notexist \ + s3tests/functional/test_s3.py::test_bucket_create_delete \ + s3tests/functional/test_s3.py::test_object_read_not_exist \ + s3tests/functional/test_s3.py::test_multi_object_delete \ + s3tests/functional/test_s3.py::test_multi_objectv2_delete \ + s3tests/functional/test_s3.py::test_object_head_zero_bytes \ + s3tests/functional/test_s3.py::test_object_write_check_etag \ + s3tests/functional/test_s3.py::test_object_write_cache_control \ + s3tests/functional/test_s3.py::test_object_write_expires \ + s3tests/functional/test_s3.py::test_object_write_read_update_read_delete \ + s3tests/functional/test_s3.py::test_object_metadata_replaced_on_put \ + s3tests/functional/test_s3.py::test_object_write_file \ + s3tests/functional/test_s3.py::test_post_object_invalid_date_format \ + s3tests/functional/test_s3.py::test_post_object_no_key_specified \ + s3tests/functional/test_s3.py::test_post_object_missing_signature \ + s3tests/functional/test_s3.py::test_post_object_condition_is_case_sensitive \ + s3tests/functional/test_s3.py::test_post_object_expires_is_case_sensitive \ + s3tests/functional/test_s3.py::test_post_object_missing_expires_condition \ + s3tests/functional/test_s3.py::test_post_object_missing_conditions_list \ + s3tests/functional/test_s3.py::test_post_object_upload_size_limit_exceeded \ + s3tests/functional/test_s3.py::test_post_object_missing_content_length_argument \ + s3tests/functional/test_s3.py::test_post_object_invalid_content_length_argument \ + s3tests/functional/test_s3.py::test_post_object_upload_size_below_minimum \ + s3tests/functional/test_s3.py::test_post_object_empty_conditions \ + s3tests/functional/test_s3.py::test_get_object_ifmatch_good \ + s3tests/functional/test_s3.py::test_get_object_ifnonematch_good \ + s3tests/functional/test_s3.py::test_get_object_ifmatch_failed \ + s3tests/functional/test_s3.py::test_get_object_ifnonematch_failed \ + s3tests/functional/test_s3.py::test_get_object_ifmodifiedsince_good \ + s3tests/functional/test_s3.py::test_get_object_ifmodifiedsince_failed \ + s3tests/functional/test_s3.py::test_get_object_ifunmodifiedsince_failed \ + s3tests/functional/test_s3.py::test_bucket_head \ + s3tests/functional/test_s3.py::test_bucket_head_notexist \ + s3tests/functional/test_s3.py::test_object_raw_authenticated \ + s3tests/functional/test_s3.py::test_object_raw_authenticated_bucket_acl \ + s3tests/functional/test_s3.py::test_object_raw_authenticated_object_acl \ + s3tests/functional/test_s3.py::test_object_raw_authenticated_object_gone \ + s3tests/functional/test_s3.py::test_object_raw_get_x_amz_expires_out_range_zero \ + s3tests/functional/test_s3.py::test_object_anon_put \ + s3tests/functional/test_s3.py::test_object_put_authenticated \ + s3tests/functional/test_s3.py::test_bucket_recreate_overwrite_acl \ + s3tests/functional/test_s3.py::test_bucket_recreate_new_acl \ + s3tests/functional/test_s3.py::test_buckets_create_then_list \ + s3tests/functional/test_s3.py::test_buckets_list_ctime \ + s3tests/functional/test_s3.py::test_list_buckets_invalid_auth \ + s3tests/functional/test_s3.py::test_list_buckets_bad_auth \ + s3tests/functional/test_s3.py::test_bucket_create_naming_good_contains_period \ + s3tests/functional/test_s3.py::test_bucket_create_naming_good_contains_hyphen \ + s3tests/functional/test_s3.py::test_bucket_list_special_prefix \ + s3tests/functional/test_s3.py::test_object_copy_zero_size \ + s3tests/functional/test_s3.py::test_object_copy_same_bucket \ + s3tests/functional/test_s3.py::test_object_copy_to_itself \ + s3tests/functional/test_s3.py::test_object_copy_diff_bucket \ + s3tests/functional/test_s3.py::test_object_copy_canned_acl \ + s3tests/functional/test_s3.py::test_object_copy_bucket_not_found \ + s3tests/functional/test_s3.py::test_object_copy_key_not_found \ + s3tests/functional/test_s3.py::test_multipart_copy_small \ + s3tests/functional/test_s3.py::test_multipart_copy_without_range \ + s3tests/functional/test_s3.py::test_multipart_copy_special_names \ + s3tests/functional/test_s3.py::test_multipart_copy_multiple_sizes \ + s3tests/functional/test_s3.py::test_multipart_get_part \ + s3tests/functional/test_s3.py::test_multipart_upload \ + s3tests/functional/test_s3.py::test_multipart_upload_empty \ + s3tests/functional/test_s3.py::test_multipart_upload_multiple_sizes \ + s3tests/functional/test_s3.py::test_multipart_upload_contents \ + s3tests/functional/test_s3.py::test_multipart_upload_overwrite_existing_object \ + s3tests/functional/test_s3.py::test_multipart_upload_size_too_small \ + s3tests/functional/test_s3.py::test_multipart_resend_first_finishes_last \ + s3tests/functional/test_s3.py::test_multipart_upload_resend_part \ + s3tests/functional/test_s3.py::test_multipart_upload_missing_part \ + s3tests/functional/test_s3.py::test_multipart_upload_incorrect_etag \ + s3tests/functional/test_s3.py::test_abort_multipart_upload \ + s3tests/functional/test_s3.py::test_list_multipart_upload \ + s3tests/functional/test_s3.py::test_atomic_read_1mb \ + s3tests/functional/test_s3.py::test_atomic_read_4mb \ + s3tests/functional/test_s3.py::test_atomic_read_8mb \ + s3tests/functional/test_s3.py::test_atomic_write_1mb \ + s3tests/functional/test_s3.py::test_atomic_write_4mb \ + s3tests/functional/test_s3.py::test_atomic_write_8mb \ + s3tests/functional/test_s3.py::test_atomic_dual_write_1mb \ + s3tests/functional/test_s3.py::test_atomic_dual_write_4mb \ + s3tests/functional/test_s3.py::test_atomic_dual_write_8mb \ + s3tests/functional/test_s3.py::test_atomic_multipart_upload_write \ + s3tests/functional/test_s3.py::test_ranged_request_response_code \ + s3tests/functional/test_s3.py::test_ranged_big_request_response_code \ + s3tests/functional/test_s3.py::test_ranged_request_skip_leading_bytes_response_code \ + s3tests/functional/test_s3.py::test_ranged_request_return_trailing_bytes_response_code \ + s3tests/functional/test_s3.py::test_copy_object_ifmatch_good \ + s3tests/functional/test_s3.py::test_copy_object_ifnonematch_failed \ + s3tests/functional/test_s3.py::test_copy_object_ifmatch_failed \ + s3tests/functional/test_s3.py::test_copy_object_ifnonematch_good \ + s3tests/functional/test_s3.py::test_lifecycle_set \ + s3tests/functional/test_s3.py::test_lifecycle_get \ + s3tests/functional/test_s3.py::test_lifecycle_set_filter kill -9 $pid || true # Clean up data directory rm -rf "$WEED_DATA_DIR" || true diff --git a/test/s3/fix_s3_tests_bucket_conflicts.py b/test/s3/fix_s3_tests_bucket_conflicts.py index 9fb71684a..bc83efe03 100644 --- a/test/s3/fix_s3_tests_bucket_conflicts.py +++ b/test/s3/fix_s3_tests_bucket_conflicts.py @@ -268,7 +268,7 @@ get_new_bucket = _sw_get_new_bucket def main() -> int: s3_tests_path = os.environ.get("S3_TESTS_PATH", "s3-tests") - init_file_path = os.path.join(s3_tests_path, "s3tests_boto3", "functional", "__init__.py") + init_file_path = os.path.join(s3_tests_path, "s3tests", "functional", "__init__.py") print("Applying s3-tests patch for bucket creation idempotency...") print(f"Target repo path: {s3_tests_path}") if not os.path.exists(s3_tests_path): diff --git a/weed/s3api/auth_credentials_test.go b/weed/s3api/auth_credentials_test.go index f1d4a21bd..c7521ad76 100644 --- a/weed/s3api/auth_credentials_test.go +++ b/weed/s3api/auth_credentials_test.go @@ -3,6 +3,7 @@ package s3api import ( "os" "reflect" + "sync" "testing" "github.com/seaweedfs/seaweedfs/weed/credential" @@ -543,3 +544,58 @@ func TestListBucketsAuthRequest(t *testing.T) { t.Log("ListBuckets operation bypasses global permission check when bucket is empty") t.Log("Object listing still properly enforces bucket-level permissions") } + +// TestSignatureVerificationDoesNotCheckPermissions tests that signature verification +// only validates the signature and identity, not permissions. Permissions should be +// checked later in authRequest based on the actual operation. +// This test validates the fix for issue #7334 +func TestSignatureVerificationDoesNotCheckPermissions(t *testing.T) { + t.Run("List-only user can authenticate via signature", func(t *testing.T) { + // Create IAM with a user that only has List permissions on specific buckets + iam := &IdentityAccessManagement{ + hashes: make(map[string]*sync.Pool), + hashCounters: make(map[string]*int32), + } + + err := iam.loadS3ApiConfiguration(&iam_pb.S3ApiConfiguration{ + Identities: []*iam_pb.Identity{ + { + Name: "list-only-user", + Credentials: []*iam_pb.Credential{ + { + AccessKey: "list_access_key", + SecretKey: "list_secret_key", + }, + }, + Actions: []string{ + "List:bucket-123", + "Read:bucket-123", + }, + }, + }, + }) + assert.NoError(t, err) + + // Before the fix, signature verification would fail because it checked for Write permission + // After the fix, signature verification should succeed (only checking signature validity) + // The actual permission check happens later in authRequest with the correct action + + // The user should be able to authenticate (signature verification passes) + // But authorization for specific actions is checked separately + identity, cred, found := iam.lookupByAccessKey("list_access_key") + assert.True(t, found, "Should find the user by access key") + assert.Equal(t, "list-only-user", identity.Name) + assert.Equal(t, "list_secret_key", cred.SecretKey) + + // User should have the correct permissions + assert.True(t, identity.canDo(Action(ACTION_LIST), "bucket-123", "")) + assert.True(t, identity.canDo(Action(ACTION_READ), "bucket-123", "")) + + // User should NOT have write permissions + assert.False(t, identity.canDo(Action(ACTION_WRITE), "bucket-123", "")) + }) + + t.Log("This test validates the fix for issue #7334") + t.Log("Signature verification no longer checks for Write permission") + t.Log("This allows list-only and read-only users to authenticate via AWS Signature V4") +} diff --git a/weed/s3api/auth_signature_v2.go b/weed/s3api/auth_signature_v2.go index 4cdc07df0..b31c37a27 100644 --- a/weed/s3api/auth_signature_v2.go +++ b/weed/s3api/auth_signature_v2.go @@ -116,11 +116,6 @@ func (iam *IdentityAccessManagement) doesSignV2Match(r *http.Request) (*Identity return nil, s3err.ErrInvalidAccessKeyID } - bucket, object := s3_constants.GetBucketAndObject(r) - if !identity.canDo(s3_constants.ACTION_WRITE, bucket, object) { - return nil, s3err.ErrAccessDenied - } - expectedAuth := signatureV2(cred, r.Method, r.URL.Path, r.URL.Query().Encode(), r.Header) if !compareSignatureV2(v2Auth, expectedAuth) { return nil, s3err.ErrSignatureDoesNotMatch @@ -163,11 +158,6 @@ func (iam *IdentityAccessManagement) doesPresignV2SignatureMatch(r *http.Request return nil, s3err.ErrInvalidAccessKeyID } - bucket, object := s3_constants.GetBucketAndObject(r) - if !identity.canDo(s3_constants.ACTION_READ, bucket, object) { - return nil, s3err.ErrAccessDenied - } - expectedSignature := preSignatureV2(cred, r.Method, r.URL.Path, r.URL.Query().Encode(), r.Header, expires) if !compareSignatureV2(signature, expectedSignature) { return nil, s3err.ErrSignatureDoesNotMatch diff --git a/weed/s3api/auth_signature_v4.go b/weed/s3api/auth_signature_v4.go index 81612f7a8..05e5c7b5f 100644 --- a/weed/s3api/auth_signature_v4.go +++ b/weed/s3api/auth_signature_v4.go @@ -190,12 +190,6 @@ func (iam *IdentityAccessManagement) doesSignatureMatch(hashedPayload string, r return nil, s3err.ErrInvalidAccessKeyID } - bucket, object := s3_constants.GetBucketAndObject(r) - canDoResult := identity.canDo(s3_constants.ACTION_WRITE, bucket, object) - if !canDoResult { - return nil, s3err.ErrAccessDenied - } - // Extract date, if not present throw error. var dateStr string if dateStr = req.Header.Get("x-amz-date"); dateStr == "" { @@ -331,12 +325,6 @@ func (iam *IdentityAccessManagement) doesPresignedSignatureMatch(hashedPayload s return nil, s3err.ErrInvalidAccessKeyID } - // Check permissions - bucket, object := s3_constants.GetBucketAndObject(r) - if !identity.canDo(s3_constants.ACTION_READ, bucket, object) { - return nil, s3err.ErrAccessDenied - } - // Parse date t, e := time.Parse(iso8601Format, dateStr) if e != nil {