zenml-nightly 0.83.1.dev20250625__py3-none-any.whl → 0.83.1.dev20250627__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 (33) 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 +40 -42
  7. zenml/integrations/aws/container_registries/aws_container_registry.py +3 -1
  8. zenml/integrations/aws/flavors/sagemaker_orchestrator_flavor.py +1 -1
  9. zenml/integrations/databricks/orchestrators/databricks_orchestrator_entrypoint_config.py +8 -3
  10. zenml/integrations/integration.py +23 -58
  11. zenml/models/__init__.py +2 -0
  12. zenml/models/v2/core/pipeline_run.py +1 -0
  13. zenml/models/v2/core/service_connector.py +178 -108
  14. zenml/service_connectors/service_connector.py +11 -61
  15. zenml/service_connectors/service_connector_utils.py +4 -2
  16. zenml/stack/stack_component.py +1 -1
  17. zenml/utils/package_utils.py +111 -1
  18. zenml/zen_server/routers/service_connectors_endpoints.py +7 -22
  19. zenml/zen_stores/migrations/versions/5bb25e95849c_add_internal_secrets.py +62 -0
  20. zenml/zen_stores/rest_zen_store.py +57 -4
  21. zenml/zen_stores/schemas/pipeline_run_schemas.py +10 -10
  22. zenml/zen_stores/schemas/secret_schemas.py +5 -0
  23. zenml/zen_stores/schemas/service_connector_schemas.py +16 -14
  24. zenml/zen_stores/schemas/step_run_schemas.py +44 -14
  25. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +4 -1
  26. zenml/zen_stores/sql_zen_store.py +238 -122
  27. zenml/zen_stores/zen_store_interface.py +9 -1
  28. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/METADATA +1 -1
  29. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/RECORD +32 -32
  30. zenml/utils/integration_utils.py +0 -34
  31. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/LICENSE +0 -0
  32. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/WHEEL +0 -0
  33. {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.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,
@@ -65,7 +64,7 @@ from sqlalchemy.exc import (
65
64
  ArgumentError,
66
65
  IntegrityError,
67
66
  )
68
- from sqlalchemy.orm import Mapped, joinedload, noload
67
+ from sqlalchemy.orm import Mapped, noload, selectinload
69
68
  from sqlalchemy.sql.base import ExecutableOption
70
69
  from sqlalchemy.util import immutabledict
71
70
  from sqlmodel import Session as SqlModelSession
@@ -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,
@@ -3037,18 +3037,17 @@ class SqlZenStore(BaseZenStore):
3037
3037
 
3038
3038
  if artifact is None:
3039
3039
  try:
3040
- with session.begin_nested():
3041
- artifact_request = ArtifactRequest(
3042
- name=name,
3043
- project=project_id,
3044
- has_custom_name=has_custom_name,
3045
- )
3046
- self._set_request_user_id(
3047
- request_model=artifact_request, session=session
3048
- )
3049
- artifact = ArtifactSchema.from_request(artifact_request)
3050
- session.add(artifact)
3051
- session.commit()
3040
+ artifact_request = ArtifactRequest(
3041
+ name=name,
3042
+ project=project_id,
3043
+ has_custom_name=has_custom_name,
3044
+ )
3045
+ self._set_request_user_id(
3046
+ request_model=artifact_request, session=session
3047
+ )
3048
+ artifact = ArtifactSchema.from_request(artifact_request)
3049
+ session.add(artifact)
3050
+ session.commit()
3052
3051
  session.refresh(artifact)
3053
3052
  except IntegrityError:
3054
3053
  # We have to rollback the failed session first in order to
@@ -3218,6 +3217,7 @@ class SqlZenStore(BaseZenStore):
3218
3217
  artifact_version_id=artifact_version_schema.id,
3219
3218
  )
3220
3219
  session.add(vis_schema)
3220
+ session.commit()
3221
3221
 
3222
3222
  # Save tags of the artifact
