zenml-nightly 0.83.1.dev20250625__py3-none-any.whl → 0.83.1.dev20250626__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 (28) hide show
  1. zenml/VERSION +1 -1
  2. zenml/cli/base.py +3 -2
  3. zenml/cli/service_connectors.py +5 -12
  4. zenml/cli/stack.py +1 -5
  5. zenml/cli/utils.py +8 -52
  6. zenml/client.py +32 -40
  7. zenml/integrations/aws/container_registries/aws_container_registry.py +3 -1
  8. zenml/integrations/databricks/orchestrators/databricks_orchestrator_entrypoint_config.py +8 -3
  9. zenml/integrations/integration.py +23 -58
  10. zenml/models/__init__.py +2 -0
  11. zenml/models/v2/core/service_connector.py +178 -108
  12. zenml/service_connectors/service_connector.py +11 -61
  13. zenml/service_connectors/service_connector_utils.py +4 -2
  14. zenml/utils/package_utils.py +111 -1
  15. zenml/zen_server/routers/service_connectors_endpoints.py +7 -22
  16. zenml/zen_stores/migrations/versions/5bb25e95849c_add_internal_secrets.py +62 -0
  17. zenml/zen_stores/rest_zen_store.py +57 -4
  18. zenml/zen_stores/schemas/secret_schemas.py +5 -0
  19. zenml/zen_stores/schemas/service_connector_schemas.py +16 -14
  20. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +4 -1
  21. zenml/zen_stores/sql_zen_store.py +214 -102
  22. zenml/zen_stores/zen_store_interface.py +9 -1
  23. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/METADATA +1 -1
  24. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/RECORD +27 -27
  25. zenml/utils/integration_utils.py +0 -34
  26. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/LICENSE +0 -0
  27. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/WHEEL +0 -0
  28. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250626.dist-info}/entry_points.txt +0 -0
