dnastack-client-library 3.1.207__py3-none-any.whl → 3.1.209__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dnastack/constants.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import os
2
2
 
3
- __version__ = "3.1.207"
3
+ __version__ = "3.1.209"
4
4
 
5
5
  LOCAL_STORAGE_DIRECTORY = os.path.join(os.path.expanduser("~"), '.dnastack')
@@ -255,16 +255,12 @@ class OAuth2Authenticator(Authenticator):
255
255
  except JSONDecodeError:
256
256
  error_msg = refresh_token_res.text
257
257
 
258
- # Handle Wallet-specific implementation
259
- reauthentication_required = (
260
- refresh_token_res.status_code == 401
261
- or
262
- (refresh_token_res.status_code == 400 and 'JWT expired' in error_msg)
263
- )
264
-
265
- if not reauthentication_required:
266
- event_details['reason'] = 'Invalid state while refreshing tokens'
267
- self.events.dispatch('refresh-failure', event_details)
258
+ # Handle token refresh failure based on HTTP status.
259
+ # 400/401 = the refresh token is invalid (expired, revoked, key rotated, etc.)
260
+ # -> prompt the user to re-authenticate
261
+ # 5xx = transient server error, re-login won't help
262
+ # -> raise InvalidStateError
263
+ reauthentication_required = refresh_token_res.status_code in (400, 401)
268
264
 
269
265
  exception_details = {
270
266
  'debug_mode': currently_in_debug_mode(),
@@ -285,8 +281,12 @@ class OAuth2Authenticator(Authenticator):
285
281
  }
286
282
 
287
283
  if reauthentication_required:
288
- raise ReauthenticationRequired('Refresh token expired')
284
+ logger.warning(f'Refresh token rejected by server (HTTP {refresh_token_res.status_code}): {error_msg}')
285
+ raise ReauthenticationRequired(f'Refresh token rejected: {error_msg}')
289
286
  else:
287
+ event_details['reason'] = 'Invalid state while refreshing tokens'
288
+ self.events.dispatch('refresh-failure', event_details)
289
+
290
290
  raise InvalidStateError('Unable to refresh the access token',
291
291
  details=exception_details)
292
292
  finally:
@@ -4,12 +4,15 @@ from enum import Enum
4
4
  from pydantic import BaseModel, Field
5
5
  import logging
6
6
 
7
+ import boto3
8
+
7
9
  from dnastack.common.tracing import Span
8
10
  from dnastack.http.client_factory import HttpClientFactory
9
11
 
10
12
 
11
13
  class CloudProvider(str, Enum):
12
14
  GCP = "gcp"
15
+ AWS = "aws"
13
16
 
14
17
 
15
18
  class CloudMetadataProvider(ABC):
@@ -89,6 +92,44 @@ class GCPMetadataProvider(CloudMetadataProvider):
89
92
  return None
90
93
 
91
94
 
95
+ class AWSMetadataProvider(CloudMetadataProvider):
96
+ """Amazon Web Services metadata provider using STS GetWebIdentityToken."""
97
+
98
+ def __init__(self, timeout: int = 5):
99
+ super().__init__(timeout)
100
+ self._session: Optional[boto3.Session] = None
101
+
102
+ @property
103
+ def name(self) -> str:
104
+ return CloudProvider.AWS.value
105
+
106
+ def is_available(self) -> bool:
107
+ """Check if AWS credentials are available."""
108
+ try:
109
+ self._session = boto3.Session()
110
+ credentials = self._session.get_credentials()
111
+ return credentials is not None
112
+ except Exception:
113
+ return False
114
+
115
+ def get_identity_token(self, audience: str, trace_context: Span) -> Optional[str]:
116
+ """Fetch AWS identity token from STS GetWebIdentityToken."""
117
+ try:
118
+ if self._session is None:
119
+ self._session = boto3.Session()
120
+
121
+ sts_client = self._session.client('sts')
122
+ response = sts_client.get_web_identity_token(Audience=[audience])
123
+ token = response.get('WebIdentityToken')
124
+ if token:
125
+ self._logger.debug(f'Successfully fetched AWS identity token for audience: {audience}')
126
+ return token
127
+
128
+ except Exception as e:
129
+ self._logger.warning(f'Failed to fetch AWS identity token: {e}')
130
+ return None
131
+
132
+
92
133
  class CloudMetadataConfig(BaseModel):
93
134
  """Configuration model for cloud metadata provider."""
94
135
  timeout: int = Field(5, ge=1, le=30, description="Timeout for metadata service request (1-30 seconds).")
@@ -98,6 +139,7 @@ class CloudProviderFactory:
98
139
  """Factory for creating cloud metadata providers."""
99
140
  _providers = {
100
141
  CloudProvider.GCP: GCPMetadataProvider,
142
+ CloudProvider.AWS: AWSMetadataProvider,
101
143
  }
102
144
 
103
145
  @classmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dnastack-client-library
3
- Version: 3.1.207
3
+ Version: 3.1.209
4
4
  Summary: DNAstack's GA4GH library and CLI
5
5
  Author-email: DNAstack <devs@dnastack.com>
6
6
  License: Apache License, Version 2.0
@@ -36,6 +36,7 @@ Requires-Dist: python-dotenv
36
36
  Requires-Dist: pip>=21.3.1
37
37
  Requires-Dist: packaging>=21.3
38
38
  Requires-Dist: selenium>=4.1.0
39
+ Requires-Dist: boto3>=1.42.30
39
40
  Provides-Extra: test
40
41
  Requires-Dist: selenium>=3.141.0; extra == "test"
41
42
  Requires-Dist: pyjwt>=2.1.0; extra == "test"