3223
3223
  self._attach_tags_to_resources(
@@ -5332,13 +5332,17 @@ class SqlZenStore(BaseZenStore):
5332
5332
  schema_class=PipelineRunSchema,
5333
5333
  session=session,
5334
5334
  query_options=[
5335
- joinedload(jl_arg(PipelineRunSchema.deployment)),
5336
- # joinedload(jl_arg(PipelineRunSchema.step_runs)).sele(
5337
- # jl_arg(StepRunSchema.input_artifacts)
5338
- # ),
5339
- # joinedload(jl_arg(PipelineRunSchema.step_runs)).joinedload(
5340
- # jl_arg(StepRunSchema.output_artifacts)
5341
- # ),
5335
+ selectinload(
5336
+ jl_arg(PipelineRunSchema.deployment)
5337
+ ).load_only(
5338
+ jl_arg(PipelineDeploymentSchema.pipeline_configuration)
5339
+ ),
5340
+ selectinload(
5341
+ jl_arg(PipelineRunSchema.step_runs)
5342
+ ).selectinload(jl_arg(StepRunSchema.input_artifacts)),
5343
+ selectinload(
5344
+ jl_arg(PipelineRunSchema.step_runs)
5345
+ ).selectinload(jl_arg(StepRunSchema.output_artifacts)),
5342
5346
  ],
5343
5347
  )
5344
5348
  assert run.deployment is not None
@@ -6743,6 +6747,40 @@ class SqlZenStore(BaseZenStore):
6743
6747
  if self.backup_secrets_store:
6744
6748
  self.backup_secrets_store.delete_secret_values(secret_id=secret_id)
6745
6749
 
6750
+ def _create_secret_schema(
6751
+ self, secret: SecretRequest, session: Session, internal: bool = False
6752
+ ) -> SecretSchema:
6753
+ """Creates a new secret schema.
6754
+
6755
+ Args:
6756
+ secret: The secret to create.
6757
+ session: The session to use.
6758
+ internal: Whether the secret is internal.
6759
+
6760
+ Returns:
6761
+ The newly created secret schema.
6762
+ """
6763
+ new_secret = SecretSchema.from_request(
6764
+ secret,
6765
+ internal=internal,
6766
+ )
6767
+ session.add(new_secret)
6768
+ session.commit()
6769
+
6770
+ try:
6771
+ # Set the secret values in the configured secrets store
6772
+ self._set_secret_values(
6773
+ secret_id=new_secret.id, values=secret.secret_values
6774
+ )
6775
+ except:
6776
+ # If setting the secret values fails, delete the secret from the
6777
+ # database.
6778
+ session.delete(new_secret)
6779
+ session.commit()
6780
+ raise
6781
+
6782
+ return new_secret
6783
+
6746
6784
  @track_decorator(AnalyticsEvent.CREATED_SECRET)
6747
6785
  def create_secret(self, secret: SecretRequest) -> SecretResponse:
6748
6786
  """Creates a new secret.
@@ -6777,31 +6815,17 @@ class SqlZenStore(BaseZenStore):
6777
6815
  if secret_exists:
6778
6816
  raise EntityExistsError(msg)
6779
6817
 
6780
- new_secret = SecretSchema.from_request(
6781
- secret,
6818
+ new_secret = self._create_secret_schema(
6819
+ secret=secret,
6820
+ session=session,
6782
6821
  )
6783
- session.add(new_secret)
6784
- session.commit()
6785
6822
 
6786
6823
  secret_model = new_secret.to_model(
6787
6824
  include_metadata=True, include_resources=True
6788
6825
  )
6789
6826
 
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
6827
+ secret_model.set_secrets(secret.secret_values)
6828
+ return secret_model
6805
6829
 
6806
6830
  def get_secret(
6807
6831
  self, secret_id: UUID, hydrate: bool = True
@@ -6821,7 +6845,11 @@ class SqlZenStore(BaseZenStore):
6821
6845
  """