@@ -54,7 +54,6 @@ from packaging import version
54
54
  from pydantic import (
55
55
  ConfigDict,
56
56
  Field,
57
- SecretStr,
58
57
  SerializeAsAny,
59
58
  field_validator,
60
59
  model_validator,
@@ -264,6 +263,7 @@ from zenml.models import (
264
263
  ServiceAccountRequest,
265
264
  ServiceAccountResponse,
266
265
  ServiceAccountUpdate,
266
+ ServiceConnectorConfiguration,
267
267
  ServiceConnectorFilter,
268
268
  ServiceConnectorRequest,
269
269
  ServiceConnectorResourcesModel,
@@ -6743,6 +6743,40 @@ class SqlZenStore(BaseZenStore):
6743
6743
  if self.backup_secrets_store:
6744
6744
  self.backup_secrets_store.delete_secret_values(secret_id=secret_id)
6745
6745
 
6746
+ def _create_secret_schema(
6747
+ self, secret: SecretRequest, session: Session, internal: bool = False
6748
+ ) -> SecretSchema:
6749
+ """Creates a new secret schema.
6750
+
6751
+ Args:
6752
+ secret: The secret to create.
6753
+ session: The session to use.
6754
+ internal: Whether the secret is internal.
6755
+
6756
+ Returns:
6757
+ The newly created secret schema.
6758
+ """
6759
+ new_secret = SecretSchema.from_request(
6760
+ secret,
6761
+ internal=internal,
6762
+ )
6763
+ session.add(new_secret)
6764
+ session.commit()
6765
+
6766
+ try:
6767
+ # Set the secret values in the configured secrets store
6768
+ self._set_secret_values(
6769
+ secret_id=new_secret.id, values=secret.secret_values
6770
+ )
6771
+ except:
6772
+ # If setting the secret values fails, delete the secret from the
6773
+ # database.
6774
+ session.delete(new_secret)
6775
+ session.commit()
6776
+ raise
6777
+
6778
+ return new_secret
6779
+
6746
6780
  @track_decorator(AnalyticsEvent.CREATED_SECRET)
6747
6781
  def create_secret(self, secret: SecretRequest) -> SecretResponse:
6748
6782
  """Creates a new secret.
@@ -6777,31 +6811,17 @@ class SqlZenStore(BaseZenStore):
6777
6811
  if secret_exists:
6778
6812
  raise EntityExistsError(msg)
6779
6813
 
6780
- new_secret = SecretSchema.from_request(
6781
- secret,
6814
+ new_secret = self._create_secret_schema(
6815
+ secret=secret,
6816
+ session=session,
6782
6817
  )
6783
- session.add(new_secret)
6784
- session.commit()
6785
6818
 
6786
6819
  secret_model = new_secret.to_model(
6787
6820
  include_metadata=True, include_resources=True
6788
6821
  )
6789
6822
 
6790
- try:
6791
- # Set the secret values in the configured secrets store
6792
- self._set_secret_values(
6793
- secret_id=new_secret.id, values=secret.secret_values
6794
- )
6795
- except:
6796
- # If setting the secret values fails, delete the secret from the
6797
- # database.
6798
- with Session(self.engine) as session:
6799
- session.delete(new_secret)
6800
- session.commit()
6801
- raise
6802
-
6803
- secret_model.set_secrets(secret.secret_values)
6804
- return secret_model
6823
+ secret_model.set_secrets(secret.secret_values)
6824
+ return secret_model
6805
6825
 
6806
6826
  def get_secret(
6807
6827
  self, secret_id: UUID, hydrate: bool = True
@@ -6821,7 +6841,11 @@ class SqlZenStore(BaseZenStore):
6821
6841
  """
6822
6842
  with Session(self.engine) as session:
6823
6843
  secret_in_db = session.exec(
6824
- select(SecretSchema).where(SecretSchema.id == secret_id)
6844
+ select(SecretSchema).where(
6845
+ SecretSchema.id == secret_id,
6846
+ # Don't return internal secrets
6847
+ col(SecretSchema.internal).is_(False),
6848
+ )
6825
6849
  ).first()
6826
6850
  if (
6827
6851
  secret_in_db is None
@@ -6870,6 +6894,10 @@ class SqlZenStore(BaseZenStore):
6870
6894
  self._get_active_user(session).id
6871
6895
  )
6872
6896
  query = select(SecretSchema)
6897
+ # Don't return internal secrets
6898
+ query = query.where(
6899
+ col(SecretSchema.internal).is_(False),
6900
+ )
6873
6901
  return self.filter_and_paginate(
6874
6902
  session=session,
6875
6903
  query=query,
@@ -6910,7 +6938,11 @@ class SqlZenStore(BaseZenStore):
6910
6938
  """
6911
6939
  with Session(self.engine) as session:
6912
6940
  existing_secret = session.exec(
6913
- select(SecretSchema).where(SecretSchema.id == secret_id)
6941
+ select(SecretSchema).where(
6942
+ SecretSchema.id == secret_id,
6943
+ # Don't update internal secrets
6944
+ col(SecretSchema.internal).is_(False),
6945
+ )
6914
6946
  ).first()
6915
6947
 
6916
6948
  active_user = self._get_active_user(session)
@@ -6978,6 +7010,27 @@ class SqlZenStore(BaseZenStore):
6978
7010
 
6979
7011
  return secret_model
6980
7012
 
7013
+ def _delete_secret_schema(self, secret_id: UUID, session: Session) -> None:
7014
+ """Deletes a secret schema.
7015
+
7016
+ Args:
7017
+ secret_id: The ID of the secret to delete.
7018
+ session: The session to use.
7019
+ """
7020
+ # Delete the secret values in the configured secrets store
7021
+ try:
7022
+ self._delete_secret_values(secret_id=secret_id)
7023
+ except KeyError:
7024
+ # If the secret values don't exist in the secrets store, we don't
7025
+ # need to raise an error.
7026
+ pass
7027
+
7028
+ secret_in_db = session.exec(
7029
+ select(SecretSchema).where(SecretSchema.id == secret_id)
7030
+ ).one()
7031
+ session.delete(secret_in_db)
7032
+ session.commit()
7033
+
6981
7034
  def delete_secret(self, secret_id: UUID) -> None:
6982
7035
  """Delete a secret.
6983
7036
 
@@ -6989,7 +7042,11 @@ class SqlZenStore(BaseZenStore):
6989
7042
  """
6990
7043
  with Session(self.engine) as session:
6991
7044
  existing_secret = session.exec(
6992
- select(SecretSchema).where(SecretSchema.id == secret_id)
7045
+ select(SecretSchema).where(
7046
+ SecretSchema.id == secret_id,
7047
+ # Don't delete internal secrets
7048
+ col(SecretSchema.internal).is_(False),
7049
+ )
6993
7050
  ).first()
6994
7051
 
6995
7052
  if not existing_secret or (
@@ -7003,19 +7060,7 @@ class SqlZenStore(BaseZenStore):
7003
7060
  "not owned by the current user."
7004
7061
  )
7005
7062
 
7006
- # Delete the secret values in the configured secrets store
7007
- try:
7008
- self._delete_secret_values(secret_id=secret_id)
7009
- except KeyError:
7010
- # If the secret values don't exist in the secrets store, we don't
7011
- # need to raise an error.
7012
- pass
7013
-
7014
- secret_in_db = session.exec(
7015
- select(SecretSchema).where(SecretSchema.id == secret_id)
7016
- ).one()
7017
- session.delete(secret_in_db)
7018
- session.commit()
7063
+ self._delete_secret_schema(secret_id=secret_id, session=session)
7019
7064
 
7020
7065
  def backup_secrets(
7021
7066
  self, ignore_errors: bool = True, delete_secrets: bool = False
@@ -7379,7 +7424,6 @@ class SqlZenStore(BaseZenStore):
7379
7424
  resource_types=service_connector.resource_types,
7380
7425
  resource_id=service_connector.resource_id,
7381
7426
  configuration=service_connector.configuration,
7382
- secrets=service_connector.secrets,
7383
7427
  )
7384
7428
 
7385
7429
  with Session(self.engine) as session:
@@ -7397,7 +7441,8 @@ class SqlZenStore(BaseZenStore):
7397
7441
  # Create the secret
7398
7442
  secret_id = self._create_connector_secret(
7399
7443
  connector_name=service_connector.name,
7400
- secrets=service_connector.secrets,
7444
+ secrets=service_connector.configuration.secrets,
7445
+ session=session,
7401
7446
  )
7402
7447
  try:
7403
7448
  # Create the service connector
@@ -7425,12 +7470,20 @@ class SqlZenStore(BaseZenStore):
7425
7470
  connector = new_service_connector.to_model(
7426
7471
  include_metadata=True, include_resources=True
7427
7472
  )
7473
+ if new_service_connector.secret_id:
7474
+ secrets = self._get_secret_values(
7475
+ secret_id=new_service_connector.secret_id
7476
+ )
7477
+ connector.add_secrets(secrets)
7428
7478
  self._populate_connector_type(connector)
7429
7479
 
7430
7480
  return connector
7431
7481
 
7432
7482
  def get_service_connector(
7433
- self, service_connector_id: UUID, hydrate: bool = True
7483
+ self,
7484
+ service_connector_id: UUID,
7485
+ hydrate: bool = True,
7486
+ expand_secrets: bool = False,
7434
7487
  ) -> ServiceConnectorResponse:
7435
7488
  """Gets a specific service connector.
7436
7489
 
@@ -7438,6 +7491,8 @@ class SqlZenStore(BaseZenStore):
7438
7491
  service_connector_id: The ID of the service connector to get.
7439
7492
  hydrate: Flag deciding whether to hydrate the output model(s)
7440
7493
  by including metadata fields in the response.
7494
+ expand_secrets: Flag deciding whether to include the secrets in the
7495
+ output model.
7441
7496
 
7442
7497
  Returns:
7443
7498
  The requested service connector, if it was found.
@@ -7453,12 +7508,20 @@ class SqlZenStore(BaseZenStore):
7453
7508
  include_metadata=hydrate, include_resources=True
7454
7509
  )
7455
7510
  self._populate_connector_type(connector)
7511
+
7512
+ if expand_secrets and service_connector.secret_id:
7513
+ secrets = self._get_secret_values(
7514
+ secret_id=service_connector.secret_id
7515
+ )
7516
+ connector.add_secrets(secrets)
7517
+
7456
7518
  return connector
7457
7519
 
7458
7520
  def list_service_connectors(
7459
7521
  self,
7460
7522
  filter_model: ServiceConnectorFilter,
7461
7523
  hydrate: bool = False,
7524
+ expand_secrets: bool = False,
7462
7525
  ) -> Page[ServiceConnectorResponse]:
7463
7526
  """List all service connectors.
7464
7527
 
@@ -7467,6 +7530,8 @@ class SqlZenStore(BaseZenStore):
7467
7530
  params.
7468
7531
  hydrate: Flag deciding whether to hydrate the output model(s)
7469
7532
  by including metadata fields in the response.
7533
+ expand_secrets: Flag deciding whether to include the secrets in the
7534
+ output models.
7470
7535
 
7471
7536
  Returns:
7472
7537
  A page of all service connectors.
@@ -7499,6 +7564,27 @@ class SqlZenStore(BaseZenStore):
7499
7564
 
7500
7565
  return items
7501
7566
 
7567
+ def to_model_and_expand_secrets(
7568
+ schema: ServiceConnectorSchema,
7569
+ ) -> ServiceConnectorResponse:
7570
+ """Convert a service connector schema to a model and expand the secrets.
7571
+
7572
+ Args:
7573
+ schema: The service connector schema to convert.
7574
+
7575
+ Returns:
7576
+ The converted service connector model.
7577
+ """
7578
+ model = schema.to_model(
7579
+ include_metadata=hydrate, include_resources=True
7580
+ )
7581
+
7582
+ if expand_secrets and schema.secret_id:
7583
+ secrets = self._get_secret_values(secret_id=schema.secret_id)
7584
+ model.add_secrets(secrets)
7585
+
7586
+ return model
7587
+
7502
7588
  with Session(self.engine) as session:
7503
7589
  query = select(ServiceConnectorSchema)
7504
7590
  paged_connectors: Page[ServiceConnectorResponse] = (
@@ -7508,11 +7594,13 @@ class SqlZenStore(BaseZenStore):
7508
7594
  table=ServiceConnectorSchema,
7509
7595
  filter_model=filter_model,
7510
7596
  custom_fetch=fetch_connectors,
7597
+ custom_schema_to_model_conversion=to_model_and_expand_secrets,
7511
7598
  hydrate=hydrate,
7512
7599
  )
7513
7600
  )
7514
7601
 
7515
7602
  self._populate_connector_type(*paged_connectors.items)
7603
+
7516
7604
  return paged_connectors
7517
7605
 
7518
7606
  def update_service_connector(
@@ -7524,16 +7612,13 @@ class SqlZenStore(BaseZenStore):
7524
7612
  set to None in the model, the field is not updated, but there are
7525
7613
  special rules concerning some fields:
7526
7614
 
7527
- * the `configuration` and `secrets` fields together represent a full
7528
- valid configuration update, not just a partial update. If either is
7529
- set (i.e. not None) in the update, their values are merged together and
7530
- will replace the existing configuration and secrets values.
7615
+ * the `configuration` field represents a full valid configuration
7616
+ update, not just a partial update. If it is set (i.e. not None) in the
7617
+ update, its values will replace the existing configuration values.
7531
7618
  * the `resource_id` field value is also a full replacement value: if set
7532
7619
  to `None`, the resource ID is removed from the service connector.
7533
7620
  * the `expiration_seconds` field value is also a full replacement value:
7534
7621
  if set to `None`, the expiration is removed from the service connector.
7535
- * the `secret_id` field value in the update is ignored, given that
7536
- secrets are managed internally by the ZenML store.
7537
7622
  * the `labels` field is also a full labels update: if set (i.e. not
7538
7623
  `None`), all existing labels are removed and replaced by the new labels
7539
7624
  in the update.
@@ -7631,24 +7716,25 @@ class SqlZenStore(BaseZenStore):
7631
7716
  update.auth_method = (
7632
7717
  update.auth_method or existing_connector_model.auth_method
7633
7718
  )
7634
- # Validate the configuration update. If the configuration or
7635
- # secrets fields are set, together they are merged into a
7636
- # full configuration that is validated against the connector
7637
- # type schema and replaces the existing configuration and
7638
- # secrets values
7719
+ # Validate the configuration update. If the configuration is
7720
+ # set, it is validated against the connector type schema and
7721
+ # replaces the existing configuration values
7639
7722
  update.validate_and_configure_resources(
7640
7723
  connector_type=connector_type,
7641
7724
  resource_types=update.resource_types,
7642
7725
  resource_id=update.resource_id,
7643
7726
  configuration=update.configuration,
7644
- secrets=update.secrets,
7645
7727
  )
7646
7728
 
7647
- # Update secret
7648
- secret_id = self._update_connector_secret(
7649
- existing_connector=existing_connector_model,
7650
- updated_connector=update,
7651
- )
7729
+ secret_id = existing_connector.secret_id
7730
+ if update.configuration is not None:
7731
+ # Update secret
7732
+ secret_id = self._update_connector_secret(
7733
+ connector_name=existing_connector.name,
7734
+ existing_secret_id=existing_connector.secret_id,
7735
+ secrets=update.configuration.secrets,
7736
+ session=session,
7737
+ )
7652
7738
 
7653
7739
  existing_connector.update(
7654
7740
  connector_update=update, secret_id=secret_id
@@ -7659,6 +7745,10 @@ class SqlZenStore(BaseZenStore):
7659
7745
  connector = existing_connector.to_model(
7660
7746
  include_metadata=True, include_resources=True
7661
7747
  )
7748
+ if secret_id:
7749
+ secrets = self._get_secret_values(secret_id=secret_id)
7750
+ connector.add_secrets(secrets)
7751
+
7662
7752
  self._populate_connector_type(connector)
7663
7753
  return connector
7664
7754
 
@@ -7693,7 +7783,10 @@ class SqlZenStore(BaseZenStore):
7693
7783
 
7694
7784
  if service_connector.secret_id:
7695
7785
  try:
7696
- self.delete_secret(service_connector.secret_id)
7786
+ self._delete_secret_schema(
7787
+ secret_id=service_connector.secret_id,
7788
+ session=session,
7789
+ )
7697
7790
  except KeyError:
7698
7791
  # If the secret doesn't exist anymore, we can ignore
7699
7792
  # this error
@@ -7704,7 +7797,8 @@ class SqlZenStore(BaseZenStore):
7704
7797
  def _create_connector_secret(
7705
7798
  self,
7706
7799
  connector_name: str,
7707
- secrets: Optional[Dict[str, Optional[SecretStr]]],
7800
+ secrets: Dict[str, PlainSerializedSecretStr],
7801
+ session: Session,
7708
7802
  ) -> Optional[UUID]:
7709
7803
  """Creates a new secret to store the service connector secret credentials.
7710
7804
 
@@ -7712,6 +7806,7 @@ class SqlZenStore(BaseZenStore):
7712
7806
  connector_name: The name of the service connector for which to
7713
7807
  create a secret.
7714
7808
  secrets: The secret credentials to store.
7809
+ session: The session to use.
7715
7810
 
7716
7811
  Returns:
7717
7812
  The ID of the newly created secret or None, if the service connector
@@ -7729,19 +7824,23 @@ class SqlZenStore(BaseZenStore):
7729
7824
  # that is not already in use
7730
7825
  while True:
7731
7826
  secret_name = f"connector-{connector_name}-{random_str(4)}".lower()
7732
- existing_secrets = self.list_secrets(
7733
- SecretFilter(
7734
- name=secret_name,
7827
+ existing_secrets = session.exec(
7828
+ select(SecretSchema).where(
7829
+ SecretSchema.name == secret_name,
7735
7830
  )
7736
- )
7737
- if not existing_secrets.size:
7831
+ ).all()
7832
+ if not existing_secrets:
7738
7833
  try:
7739
- return self.create_secret(
7834
+ return self._create_secret_schema(
7740
7835
  SecretRequest(
7836
+ user=self._get_active_user(session=session).id,
7741
7837
  name=secret_name,
7742
7838
  private=False,
7743
7839
  values=secrets,
7744
- )
7840
+ ),
7841
+ session=session,
7842
+ # Hide service connector secrets from the user
7843
+ internal=True,
7745
7844
  ).id
7746
7845
  except KeyError:
7747
7846
  # The secret already exists, try again
@@ -7811,48 +7910,51 @@ class SqlZenStore(BaseZenStore):
7811
7910
 
7812
7911
  def _update_connector_secret(
7813
7912
  self,
7814
- existing_connector: ServiceConnectorResponse,
7815
- updated_connector: ServiceConnectorUpdate,
7913
+ connector_name: str,
7914
+ existing_secret_id: Optional[UUID],
7915
+ secrets: Dict[str, PlainSerializedSecretStr],
7916
+ session: Session,
7816
7917
  ) -> Optional[UUID]:
7817
7918
  """Updates the secret for a service connector.
7818
7919
 
7819
- If the secrets field in the service connector update is set (i.e. not
7820
- None), the existing secret, if any, is replaced. If the secrets field is
7821
- set to an empty dict, the existing secret is deleted.
7822
-
7823
7920
  Args:
7824
- existing_connector: Existing service connector for which to update a
7825
- secret.
7826
- updated_connector: Updated service connector.
7921
+ connector_name: The name of the service connector for which to
7922
+ update a secret.
7923
+ existing_secret_id: The ID of the existing secret to update, if one
7924
+ exists.
7925
+ secrets: The secrets to store.
7926
+ session: The session to use.
7827
7927
 
7828
7928
  Returns:
7829
7929
  The ID of the updated secret or None, if the new service connector
7830
7930
  does not contain any secret credentials.
7831
7931
  """
7832
- if updated_connector.secrets is None:
7833
- # If the connector update does not contain a secrets update, keep
7834
- # the existing secret (if any)
7835
- return existing_connector.secret_id
7836
-
7837
- # Delete the existing secret (if any), to be replaced by the new secret
7838
- if existing_connector.secret_id:
7839
- try:
7840
- self.delete_secret(existing_connector.secret_id)
7841
- except KeyError:
7842
- # Ignore if the secret no longer exists
7843
- pass
7844
-
7845
7932
  # If the new service connector does not contain any secret credentials,
7846
7933
  # return None
7847
- if not updated_connector.secrets:
7934
+ if not secrets:
7935
+ if existing_secret_id:
7936
+ try:
7937
+ self.delete_secret(existing_secret_id)
7938
+ except KeyError:
7939
+ # Ignore if the secret no longer exists
7940
+ pass
7848
7941
  return None
7849
7942
 
7850
- assert existing_connector.user is not None
7851
- # A secret does not exist yet, create a new one
7852
- return self._create_connector_secret(
7853
- connector_name=updated_connector.name or existing_connector.name,
7854
- secrets=updated_connector.secrets,
7943
+ if not existing_secret_id:
7944
+ # A secret does not exist yet, create a new one
7945
+ return self._create_connector_secret(
7946
+ connector_name=connector_name,
7947
+ secrets=secrets,
7948
+ session=session,
7949
+ )
7950
+
7951
+ # Update the existing secret - we only need to update the values
7952
+ self._update_secret_values(
7953
+ secret_id=existing_secret_id,
7954
+ values={k: v.get_secret_value() for k, v in secrets.items()},
7955
+ overwrite=True,
7855
7956
  )
7957
+ return existing_secret_id
7856
7958
 
7857
7959
  def verify_service_connector_config(
7858
7960
  self,
@@ -7896,7 +7998,9 @@ class SqlZenStore(BaseZenStore):
7896
7998
  The list of resources that the service connector has access to,
7897
7999
  scoped to the supplied resource type and ID, if provided.
7898
8000
  """
7899
- connector = self.get_service_connector(service_connector_id)
8001
+ connector = self.get_service_connector(
8002
+ service_connector_id, expand_secrets=True
8003
+ )
7900
8004
 
7901
8005
  connector_instance = service_connector_registry.instantiate_connector(
7902
8006
  model=connector
@@ -7925,7 +8029,9 @@ class SqlZenStore(BaseZenStore):
7925
8029
  A service connector client that can be used to access the given
7926
8030
  resource.
7927
8031
  """
7928
- connector = self.get_service_connector(service_connector_id)
8032
+ connector = self.get_service_connector(
8033
+ service_connector_id, expand_secrets=True
8034
+ )
7929
8035
 
7930
8036
  connector_instance = service_connector_registry.instantiate_connector(
7931
8037
  model=connector
@@ -8131,7 +8237,9 @@ class SqlZenStore(BaseZenStore):
8131
8237
  # Fetch an existing service connector
8132
8238
  if isinstance(connector_id_or_info, UUID):
8133
8239
  existing_service_connector = (
8134
- self.get_service_connector(connector_id_or_info)
8240
+ self.get_service_connector(
8241
+ connector_id_or_info, expand_secrets=True
8242
+ )
8135
8243
  )
8136
8244
  if need_to_generate_permanent_tokens:
8137
8245
  if (
@@ -8140,20 +8248,22 @@ class SqlZenStore(BaseZenStore):
8140
8248
  )
8141
8249
  is not False
8142
8250
  ):
8143
- connector_config = (
8144
- existing_service_connector.configuration
8145
- )
8251
+ connector_config = existing_service_connector.configuration.plain
8146
8252
  connector_config[
8147
8253
  "generate_temporary_tokens"
8148
8254
  ] = False
8149
8255
  self.update_service_connector(
8150
8256
  existing_service_connector.id,
8151
8257
  ServiceConnectorUpdate(
8152
- configuration=connector_config
8258
+ configuration=ServiceConnectorConfiguration(
8259
+ **connector_config
8260
+ )
8153
8261
  ),
8154
8262
  )
8155
8263
  service_connectors.append(
8156
- self.get_service_connector(connector_id_or_info)
8264
+ self.get_service_connector(
8265
+ connector_id_or_info, expand_secrets=True
8266
+ )
8157
8267
  )
8158
8268
  # Create a new service connector
8159
8269
  else:
@@ -8169,7 +8279,9 @@ class SqlZenStore(BaseZenStore):
8169
8279
  name=connector_name,
8170
8280
  connector_type=connector_id_or_info.type,
8171
8281
  auth_method=connector_id_or_info.auth_method,
8172
- configuration=connector_config,
8282
+ configuration=ServiceConnectorConfiguration(
8283
+ **connector_config
8284
+ ),
8173
8285
  labels={
8174
8286
  k: str(v)
8175
8287
  for k, v in stack.labels.items()
@@ -1980,7 +1980,10 @@ class ZenStoreInterface(ABC):
1980
1980
 
1981
1981
  @abstractmethod
1982
1982
  def get_service_connector(
1983
- self, service_connector_id: UUID, hydrate: bool = True
1983
+ self,
1984
+ service_connector_id: UUID,
1985
+ hydrate: bool = True,
1986
+ expand_secrets: bool = False,
1984
1987
  ) -> ServiceConnectorResponse:
1985
1988
  """Gets a specific service connector.
1986
1989
 
@@ -1988,6 +1991,8 @@ class ZenStoreInterface(ABC):
1988
1991
  service_connector_id: The ID of the service connector to get.
1989
1992
  hydrate: Flag deciding whether to hydrate the output model(s)
1990
1993
  by including metadata fields in the response.
1994
+ expand_secrets: Flag deciding whether to include the secrets
1995
+ associated with the service connector.
1991
1996
 
1992
1997
  Returns:
1993
1998
  The requested service connector, if it was found.
@@ -2001,6 +2006,7 @@ class ZenStoreInterface(ABC):
2001
2006
  self,
2002
2007
  filter_model: ServiceConnectorFilter,
2003
2008
  hydrate: bool = False,
2009
+ expand_secrets: bool = False,
2004
2010
  ) -> Page[ServiceConnectorResponse]:
2005
2011
  """List all service connectors.
2006
2012
 
@@ -2009,6 +2015,8 @@ class ZenStoreInterface(ABC):
2009
2015
  params.
2010
2016
  hydrate: Flag deciding whether to hydrate the output model(s)
2011
2017
  by including metadata fields in the response.
2018
+ expand_secrets: Flag deciding whether to include the secrets
2019
+ associated with the service connector.
2012
2020
 
2013
2021
  Returns:
2014
2022
  A page of all service connectors.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: zenml-nightly
3
- Version: 0.83.1.dev20250625
3
+ Version: 0.83.1.dev20250626
4
4
  Summary: ZenML: Write production-ready ML code.
5
5
  License: Apache-2.0
6
6
  Keywords: machine learning,production,pipeline,mlops,devops