@@ -1,6 +1,6 @@
1
1
  dnastack/__init__.py,sha256=mslf7se8vBSK_HkqWTGPdibeVhT4xyKXgzQBV7dEK1M,333
2
2
  dnastack/__main__.py,sha256=EKmtIs4TBseQJi-OT_U6LqRyKLiyrGTBuTQg9zE-G2I,4376
3
- dnastack/constants.py,sha256=ATOtsE118-FzkYW3GE1qbxQMUBSg9xDjPCGSqbHtQtA,113
3
+ dnastack/constants.py,sha256=Cfd54tZ7BhkWKBRgpXZi0KUD7b5Kxn89WjwHArZw5nc,113
4
4
  dnastack/feature_flags.py,sha256=UMNDB07R_ep6Fx3iClhzwOpkWfyYnb418FpoJo50CGs,1411
5
5
  dnastack/json_path.py,sha256=TyghhDf7nGQmnsUWBhenU_fKsE_Ez-HLVER6HgH5-hU,2700
6
6
  dnastack/omics_cli.py,sha256=ZppKZTHv_XjUUZyRIzSkx0Ug5ODAYrCOTsU0ezCOVrA,3694
@@ -189,18 +189,18 @@ dnastack/http/authenticators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
189
189
  dnastack/http/authenticators/abstract.py,sha256=Q74LnZwsMKs5TfGI_4oZtXBCpgJKkkimkv_Y8YPHuoM,9246
190
190
  dnastack/http/authenticators/constants.py,sha256=mSpBnm5lMMmMJwr13KIfCoOXXJLP4qGDkFprYXALu8o,1278
191
191
  dnastack/http/authenticators/factory.py,sha256=zjV5xMZKlkKqUHA2QDXmut-2HxTnqAz8vwxTBEkMg60,2627
192
- dnastack/http/authenticators/oauth2.py,sha256=FKAoCCt_s9XmtVcOJpdll09XSU-lqxne_VO3zqm2DkE,20066
192
+ dnastack/http/authenticators/oauth2.py,sha256=6shpSY9v7Ccs6Iy4GjWgx22uq9r_wkEg3z4xeWlHlxE,20298
193
193
  dnastack/http/authenticators/oauth2_adapter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
194
194
  dnastack/http/authenticators/oauth2_adapter/abstract.py,sha256=Tm4Nnroo5_vp0UgZHhcEDVRRbhIrvVdfPr8nTyihoH4,2832
195
195
  dnastack/http/authenticators/oauth2_adapter/client_credential.py,sha256=2iVOof4YZEVGizDRDBISbv8U_xIemtUnHzzxa3mxswc,2770
196
- dnastack/http/authenticators/oauth2_adapter/cloud_providers.py,sha256=UHQ-YHHr5ipqSQVzCfr95Uv3zkFcop_RCpK4q6a2yJg,4317
196
+ dnastack/http/authenticators/oauth2_adapter/cloud_providers.py,sha256=sWto8WfK2-8xjx3SbrRMIaYg2V8cwohR1XIU6xTXzfA,5763
197
197
  dnastack/http/authenticators/oauth2_adapter/device_code_flow.py,sha256=dXI5CyUcsqYg6gf5vDC_3eY6Cc-H1C8W7FeD_24j92A,6750
198
198
  dnastack/http/authenticators/oauth2_adapter/factory.py,sha256=ZtNXOklWEim-26ooNoPp3ji_hRg1vf4fHHnY94F0wLI,1087
199
199
  dnastack/http/authenticators/oauth2_adapter/models.py,sha256=7UsC8DkStMBx7Bz_xHQNi_J1UO_H4nfHme7oBhokj2I,1339
200
200
  dnastack/http/authenticators/oauth2_adapter/token_exchange.py,sha256=nSuAsSKWa_UNqHSbPMOEk4komaFITYAnE04Sk5WOrLc,6332
201
- dnastack_client_library-3.1.207.dist-info/licenses/LICENSE,sha256=uwybO-wUbQhxkosgjhJlxmYATMy-AzoULFO9FUedE34,11580
202
- dnastack_client_library-3.1.207.dist-info/METADATA,sha256=plCNoaEWQp1W31XbH_9uJFvo-N1vqxKTVHjg0YYfddo,1761
203
- dnastack_client_library-3.1.207.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
204
- dnastack_client_library-3.1.207.dist-info/entry_points.txt,sha256=Y6OeicsiyGn3-8D-SiV4NiKlJgXfkSqK88kFBR6R1rY,89
205
- dnastack_client_library-3.1.207.dist-info/top_level.txt,sha256=P2RgRyqJ7hfNy1wLVRoVLJYEppUVkCX3syGK9zBqkt8,9
206
- dnastack_client_library-3.1.207.dist-info/RECORD,,
201
+ dnastack_client_library-3.1.209.dist-info/licenses/LICENSE,sha256=uwybO-wUbQhxkosgjhJlxmYATMy-AzoULFO9FUedE34,11580
202
+ dnastack_client_library-3.1.209.dist-info/METADATA,sha256=wi1ZarZ4hhrHe-Lle2I5OpuE9fDFMUN_2CxB1Lb8z9k,1791
203
+ dnastack_client_library-3.1.209.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
204
+ dnastack_client_library-3.1.209.dist-info/entry_points.txt,sha256=Y6OeicsiyGn3-8D-SiV4NiKlJgXfkSqK88kFBR6R1rY,89
205
+ dnastack_client_library-3.1.209.dist-info/top_level.txt,sha256=P2RgRyqJ7hfNy1wLVRoVLJYEppUVkCX3syGK9zBqkt8,9
206
+ dnastack_client_library-3.1.209.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5