6822
6846
  with Session(self.engine) as session:
6823
6847
  secret_in_db = session.exec(
6824
- select(SecretSchema).where(SecretSchema.id == secret_id)
6848
+ select(SecretSchema).where(
6849
+ SecretSchema.id == secret_id,
6850
+ # Don't return internal secrets
6851
+ col(SecretSchema.internal).is_(False),
6852
+ )
6825
6853
  ).first()
6826
6854
  if (
6827
6855
  secret_in_db is None
@@ -6870,6 +6898,10 @@ class SqlZenStore(BaseZenStore):
6870
6898
  self._get_active_user(session).id
6871
6899
  )
6872
6900
  query = select(SecretSchema)
6901
+ # Don't return internal secrets
6902
+ query = query.where(
6903
+ col(SecretSchema.internal).is_(False),
6904
+ )
6873
6905
  return self.filter_and_paginate(
6874
6906
  session=session,
6875
6907
  query=query,
@@ -6910,7 +6942,11 @@ class SqlZenStore(BaseZenStore):
6910
6942
  """
6911
6943
  with Session(self.engine) as session:
6912
6944
  existing_secret = session.exec(
6913
- select(SecretSchema).where(SecretSchema.id == secret_id)
6945
+ select(SecretSchema).where(
6946
+ SecretSchema.id == secret_id,
6947
+ # Don't update internal secrets
6948
+ col(SecretSchema.internal).is_(False),
6949
+ )
6914
6950
  ).first()
6915
6951
 
6916
6952
  active_user = self._get_active_user(session)
@@ -6978,6 +7014,27 @@ class SqlZenStore(BaseZenStore):
6978
7014
 
6979
7015
  return secret_model
6980
7016
 
7017
+ def _delete_secret_schema(self, secret_id: UUID, session: Session) -> None:
7018
+ """Deletes a secret schema.
7019
+
7020
+ Args:
7021
+ secret_id: The ID of the secret to delete.
7022
+ session: The session to use.
7023
+ """
7024
+ # Delete the secret values in the configured secrets store
7025
+ try:
7026
+ self._delete_secret_values(secret_id=secret_id)
7027
+ except KeyError:
7028
+ # If the secret values don't exist in the secrets store, we don't
7029
+ # need to raise an error.
7030
+ pass
7031
+
7032
+ secret_in_db = session.exec(
7033
+ select(SecretSchema).where(SecretSchema.id == secret_id)
7034
+ ).one()
7035
+ session.delete(secret_in_db)
7036
+ session.commit()
7037
+
6981
7038
  def delete_secret(self, secret_id: UUID) -> None:
6982
7039
  """Delete a secret.
6983
7040
 
@@ -6989,7 +7046,11 @@ class SqlZenStore(BaseZenStore):
6989
7046
  """
6990
7047
  with Session(self.engine) as session:
6991
7048
  existing_secret = session.exec(
6992
- select(SecretSchema).where(SecretSchema.id == secret_id)
7049
+ select(SecretSchema).where(
7050
+ SecretSchema.id == secret_id,
7051
+ # Don't delete internal secrets
7052
+ col(SecretSchema.internal).is_(False),
7053
+ )
6993
7054
  ).first()
6994
7055
 
6995
7056
  if not existing_secret or (
@@ -7003,19 +7064,7 @@ class SqlZenStore(BaseZenStore):
7003
7064
  "not owned by the current user."
7004
7065
  )
7005
7066
 
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()
7067
+ self._delete_secret_schema(secret_id=secret_id, session=session)
7019
7068
 
7020
7069
  def backup_secrets(
7021
7070
  self, ignore_errors: bool = True, delete_secrets: bool = False
@@ -7379,7 +7428,6 @@ class SqlZenStore(BaseZenStore):
7379
7428
  resource_types=service_connector.resource_types,
7380
7429
  resource_id=service_connector.resource_id,
7381
7430
  configuration=service_connector.configuration,
7382
- secrets=service_connector.secrets,
7383
7431
  )
7384
7432
 
7385
7433
  with Session(self.engine) as session:
@@ -7397,7 +7445,8 @@ class SqlZenStore(BaseZenStore):
7397
7445
  # Create the secret
7398
7446
  secret_id = self._create_connector_secret(
7399
7447
  connector_name=service_connector.name,
7400
- secrets=service_connector.secrets,
7448
+ secrets=service_connector.configuration.secrets,
7449
+ session=session,
7401
7450
  )
7402
7451
  try:
7403
7452
  # Create the service connector
@@ -7425,12 +7474,20 @@ class SqlZenStore(BaseZenStore):
7425
7474
  connector = new_service_connector.to_model(
7426
7475
  include_metadata=True, include_resources=True
7427
7476
  )
7477
+ if new_service_connector.secret_id:
7478
+ secrets = self._get_secret_values(
7479
+ secret_id=new_service_connector.secret_id
7480
+ )
7481
+ connector.add_secrets(secrets)
7428
7482
  self._populate_connector_type(connector)
7429
7483
 
7430
7484
  return connector
7431
7485
 
7432
7486
  def get_service_connector(
7433
- self, service_connector_id: UUID, hydrate: bool = True
7487
+ self,
7488
+ service_connector_id: UUID,
7489
+ hydrate: bool = True,
7490
+ expand_secrets: bool = False,
7434
7491
  ) -> ServiceConnectorResponse:
7435
7492
  """Gets a specific service connector.
7436
7493
 
@@ -7438,6 +7495,8 @@ class SqlZenStore(BaseZenStore):
7438
7495
  service_connector_id: The ID of the service connector to get.
7439
7496
  hydrate: Flag deciding whether to hydrate the output model(s)
7440
7497
  by including metadata fields in the response.
7498
+ expand_secrets: Flag deciding whether to include the secrets in the
7499
+ output model.
7441
7500
 
7442
7501
  Returns:
7443
7502
  The requested service connector, if it was found.
@@ -7453,12 +7512,20 @@ class SqlZenStore(BaseZenStore):
7453
7512
  include_metadata=hydrate, include_resources=True
7454
7513
  )
