digitalhub 0.13.0b4__py3-none-any.whl → 0.14.0b0__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.

Potentially problematic release.


This version of digitalhub might be problematic. Click here for more details.

Files changed (61) hide show
  1. digitalhub/__init__.py +3 -8
  2. digitalhub/entities/_base/_base/entity.py +0 -11
  3. digitalhub/entities/_base/entity/builder.py +5 -5
  4. digitalhub/entities/_base/executable/entity.py +1 -1
  5. digitalhub/entities/_base/runtime_entity/builder.py +53 -18
  6. digitalhub/entities/_commons/utils.py +64 -21
  7. digitalhub/entities/_processors/base.py +11 -3
  8. digitalhub/entities/_processors/context.py +71 -22
  9. digitalhub/entities/_processors/utils.py +3 -3
  10. digitalhub/entities/artifact/crud.py +20 -4
  11. digitalhub/entities/artifact/utils.py +1 -1
  12. digitalhub/entities/dataitem/crud.py +20 -4
  13. digitalhub/entities/dataitem/table/entity.py +0 -21
  14. digitalhub/entities/dataitem/utils.py +1 -1
  15. digitalhub/entities/function/_base/entity.py +1 -1
  16. digitalhub/entities/function/crud.py +15 -4
  17. digitalhub/entities/model/_base/entity.py +21 -1
  18. digitalhub/entities/model/crud.py +21 -5
  19. digitalhub/entities/model/utils.py +1 -1
  20. digitalhub/entities/project/_base/entity.py +65 -33
  21. digitalhub/entities/project/crud.py +8 -1
  22. digitalhub/entities/run/_base/entity.py +21 -1
  23. digitalhub/entities/run/crud.py +22 -5
  24. digitalhub/entities/secret/crud.py +22 -5
  25. digitalhub/entities/task/crud.py +22 -5
  26. digitalhub/entities/trigger/crud.py +20 -4
  27. digitalhub/entities/workflow/_base/entity.py +1 -1
  28. digitalhub/entities/workflow/crud.py +15 -4
  29. digitalhub/factory/enums.py +18 -0
  30. digitalhub/factory/factory.py +136 -57
  31. digitalhub/factory/utils.py +3 -54
  32. digitalhub/stores/client/api.py +6 -10
  33. digitalhub/stores/client/builder.py +3 -3
  34. digitalhub/stores/client/dhcore/client.py +104 -162
  35. digitalhub/stores/client/dhcore/configurator.py +92 -289
  36. digitalhub/stores/client/dhcore/enums.py +0 -16
  37. digitalhub/stores/client/dhcore/params_builder.py +41 -83
  38. digitalhub/stores/client/dhcore/utils.py +14 -22
  39. digitalhub/stores/client/local/client.py +77 -45
  40. digitalhub/stores/credentials/ini_module.py +0 -16
  41. digitalhub/stores/data/local/store.py +0 -103
  42. digitalhub/stores/data/s3/configurator.py +60 -6
  43. digitalhub/stores/data/s3/store.py +44 -2
  44. digitalhub/stores/data/sql/store.py +15 -0
  45. digitalhub/utils/file_utils.py +0 -17
  46. digitalhub/utils/generic_utils.py +1 -2
  47. digitalhub/utils/store_utils.py +44 -0
  48. {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b0.dist-info}/METADATA +3 -2
  49. {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b0.dist-info}/RECORD +58 -59
  50. digitalhub/entities/task/_base/utils.py +0 -22
  51. digitalhub/stores/client/dhcore/models.py +0 -40
  52. digitalhub/stores/data/s3/utils.py +0 -78
  53. /digitalhub/entities/{_base/entity/_constructors → _constructors}/__init__.py +0 -0
  54. /digitalhub/entities/{_base/entity/_constructors → _constructors}/metadata.py +0 -0
  55. /digitalhub/entities/{_base/entity/_constructors → _constructors}/name.py +0 -0
  56. /digitalhub/entities/{_base/entity/_constructors → _constructors}/spec.py +0 -0
  57. /digitalhub/entities/{_base/entity/_constructors → _constructors}/status.py +0 -0
  58. /digitalhub/entities/{_base/entity/_constructors → _constructors}/uuid.py +0 -0
  59. {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b0.dist-info}/WHEEL +0 -0
  60. {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b0.dist-info}/licenses/AUTHORS +0 -0
  61. {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -22,38 +22,22 @@ if typing.TYPE_CHECKING:
22
22
 
23
23
  class ClientDHCoreConfigurator(Configurator):
24
24
  """
25
- Configurator object used to configure the client.
26
-
27
- The configurator starts reading the credentials from the
28
- environment and from the ini file and stores them into the
29
- creds_handler object.
30
-
31
- While reading the credentials from the two sources (environment and file),
32
- the configurator evaluate if the required keys are present in both sources.
33
- If the required keys are not present in both sources, the configurator
34
- will rise an error, otherwise decide which source to use.
35
-
36
- Once the credentials are read, the configurator check the current profile
37
- name from the ini file, and set it. The default one is __default. The
38
- profile is used to discriminate a set of credentials inside the ini file.
39
-
40
- The configurator finally set the authentication type based on the credentials.
41
- The logic is the following:
42
-
43
- 1. Check for a personal access token. Use it immediately to
44
- require a timed access token in an exchange endpoint.
45
- Switche then the origin to file and .
46
- Set the auth type to EXCHANGE.
47
- 2. Check for an access token and a refresh token.
48
- Set the auth type to OAUTH2.
49
- 3. Check for username and password.
50
- Set the auth type to BASIC.
51
- 4. If none of the above is true, leave the auth type to None.
25
+ DHCore client configurator for credential management and authentication.
26
+
27
+ Handles loading credentials from environment variables and configuration files,
28
+ evaluates authentication types, and manages token refresh operations. Supports
29
+ multiple authentication methods: EXCHANGE (personal access token), OAUTH2
30
+ (access + refresh tokens), ACCESS_TOKEN (access token only), and BASIC
31
+ (username + password).
32
+
33
+ The configurator automatically determines the best authentication method and
34
+ handles token exchange for personal access tokens by switching to file-based
35
+ credential storage.
52
36
  """
53
37
 
54
38
  keys = [*list_enum(CredsEnvVar)]
55
39
  required_keys = [CredsEnvVar.DHCORE_ENDPOINT.value]
56
- keys_to_unprefix = [
40
+ keys_to_prefix = [
57
41
  CredsEnvVar.DHCORE_REFRESH_TOKEN.value,
58
42
  CredsEnvVar.DHCORE_ACCESS_TOKEN.value,
59
43
  CredsEnvVar.DHCORE_ISSUER.value,
@@ -62,10 +46,7 @@ class ClientDHCoreConfigurator(Configurator):
62
46
 
63
47
  def __init__(self) -> None:
64
48
  """
65
- Initialize the DHCore configurator.
66
-
67
- Sets up the configurator by calling the parent constructor and
68
- initializing the authentication type evaluation process.
49
+ Initialize DHCore configurator and evaluate authentication type.
69
50
 
70
51
  Returns
71
52
  -------
@@ -81,20 +62,14 @@ class ClientDHCoreConfigurator(Configurator):
81
62
 
82
63
  def load_env_vars(self) -> None:
83
64
  """
84
- Load credentials from environment variables.
65
+ Load and sanitize credentials from environment variables.
85
66
 
86
- Retrieves DHCore credentials from environment variables, sanitizes
87
- them (particularly endpoint URLs), and stores them in the credentials
88
- handler for the environment origin.
67
+ Sanitizes endpoint and issuer URLs to ensure proper HTTP/HTTPS schemes
68
+ and removes trailing slashes.
89
69
 
90
70
  Returns
91
71
  -------
92
72
  None
93
-
94
- Notes
95
- -----
96
- This method sanitizes endpoint and issuer URLs to ensure they have
97
- proper schemes and removes trailing slashes.
98
73
  """
99
74
  env_creds = self._creds_handler.load_from_env(self.keys)
100
75
  env_creds = self._sanitize_env_vars(env_creds)
@@ -102,30 +77,25 @@ class ClientDHCoreConfigurator(Configurator):
102
77
 
103
78
  def _sanitize_env_vars(self, creds: dict) -> dict:
104
79
  """
105
- Sanitize credentials loaded from environment variables.
80
+ Sanitize environment variable credentials.
106
81
 
107
- Validates and normalizes endpoint and issuer URLs from environment
108
- variables. Ensures URLs have proper schemes and removes trailing slashes.
82
+ Validates and normalizes endpoint and issuer URLs. Environment variables
83
+ use full "DHCORE_" prefixes.
109
84
 
110
85
  Parameters
111
86
  ----------
112
87
  creds : dict
113
- Raw credentials dictionary loaded from environment variables.
88
+ Raw credentials from environment variables.
114
89
 
115
90
  Returns
116
91
  -------
117
92
  dict
118
- Sanitized credentials dictionary with normalized URLs.
93
+ Sanitized credentials with normalized URLs.
119
94
 
120
95
  Raises
121
96
  ------
122
97
  ClientError
123
98
  If endpoint or issuer URLs have invalid schemes.
124
-
125
- Notes
126
- -----
127
- Environment variables are expected to have the full "DHCORE_" prefix
128
- for issuer endpoints.
129
99
  """
130
100
  creds[CredsEnvVar.DHCORE_ENDPOINT.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ENDPOINT.value])
131
101
  creds[CredsEnvVar.DHCORE_ISSUER.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ISSUER.value])
@@ -133,112 +103,73 @@ class ClientDHCoreConfigurator(Configurator):
133
103
 
134
104
  def load_file_vars(self) -> None:
135
105
  """
136
- Load credentials from configuration file.
106
+ Load credentials from configuration file with CLI compatibility.
137
107
 
138
- Retrieves DHCore credentials from the .dhcore.ini file, handles
139
- compatibility with CLI format (keys without DHCORE_ prefix), and
140
- falls back to environment variables for missing endpoint and
141
- personal access token values.
108
+ Handles keys without "DHCORE_" prefix for CLI compatibility. Falls back
109
+ to environment variables for missing endpoint and personal access token values.
142
110
 
143
111
  Returns
144
112
  -------
145
113
  None
146
-
147
- Notes
148
- -----
149
- This method handles the case where:
150
- - Endpoint might not be present in file response, falls back to env
151
- - Personal access token might not be present, falls back to env
152
- - File format uses keys without "DHCORE_" prefix for compatibility
153
114
  """
154
- keys = [*self._remove_prefix_dhcore()]
155
- file_creds = self._creds_handler.load_from_file(keys)
156
- env_creds = self._creds_handler.load_from_env(self.keys)
157
-
158
- # Because in the response there is no endpoint
159
- if file_creds[CredsEnvVar.DHCORE_ENDPOINT.value] is None:
160
- file_creds[CredsEnvVar.DHCORE_ENDPOINT.value] = env_creds.get(CredsEnvVar.DHCORE_ENDPOINT.value)
115
+ file_creds = self._creds_handler.load_from_file(self.keys)
161
116
 
162
117
  # Because in the response there is no personal access token
163
- if file_creds[CredsEnvVar.DHCORE_PERSONAL_ACCESS_TOKEN.value] is None:
164
- file_creds[CredsEnvVar.DHCORE_PERSONAL_ACCESS_TOKEN.value] = env_creds.get(
165
- CredsEnvVar.DHCORE_PERSONAL_ACCESS_TOKEN.value
166
- )
118
+ pat = CredsEnvVar.DHCORE_PERSONAL_ACCESS_TOKEN.value
119
+ if file_creds[pat] is None:
120
+ file_creds[pat] = self._creds_handler.load_from_env([pat]).get(pat)
167
121
 
168
122
  file_creds = self._sanitize_file_vars(file_creds)
169
123
  self._creds_handler.set_credentials(self._file, file_creds)
170
124
 
171
125
  def _sanitize_file_vars(self, creds: dict) -> dict:
172
126
  """
173
- Sanitize credentials loaded from configuration file.
127
+ Sanitize configuration file credentials.
174
128
 
175
- Handles the different key formats used in configuration files compared
176
- to environment variables. File format omits "DHCORE_" prefix for
177
- certain keys for CLI compatibility.
129
+ Handles different key formats between file and environment variables.
130
+ File format omits "DHCORE_" prefix for: issuer, client_id, access_token,
131
+ refresh_token. Full names used for: endpoint, user, password, personal_access_token.
178
132
 
179
133
  Parameters
180
134
  ----------
181
135
  creds : dict
182
- Raw credentials dictionary loaded from configuration file.
136
+ Raw credentials from configuration file.
183
137
 
184
138
  Returns
185
139
  -------
186
140
  dict
187
- Sanitized credentials dictionary with standardized key names
188
- and normalized URLs, filtered to include only valid keys.
141
+ Sanitized credentials with standardized keys and normalized URLs.
189
142
 
190
143
  Raises
191
144
  ------
192
145
  ClientError
193
146
  If endpoint or issuer URLs have invalid schemes.
194
-
195
- Notes
196
- -----
197
- File format expects these keys without "DHCORE_" prefix:
198
- - issuer, client_id, access_token, refresh_token
199
- But uses full names for: endpoint, user, password, personal_access_token
200
147
  """
201
148
  creds[CredsEnvVar.DHCORE_ENDPOINT.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ENDPOINT.value])
202
- creds[CredsEnvVar.DHCORE_ISSUER.value] = self._sanitize_endpoint(
203
- creds[CredsEnvVar.DHCORE_ISSUER.value.removeprefix("DHCORE_")]
204
- )
205
- creds[CredsEnvVar.DHCORE_REFRESH_TOKEN.value] = creds[
206
- CredsEnvVar.DHCORE_REFRESH_TOKEN.value.removeprefix("DHCORE_")
207
- ]
208
- creds[CredsEnvVar.DHCORE_ACCESS_TOKEN.value] = creds[
209
- CredsEnvVar.DHCORE_ACCESS_TOKEN.value.removeprefix("DHCORE_")
210
- ]
211
- creds[CredsEnvVar.DHCORE_CLIENT_ID.value] = creds[CredsEnvVar.DHCORE_CLIENT_ID.value.removeprefix("DHCORE_")]
149
+ creds[CredsEnvVar.DHCORE_ISSUER.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ISSUER.value])
212
150
  return {k: v for k, v in creds.items() if k in self.keys}
213
151
 
214
152
  @staticmethod
215
153
  def _sanitize_endpoint(endpoint: str | None = None) -> str | None:
216
154
  """
217
- Sanitize and validate endpoint URL.
155
+ Validate and normalize endpoint URL.
218
156
 
219
- Validates that the endpoint URL has a proper HTTP/HTTPS scheme,
220
- trims whitespace, and removes trailing slashes for consistency.
157
+ Ensures proper HTTP/HTTPS scheme, trims whitespace, and removes trailing slashes.
221
158
 
222
159
  Parameters
223
160
  ----------
224
161
  endpoint : str, optional
225
- The endpoint URL to sanitize. If None, returns None.
162
+ Endpoint URL to sanitize.
226
163
 
227
164
  Returns
228
165
  -------
229
166
  str or None
230
- The sanitized endpoint URL with trailing slash removed,
231
- or None if input was None.
167
+ Sanitized URL or None if input was None.
232
168
 
233
169
  Raises
234
170
  ------
235
171
  ClientError
236
- If the endpoint does not start with http:// or https://.
237
-
238
- Notes
239
- -----
240
- This method ensures endpoint URLs are properly formatted for
241
- HTTP requests and prevents common URL formatting issues.
172
+ If endpoint lacks http:// or https:// scheme.
242
173
  """
243
174
  if endpoint is None:
244
175
  return
@@ -252,23 +183,17 @@ class ClientDHCoreConfigurator(Configurator):
252
183
  """
253
184
  Get the configured DHCore backend endpoint.
254
185
 
255
- Retrieves the DHCore endpoint URL from the current credential source
256
- (environment or file based on current origin).
186
+ Returns the sanitized and validated endpoint URL from current credential source.
257
187
 
258
188
  Returns
259
189
  -------
260
190
  str
261
- The DHCore backend endpoint URL.
191
+ DHCore backend endpoint URL.
262
192
 
263
193
  Raises
264
194
  ------
265
195
  KeyError
266
- If the endpoint is not configured in the current credential source.
267
-
268
- Notes
269
- -----
270
- The endpoint returned is already sanitized and validated during
271
- the credential loading process.
196
+ If endpoint not configured in current credential source.
272
197
  """
273
198
  creds = self._creds_handler.get_credentials(self._origin)
274
199
  return creds[CredsEnvVar.DHCORE_ENDPOINT.value]
@@ -279,22 +204,14 @@ class ClientDHCoreConfigurator(Configurator):
279
204
 
280
205
  def change_origin(self) -> None:
281
206
  """
282
- Change the credentials origin and re-evaluate authentication type.
207
+ Switch credential source and re-evaluate authentication type.
283
208
 
284
- Switches the credential source (between environment and file) and
285
- re-evaluates the authentication type based on the new credential set.
286
- This is typically called when the current credential source fails
287
- or when switching contexts.
209
+ Changes between environment and file credential sources, then re-evaluates
210
+ authentication type based on the new credentials.
288
211
 
289
212
  Returns
290
213
  -------
291
214
  None
292
-
293
- Notes
294
- -----
295
- This method extends the parent class behavior by also re-evaluating
296
- the authentication type, which may change based on different
297
- credentials available in the new source.
298
215
  """
299
216
  super().change_origin()
300
217
 
@@ -307,29 +224,16 @@ class ClientDHCoreConfigurator(Configurator):
307
224
 
308
225
  def set_auth_type(self) -> None:
309
226
  """
310
- Evaluate and set the authentication type from available credentials.
227
+ Determine authentication type from available credentials.
311
228
 
312
- Analyzes the available credentials and determines the appropriate
313
- authentication method based on the following priority:
314
- 1. EXCHANGE - Personal access token available
315
- 2. OAUTH2 - Access token and refresh token available
316
- 3. ACCESS_TOKEN - Only access token available
317
- 4. BASIC - Username and password available
318
- 5. None - No valid credentials found
319
-
320
- For EXCHANGE authentication, automatically performs token exchange
321
- and switches to file-based credential storage.
229
+ Evaluates credentials in priority order: EXCHANGE (personal access token),
230
+ OAUTH2 (access + refresh tokens), ACCESS_TOKEN (access only), BASIC
231
+ (username + password). For EXCHANGE type, automatically exchanges the
232
+ personal access token and switches to file-based credentials storage.
322
233
 
323
234
  Returns
324
235
  -------
325
236
  None
326
-
327
- Notes
328
- -----
329
- When EXCHANGE authentication is detected, this method automatically:
330
- - Performs credential refresh to exchange the personal access token
331
- - Changes origin to file-based storage for the new tokens
332
- - Updates the authentication type accordingly
333
237
  """
334
238
  creds = creds_handler.get_credentials(self._origin)
335
239
  self._auth_type = self._eval_auth_type(creds)
@@ -343,55 +247,34 @@ class ClientDHCoreConfigurator(Configurator):
343
247
 
344
248
  def refreshable_auth_types(self) -> bool:
345
249
  """
346
- Check if the current authentication type supports token refresh.
250
+ Check if current authentication supports token refresh.
347
251
 
348
- Determines whether the current authentication method supports
349
- automatic token refresh capabilities.
252
+ Returns True for OAUTH2 (refresh token) and EXCHANGE (personal access token),
253
+ False for BASIC and ACCESS_TOKEN.
350
254
 
351
255
  Returns
352
256
  -------
353
257
  bool
354
- True if the authentication type supports refresh (OAUTH2 or EXCHANGE),
355
- False otherwise (BASIC or ACCESS_TOKEN).
356
-
357
- Notes
358
- -----
359
- Only OAUTH2 and EXCHANGE authentication types support refresh:
360
- - OAUTH2: Uses refresh token to get new access tokens
361
- - EXCHANGE: Uses personal access token for token exchange
362
- - BASIC and ACCESS_TOKEN do not support refresh
258
+ Whether authentication type supports refresh.
363
259
  """
364
260
  return self._auth_type in [AuthType.OAUTH2.value, AuthType.EXCHANGE.value]
365
261
 
366
262
  def get_auth_parameters(self, kwargs: dict) -> dict:
367
263
  """
368
- Add authentication parameters to HTTP request arguments.
264
+ Add authentication headers/parameters to HTTP request kwargs.
369
265
 
370
- Modifies the provided kwargs dictionary to include the appropriate
371
- authentication headers or parameters based on the current authentication
372
- type and available credentials.
266
+ Adds Authorization Bearer header for token-based auth or auth tuple
267
+ for basic authentication.
373
268
 
374
269
  Parameters
375
270
  ----------
376
271
  kwargs : dict
377
- HTTP request keyword arguments to be modified with authentication.
272
+ HTTP request arguments to modify.
378
273
 
379
274
  Returns
380
275
  -------
381
276
  dict
382
- The modified kwargs dictionary with authentication parameters added.
383
-
384
- Notes
385
- -----
386
- Authentication is added based on auth type:
387
- - OAUTH2/EXCHANGE/ACCESS_TOKEN: Adds Authorization Bearer header
388
- - BASIC: Adds auth tuple with username/password
389
- - None: No authentication added
390
-
391
- The method assumes that:
392
- - Authentication type has been properly set
393
- - For EXCHANGE type, refresh token has been obtained
394
- - Required credentials are available for the current auth type
277
+ Modified kwargs with authentication parameters.
395
278
  """
396
279
  creds = creds_handler.get_credentials(self._origin)
397
280
  if self._auth_type in (
@@ -411,18 +294,16 @@ class ClientDHCoreConfigurator(Configurator):
411
294
 
412
295
  def refresh_credentials(self, change_origin: bool = False) -> None:
413
296
  """
414
- Refresh authentication credentials by obtaining new access tokens.
297
+ Refresh authentication tokens using OAuth2 flows.
415
298
 
416
- Performs credential refresh using either OAuth2 refresh token flow
417
- or personal access token exchange, depending on the current
418
- authentication type. Updates stored credentials with new tokens.
299
+ Uses refresh_token grant for OAUTH2 or token exchange for EXCHANGE authentication.
300
+ On 400/401/403 errors with change_origin=True, attempts to switch credential
301
+ sources and retry. Saves new credentials to configuration file.
419
302
 
420
303
  Parameters
421
304
  ----------
422
305
  change_origin : bool, default False
423
- Whether to allow changing credential source if refresh fails.
424
- If True and refresh fails, attempts to switch credential sources
425
- and retry once.
306
+ Whether to switch credential sources on auth failure.
426
307
 
427
308
  Returns
428
309
  -------
@@ -431,21 +312,7 @@ class ClientDHCoreConfigurator(Configurator):
431
312
  Raises
432
313
  ------
433
314
  ClientError
434
- If the authentication type doesn't support refresh, if required
435
- credentials are missing, or if refresh fails and change_origin
436
- is False.
437
-
438
- Notes
439
- -----
440
- Refresh behavior by authentication type:
441
- - OAUTH2: Uses refresh_token grant to get new access/refresh tokens
442
- - EXCHANGE: Uses token exchange with personal access token
443
-
444
- If refresh fails with 400/401/403 status and change_origin=True,
445
- attempts to switch credential sources and retry once.
446
-
447
- New credentials are automatically saved to the configuration file
448
- and the origin is switched to file-based storage.
315
+ If auth type doesn't support refresh or credentials missing.
449
316
  """
450
317
  if not self.refreshable_auth_types():
451
318
  raise ClientError(f"Auth type {self._auth_type} does not support refresh.")
@@ -491,64 +358,26 @@ class ClientDHCoreConfigurator(Configurator):
491
358
  # Read new credentials and propagate to config file
492
359
  self._export_new_creds(response.json())
493
360
 
494
- def _remove_prefix_dhcore(self) -> list[str]:
495
- """
496
- Remove DHCORE_ prefix from selected credential keys for CLI compatibility.
497
-
498
- Creates a list of credential key names with "DHCORE_" prefix removed
499
- from specific keys that are stored without the prefix in configuration
500
- files for compatibility with CLI tools.
501
-
502
- Returns
503
- -------
504
- list[str]
505
- List of credential keys with selective prefix removal applied.
506
-
507
- Notes
508
- -----
509
- Keys that have prefix removed (defined in keys_to_unprefix):
510
- - DHCORE_REFRESH_TOKEN -> refresh_token
511
- - DHCORE_ACCESS_TOKEN -> access_token
512
- - DHCORE_ISSUER -> issuer
513
- - DHCORE_CLIENT_ID -> client_id
514
-
515
- Other keys retain their full names for consistency.
516
- """
517
- new_list = []
518
- for key in self.keys:
519
- if key in self.keys_to_unprefix:
520
- new_list.append(key.removeprefix("DHCORE_"))
521
- else:
522
- new_list.append(key)
523
- return new_list
524
-
525
361
  def _get_refresh_endpoint(self) -> str:
526
362
  """
527
- Discover the OAuth2 token refresh endpoint from the issuer.
363
+ Discover OAuth2 token endpoint from issuer well-known configuration.
528
364
 
529
- Queries the OAuth2 issuer's well-known configuration endpoint to
530
- discover the token endpoint used for credential refresh operations.
365
+ Queries /.well-known/openid-configuration to extract token_endpoint for
366
+ credential refresh operations.
531
367
 
532
368
  Returns
533
369
  -------
534
370
  str
535
- The token endpoint URL for credential refresh.
371
+ Token endpoint URL for credential refresh.
536
372
 
537
373
  Raises
538
374
  ------
539
375
  ClientError
540
- If the issuer endpoint is not configured.
376
+ If issuer endpoint not configured.
541
377
  HTTPError
542
- If the well-known configuration endpoint is not accessible.
378
+ If well-known configuration endpoint inaccessible.
543
379
  KeyError
544
- If the token_endpoint is not found in the issuer configuration.
545
-
546
- Notes
547
- -----
548
- This method follows the OAuth2/OpenID Connect discovery standard by:
549
- 1. Accessing the issuer's /.well-known/openid-configuration endpoint
550
- 2. Extracting the token_endpoint from the configuration
551
- 3. Using this endpoint for subsequent token refresh operations
380
+ If token_endpoint not found in issuer configuration.
552
381
  """
553
382
  # Get issuer endpoint
554
383
  creds = self._creds_handler.get_credentials(self._origin)
@@ -570,30 +399,22 @@ class ClientDHCoreConfigurator(Configurator):
570
399
  **kwargs,
571
400
  ) -> Response:
572
401
  """
573
- Make HTTP request to OAuth2 token refresh endpoint.
402
+ Make OAuth2 token refresh request.
574
403
 
575
- Performs a POST request to the OAuth2 token endpoint with the
576
- appropriate form-encoded payload for token refresh or exchange.
404
+ Sends POST request with form-encoded payload using required OAuth2
405
+ content type and 60-second timeout.
577
406
 
578
407
  Parameters
579
408
  ----------
580
409
  url : str
581
- The token endpoint URL to call.
410
+ Token endpoint URL.
582
411
  **kwargs : dict
583
- Token request parameters such as grant_type, client_id,
584
- refresh_token, subject_token, etc.
412
+ Token request parameters (grant_type, client_id, etc.).
585
413
 
586
414
  Returns
587
415
  -------
588
416
  Response
589
- The HTTP response object from the token endpoint.
590
-
591
- Notes
592
- -----
593
- This method:
594
- - Uses application/x-www-form-urlencoded content type as required by OAuth2
595
- - Sets a 60-second timeout for the request
596
- - Returns the raw response for caller to handle status and parsing
417
+ Raw HTTP response for caller handling.
597
418
  """
598
419
  # Send request to get new access token
599
420
  payload = {**kwargs}
@@ -602,30 +423,20 @@ class ClientDHCoreConfigurator(Configurator):
602
423
 
603
424
  def _eval_auth_type(self, creds: dict) -> str | None:
604
425
  """
605
- Evaluate authentication type based on available credentials.
426
+ Determine authentication type from available credentials.
606
427
 
607
- Analyzes the provided credentials and determines the most appropriate
608
- authentication method based on which credential types are available.
428
+ Evaluates in priority order: EXCHANGE (personal access token), OAUTH2
429
+ (access + refresh tokens), ACCESS_TOKEN (access only), BASIC (username + password).
609
430
 
610
431
  Parameters
611
432
  ----------
612
433
  creds : dict
613
- Dictionary containing credential values.
434
+ Available credential values.
614
435
 
615
436
  Returns
616
437
  -------
617
438
  str or None
618
- The determined authentication type from AuthType enum, or None
619
- if no valid authentication method can be determined.
620
-
621
- Notes
622
- -----
623
- Authentication type priority (checked in order):
624
- 1. EXCHANGE - Personal access token is available
625
- 2. OAUTH2 - Both access token and refresh token are available
626
- 3. ACCESS_TOKEN - Only access token is available
627
- 4. BASIC - Both username and password are available
628
- 5. None - No valid credential combination found
439
+ Authentication type from AuthType enum, or None if no valid credentials.
629
440
  """
630
441
  if creds[CredsEnvVar.DHCORE_PERSONAL_ACCESS_TOKEN.value] is not None:
631
442
  return AuthType.EXCHANGE.value
@@ -642,32 +453,24 @@ class ClientDHCoreConfigurator(Configurator):
642
453
 
643
454
  def _export_new_creds(self, response: dict) -> None:
644
455
  """
645
- Save new credentials from token refresh response.
456
+ Save refreshed credentials and switch to file-based storage.
646
457
 
647
- Takes the response from a successful token refresh operation and
648
- persists the new credentials to the configuration file, then
649
- reloads file-based credentials and switches to file origin.
458
+ Persists new tokens (access_token, refresh_token, etc.) to configuration
459
+ file and switches credential origin to file storage.
650
460
 
651
461
  Parameters
652
462
  ----------
653
463
  response : dict
654
- Token response containing new access_token, refresh_token,
655
- and other credential information.
464
+ OAuth2 token response with new credentials.
656
465
 
657
466
  Returns
658
467
  -------
659
468
  None
660
-
661
- Notes
662
- -----
663
- This method:
664
- 1. Writes new credentials to the configuration file
665
- 2. Reloads file-based credentials to ensure consistency
666
- 3. Changes current origin to file since new tokens are file-based
667
-
668
- The response typically contains access_token, refresh_token,
669
- token_type, expires_in, and other OAuth2 standard fields.
670
469
  """
470
+ for key in self.keys_to_prefix:
471
+ key = key.lower()
472
+ if key.removeprefix("dhcore_") in response:
473
+ response[key] = response.pop(key.removeprefix("dhcore_"))
671
474
  creds_handler.write_env(response)
672
475
  self.load_file_vars()
673
476
 
@@ -7,22 +7,6 @@ from __future__ import annotations
7
7
  from enum import Enum
8
8
 
9
9
 
10
- class DhcoreEnvVar(Enum):
11
- """
12
- Environment variables.
13
- """
14
-
15
- ENDPOINT = "DHCORE_ENDPOINT"
16
- ISSUER = "DHCORE_ISSUER"
17
- USER = "DHCORE_USER"
18
- PASSWORD = "DHCORE_PASSWORD"
19
- CLIENT_ID = "DHCORE_CLIENT_ID"
20
- ACCESS_TOKEN = "DHCORE_ACCESS_TOKEN"
21
- REFRESH_TOKEN = "DHCORE_REFRESH_TOKEN"
22
- PERSONAL_ACCESS_TOKEN = "DHCORE_PERSONAL_ACCESS_TOKEN"
23
- WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
24
-
25
-
26
10
  class AuthType(Enum):
27
11
  """
28
12
  Authentication types.