From 58938bca8b0d7828311627d15665ef460670d37a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:39:14 +0200 Subject: [PATCH 1/9] feat(auth): add new IAM profile selector to VPC Instance Auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lídia Tarcza <100163235+diatrcz@users.noreply.github.com> --- .../vpc_instance_authenticator.py | 34 ++++++++++++++++--- ibm_cloud_sdk_core/get_authenticator.py | 1 + .../vpc_instance_token_manager.py | 22 ++++++++++-- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py b/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py index c2b7a13..3a6898e 100644 --- a/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py +++ b/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py @@ -61,6 +61,7 @@ def __init__( self, iam_profile_crn: Optional[str] = None, iam_profile_id: Optional[str] = None, + iam_profile_name: Optional[str] = None, url: Optional[str] = None, *, token_lifetime: Optional[int] = None, @@ -79,6 +80,7 @@ def __init__( url=url, iam_profile_crn=iam_profile_crn, iam_profile_id=iam_profile_id, + iam_profile_name=iam_profile_name, token_lifetime=token_lifetime, service_version=service_version, ) @@ -92,8 +94,17 @@ def authentication_type(self) -> str: def validate(self) -> None: super().validate() - if self.token_manager.iam_profile_crn and self.token_manager.iam_profile_id: - raise ValueError('At most one of "iam_profile_id" or "iam_profile_crn" may be specified.') + counter = 0 + + if self.token_manager.iam_profile_crn: + counter += 1 + if self.token_manager.iam_profile_id: + counter += 1 + if self.token_manager.iam_profile_name: + counter += 1 + + if counter > 1: + raise ValueError('At most one of "iam_profile_id", "iam_profile_crn" or "iam_profile_name" may be specified.') if self.token_manager.service_version not in self.VPC_AUTH_METADATA_SERVICE_SUPPORTED_VERSIONS: raise ValueError( @@ -125,7 +136,7 @@ def set_iam_profile_crn(self, iam_profile_crn: str) -> None: the identity of the compute resource. Raises: - ValueError: At most one of iam_profile_crn or iam_profile_id may be specified. + ValueError: At most one of iam_profile_crn, iam_profile_id or iam_profile_name may be specified. If neither one is specified, then the default IAM profile defined for the compute resource will be used. """ @@ -140,13 +151,28 @@ def set_iam_profile_id(self, iam_profile_id: str) -> None: the IAM access token Raises: - ValueError: At most one of iam_profile_crn or iam_profile_id may be specified. + ValueError: At most one of iam_profile_crn, iam_profile_id or iam_profile_name may be specified. If neither one is specified, then the default IAM profile defined for the compute resource will be used. """ self.token_manager.set_iam_profile_id(iam_profile_id) self.validate() + def set_iam_profile_name(self, iam_profile_name: str) -> None: + """Sets the ID of the IAM profile. + + Args: + iam_profile_name (str): name of the linked trusted IAM profile to be used when obtaining + the IAM access token + + Raises: + ValueError: At most one of iam_profile_crn, iam_profile_id or iam_profile_name may be specified. + If neither one is specified, then the default IAM profile defined + for the compute resource will be used. + """ + self.token_manager.set_iam_profile_name(iam_profile_name) + self.validate() + def set_token_lifetime(self, token_lifetime: int) -> None: """Sets the token lifetime. diff --git a/ibm_cloud_sdk_core/get_authenticator.py b/ibm_cloud_sdk_core/get_authenticator.py index f57b352..e18fa97 100644 --- a/ibm_cloud_sdk_core/get_authenticator.py +++ b/ibm_cloud_sdk_core/get_authenticator.py @@ -126,6 +126,7 @@ def __construct_authenticator(config: dict) -> Authenticator: authenticator = VPCInstanceAuthenticator( iam_profile_crn=config.get('IAM_PROFILE_CRN'), iam_profile_id=config.get('IAM_PROFILE_ID'), + iam_profile_name=config.get('IAM_PROFILE_NAME'), url=config.get('AUTH_URL'), service_version=config.get('VPC_IMS_VERSION'), ) diff --git a/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py b/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py index 0ce4656..b67ce4c 100644 --- a/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py +++ b/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py @@ -37,11 +37,15 @@ class VPCInstanceTokenManager(JWTTokenManager): Keyword Arguments: iam_profile_crn (str, optional): The CRN of the linked trusted IAM profile to be used as the identity of the compute resource. - At most one of iam_profile_crn or iam_profile_id may be specified. If neither one is specified, + At most one of iam_profile_crn or iam_profile_id or iam_profile_name may be specified. If neither one is specified, then the default IAM profile defined for the compute resource will be used. Defaults to None. iam_profile_id (str, optional): The ID of the linked trusted IAM profile to be used when obtaining the IAM access token. - At most one of iam_profile_crn or iam_profile_id may be specified. If neither one is specified, + At most one of iam_profile_crn or iam_profile_id or iam_profile_name may be specified. If neither one is specified, + then the default IAM profile defined for the compute resource will be used. Defaults to None. + iam_profile_name (str, optional): + The name of the linked trusted IAM profile to be used as the identity of the compute resource. + At most one of iam_profile_crn, iam_profile_id, or iam_profile_name may be specified. If neither one is specified, then the default IAM profile defined for the compute resource will be used. Defaults to None. url (str, optional): The VPC Instance Metadata Service's base endpoint URL. Defaults to 'http://169.254.169.254'. @@ -49,6 +53,7 @@ class VPCInstanceTokenManager(JWTTokenManager): Attributes: iam_profile_crn (str, optional): The CRN of the linked trusted IAM profile. iam_profile_id (str, optional): The ID of the linked trusted IAM profile. + iam_profile_id (str, optional): The name of the linked trusted IAM profile. url (str, optional): The VPC Instance Metadata Service's base endpoint URL. """ @@ -68,6 +73,7 @@ def __init__( self, iam_profile_crn: Optional[str] = None, iam_profile_id: Optional[str] = None, + iam_profile_name: Optional[str] = None, url: Optional[str] = None, *, token_lifetime: Optional[int] = None, @@ -87,6 +93,7 @@ def __init__( self.iam_profile_crn = iam_profile_crn self.iam_profile_id = iam_profile_id + self.iam_profile_name = iam_profile_name self.token_lifetime = token_lifetime self.service_version = service_version @@ -112,6 +119,8 @@ def request_token(self) -> dict: request_payload = {'trusted_profile': {'crn': self.iam_profile_crn}} if self.iam_profile_id: request_payload = {'trusted_profile': {'id': self.iam_profile_id}} + if self.iam_profile_name: + request_payload = {'trusted_profile': {'name': self.iam_profile_name}} headers = { 'Content-Type': 'application/json', @@ -151,6 +160,15 @@ def set_iam_profile_id(self, iam_profile_id: str) -> None: """ self.iam_profile_id = iam_profile_id + def set_iam_profile_name(self, iam_profile_name: str) -> None: + """Sets the name of the IAM profile. + + Args: + iam_profile_name (str): name of the linked trusted IAM profile to be used when obtaining + the IAM access token + """ + self.iam_profile_name = iam_profile_name + def set_token_lifetime(self, token_lifetime: int) -> None: """Sets the lifetime of token. From 9bc42f433af3052a1af85af10bf3a2d8131abc74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Tue, 7 Jul 2026 16:05:45 +0200 Subject: [PATCH 2/9] test: add test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lídia Tarcza <100163235+diatrcz@users.noreply.github.com> --- .../vpc_instance_token_manager.py | 15 ++-- test/test_vpc_instance_authenticator.py | 71 +++++++++++++++++-- test/test_vpc_instance_token_manager.py | 51 +++++++++++++ 3 files changed, 127 insertions(+), 10 deletions(-) diff --git a/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py b/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py index b67ce4c..3f15a63 100644 --- a/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py +++ b/ibm_cloud_sdk_core/token_managers/vpc_instance_token_manager.py @@ -37,16 +37,19 @@ class VPCInstanceTokenManager(JWTTokenManager): Keyword Arguments: iam_profile_crn (str, optional): The CRN of the linked trusted IAM profile to be used as the identity of the compute resource. - At most one of iam_profile_crn or iam_profile_id or iam_profile_name may be specified. If neither one is specified, - then the default IAM profile defined for the compute resource will be used. Defaults to None. + At most one of iam_profile_crn or iam_profile_id or iam_profile_name may be specified. + If neither one is specified, then the default IAM profile defined for the compute resource will be used. + Defaults to None. iam_profile_id (str, optional): The ID of the linked trusted IAM profile to be used when obtaining the IAM access token. - At most one of iam_profile_crn or iam_profile_id or iam_profile_name may be specified. If neither one is specified, - then the default IAM profile defined for the compute resource will be used. Defaults to None. + At most one of iam_profile_crn or iam_profile_id or iam_profile_name may be specified. + If neither one is specified, then the default IAM profile defined for the compute resource will be used. + Defaults to None. iam_profile_name (str, optional): The name of the linked trusted IAM profile to be used as the identity of the compute resource. - At most one of iam_profile_crn, iam_profile_id, or iam_profile_name may be specified. If neither one is specified, - then the default IAM profile defined for the compute resource will be used. Defaults to None. + At most one of iam_profile_crn, iam_profile_id, or iam_profile_name may be specified. + If neither one is specified, then the default IAM profile defined for the compute resource will be used. + Defaults to None. url (str, optional): The VPC Instance Metadata Service's base endpoint URL. Defaults to 'http://169.254.169.254'. diff --git a/test/test_vpc_instance_authenticator.py b/test/test_vpc_instance_authenticator.py index c280888..24f27eb 100644 --- a/test/test_vpc_instance_authenticator.py +++ b/test/test_vpc_instance_authenticator.py @@ -10,6 +10,9 @@ TEST_IAM_PROFILE_CRN = 'crn:iam-profile:123' TEST_IAM_PROFILE_ID = 'iam-id-123' +TEST_IAM_PROFILE_NAME = 'iam-profile-name-1' + +EXPECTED_ERROR = 'At most one of "iam_profile_id", "iam_profile_crn" or "iam_profile_name" may be specified.' def test_constructor(): @@ -18,6 +21,17 @@ def test_constructor(): assert authenticator.authentication_type() == Authenticator.AUTHTYPE_VPC assert authenticator.token_manager.iam_profile_crn is None assert authenticator.token_manager.iam_profile_id == TEST_IAM_PROFILE_ID + assert authenticator.token_manager.iam_profile_name is None + assert authenticator.token_manager.url == 'someurl.com' + + +def test_constructor_with_iam_profile_name(): + authenticator = VPCInstanceAuthenticator(iam_profile_name=TEST_IAM_PROFILE_NAME, url='someurl.com') + assert authenticator is not None + assert authenticator.authentication_type() == Authenticator.AUTHTYPE_VPC + assert authenticator.token_manager.iam_profile_crn is None + assert authenticator.token_manager.iam_profile_id is None + assert authenticator.token_manager.iam_profile_name == TEST_IAM_PROFILE_NAME assert authenticator.token_manager.url == 'someurl.com' @@ -29,11 +43,10 @@ def test_setters(): assert authenticator.token_manager.iam_profile_id == TEST_IAM_PROFILE_ID assert authenticator.token_manager.url == 'someurl.com' - # Set the IAM profile CRN to trigger a validation which will fail, - # because at most one of iam_profile_crn or iam_profile_id may be specified. + # Setting CRN while ID is still set must raise a validation error. with pytest.raises(ValueError) as err: authenticator.set_iam_profile_crn(TEST_IAM_PROFILE_CRN) - assert str(err.value) == 'At most one of "iam_profile_id" or "iam_profile_crn" may be specified.' + assert str(err.value) == EXPECTED_ERROR authenticator.set_iam_profile_id(None) assert authenticator.token_manager.iam_profile_id is None @@ -42,13 +55,63 @@ def test_setters(): assert authenticator.token_manager.iam_profile_crn == TEST_IAM_PROFILE_CRN +def test_setter_iam_profile_name(): + authenticator = VPCInstanceAuthenticator() + assert authenticator.token_manager.iam_profile_name is None + + authenticator.set_iam_profile_name(TEST_IAM_PROFILE_NAME) + assert authenticator.token_manager.iam_profile_name == TEST_IAM_PROFILE_NAME + + # Setting name while CRN is still set must raise a validation error. + authenticator2 = VPCInstanceAuthenticator(iam_profile_crn=TEST_IAM_PROFILE_CRN) + with pytest.raises(ValueError) as err: + authenticator2.set_iam_profile_name(TEST_IAM_PROFILE_NAME) + assert str(err.value) == EXPECTED_ERROR + + # Setting name while ID is still set must raise a validation error. + authenticator3 = VPCInstanceAuthenticator(iam_profile_id=TEST_IAM_PROFILE_ID) + with pytest.raises(ValueError) as err: + authenticator3.set_iam_profile_name(TEST_IAM_PROFILE_NAME) + assert str(err.value) == EXPECTED_ERROR + + # Clearing name is always allowed. + authenticator.set_iam_profile_name(None) + assert authenticator.token_manager.iam_profile_name is None + + def test_constructor_validate_failed(): + # CRN + ID + with pytest.raises(ValueError) as err: + VPCInstanceAuthenticator( + iam_profile_crn=TEST_IAM_PROFILE_CRN, + iam_profile_id=TEST_IAM_PROFILE_ID, + ) + assert str(err.value) == EXPECTED_ERROR + + # CRN + NAME + with pytest.raises(ValueError) as err: + VPCInstanceAuthenticator( + iam_profile_crn=TEST_IAM_PROFILE_CRN, + iam_profile_name=TEST_IAM_PROFILE_NAME, + ) + assert str(err.value) == EXPECTED_ERROR + + # ID + NAME + with pytest.raises(ValueError) as err: + VPCInstanceAuthenticator( + iam_profile_id=TEST_IAM_PROFILE_ID, + iam_profile_name=TEST_IAM_PROFILE_NAME, + ) + assert str(err.value) == EXPECTED_ERROR + + # CRN + ID + NAME with pytest.raises(ValueError) as err: VPCInstanceAuthenticator( iam_profile_crn=TEST_IAM_PROFILE_CRN, iam_profile_id=TEST_IAM_PROFILE_ID, + iam_profile_name=TEST_IAM_PROFILE_NAME, ) - assert str(err.value) == 'At most one of "iam_profile_id" or "iam_profile_crn" may be specified.' + assert str(err.value) == EXPECTED_ERROR def test_constructor_with_unsupported_service_version(): diff --git a/test/test_vpc_instance_token_manager.py b/test/test_vpc_instance_token_manager.py index d07ac68..9fafdc9 100644 --- a/test/test_vpc_instance_token_manager.py +++ b/test/test_vpc_instance_token_manager.py @@ -35,6 +35,7 @@ TEST_IAM_TOKEN = 'iam-abc123' TEST_IAM_PROFILE_CRN = 'crn:iam-profile:123' TEST_IAM_PROFILE_ID = 'iam-id-123' +TEST_IAM_PROFILE_NAME = 'iam-profile-name-1' EXPIRATION_WINDOW = 10 @@ -49,6 +50,18 @@ def test_constructor(): assert token_manager.iam_profile_crn is TEST_IAM_PROFILE_CRN assert token_manager.iam_profile_id is None + assert token_manager.iam_profile_name is None + assert token_manager.access_token is None + + +def test_constructor_with_iam_profile_name(): + token_manager = VPCInstanceTokenManager( + iam_profile_name=TEST_IAM_PROFILE_NAME, + ) + + assert token_manager.iam_profile_crn is None + assert token_manager.iam_profile_id is None + assert token_manager.iam_profile_name == TEST_IAM_PROFILE_NAME assert token_manager.access_token is None @@ -59,6 +72,7 @@ def test_setters(): assert token_manager.iam_profile_crn is TEST_IAM_PROFILE_CRN assert token_manager.iam_profile_id is None + assert token_manager.iam_profile_name is None assert token_manager.access_token is None token_manager.set_iam_profile_crn(None) @@ -67,6 +81,13 @@ def test_setters(): token_manager.set_iam_profile_id(TEST_IAM_PROFILE_ID) assert token_manager.iam_profile_id == TEST_IAM_PROFILE_ID + token_manager.set_iam_profile_id(None) + token_manager.set_iam_profile_name(TEST_IAM_PROFILE_NAME) + assert token_manager.iam_profile_name == TEST_IAM_PROFILE_NAME + + token_manager.set_iam_profile_name(None) + assert token_manager.iam_profile_name is None + @responses.activate def test_retrieve_instance_identity_token(): @@ -249,6 +270,36 @@ def mock_retrieve_instance_identity_token(): assert responses.calls[0].request.params['version'] == '2022-03-01' +@responses.activate +def test_request_token_with_name(): + token_manager = VPCInstanceTokenManager( + iam_profile_name=TEST_IAM_PROFILE_NAME, + ) + + # Mock the retrieve instance identity token method. + def mock_retrieve_instance_identity_token(): + return TEST_TOKEN + + token_manager.retrieve_instance_identity_token = mock_retrieve_instance_identity_token + + response = { + 'access_token': TEST_IAM_TOKEN, + } + + responses.add( + responses.POST, 'http://169.254.169.254/instance_identity/v1/iam_token', body=json.dumps(response), status=200 + ) + + response = token_manager.request_token() + assert len(responses.calls) == 1 + assert responses.calls[0].request.headers['Content-Type'] == 'application/json' + assert responses.calls[0].request.headers['Accept'] == 'application/json' + assert responses.calls[0].request.headers['Metadata-Flavor'] == 'ibm' + assert responses.calls[0].request.headers['Authorization'] == 'Bearer ' + TEST_TOKEN + assert responses.calls[0].request.body == '{"trusted_profile": {"name": "iam-profile-name-1"}}' + assert responses.calls[0].request.params['version'] == '2022-03-01' + + @responses.activate def test_request_token(): token_manager = VPCInstanceTokenManager() From 62a70eeedd8270adf8f561d6acd97acd67d93789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Tue, 7 Jul 2026 16:10:05 +0200 Subject: [PATCH 3/9] docs: update documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lídia Tarcza <100163235+diatrcz@users.noreply.github.com> --- Authentication.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Authentication.md b/Authentication.md index 7a6d179..898c37d 100644 --- a/Authentication.md +++ b/Authentication.md @@ -440,7 +440,9 @@ The IAM access token is added to each outbound request in the `Authorization` he - iam_profile_id: (optional) the id of the linked trusted IAM profile to be used when obtaining the IAM access token. -- url: (optional) The VPC Instance Metadata Service's base URL. +- iam_profile_name: (optional) the name of the linked trusted IAM profile to be used as the identity of the compute resource. + +- url: (optional) The VPC Instance Metadata Service's base URL. The default value of this property is `http://169.254.169.254`. However, if the VPC Instance Metadata Service is configured with the HTTP Secure Protocol setting (`https`), then you should configure this property to be `https://api.metadata.cloud.ibm.com`. @@ -452,12 +454,12 @@ The default value is `2022-03-01`. When set to `2025-08-26`, the authenticator w The default value is `300` seconds. This property can only be configured programmatically (not via environment variables). Usage Notes: -1. At most one of `iam_profile_crn` or `iam_profile_id` may be specified. The specified value must map +1. At most one of `iam_profile_crn`, `iam_profile_id` or `iam_profile_name` may be specified. The specified value must map to a trusted IAM profile that has been linked to the compute resource (virtual server instance). -2. If both `iam_profile_crn` and `iam_profile_id` are specified, then an error occurs. +2. If more than on from `iam_profile_crn`, `iam_profile_id` and `iam_profile_name` are specified, then an error occurs. -3. If neither `iam_profile_crn` nor `iam_profile_id` are specified, then the default trusted profile linked to the compute resource will be used to perform the IAM token exchange. +3. If neither `iam_profile_crn`, `iam_profile_id` nor `iam_profile_name` are specified, then the default trusted profile linked to the compute resource will be used to perform the IAM token exchange. If no default trusted profile is defined for the compute resource, then an error occurs. From 7d5e58d54e8f04802d41be7f740cd8902467ece9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Tue, 7 Jul 2026 16:24:25 +0200 Subject: [PATCH 4/9] fix: add lint fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lídia Tarcza <100163235+diatrcz@users.noreply.github.com> --- .../authenticators/vpc_instance_authenticator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py b/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py index 3a6898e..205d181 100644 --- a/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py +++ b/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py @@ -104,7 +104,8 @@ def validate(self) -> None: counter += 1 if counter > 1: - raise ValueError('At most one of "iam_profile_id", "iam_profile_crn" or "iam_profile_name" may be specified.') + raise ValueError( + 'At most one of "iam_profile_id", "iam_profile_crn" or "iam_profile_name" may be specified.') if self.token_manager.service_version not in self.VPC_AUTH_METADATA_SERVICE_SUPPORTED_VERSIONS: raise ValueError( From 47694ac2fa395acef6f78ce2eb5ea34bd29c0faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:55:45 +0200 Subject: [PATCH 5/9] test: modify test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lídia Tarcza <100163235+diatrcz@users.noreply.github.com> --- ibm_cloud_sdk_core/base_service.py | 2 +- test/test_base_service.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ibm_cloud_sdk_core/base_service.py b/ibm_cloud_sdk_core/base_service.py index 636e514..dca06aa 100644 --- a/ibm_cloud_sdk_core/base_service.py +++ b/ibm_cloud_sdk_core/base_service.py @@ -450,7 +450,7 @@ def prepare_request( # In any other cases, we use the in memory compression directly from # the `gzip` package for backward compatibility. raw_data = request['data'] - request['data'] = GzipStream(raw_data) if isinstance(raw_data, io.IOBase) else gzip.compress(raw_data) + request['data'] = GzipStream(raw_data) if isinstance(raw_data, io.IOBase) else gzip.compress(raw_data, mtime=0) # Next, we need to process the 'files' argument to try to fill in # any missing filenames where possible. diff --git a/test/test_base_service.py b/test/test_base_service.py index a90f79e..2f598e0 100644 --- a/test/test_base_service.py +++ b/test/test_base_service.py @@ -739,7 +739,7 @@ def test_gzip_compression_external(): assert service.service_url == 'https://mockurl' assert service.get_enable_gzip_compression() is True prepped = service.prepare_request('GET', url='', data=json.dumps({"foo": "bar"})) - assert prepped['data'] == gzip.compress(b'{"foo": "bar"}') + assert prepped['data'] == gzip.compress(b'{"foo": "bar"}', mtime=0) assert prepped['headers'].get('content-encoding') == 'gzip' From cca80ab3b271380f404a91467b36d09311b6415e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:40:33 +0200 Subject: [PATCH 6/9] test: fix test cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lídia Tarcza <100163235+diatrcz@users.noreply.github.com> --- test/test_base_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_base_service.py b/test/test_base_service.py index 2f598e0..20f7643 100644 --- a/test/test_base_service.py +++ b/test/test_base_service.py @@ -634,13 +634,13 @@ def test_gzip_compression(): service.set_enable_gzip_compression(True) assert service.get_enable_gzip_compression() prepped = service.prepare_request('GET', url='', data=json.dumps({"foo": "bar"})) - assert prepped['data'] == gzip.compress(b'{"foo": "bar"}') + assert gzip.decompress(prepped['data']) == b'{"foo": "bar"}' assert prepped['headers'].get('content-encoding') == 'gzip' # Should return compressed data when gzip is on for non-json data assert service.get_enable_gzip_compression() prepped = service.prepare_request('GET', url='', data=b'rawdata') - assert prepped['data'] == gzip.compress(b'rawdata') + assert gzip.decompress(prepped['data']) == b'rawdata' assert prepped['headers'].get('content-encoding') == 'gzip' # Should return compressed data when gzip is on for gzip file data From 08597e732f2b5a7d1823a82f1000c55961f6705e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:44:04 +0200 Subject: [PATCH 7/9] Revert "test: fix test cases" This reverts commit cca80ab3b271380f404a91467b36d09311b6415e. --- test/test_base_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_base_service.py b/test/test_base_service.py index 20f7643..2f598e0 100644 --- a/test/test_base_service.py +++ b/test/test_base_service.py @@ -634,13 +634,13 @@ def test_gzip_compression(): service.set_enable_gzip_compression(True) assert service.get_enable_gzip_compression() prepped = service.prepare_request('GET', url='', data=json.dumps({"foo": "bar"})) - assert gzip.decompress(prepped['data']) == b'{"foo": "bar"}' + assert prepped['data'] == gzip.compress(b'{"foo": "bar"}') assert prepped['headers'].get('content-encoding') == 'gzip' # Should return compressed data when gzip is on for non-json data assert service.get_enable_gzip_compression() prepped = service.prepare_request('GET', url='', data=b'rawdata') - assert gzip.decompress(prepped['data']) == b'rawdata' + assert prepped['data'] == gzip.compress(b'rawdata') assert prepped['headers'].get('content-encoding') == 'gzip' # Should return compressed data when gzip is on for gzip file data From 104ae57ccef4d3d4f6c0c90a041b710a851cd02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:44:09 +0200 Subject: [PATCH 8/9] Revert "test: modify test cases" This reverts commit 47694ac2fa395acef6f78ce2eb5ea34bd29c0faa. --- ibm_cloud_sdk_core/base_service.py | 2 +- test/test_base_service.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ibm_cloud_sdk_core/base_service.py b/ibm_cloud_sdk_core/base_service.py index dca06aa..636e514 100644 --- a/ibm_cloud_sdk_core/base_service.py +++ b/ibm_cloud_sdk_core/base_service.py @@ -450,7 +450,7 @@ def prepare_request( # In any other cases, we use the in memory compression directly from # the `gzip` package for backward compatibility. raw_data = request['data'] - request['data'] = GzipStream(raw_data) if isinstance(raw_data, io.IOBase) else gzip.compress(raw_data, mtime=0) + request['data'] = GzipStream(raw_data) if isinstance(raw_data, io.IOBase) else gzip.compress(raw_data) # Next, we need to process the 'files' argument to try to fill in # any missing filenames where possible. diff --git a/test/test_base_service.py b/test/test_base_service.py index 2f598e0..a90f79e 100644 --- a/test/test_base_service.py +++ b/test/test_base_service.py @@ -739,7 +739,7 @@ def test_gzip_compression_external(): assert service.service_url == 'https://mockurl' assert service.get_enable_gzip_compression() is True prepped = service.prepare_request('GET', url='', data=json.dumps({"foo": "bar"})) - assert prepped['data'] == gzip.compress(b'{"foo": "bar"}', mtime=0) + assert prepped['data'] == gzip.compress(b'{"foo": "bar"}') assert prepped['headers'].get('content-encoding') == 'gzip' From 50f974a2ef74ba1ca60163e7f3ef7c8f5115d907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=ADdia=20Tarcza?= <100163235+diatrcz@users.noreply.github.com> Date: Thu, 9 Jul 2026 11:47:30 +0200 Subject: [PATCH 9/9] chore: modify lint issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lídia Tarcza <100163235+diatrcz@users.noreply.github.com> --- .../authenticators/vpc_instance_authenticator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py b/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py index 205d181..6f29d21 100644 --- a/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py +++ b/ibm_cloud_sdk_core/authenticators/vpc_instance_authenticator.py @@ -105,7 +105,8 @@ def validate(self) -> None: if counter > 1: raise ValueError( - 'At most one of "iam_profile_id", "iam_profile_crn" or "iam_profile_name" may be specified.') + 'At most one of "iam_profile_id", "iam_profile_crn" or "iam_profile_name" may be specified.' + ) if self.token_manager.service_version not in self.VPC_AUTH_METADATA_SERVICE_SUPPORTED_VERSIONS: raise ValueError(