7455
7514
  self._populate_connector_type(connector)
7515
+
7516
+ if expand_secrets and service_connector.secret_id:
7517
+ secrets = self._get_secret_values(
7518
+ secret_id=service_connector.secret_id
7519
+ )
7520
+ connector.add_secrets(secrets)
7521
+
7456
7522
  return connector
7457
7523
 
7458
7524
  def list_service_connectors(
7459
7525
  self,
7460
7526
  filter_model: ServiceConnectorFilter,
7461
7527
  hydrate: bool = False,
7528
+ expand_secrets: bool = False,
7462
7529
  ) -> Page[ServiceConnectorResponse]:
7463
7530
  """List all service connectors.
7464
7531
 
@@ -7467,6 +7534,8 @@ class SqlZenStore(BaseZenStore):
7467
7534
  params.
7468
7535
  hydrate: Flag deciding whether to hydrate the output model(s)
7469
7536
  by including metadata fields in the response.
7537
+ expand_secrets: Flag deciding whether to include the secrets in the
7538
+ output models.
7470
7539
 
7471
7540
  Returns:
7472
7541
  A page of all service connectors.
@@ -7499,6 +7568,27 @@ class SqlZenStore(BaseZenStore):
7499
7568
 
7500
7569
  return items
7501
7570
 
7571
+ def to_model_and_expand_secrets(
7572
+ schema: ServiceConnectorSchema,
7573
+ ) -> ServiceConnectorResponse:
7574
+ """Convert a service connector schema to a model and expand the secrets.
7575
+
7576
+ Args:
7577
+ schema: The service connector schema to convert.
7578
+
7579
+ Returns:
7580
+ The converted service connector model.
7581
+ """
7582
+ model = schema.to_model(
7583
+ include_metadata=hydrate, include_resources=True
7584
+ )
7585
+
7586
+ if expand_secrets and schema.secret_id:
7587
+ secrets = self._get_secret_values(secret_id=schema.secret_id)
7588
+ model.add_secrets(secrets)
7589
+
7590
+ return model
7591
+
7502
7592
  with Session(self.engine) as session:
7503
7593
  query = select(ServiceConnectorSchema)
7504
7594
  paged_connectors: Page[ServiceConnectorResponse] = (
@@ -7508,11 +7598,13 @@ class SqlZenStore(BaseZenStore):
7508
7598
  table=ServiceConnectorSchema,
7509
7599
  filter_model=filter_model,
7510
7600
  custom_fetch=fetch_connectors,
7601
+ custom_schema_to_model_conversion=to_model_and_expand_secrets,
7511
7602
  hydrate=hydrate,
7512
7603
  )
7513
7604
  )
7514
7605
 
7515
7606
  self._populate_connector_type(*paged_connectors.items)
7607
+
7516
7608
  return paged_connectors
7517
7609
 
7518
7610
  def update_service_connector(
@@ -7524,16 +7616,13 @@ class SqlZenStore(BaseZenStore):
7524
7616
  set to None in the model, the field is not updated, but there are
7525
7617
  special rules concerning some fields:
7526
7618
 
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.
7619
+ * the `configuration` field represents a full valid configuration
7620
+ update, not just a partial update. If it is set (i.e. not None) in the
7621
+ update, its values will replace the existing configuration values.
7531
7622
  * the `resource_id` field value is also a full replacement value: if set
7532
7623
  to `None`, the resource ID is removed from the service connector.
7533
7624
  * the `expiration_seconds` field value is also a full replacement value:
7534
7625
  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
7626
  * the `labels` field is also a full labels update: if set (i.e. not
7538
7627
  `None`), all existing labels are removed and replaced by the new labels
7539
7628
  in the update.
@@ -7631,24 +7720,25 @@ class SqlZenStore(BaseZenStore):
7631
7720
  update.auth_method = (
7632
7721
  update.auth_method or existing_connector_model.auth_method
7633
7722
  )
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
7723
+ # Validate the configuration update. If the configuration is
7724
+ # set, it is validated against the connector type schema and
7725
+ # replaces the existing configuration values
7639
7726
  update.validate_and_configure_resources(
7640
7727
  connector_type=connector_type,
7641
7728
  resource_types=update.resource_types,
7642
7729
  resource_id=update.resource_id,
7643
7730
  configuration=update.configuration,
7644
- secrets=update.secrets,
7645
7731
  )
7646
7732
 
7647
- # Update secret
7648
- secret_id = self._update_connector_secret(
7649
- existing_connector=existing_connector_model,
7650
- updated_connector=update,
7651
- )
7733
+ secret_id = existing_connector.secret_id
7734
+ if update.configuration is not None:
7735
+ # Update secret
7736
+ secret_id = self._update_connector_secret(
7737
+ connector_name=existing_connector.name,
7738
+ existing_secret_id=existing_connector.secret_id,
7739
+ secrets=update.configuration.secrets,
7740
+ session=session,
7741
+ )
7652
7742
 
7653
7743
  existing_connector.update(
7654
7744
  connector_update=update, secret_id=secret_id
@@ -7659,6 +7749,10 @@ class SqlZenStore(BaseZenStore):
7659
7749
  connector = existing_connector.to_model(
7660
7750
  include_metadata=True, include_resources=True
7661
7751
  )
7752
+ if secret_id:
7753
+ secrets = self._get_secret_values(secret_id=secret_id)
7754
+ connector.add_secrets(secrets)
7755
+
7662
7756
  self._populate_connector_type(connector)
7663
7757
  return connector
7664
7758
 
@@ -7693,7 +7787,10 @@ class SqlZenStore(BaseZenStore):
7693
7787
 
7694
7788
  if service_connector.secret_id:
7695
7789
  try:
7696
- self.delete_secret(service_connector.secret_id)
7790
+ self._delete_secret_schema(
7791
+ secret_id=service_connector.secret_id,
7792
+ session=session,
7793
+ )
7697
7794
  except KeyError:
7698
7795
  # If the secret doesn't exist anymore, we can ignore
7699
7796
  # this error
@@ -7704,7 +7801,8 @@ class SqlZenStore(BaseZenStore):
7704
7801
  def _create_connector_secret(
7705
7802
  self,
7706
7803
  connector_name: str,
7707
- secrets: Optional[Dict[str, Optional[SecretStr]]],
7804
+ secrets: Dict[str, PlainSerializedSecretStr],
7805
+ session: Session,
7708
7806
  ) -> Optional[UUID]:
7709
7807
  """Creates a new secret to store the service connector secret credentials.
