airbyte-internal-ops 0.5.0__py3-none-any.whl → 0.5.2__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.
Files changed (87) hide show
  1. {airbyte_internal_ops-0.5.0.dist-info → airbyte_internal_ops-0.5.2.dist-info}/METADATA +2 -1
  2. {airbyte_internal_ops-0.5.0.dist-info → airbyte_internal_ops-0.5.2.dist-info}/RECORD +18 -87
  3. airbyte_ops_mcp/cli/cloud.py +12 -8
  4. airbyte_ops_mcp/cloud_admin/api_client.py +51 -51
  5. airbyte_ops_mcp/constants.py +58 -0
  6. airbyte_ops_mcp/{_legacy/airbyte_ci/metadata_service/docker_hub.py → docker_hub.py} +16 -10
  7. airbyte_ops_mcp/mcp/cloud_connector_versions.py +44 -23
  8. airbyte_ops_mcp/mcp/prod_db_queries.py +128 -4
  9. airbyte_ops_mcp/mcp/regression_tests.py +10 -5
  10. airbyte_ops_mcp/{_legacy/airbyte_ci/metadata_service/validators/metadata_validator.py → metadata_validator.py} +18 -12
  11. airbyte_ops_mcp/prod_db_access/queries.py +51 -0
  12. airbyte_ops_mcp/prod_db_access/sql.py +76 -0
  13. airbyte_ops_mcp/regression_tests/__init__.py +2 -0
  14. airbyte_ops_mcp/regression_tests/connection_fetcher.py +16 -5
  15. airbyte_ops_mcp/regression_tests/connection_secret_retriever.py +25 -5
  16. airbyte_ops_mcp/regression_tests/models.py +2 -2
  17. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/README.md +0 -91
  18. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/bin/bundle-schemas.js +0 -48
  19. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/bin/generate-metadata-models.sh +0 -36
  20. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ActorDefinitionResourceRequirements.py +0 -54
  21. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/AirbyteInternal.py +0 -22
  22. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/AllowedHosts.py +0 -18
  23. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorBreakingChanges.py +0 -65
  24. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorBuildOptions.py +0 -15
  25. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorIPCOptions.py +0 -25
  26. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorMetadataDefinitionV0.json +0 -897
  27. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorMetadataDefinitionV0.py +0 -478
  28. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorMetrics.py +0 -24
  29. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorPackageInfo.py +0 -12
  30. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorRegistryDestinationDefinition.py +0 -407
  31. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorRegistryReleases.py +0 -406
  32. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorRegistrySourceDefinition.py +0 -407
  33. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorRegistryV0.py +0 -413
  34. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorReleases.py +0 -98
  35. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ConnectorTestSuiteOptions.py +0 -58
  36. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/GeneratedFields.py +0 -62
  37. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/GitInfo.py +0 -31
  38. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/JobType.py +0 -23
  39. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/NormalizationDestinationDefinitionConfig.py +0 -24
  40. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/RegistryOverrides.py +0 -111
  41. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ReleaseStage.py +0 -15
  42. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/RemoteRegistries.py +0 -23
  43. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/ResourceRequirements.py +0 -18
  44. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/RolloutConfiguration.py +0 -29
  45. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/Secret.py +0 -34
  46. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/SecretStore.py +0 -22
  47. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/SourceFileInfo.py +0 -16
  48. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/SuggestedStreams.py +0 -18
  49. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/SupportLevel.py +0 -15
  50. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/TestConnections.py +0 -14
  51. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/__init__.py +0 -31
  52. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/generated/airbyte-connector-metadata-schema.json +0 -0
  53. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ActorDefinitionResourceRequirements.yaml +0 -30
  54. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/AirbyteInternal.yaml +0 -32
  55. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/AllowedHosts.yaml +0 -13
  56. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorBreakingChanges.yaml +0 -65
  57. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorBuildOptions.yaml +0 -10
  58. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorIPCOptions.yaml +0 -29
  59. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorMetadataDefinitionV0.yaml +0 -172
  60. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorMetrics.yaml +0 -30
  61. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorPackageInfo.yaml +0 -9
  62. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorRegistryDestinationDefinition.yaml +0 -90
  63. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorRegistryReleases.yaml +0 -35
  64. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorRegistrySourceDefinition.yaml +0 -92
  65. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorRegistryV0.yaml +0 -18
  66. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorReleases.yaml +0 -16
  67. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ConnectorTestSuiteOptions.yaml +0 -28
  68. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/GeneratedFields.yaml +0 -16
  69. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/GitInfo.yaml +0 -21
  70. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/JobType.yaml +0 -14
  71. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/NormalizationDestinationDefinitionConfig.yaml +0 -21
  72. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/RegistryOverrides.yaml +0 -38
  73. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ReleaseStage.yaml +0 -11
  74. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/RemoteRegistries.yaml +0 -25
  75. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/ResourceRequirements.yaml +0 -16
  76. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/RolloutConfiguration.yaml +0 -29
  77. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/Secret.yaml +0 -19
  78. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/SecretStore.yaml +0 -16
  79. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/SourceFileInfo.yaml +0 -17
  80. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/SuggestedStreams.yaml +0 -13
  81. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/SupportLevel.yaml +0 -10
  82. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/models/TestConnections.yaml +0 -17
  83. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/package-lock.json +0 -62
  84. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/package.json +0 -12
  85. airbyte_ops_mcp/_legacy/airbyte_ci/metadata_models/transform.py +0 -71
  86. {airbyte_internal_ops-0.5.0.dist-info → airbyte_internal_ops-0.5.2.dist-info}/WHEEL +0 -0
  87. {airbyte_internal_ops-0.5.0.dist-info → airbyte_internal_ops-0.5.2.dist-info}/entry_points.txt +0 -0
