Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-s3transfer for openSUSE:Factory checked in at 2024-12-10 23:43:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-s3transfer (Old) and /work/SRC/openSUSE:Factory/.python-s3transfer.new.29675 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-s3transfer" Tue Dec 10 23:43:02 2024 rev:33 rq:1229332 version:0.10.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-s3transfer/python-s3transfer.changes 2024-10-23 21:08:20.717875955 +0200 +++ /work/SRC/openSUSE:Factory/.python-s3transfer.new.29675/python-s3transfer.changes 2024-12-10 23:43:09.283609804 +0100 @@ -1,0 +2,6 @@ +Mon Dec 9 11:00:31 UTC 2024 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to version 0.10.4 + * enhancement:``s3``: Added Multi-Region Access Points support to CRT transfers + +------------------------------------------------------------------- Old: ---- s3transfer-0.10.3.tar.gz New: ---- s3transfer-0.10.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-s3transfer.spec ++++++ --- /var/tmp/diff_new_pack.PxREUM/_old 2024-12-10 23:43:10.719669638 +0100 +++ /var/tmp/diff_new_pack.PxREUM/_new 2024-12-10 23:43:10.739670471 +0100 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-s3transfer -Version: 0.10.3 +Version: 0.10.4 Release: 0 Summary: Python S3 transfer manager License: Apache-2.0 ++++++ s3transfer-0.10.3.tar.gz -> s3transfer-0.10.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/s3transfer-0.10.3/PKG-INFO new/s3transfer-0.10.4/PKG-INFO --- old/s3transfer-0.10.3/PKG-INFO 2024-10-08 20:06:31.916945200 +0200 +++ new/s3transfer-0.10.4/PKG-INFO 2024-11-20 20:06:53.222139400 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: s3transfer -Version: 0.10.3 +Version: 0.10.4 Summary: An Amazon S3 Transfer Manager Home-page: https://github.com/boto/s3transfer Author: Amazon Web Services diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/s3transfer-0.10.3/s3transfer/__init__.py new/s3transfer-0.10.4/s3transfer/__init__.py --- old/s3transfer-0.10.3/s3transfer/__init__.py 2024-10-08 20:06:31.000000000 +0200 +++ new/s3transfer-0.10.4/s3transfer/__init__.py 2024-11-20 20:06:53.000000000 +0100 @@ -145,7 +145,7 @@ from s3transfer.exceptions import RetriesExceededError, S3UploadFailedError __author__ = 'Amazon Web Services' -__version__ = '0.10.3' +__version__ = '0.10.4' class NullHandler(logging.Handler): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/s3transfer-0.10.3/s3transfer/crt.py new/s3transfer-0.10.4/s3transfer/crt.py --- old/s3transfer-0.10.3/s3transfer/crt.py 2024-10-08 20:03:26.000000000 +0200 +++ new/s3transfer-0.10.4/s3transfer/crt.py 2024-11-20 20:06:53.000000000 +0100 @@ -11,6 +11,7 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. import logging +import re import threading from io import BytesIO @@ -36,6 +37,7 @@ from botocore.compat import urlsplit from botocore.config import Config from botocore.exceptions import NoCredentialsError +from botocore.utils import ArnParser, InvalidArnException from s3transfer.constants import MB from s3transfer.exceptions import TransferNotDoneError @@ -874,7 +876,18 @@ x.title() for x in request_type.split('_') ) - if is_s3express_bucket(call_args.bucket): + arn_handler = _S3ArnParamHandler() + if ( + accesspoint_arn_details := arn_handler.handle_arn(call_args.bucket) + ) and accesspoint_arn_details['region'] == "": + # Configure our region to `*` to propogate in `x-amz-region-set` + # for multi-region support in MRAP accesspoints. + make_request_args['signing_config'] = AwsSigningConfig( + algorithm=AwsSigningAlgorithm.V4_ASYMMETRIC, + region="*", + ) + call_args.bucket = accesspoint_arn_details['resource_name'] + elif is_s3express_bucket(call_args.bucket): make_request_args['signing_config'] = AwsSigningConfig( algorithm=AwsSigningAlgorithm.V4_S3EXPRESS ) @@ -917,3 +930,41 @@ def __call__(self, chunk, **kwargs): self._fileobj.write(chunk) + + +class _S3ArnParamHandler: + """Partial port of S3ArnParamHandler from botocore. + + This is used to make a determination on MRAP accesspoints for signing + purposes. This should be safe to remove once we properly integrate auth + resolution from Botocore into the CRT transfer integration. + """ + + _RESOURCE_REGEX = re.compile( + r'^(?P<resource_type>accesspoint|outpost)[/:](?P<resource_name>.+)$' + ) + + def __init__(self): + self._arn_parser = ArnParser() + + def handle_arn(self, bucket): + arn_details = self._get_arn_details_from_bucket(bucket) + if arn_details is None: + return + if arn_details['resource_type'] == 'accesspoint': + return arn_details + + def _get_arn_details_from_bucket(self, bucket): + try: + arn_details = self._arn_parser.parse_arn(bucket) + self._add_resource_type_and_name(arn_details) + return arn_details + except InvalidArnException: + pass + return None + + def _add_resource_type_and_name(self, arn_details): + match = self._RESOURCE_REGEX.match(arn_details['resource']) + if match: + arn_details['resource_type'] = match.group('resource_type') + arn_details['resource_name'] = match.group('resource_name') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/s3transfer-0.10.3/s3transfer.egg-info/PKG-INFO new/s3transfer-0.10.4/s3transfer.egg-info/PKG-INFO --- old/s3transfer-0.10.3/s3transfer.egg-info/PKG-INFO 2024-10-08 20:06:31.000000000 +0200 +++ new/s3transfer-0.10.4/s3transfer.egg-info/PKG-INFO 2024-11-20 20:06:53.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: s3transfer -Version: 0.10.3 +Version: 0.10.4 Summary: An Amazon S3 Transfer Manager Home-page: https://github.com/boto/s3transfer Author: Amazon Web Services diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/s3transfer-0.10.3/tests/functional/test_crt.py new/s3transfer-0.10.4/tests/functional/test_crt.py --- old/s3transfer-0.10.3/tests/functional/test_crt.py 2024-10-08 20:06:31.000000000 +0200 +++ new/s3transfer-0.10.4/tests/functional/test_crt.py 2024-11-20 20:06:53.000000000 +0100 @@ -69,6 +69,10 @@ self.region = 'us-west-2' self.bucket = "test_bucket" self.s3express_bucket = 's3expressbucket--usw2-az5--x-s3' + self.mrap_accesspoint = ( + 'arn:aws:s3::123456789012:accesspoint/mfzwi23gnjvgw.mrap' + ) + self.mrap_bucket = 'mfzwi23gnjvgw.mrap' self.key = "test_key" self.expected_content = b'my content' self.expected_download_content = b'new content' @@ -80,6 +84,10 @@ self.expected_host = f"s3.{self.region}.amazonaws.com" self.expected_s3express_host = f'{self.s3express_bucket}.s3express-usw2-az5.us-west-2.amazonaws.com' self.expected_s3express_path = f'/{self.key}' + self.expected_mrap_host = ( + f'{self.mrap_bucket}.accesspoint.s3-global.amazonaws.com' + ) + self.expected_mrap_path = f"/{self.key}" self.s3_request = mock.Mock(awscrt.s3.S3Request) self.s3_crt_client = mock.Mock(awscrt.s3.S3Client) self.s3_crt_client.make_request.side_effect = ( @@ -137,7 +145,7 @@ for expected_missing_header in expected_missing_headers: self.assertNotIn(expected_missing_header.lower(), header_names) - def _assert_exected_s3express_request( + def _assert_expected_s3express_request( self, make_request_kwargs, expected_http_method='GET' ): self._assert_expected_crt_http_request( @@ -152,6 +160,22 @@ awscrt.auth.AwsSigningAlgorithm.V4_S3EXPRESS, ) + def _assert_expected_mrap_request( + self, make_request_kwargs, expected_http_method='GET' + ): + self._assert_expected_crt_http_request( + make_request_kwargs["request"], + expected_host=self.expected_mrap_host, + expected_path=self.expected_mrap_path, + expected_http_method=expected_http_method, + ) + self.assertIn('signing_config', make_request_kwargs) + self.assertEqual( + make_request_kwargs['signing_config'].algorithm, + awscrt.auth.AwsSigningAlgorithm.V4_ASYMMETRIC, + ) + self.assertEqual(make_request_kwargs['signing_config'].region, "*") + def _assert_subscribers_called(self, expected_future=None): self.assertTrue(self.record_subscriber.on_queued_called) self.assertTrue(self.record_subscriber.on_done_called) @@ -404,7 +428,21 @@ [self.record_subscriber], ) future.result() - self._assert_exected_s3express_request( + self._assert_expected_s3express_request( + self.s3_crt_client.make_request.call_args[1], + expected_http_method='PUT', + ) + + def test_upload_with_mrap(self): + future = self.transfer_manager.upload( + self.filename, + self.mrap_accesspoint, + self.key, + {}, + [self.record_subscriber], + ) + future.result() + self._assert_expected_mrap_request( self.s3_crt_client.make_request.call_args[1], expected_http_method='PUT', ) @@ -532,7 +570,21 @@ [self.record_subscriber], ) future.result() - self._assert_exected_s3express_request( + self._assert_expected_s3express_request( + self.s3_crt_client.make_request.call_args[1], + expected_http_method='GET', + ) + + def test_download_with_mrap(self): + future = self.transfer_manager.download( + self.mrap_accesspoint, + self.key, + self.filename, + {}, + [self.record_subscriber], + ) + future.result() + self._assert_expected_mrap_request( self.s3_crt_client.make_request.call_args[1], expected_http_method='GET', ) @@ -577,7 +629,7 @@ self.s3express_bucket, self.key, {}, [self.record_subscriber] ) future.result() - self._assert_exected_s3express_request( + self._assert_expected_s3express_request( self.s3_crt_client.make_request.call_args[1], expected_http_method='DELETE', )