7710
7808
 
@@ -7712,6 +7810,7 @@ class SqlZenStore(BaseZenStore):
7712
7810
  connector_name: The name of the service connector for which to
7713
7811
  create a secret.
7714
7812
  secrets: The secret credentials to store.
7813
+ session: The session to use.
7715
7814
 
7716
7815
  Returns:
7717
7816
  The ID of the newly created secret or None, if the service connector
@@ -7729,19 +7828,23 @@ class SqlZenStore(BaseZenStore):
7729
7828
  # that is not already in use
7730
7829
  while True:
7731
7830
  secret_name = f"connector-{connector_name}-{random_str(4)}".lower()
7732
- existing_secrets = self.list_secrets(
7733
- SecretFilter(
7734
- name=secret_name,
7831
+ existing_secrets = session.exec(
7832
+ select(SecretSchema).where(
7833
+ SecretSchema.name == secret_name,
7735
7834
  )
7736
- )
7737
- if not existing_secrets.size:
7835
+ ).all()
7836
+ if not existing_secrets:
7738
7837
  try:
7739
- return self.create_secret(
7838
+ return self._create_secret_schema(
7740
7839
  SecretRequest(
7840
+ user=self._get_active_user(session=session).id,
7741
7841
  name=secret_name,
7742
7842
  private=False,
7743
7843
  values=secrets,
7744
- )
7844
+ ),
7845
+ session=session,
7846
+ # Hide service connector secrets from the user
7847
+ internal=True,
7745
7848
  ).id
7746
7849
  except KeyError:
7747
7850
  # The secret already exists, try again
@@ -7811,48 +7914,51 @@ class SqlZenStore(BaseZenStore):
7811
7914
 
7812
7915
  def _update_connector_secret(
7813
7916
  self,
7814
- existing_connector: ServiceConnectorResponse,
7815
- updated_connector: ServiceConnectorUpdate,
7917
+ connector_name: str,
7918
+ existing_secret_id: Optional[UUID],
7919
+ secrets: Dict[str, PlainSerializedSecretStr],
7920
+ session: Session,
7816
7921
  ) -> Optional[UUID]:
7817
7922
  """Updates the secret for a service connector.
7818
7923
 
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
7924
  Args:
7824
- existing_connector: Existing service connector for which to update a
7825
- secret.
7826
- updated_connector: Updated service connector.
7925
+ connector_name: The name of the service connector for which to
7926
+ update a secret.
7927
+ existing_secret_id: The ID of the existing secret to update, if one
7928
+ exists.
7929
+ secrets: The secrets to store.
7930
+ session: The session to use.
7827
7931
 
7828
7932
  Returns:
7829
7933
  The ID of the updated secret or None, if the new service connector
7830
7934
  does not contain any secret credentials.
7831
7935
  """
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
7936
  # If the new service connector does not contain any secret credentials,
7846
7937
  # return None
7847
- if not updated_connector.secrets:
7938
+ if not secrets:
7939
+ if existing_secret_id:
7940
+ try:
7941
+ self.delete_secret(existing_secret_id)
7942
+ except KeyError:
7943
+ # Ignore if the secret no longer exists
7944
+ pass
7848
7945
  return None
7849
7946
 
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,
7947
+ if not existing_secret_id:
7948
+ # A secret does not exist yet, create a new one
7949
+ return self._create_connector_secret(
7950
+ connector_name=connector_name,
7951
+ secrets=secrets,
7952
+ session=session,
7953
+ )
7954
+
7955
+ # Update the existing secret - we only need to update the values
7956
+ self._update_secret_values(
7957
+ secret_id=existing_secret_id,
7958
+ values={k: v.get_secret_value() for k, v in secrets.items()},
7959
+ overwrite=True,
7855
7960
  )
7961
+ return existing_secret_id
7856
7962
 
7857
7963
  def verify_service_connector_config(
7858
7964
  self,
@@ -7896,7 +8002,9 @@ class SqlZenStore(BaseZenStore):
7896
8002
  The list of resources that the service connector has access to,
7897
8003
  scoped to the supplied resource type and ID, if provided.
7898
8004
  """
7899
- connector = self.get_service_connector(service_connector_id)
8005
+ connector = self.get_service_connector(
8006
+ service_connector_id, expand_secrets=True
8007
+ )
7900
8008
 
7901
8009
  connector_instance = service_connector_registry.instantiate_connector(
7902
8010
  model=connector
@@ -7925,7 +8033,9 @@ class SqlZenStore(BaseZenStore):
7925
8033
  A service connector client that can be used to access the given
7926
8034
  resource.
7927
8035
  """
7928
- connector = self.get_service_connector(service_connector_id)
8036
+ connector = self.get_service_connector(
8037
+ service_connector_id, expand_secrets=True
8038
+ )
7929
8039
 
7930
8040
  connector_instance = service_connector_registry.instantiate_connector(
7931
8041
  model=connector
@@ -8131,7 +8241,9 @@ class SqlZenStore(BaseZenStore):
8131
8241
  # Fetch an existing service connector
8132
8242
  if isinstance(connector_id_or_info, UUID):
8133
8243
  existing_service_connector = (
8134
- self.get_service_connector(connector_id_or_info)
8244
+ self.get_service_connector(
8245
+ connector_id_or_info, expand_secrets=True
8246
+ )
8135
8247
  )
8136
8248
  if need_to_generate_permanent_tokens:
8137
8249
  if (
@@ -8140,20 +8252,22 @@ class SqlZenStore(BaseZenStore):
8140
8252
  )
8141
8253
  is not False
8142
8254
  ):
8143
- connector_config = (
8144
- existing_service_connector.configuration
8145
- )
8255
+ connector_config = existing_service_connector.configuration.plain
8146
8256
  connector_config[
8147
8257
  "generate_temporary_tokens"
8148
8258
  ] = False
8149
8259
  self.update_service_connector(
8150
8260
  existing_service_connector.id,
8151
8261
  ServiceConnectorUpdate(
8152
- configuration=connector_config
8262
+ configuration=ServiceConnectorConfiguration(
8263
+ **connector_config
8264
+ )
8153
8265
  ),
8154
8266
  )
8155
8267
  service_connectors.append(
8156
- self.get_service_connector(connector_id_or_info)
8268
+ self.get_service_connector(
8269
+ connector_id_or_info, expand_secrets=True
8270
+ )
8157
8271
  )
8158
8272
  # Create a new service connector
8159
8273
  else:
@@ -8169,7 +8283,9 @@ class SqlZenStore(BaseZenStore):
8169
8283
  name=connector_name,
8170
8284
  connector_type=connector_id_or_info.type,
8171
8285
  auth_method=connector_id_or_info.auth_method,
8172
- configuration=connector_config,
8286
+ configuration=ServiceConnectorConfiguration(
8287
+ **connector_config
8288
+ ),
8173
8289
  labels={
8174
8290
  k: str(v)
8175
8291
  for k, v in stack.labels.items()