@@ -132,7 +132,7 @@ def _get_access_token(
132
132
 
133
133
  def get_user_id_by_email(
134
134
  email: str,
135
- api_root: str,
135
+ config_api_root: str,
136
136
  client_id: str | None = None,
137
137
  client_secret: str | None = None,
138
138
  bearer_token: str | None = None,
@@ -141,7 +141,7 @@ def get_user_id_by_email(
141
141
 
142
142
  Args:
143
143
  email: The user's email address
144
- api_root: The API root URL
144
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
145
145
  client_id: The Airbyte Cloud client ID (required if no bearer_token)
146
146
  client_secret: The Airbyte Cloud client secret (required if no bearer_token)
147
147
  bearer_token: Pre-existing bearer token (takes precedence over client credentials)
@@ -154,7 +154,7 @@ def get_user_id_by_email(
154
154
  """
155
155
  access_token = _get_access_token(client_id, client_secret, bearer_token)
156
156
 
157
- endpoint = f"{api_root}/users/list_instance_admin"
157
+ endpoint = f"{config_api_root}/users/list_instance_admin"
158
158
  response = requests.post(
159
159
  endpoint,
160
160
  json={},
@@ -196,7 +196,7 @@ def resolve_connector_version_id(
196
196
  actor_definition_id: str,
197
197
  connector_type: Literal["source", "destination"],
198
198
  version: str,
199
- api_root: str,
199
+ config_api_root: str,
200
200
  client_id: str | None = None,
201
201
  client_secret: str | None = None,
202
202
  bearer_token: str | None = None,
@@ -207,7 +207,7 @@ def resolve_connector_version_id(
207
207
  actor_definition_id: The actor definition ID
208
208
  connector_type: Either "source" or "destination"
209
209
  version: The version string (e.g., "0.1.47-preview.abe7cb4")
210
- api_root: The API root URL
210
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
211
211
  client_id: The Airbyte Cloud client ID (required if no bearer_token)
212
212
  client_secret: The Airbyte Cloud client secret (required if no bearer_token)
213
213
  bearer_token: Pre-existing bearer token (takes precedence over client credentials)
@@ -220,7 +220,7 @@ def resolve_connector_version_id(
220
220
  """
221
221
  access_token = _get_access_token(client_id, client_secret, bearer_token)
222
222
 
223
- endpoint = f"{api_root}/actor_definition_versions/resolve"
223
+ endpoint = f"{config_api_root}/actor_definition_versions/resolve"
224
224
  payload = {
225
225
  "actorDefinitionId": actor_definition_id,
226
226
  "actorType": connector_type,
@@ -270,7 +270,7 @@ def _get_scoped_configuration_context(
270
270
  actor_definition_id: str,
271
271
  scope_type: _ScopeType,
272
272
  scope_id: str,
273
- api_root: str,
273
+ config_api_root: str,
274
274
  access_token: str,
275
275
  ) -> dict[str, Any] | None:
276
276
  """Get the active scoped configuration for a single scope level.
@@ -282,7 +282,7 @@ def _get_scoped_configuration_context(
282
282
  actor_definition_id: The actor definition ID for the connector
283
283
  scope_type: The scope type enum (ACTOR, WORKSPACE, or ORGANIZATION)
284
284
  scope_id: The ID for the scope (connector_id, workspace_id, or organization_id)
285
- api_root: The API root URL
285
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
286
286
  access_token: Pre-authenticated access token
287
287
 
288
288
  Returns:
@@ -291,7 +291,7 @@ def _get_scoped_configuration_context(
291
291
  Raises:
292
292
  PyAirbyteInputError: If the API request fails
293
293
  """
294
- endpoint = f"{api_root}/scoped_configuration/get_context"
294
+ endpoint = f"{config_api_root}/scoped_configuration/get_context"
295
295
  context_payload = {
296
296
  "config_key": _ScopedConfigKey.CONNECTOR_VERSION.value,
297
297
  "resource_type": _ResourceType.ACTOR_DEFINITION.value,
@@ -333,7 +333,7 @@ def get_all_scoped_configuration_contexts(
333
333
  actor_definition_id: str,
334
334
  workspace_id: str,
335
335
  organization_id: str,
336
- api_root: str,
336
+ config_api_root: str,
337
337
  client_id: str | None = None,
338
338
  client_secret: str | None = None,
339
339
  bearer_token: str | None = None,
@@ -349,7 +349,7 @@ def get_all_scoped_configuration_contexts(
349
349
  actor_definition_id: The actor definition ID for the connector
350
350
  workspace_id: The workspace ID (required - must always check workspace scope)
351
351
  organization_id: The organization ID (required - must always check org scope)
352
- api_root: The API root URL
352
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
353
353
  client_id: The Airbyte Cloud client ID (required if no bearer_token)
354
354
  client_secret: The Airbyte Cloud client secret (required if no bearer_token)
355
355
  bearer_token: Pre-existing bearer token (takes precedence over client credentials)
@@ -381,7 +381,7 @@ def get_all_scoped_configuration_contexts(
381
381
  actor_definition_id=actor_definition_id,
382
382
  scope_type=scope_type_enum,
383
383
  scope_id=scope_id,
384
- api_root=api_root,
384
+ config_api_root=config_api_root,
385
385
  access_token=access_token,
386
386
  )
387
387
  if active_config:
@@ -393,7 +393,7 @@ def get_all_scoped_configuration_contexts(
393
393
  def get_connector_version(
394
394
  connector_id: str,
395
395
  connector_type: Literal["source", "destination"],
396
- api_root: str,
396
+ config_api_root: str,
397
397
  client_id: str | None = None,
398
398
  client_secret: str | None = None,
399
399
  bearer_token: str | None = None,
@@ -408,7 +408,7 @@ def get_connector_version(
408
408
  Args:
409
409
  connector_id: The ID of the deployed connector (source or destination)
410
410
  connector_type: Either "source" or "destination"
411
- api_root: The API root URL
411
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
412
412
  client_id: The Airbyte Cloud client ID (required if no bearer_token)
413
413
  client_secret: The Airbyte Cloud client secret (required if no bearer_token)
414
414
  bearer_token: Pre-existing bearer token (takes precedence over client credentials)
@@ -427,13 +427,13 @@ def get_connector_version(
427
427
  access_token = _get_access_token(client_id, client_secret, bearer_token)
428
428
 
429
429
  # Determine endpoint based on connector type
430
- # api_root already includes /v1
430
+ # config_api_root already includes /v1
431
431
  if connector_type == "source":
432
- endpoint = f"{api_root}/actor_definition_versions/get_for_source"
432
+ endpoint = f"{config_api_root}/actor_definition_versions/get_for_source"
433
433
  payload = {"sourceId": connector_id}
434
434
  definition_id_key = "sourceDefinitionId"
435
435
  else:
436
- endpoint = f"{api_root}/actor_definition_versions/get_for_destination"
436
+ endpoint = f"{config_api_root}/actor_definition_versions/get_for_destination"
437
437
  payload = {"destinationId": connector_id}
438
438
  definition_id_key = "destinationDefinitionId"
439
439
 
@@ -456,7 +456,7 @@ def get_connector_version(
456
456
  "connector_type": connector_type,
457
457
  "endpoint": endpoint,
458
458
  "payload": payload,
459
- "api_root": api_root,
459
+ "config_api_root": config_api_root,
460
460
  "status_code": response.status_code,
461
461
  "response": response.text,
462
462
  },
@@ -474,7 +474,7 @@ def get_connector_version(
474
474
  # If workspace_id is provided, also get detailed scoped configuration context
475
475
  if workspace_id:
476
476
  # Get actor_definition_id from the connector info
477
- get_endpoint = f"{api_root}/{connector_type}s/get"
477
+ get_endpoint = f"{config_api_root}/{connector_type}s/get"
478
478
  get_payload: dict[str, str] = {f"{connector_type}Id": connector_id}
479
479
 
480
480
  get_response = requests.post(
@@ -494,7 +494,7 @@ def get_connector_version(
494
494
 
495
495
  if actor_definition_id:
496
496
  # Get organization_id from workspace
497
- workspace_endpoint = f"{api_root}/workspaces/get"
497
+ workspace_endpoint = f"{config_api_root}/workspaces/get"
498
498
  workspace_response = requests.post(
499
499
  workspace_endpoint,
500
500
  json={"workspaceId": workspace_id},
@@ -517,7 +517,7 @@ def get_connector_version(
517
517
  actor_definition_id=actor_definition_id,
518
518
  workspace_id=workspace_id,
519
519
  organization_id=organization_id,
520
- api_root=api_root,
520
+ config_api_root=config_api_root,
521
521
  bearer_token=access_token,
522
522
  )
523
523
 
@@ -527,7 +527,7 @@ def get_connector_version(
527
527
  def set_connector_version_override(
528
528
  connector_id: str,
529
529
  connector_type: Literal["source", "destination"],
530
- api_root: str,
530
+ config_api_root: str,
531
531
  client_id: str | None = None,
532
532
  client_secret: str | None = None,
533
533
  workspace_id: str | None = None,
@@ -554,7 +554,7 @@ def set_connector_version_override(
554
554
  Args:
555
555
  connector_id: The ID of the deployed connector
556
556
  connector_type: Either "source" or "destination"
557
- api_root: The API root URL
557
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
558
558
  client_id: The Airbyte Cloud client ID (required if no bearer_token)
559
559
  client_secret: The Airbyte Cloud client secret (required if no bearer_token)
560
560
  workspace_id: The workspace ID
@@ -590,7 +590,7 @@ def set_connector_version_override(
590
590
  if unset:
591
591
  # To unset, we need to delete the scoped configuration
592
592
  # First, get the actor_definition_id for the connector
593
- get_endpoint: str = f"{api_root}/{connector_type}s/get"
593
+ get_endpoint: str = f"{config_api_root}/{connector_type}s/get"
594
594
  get_payload: dict[str, str] = {f"{connector_type}Id": connector_id}
595
595
  definition_id_key = f"{connector_type}DefinitionId"
596
596
 
@@ -623,7 +623,7 @@ def set_connector_version_override(
623
623
  actor_definition_id=actor_definition_id,
624
624
  scope_type=_ScopeType.ACTOR,
625
625
  scope_id=connector_id,
626
- api_root=api_root,
626
+ config_api_root=config_api_root,
627
627
  access_token=access_token,
628
628
  )
629
629
 
@@ -632,7 +632,7 @@ def set_connector_version_override(
632
632
  return False
633
633
 
634
634
  # Delete the active configuration
635
- delete_endpoint = f"{api_root}/scoped_configuration/delete"
635
+ delete_endpoint = f"{config_api_root}/scoped_configuration/delete"
636
636
  delete_payload = {"scopedConfigurationId": active_config["id"]}
637
637
 
638
638
  response = requests.post(
@@ -662,7 +662,7 @@ def set_connector_version_override(
662
662
  else:
663
663
  # Set a new override
664
664
  # First, get the actor_definition_id for the connector
665
- get_endpoint = f"{api_root}/{connector_type}s/get"
665
+ get_endpoint = f"{config_api_root}/{connector_type}s/get"
666
666
  get_payload: dict[str, str] = {f"{connector_type}Id": connector_id}
667
667
  definition_id_key = f"{connector_type}DefinitionId"
668
668
 
@@ -695,7 +695,7 @@ def set_connector_version_override(
695
695
  actor_definition_id=actor_definition_id,
696
696
  connector_type=connector_type,
697
697
  version=version,
698
- api_root=api_root,
698
+ config_api_root=config_api_root,
699
699
  client_id=client_id,
700
700
  client_secret=client_secret,
701
701
  bearer_token=bearer_token,
@@ -703,7 +703,7 @@ def set_connector_version_override(
703
703
 
704
704
  # Get organization_id from workspace info for comprehensive scope checking
705
705
  # This is REQUIRED - we must always check all three scopes
706
- workspace_endpoint = f"{api_root}/workspaces/get"
706
+ workspace_endpoint = f"{config_api_root}/workspaces/get"
707
707
  workspace_payload = {"workspaceId": workspace_id}
708
708
  workspace_response = requests.post(
709
709
  workspace_endpoint,
@@ -745,7 +745,7 @@ def set_connector_version_override(
745
745
  actor_definition_id=actor_definition_id,
746
746
  workspace_id=workspace_id,
747
747
  organization_id=organization_id,
748
- api_root=api_root,
748
+ config_api_root=config_api_root,
749
749
  client_id=client_id,
750
750
  client_secret=client_secret,
751
751
  bearer_token=bearer_token,
@@ -836,7 +836,7 @@ def set_connector_version_override(
836
836
  },
837
837
  )
838
838
 
839
- delete_endpoint = f"{api_root}/scoped_configuration/delete"
839
+ delete_endpoint = f"{config_api_root}/scoped_configuration/delete"
840
840
  delete_payload = {"scopedConfigurationId": actor_config["id"]}
841
841
 
842
842
  delete_response = requests.post(
@@ -889,14 +889,14 @@ def set_connector_version_override(
889
889
  )
890
890
  origin = get_user_id_by_email(
891
891
  email=user_email,
892
- api_root=api_root,
892
+ config_api_root=config_api_root,
893
893
  client_id=client_id,
894
894
  client_secret=client_secret,
895
895
  bearer_token=bearer_token,
896
896
  )
897
897
 
898
898
  # Create the override with correct schema
899
- endpoint = f"{api_root}/scoped_configuration/create"
899
+ endpoint = f"{config_api_root}/scoped_configuration/create"
900
900
 
901
901
  # Build payload with explicit string values for auditability
902
902
  # (enum.value ensures we log exactly what we send)
@@ -968,7 +968,7 @@ def set_workspace_connector_version_override(
968
968
  workspace_id: str,
969
969
  connector_name: str,
970
970
  connector_type: Literal["source", "destination"],
971
- api_root: str,
971
+ config_api_root: str,
972
972
  client_id: str | None = None,
973
973
  client_secret: str | None = None,
974
974
  version: str | None = None,
@@ -988,7 +988,7 @@ def set_workspace_connector_version_override(
988
988
  workspace_id: The workspace ID
989
989
  connector_name: The connector name (e.g., 'source-github')
990
990
  connector_type: Either "source" or "destination"
991
- api_root: The API root URL
991
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
992
992
  client_id: The Airbyte Cloud client ID (required if no bearer_token)
993
993
  client_secret: The Airbyte Cloud client secret (required if no bearer_token)
994
994
  version: The version to pin to (e.g., "0.1.0"), or None to unset
@@ -1026,7 +1026,7 @@ def set_workspace_connector_version_override(
1026
1026
  actor_definition_id=actor_definition_id,
1027
1027
  scope_type=_ScopeType.WORKSPACE,
1028
1028
  scope_id=workspace_id,
1029
- api_root=api_root,
1029
+ config_api_root=config_api_root,
1030
1030
  access_token=access_token,
1031
1031
  )
1032
1032
 
@@ -1052,7 +1052,7 @@ def set_workspace_connector_version_override(
1052
1052
  )
1053
1053
 
1054
1054
  # Delete the configuration
1055
- delete_endpoint = f"{api_root}/scoped_configuration/delete"
1055
+ delete_endpoint = f"{config_api_root}/scoped_configuration/delete"
1056
1056
  delete_payload = {"scopedConfigurationId": active_config["id"]}
1057
1057
 
1058
1058
  response = requests.post(
@@ -1085,7 +1085,7 @@ def set_workspace_connector_version_override(
1085
1085
  actor_definition_id=actor_definition_id,
1086
1086
  connector_type=connector_type,
1087
1087
  version=version,
1088
- api_root=api_root,
1088
+ config_api_root=config_api_root,
1089
1089
  bearer_token=access_token,
1090
1090
  )
1091
1091
 
@@ -1094,7 +1094,7 @@ def set_workspace_connector_version_override(
1094
1094
  actor_definition_id=actor_definition_id,
1095
1095
  scope_type=_ScopeType.WORKSPACE,
1096
1096
  scope_id=workspace_id,
1097
- api_root=api_root,
1097
+ config_api_root=config_api_root,
1098
1098
  access_token=access_token,
1099
1099
  )
1100
1100
 
@@ -1123,7 +1123,7 @@ def set_workspace_connector_version_override(
1123
1123
  and api_scope_id == workspace_id
1124
1124
  ):
1125
1125
  # Delete existing workspace-level config before creating new one
1126
- delete_endpoint = f"{api_root}/scoped_configuration/delete"
1126
+ delete_endpoint = f"{config_api_root}/scoped_configuration/delete"
1127
1127
  delete_payload = {"scopedConfigurationId": existing_config["id"]}
1128
1128
 
1129
1129
  delete_response = requests.post(
@@ -1150,12 +1150,12 @@ def set_workspace_connector_version_override(
1150
1150
  )
1151
1151
  origin = get_user_id_by_email(
1152
1152
  email=user_email,
1153
- api_root=api_root,
1153
+ config_api_root=config_api_root,
1154
1154
  bearer_token=access_token,
1155
1155
  )
1156
1156
 
1157
1157
  # Create the override
1158
- endpoint = f"{api_root}/scoped_configuration/create"
1158
+ endpoint = f"{config_api_root}/scoped_configuration/create"
1159
1159
  payload: dict[str, Any] = {
1160
1160
  "config_key": _ScopedConfigKey.CONNECTOR_VERSION.value,
1161
1161
  "resource_type": _ResourceType.ACTOR_DEFINITION.value,
@@ -1202,7 +1202,7 @@ def set_organization_connector_version_override(
1202
1202
  organization_id: str,
1203
1203
  connector_name: str,
1204
1204
  connector_type: Literal["source", "destination"],
1205
- api_root: str,
1205
+ config_api_root: str,
1206
1206
  client_id: str | None = None,
1207
1207
  client_secret: str | None = None,
1208
1208
  version: str | None = None,
@@ -1222,7 +1222,7 @@ def set_organization_connector_version_override(
1222
1222
  organization_id: The organization ID
1223
1223
  connector_name: The connector name (e.g., 'source-github')
1224
1224
  connector_type: Either "source" or "destination"
1225
- api_root: The API root URL
1225
+ config_api_root: The Config API root URL (e.g., CLOUD_CONFIG_API_ROOT)
1226
1226
  client_id: The Airbyte Cloud client ID (required if no bearer_token)
1227
1227
  client_secret: The Airbyte Cloud client secret (required if no bearer_token)
1228
1228
  version: The version to pin to (e.g., "0.1.0"), or None to unset
@@ -1260,7 +1260,7 @@ def set_organization_connector_version_override(
1260
1260
  actor_definition_id=actor_definition_id,
1261
1261
  scope_type=_ScopeType.ORGANIZATION,
1262
1262
  scope_id=organization_id,
1263
- api_root=api_root,
1263
+ config_api_root=config_api_root,
1264
1264
  access_token=access_token,
1265
1265
  )
1266
1266
 
@@ -1288,7 +1288,7 @@ def set_organization_connector_version_override(
1288
1288
  )
1289
1289
 
1290
1290
  # Delete the configuration
1291
- delete_endpoint = f"{api_root}/scoped_configuration/delete"
1291
+ delete_endpoint = f"{config_api_root}/scoped_configuration/delete"
1292
1292
  delete_payload = {"scopedConfigurationId": active_config["id"]}
1293
1293
 
1294
1294
  response = requests.post(
@@ -1321,7 +1321,7 @@ def set_organization_connector_version_override(
1321
1321
  actor_definition_id=actor_definition_id,
1322
1322
  connector_type=connector_type,
1323
1323
  version=version,
1324
- api_root=api_root,
1324
+ config_api_root=config_api_root,
1325
1325
  bearer_token=access_token,
1326
1326
  )
1327
1327
 
@@ -1330,7 +1330,7 @@ def set_organization_connector_version_override(
1330
1330
  actor_definition_id=actor_definition_id,
1331
1331
  scope_type=_ScopeType.ORGANIZATION,
1332
1332
  scope_id=organization_id,
1333
- api_root=api_root,
1333
+ config_api_root=config_api_root,
1334
1334
  access_token=access_token,
1335
1335
  )
1336
1336
 
@@ -1359,7 +1359,7 @@ def set_organization_connector_version_override(
1359
1359
  and api_scope_id == organization_id
1360
1360
  ):
1361
1361
  # Delete existing organization-level config before creating new one
1362
- delete_endpoint = f"{api_root}/scoped_configuration/delete"
1362
+ delete_endpoint = f"{config_api_root}/scoped_configuration/delete"
1363
1363
  delete_payload = {"scopedConfigurationId": existing_config["id"]}
1364
1364
 
1365
1365
  delete_response = requests.post(
@@ -1386,12 +1386,12 @@ def set_organization_connector_version_override(
1386
1386
  )
1387
1387
  origin = get_user_id_by_email(
1388
1388
  email=user_email,
1389
- api_root=api_root,
1389
+ config_api_root=config_api_root,
1390
1390
  bearer_token=access_token,
1391
1391
  )
1392
1392
 
1393
1393
  # Create the override
1394
- endpoint = f"{api_root}/scoped_configuration/create"
1394
+ endpoint = f"{config_api_root}/scoped_configuration/create"
1395
1395
  payload: dict[str, Any] = {
1396
1396
  "config_key": _ScopedConfigKey.CONNECTOR_VERSION.value,
1397
1397
  "resource_type": _ResourceType.ACTOR_DEFINITION.value,
@@ -122,6 +122,64 @@ class OrganizationAliasEnum(StrEnum):
122
122
  return alias_mapping[org_id]
123
123
 
124
124
 
125
+ # =============================================================================
126
+ # Workspace ID Aliases
127
+ # =============================================================================
128
+
129
+
130
+ class WorkspaceAliasEnum(StrEnum):
131
+ """Workspace ID aliases that can be used in place of UUIDs.
132
+
133
+ Each member's name is the alias (e.g., "@devin-ai-sandbox") and its value
134
+ is the actual workspace UUID. Use `WorkspaceAliasEnum.resolve()` to
135
+ resolve aliases to actual IDs.
136
+ """
137
+
138
+ DEVIN_AI_SANDBOX = "266ebdfe-0d7b-4540-9817-de7e4505ba61"
139
+ """The Devin AI sandbox workspace for testing and development.
140
+
141
+ Alias: @devin-ai-sandbox
142
+ """
143
+
144
+ @classmethod
145
+ def resolve(cls, workspace_id: str | None) -> str | None:
146
+ """Resolve a workspace ID alias to its actual UUID.
147
+
148
+ Accepts either an alias string (e.g., "@devin-ai-sandbox") or a
149
+ WorkspaceAliasEnum enum member, and returns the actual UUID.
150
+
151
+ Returns:
152
+ The resolved workspace ID (UUID), or None if input is None.
153
+ If the input doesn't start with "@", it is returned unchanged.
154
+
155
+ Raises:
156
+ PyAirbyteInputError: If the input starts with "@" but is not a recognized alias.
157
+ """
158
+ if workspace_id is None:
159
+ return None
160
+
161
+ # Handle WorkspaceAliasEnum enum members directly
162
+ if isinstance(workspace_id, cls):
163
+ return workspace_id.value
164
+
165
+ # If it doesn't look like an alias, return as-is (assume it's a UUID)
166
+ if not workspace_id.startswith("@"):
167
+ return workspace_id
168
+
169
+ # Handle alias strings or raise an error if invalid
170
+ alias_mapping = {
171
+ "@devin-ai-sandbox": cls.DEVIN_AI_SANDBOX.value,
172
+ }
173
+ if workspace_id not in alias_mapping:
174
+ raise PyAirbyteInputError(
175
+ message=f"Unknown workspace alias: {workspace_id}",
176
+ context={
177
+ "valid_aliases": list(alias_mapping.keys()),
178
+ },
179
+ )
180
+ return alias_mapping[workspace_id]
181
+
182
+
125
183
  CONNECTION_RETRIEVER_PG_CONNECTION_DETAILS_SECRET_ID = (
126
184
  "projects/587336813068/secrets/CONNECTION_RETRIEVER_PG_CONNECTION_DETAILS"
127
185
  )
@@ -1,6 +1,13 @@
1
1
  #
2
2
  # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
3
  #
4
+ """DockerHub API client with authentication, pagination, and retry support.
5
+
6
+ Provides utilities for interacting with the DockerHub API, including fetching
7
+ image tags and digests, checking image existence, and finding the latest version.
8
+ Supports authenticated requests to avoid rate limits and includes retry logic
9
+ for handling API flakiness.
10
+ """
4
11
 
5
12
  import os
6
13
  import time
@@ -95,17 +102,16 @@ def get_docker_hub_tags_and_digests(
95
102
  for result in json_response.get("results", [])
96
103
  }
97
104
  )
98
- if paginate:
99
- if next_page_url := json_response.get("next"):
100
- tags_and_digests.update(
101
- get_docker_hub_tags_and_digests(
102
- image_name,
103
- retries=retries,
104
- wait_sec=wait_sec,
105
- next_page_url=next_page_url,
106
- tags_and_digests=tags_and_digests,
107
- )
105
+ if paginate and (next_page_url := json_response.get("next")):
106
+ tags_and_digests.update(
107
+ get_docker_hub_tags_and_digests(
108
+ image_name,
109
+ retries=retries,
110
+ wait_sec=wait_sec,
111
+ next_page_url=next_page_url,
112
+ tags_and_digests=tags_and_digests,
108
113
  )
114
+ )
109
115
  return tags_and_digests
110
116
 
111
117