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
@@ -16,9 +16,15 @@
16
16
  import json
17
17
  from datetime import datetime
18
18
  from typing import Any, ClassVar, Dict, List, Optional, Union
19
- from uuid import UUID
20
19
 
21
- from pydantic import Field, SecretStr, ValidationError, model_validator
20
+ from pydantic import (
21
+ Field,
22
+ GetCoreSchemaHandler,
23
+ SecretStr,
24
+ ValidationError,
25
+ model_validator,
26
+ )
27
+ from pydantic_core import CoreSchema, core_schema
22
28
 
23
29
  from zenml.constants import STR_FIELD_MAX_LENGTH
24
30
  from zenml.logger import get_logger
@@ -38,6 +44,120 @@ from zenml.utils.secret_utils import PlainSerializedSecretStr
38
44
 
39
45
  logger = get_logger(__name__)
40
46
 
47
+ # ------------------ Configuration Model ------------------
48
+
49
+
50
+ class ServiceConnectorConfiguration(Dict[str, Any]):
51
+ """Model for service connector configuration."""
52
+
53
+ @classmethod
54
+ def from_dict(
55
+ cls, data: Dict[str, Any]
56
+ ) -> "ServiceConnectorConfiguration":
57
+ """Create a configuration model from a dictionary.
58
+
59
+ Args:
60
+ data: The dictionary to create the configuration model from.
61
+
62
+ Returns:
63
+ A configuration model.
64
+ """
65
+ return cls(**data)
66
+
67
+ @property
68
+ def secrets(self) -> Dict[str, PlainSerializedSecretStr]:
69
+ """Get the secrets from the configuration.
70
+
71
+ Returns:
72
+ A dictionary of secrets.
73
+ """
74
+ return {k: v for k, v in self.items() if isinstance(v, SecretStr)}
75
+
76
+ @property
77
+ def plain_secrets(self) -> Dict[str, str]:
78
+ """Get the plain secrets from the configuration.
79
+
80
+ Returns:
81
+ A dictionary of secrets.
82
+ """
83
+ return {
84
+ k: v.get_secret_value()
85
+ for k, v in self.items()
86
+ if isinstance(v, SecretStr)
87
+ }
88
+
89
+ @property
90
+ def non_secrets(self) -> Dict[str, Any]:
91
+ """Get the non-secrets from the configuration.
92
+
93
+ Returns:
94
+ A dictionary of non-secrets.
95
+ """
96
+ return {k: v for k, v in self.items() if not isinstance(v, SecretStr)}
97
+
98
+ @property
99
+ def plain(self) -> Dict[str, Any]:
100
+ """Get the configuration with secrets unpacked.
101
+
102
+ Returns:
103
+ A dictionary of configuration with secrets unpacked.
104
+ """
105
+ return {
106
+ k: v.get_secret_value() if isinstance(v, SecretStr) else v
107
+ for k, v in self.items()
108
+ }
109
+
110
+ def get_plain(self, key: str, default: Any = None) -> Any:
111
+ """Get the plain value for the given key.
112
+
113
+ Args:
114
+ key: The key to get the value for.
115
+ default: The default value to return if the key is not found.
116
+
117
+ Returns:
118
+ The plain value for the given key.
119
+ """
120
+ result = self.get(key, default)
121
+ if isinstance(result, SecretStr):
122
+ return result.get_secret_value()
123
+ return result
124
+
125
+ def add_secrets(self, secrets: Dict[str, str]) -> None:
126
+ """Add the secrets to the configuration.
127
+
128
+ Args:
129
+ secrets: The secrets to add to the configuration.
130
+ """
131
+ self.update({k: SecretStr(v) for k, v in secrets.items()})
132
+
133
+ @classmethod
134
+ def __get_pydantic_core_schema__(
135
+ cls, source_type: Any, handler: GetCoreSchemaHandler
136
+ ) -> CoreSchema:
137
+ """Additional method for pydantic to recognize it as a valid type.
138
+
139
+ Args:
140
+ source_type: the source type
141
+ handler: the handler
142
+
143
+ Returns:
144
+ the schema for the custom type.
145
+ """
146
+ return core_schema.no_info_after_validator_function(
147
+ cls,
148
+ handler(
149
+ core_schema.dict_schema(
150
+ keys_schema=core_schema.str_schema(),
151
+ values_schema=core_schema.any_schema(),
152
+ )
153
+ ),
154
+ serialization=core_schema.plain_serializer_function_ser_schema(
155
+ lambda v: v.plain,
156
+ when_used="json",
157
+ ),
158
+ )
159
+
160
+
41
161
  # ------------------ Request Model ------------------
42
162
 
43
163
 
@@ -97,13 +217,9 @@ class ServiceConnectorRequest(UserScopedRequest):
97
217
  "connectors and authentication methods that involve generating "
98
218
  "temporary credentials from the ones configured in the connector.",
99
219
  )
100
- configuration: Dict[str, Any] = Field(
101
- default_factory=dict,
102
- title="The service connector configuration, not including secrets.",
103
- )
104
- secrets: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
105
- default_factory=dict,
106
- title="The service connector secrets.",
220
+ configuration: ServiceConnectorConfiguration = Field(
221
+ default_factory=ServiceConnectorConfiguration,
222
+ title="The service connector configuration.",
107
223
  )
108
224
  labels: Dict[str, str] = Field(
109
225
  default_factory=dict,
@@ -178,7 +294,6 @@ class ServiceConnectorRequest(UserScopedRequest):
178
294
  resource_types: Optional[Union[str, List[str]]] = None,
179
295
  resource_id: Optional[str] = None,
180
296
  configuration: Optional[Dict[str, Any]] = None,
181
- secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
182
297
  ) -> None:
183
298
  """Validate and configure the resources that the connector can be used to access.
184
299
 
@@ -191,7 +306,6 @@ class ServiceConnectorRequest(UserScopedRequest):
191
306
  resource_id: Uniquely identifies a specific resource instance that
192
307
  the connector instance can be used to access.
193
308
  configuration: The connector configuration.
194
- secrets: The connector secrets.
195
309
  """
196
310
  _validate_and_configure_resources(
197
311
  connector=self,
@@ -199,7 +313,6 @@ class ServiceConnectorRequest(UserScopedRequest):
199
313
  resource_types=resource_types,
200
314
  resource_id=resource_id,
201
315
  configuration=configuration,
202
- secrets=secrets,
203
316
  )
204
317
 
205
318
 
@@ -219,10 +332,9 @@ class ServiceConnectorUpdate(BaseUpdate):
219
332
 
220
333
  In addition to the above exceptions, the following rules apply:
221
334
 
222
- * the `configuration` and `secrets` fields together represent a full
223
- valid configuration update, not just a partial update. If either is
224
- set (i.e. not None) in the update, their values are merged together and
225
- will replace the existing configuration and secrets values.
335
+ * the `configuration` field represents a full valid configuration update,
336
+ not just a partial update. If it is set (i.e. not None) in the update,
337
+ its values will replace the existing configuration values.
226
338
  * the `labels` field is also a full labels update: if set (i.e. not
227
339
  `None`), all existing labels are removed and replaced by the new labels
228
340
  in the update.
@@ -289,12 +401,8 @@ class ServiceConnectorUpdate(BaseUpdate):
289
401
  "configured in the connector.",
290
402
  default=None,
291
403
  )
292
- configuration: Optional[Dict[str, Any]] = Field(
293
- title="The service connector configuration, not including secrets.",
294
- default=None,
295
- )
296
- secrets: Optional[Dict[str, Optional[PlainSerializedSecretStr]]] = Field(
297
- title="The service connector secrets.",
404
+ configuration: Optional[ServiceConnectorConfiguration] = Field(
405
+ title="The service connector full configuration replacement.",
298
406
  default=None,
299
407
  )
300
408
  labels: Optional[Dict[str, str]] = Field(
@@ -348,7 +456,6 @@ class ServiceConnectorUpdate(BaseUpdate):
348
456
  resource_types: Optional[Union[str, List[str]]] = None,
349
457
  resource_id: Optional[str] = None,
350
458
  configuration: Optional[Dict[str, Any]] = None,
351
- secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
352
459
  ) -> None:
353
460
  """Validate and configure the resources that the connector can be used to access.
354
461
 
@@ -361,7 +468,6 @@ class ServiceConnectorUpdate(BaseUpdate):
361
468
  resource_id: Uniquely identifies a specific resource instance that
362
469
  the connector instance can be used to access.
363
470
  configuration: The connector configuration.
364
- secrets: The connector secrets.
365
471
  """
366
472
  _validate_and_configure_resources(
367
473
  connector=self,
@@ -369,7 +475,6 @@ class ServiceConnectorUpdate(BaseUpdate):
369
475
  resource_types=resource_types,
370
476
  resource_id=resource_id,
371
477
  configuration=configuration,
372
- secrets=secrets,
373
478
  )
374
479
 
375
480
  def convert_to_request(self) -> "ServiceConnectorRequest":
@@ -447,14 +552,9 @@ class ServiceConnectorResponseBody(UserScopedResponseBody):
447
552
  class ServiceConnectorResponseMetadata(UserScopedResponseMetadata):
448
553
  """Response metadata for service connectors."""
449
554
 
450
- configuration: Dict[str, Any] = Field(
451
- default_factory=dict,
452
- title="The service connector configuration, not including secrets.",
453
- )
454
- secret_id: Optional[UUID] = Field(
455
- default=None,
456
- title="The ID of the secret that contains the service connector "
457
- "secret configuration values.",
555
+ configuration: ServiceConnectorConfiguration = Field(
556
+ default_factory=ServiceConnectorConfiguration,
557
+ title="The service connector configuration.",
458
558
  )
459
559
  expiration_seconds: Optional[int] = Field(
460
560
  default=None,
@@ -463,10 +563,6 @@ class ServiceConnectorResponseMetadata(UserScopedResponseMetadata):
463
563
  "connectors and authentication methods that involve generating "
464
564
  "temporary credentials from the ones configured in the connector.",
465
565
  )
466
- secrets: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
467
- default_factory=dict,
468
- title="The service connector secrets.",
469
- )
470
566
  labels: Dict[str, str] = Field(
471
567
  default_factory=dict,
472
568
  title="Service connector labels.",
@@ -604,19 +700,6 @@ class ServiceConnectorResponse(
604
700
  """
605
701
  return not self.is_multi_type and not self.is_multi_instance
606
702
 
607
- @property
608
- def full_configuration(self) -> Dict[str, str]:
609
- """Get the full connector configuration, including secrets.
610
-
611
- Returns:
612
- The full connector configuration, including secrets.
613
- """
614
- config = self.configuration.copy()
615
- config.update(
616
- {k: v.get_secret_value() for k, v in self.secrets.items() if v}
617
- )
618
- return config
619
-
620
703
  def set_connector_type(
621
704
  self, value: Union[str, "ServiceConnectorTypeModel"]
622
705
  ) -> None:
@@ -627,13 +710,22 @@ class ServiceConnectorResponse(
627
710
  """
628
711
  self.get_body().connector_type = value
629
712
 
713
+ def validate_configuration(self) -> None:
714
+ """Validate the configuration of the connector."""
715
+ if isinstance(self.connector_type, ServiceConnectorTypeModel):
716
+ self.validate_and_configure_resources(
717
+ connector_type=self.connector_type,
718
+ resource_types=self.resource_types,
719
+ resource_id=self.resource_id,
720
+ configuration=self.configuration,
721
+ )
722
+
630
723
  def validate_and_configure_resources(
631
724
  self,
632
725
  connector_type: "ServiceConnectorTypeModel",
633
726
  resource_types: Optional[Union[str, List[str]]] = None,
634
727
  resource_id: Optional[str] = None,
635
728
  configuration: Optional[Dict[str, Any]] = None,
636
- secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
637
729
  ) -> None:
638
730
  """Validate and configure the resources that the connector can be used to access.
639
731
 
@@ -646,7 +738,6 @@ class ServiceConnectorResponse(
646
738
  resource_id: Uniquely identifies a specific resource instance that
647
739
  the connector instance can be used to access.
648
740
  configuration: The connector configuration.
649
- secrets: The connector secrets.
650
741
  """
651
742
  _validate_and_configure_resources(
652
743
  connector=self,
@@ -654,7 +745,6 @@ class ServiceConnectorResponse(
654
745
  resource_types=resource_types,
655
746
  resource_id=resource_id,
656
747
  configuration=configuration,
657
- secrets=secrets,
658
748
  )
659
749
 
660
750
  # Body and metadata properties
@@ -731,7 +821,7 @@ class ServiceConnectorResponse(
731
821
  return self.get_body().expires_skew_tolerance
732
822
 
733
823
  @property
734
- def configuration(self) -> Dict[str, Any]:
824
+ def configuration(self) -> ServiceConnectorConfiguration:
735
825
  """The `configuration` property.
736
826
 
737
827
  Returns:
@@ -739,14 +829,20 @@ class ServiceConnectorResponse(
739
829
  """
740
830
  return self.get_metadata().configuration
741
831
 
742
- @property
743
- def secret_id(self) -> Optional[UUID]:
744
- """The `secret_id` property.
832
+ def remove_secrets(self) -> None:
833
+ """Remove the secrets from the configuration."""
834
+ metadata = self.get_metadata()
835
+ metadata.configuration = ServiceConnectorConfiguration(
836
+ **metadata.configuration.non_secrets
837
+ )
745
838
 
746
- Returns:
747
- the value of the property.
839
+ def add_secrets(self, secrets: Dict[str, str]) -> None:
840
+ """Add the secrets to the configuration.
841
+
842
+ Args:
843
+ secrets: The secrets to add to the configuration.
748
844
  """
749
- return self.get_metadata().secret_id
845
+ self.get_metadata().configuration.add_secrets(secrets)
750
846
 
751
847
  @property
752
848
  def expiration_seconds(self) -> Optional[int]:
@@ -757,15 +853,6 @@ class ServiceConnectorResponse(
757
853
  """
758
854
  return self.get_metadata().expiration_seconds
759
855
 
760
- @property
761
- def secrets(self) -> Dict[str, Optional[SecretStr]]:
762
- """The `secrets` property.
763
-
764
- Returns:
765
- the value of the property.
766
- """
767
- return self.get_metadata().secrets
768
-
769
856
  @property
770
857
  def labels(self) -> Dict[str, str]:
771
858
  """The `labels` property.
@@ -826,12 +913,6 @@ class ServiceConnectorFilter(UserScopedFilter):
826
913
  "value, the filter will match all service connectors that have that "
827
914
  "label present, regardless of value.",
828
915
  )
829
- secret_id: Optional[Union[UUID, str]] = Field(
830
- default=None,
831
- title="Filter by the ID of the secret that contains the service "
832
- "connector's credentials",
833
- union_mode="left_to_right",
834
- )
835
916
 
836
917
  # Use this internally to configure and access the labels as a dictionary
837
918
  labels: Optional[Dict[str, Optional[str]]] = Field(
@@ -877,7 +958,6 @@ def _validate_and_configure_resources(
877
958
  resource_types: Optional[Union[str, List[str]]] = None,
878
959
  resource_id: Optional[str] = None,
879
960
  configuration: Optional[Dict[str, Any]] = None,
880
- secrets: Optional[Dict[str, Optional[SecretStr]]] = None,
881
961
  ) -> None:
882
962
  """Validate and configure the resources that a connector can be used to access.
883
963
 
@@ -891,7 +971,6 @@ def _validate_and_configure_resources(
891
971
  resource_id: Uniquely identifies a specific resource instance that
892
972
  the connector instance can be used to access.
893
973
  configuration: The connector configuration.
894
- secrets: The connector secrets.
895
974
 
896
975
  Raises:
897
976
  ValueError: If the connector configuration is not valid.
@@ -970,16 +1049,14 @@ def _validate_and_configure_resources(
970
1049
  )
971
1050
  update_connector_body.supports_instances = False
972
1051
 
973
- if configuration is None and secrets is None:
974
- # No configuration or secrets provided
1052
+ if configuration is None:
1053
+ # No configuration provided
975
1054
  return
976
1055
 
977
- update_connector_metadata.configuration = {}
978
- update_connector_metadata.secrets = {}
1056
+ update_connector_metadata.configuration = ServiceConnectorConfiguration()
979
1057
 
980
- # Validate and configure the connector configuration and secrets
1058
+ # Validate and configure the connector configuration
981
1059
  configuration = configuration or {}
982
- secrets = secrets or {}
983
1060
  supported_attrs = []
984
1061
  for attr_name, attr_schema in auth_method_spec.config_schema.get(
985
1062
  "properties", {}
@@ -1009,7 +1086,10 @@ def _validate_and_configure_resources(
1009
1086
  secret = attr_schema.get("format", "") == "password"
1010
1087
  attr_type = attr_schema.get("type", "string")
1011
1088
 
1012
- value = configuration.get(attr_name, secrets.get(attr_name))
1089
+ value = configuration.get(attr_name)
1090
+ if isinstance(value, SecretStr):
1091
+ value = value.get_secret_value()
1092
+
1013
1093
  if required:
1014
1094
  if value is None:
1015
1095
  raise ValueError(
@@ -1019,19 +1099,21 @@ def _validate_and_configure_resources(
1019
1099
  elif value is None:
1020
1100
  continue
1021
1101
 
1022
- # Split the configuration into secrets and non-secrets
1023
1102
  if secret:
1024
- if isinstance(value, SecretStr):
1025
- update_connector_metadata.secrets[attr_name] = value
1026
- else:
1027
- update_connector_metadata.secrets[attr_name] = SecretStr(value)
1028
- else:
1029
- if attr_type == "array" and isinstance(value, str):
1030
- try:
1031
- value = json.loads(value)
1032
- except json.decoder.JSONDecodeError:
1033
- value = value.split(",")
1034
- update_connector_metadata.configuration[attr_name] = value
1103
+ if not isinstance(value, str):
1104
+ raise ValueError(
1105
+ f"connector configuration is not valid: attribute '{attr_name}' "
1106
+ "is a secret but is not a string"
1107
+ )
1108
+ value = SecretStr(value)
1109
+
1110
+ elif attr_type == "array" and isinstance(value, str):
1111
+ try:
1112
+ value = json.loads(value)
1113
+ except json.decoder.JSONDecodeError:
1114
+ value = value.split(",")
1115
+
1116
+ update_connector_metadata.configuration[attr_name] = value
1035
1117
 
1036
1118
  # Warn about attributes that are not part of the configuration schema
1037
1119
  for attr_name in set(list(configuration.keys())) - set(supported_attrs):
@@ -1040,15 +1122,3 @@ def _validate_and_configure_resources(
1040
1122
  f"configuration {attr_name}. Supported attributes are: "
1041
1123
  f"{supported_attrs}",
1042
1124
  )
1043
- # Warn about secrets that are not part of the configuration schema
1044
- connector_secrets = (
1045
- set(connector.secrets.keys())
1046
- if connector.secrets is not None
1047
- else set()
1048
- )
1049
- for attr_name in set(secrets.keys()) - connector_secrets:
1050
- logger.warning(
1051
- f"Ignoring unknown attribute in connector '{connector.name}' "
1052
- f"configuration {attr_name}. Supported attributes are: "
1053
- f"{supported_attrs}",
1054
- )
@@ -31,12 +31,10 @@ from uuid import UUID
31
31
 
32
32
  from pydantic import (
33
33
  BaseModel,
34
- SecretStr,
35
34
  ValidationError,
36
35
  )
37
36
  from pydantic._internal._model_construction import ModelMetaclass
38
37
 
39
- from zenml.client import Client
40
38
  from zenml.constants import (
41
39
  ENV_ZENML_ENABLE_IMPLICIT_AUTH_METHODS,
42
40
  SERVICE_CONNECTOR_SKEW_TOLERANCE_SECONDS,
@@ -63,32 +61,6 @@ logger = get_logger(__name__)
63
61
  class AuthenticationConfig(BaseModel):
64
62
  """Base authentication configuration."""
65
63
 
66
- @property
67
- def secret_values(self) -> Dict[str, SecretStr]:
68
- """Get the secret values as a dictionary.
69
-
70
- Returns:
71
- A dictionary of all secret values in the configuration.
72
- """
73
- return {
74
- k: v
75
- for k, v in self.model_dump(exclude_none=True).items()
76
- if isinstance(v, SecretStr)
77
- }
78
-
79
- @property
80
- def non_secret_values(self) -> Dict[str, str]:
81
- """Get the non-secret values as a dictionary.
82
-
83
- Returns:
84
- A dictionary of all non-secret values in the configuration.
85
- """
86
- return {
87
- k: v
88
- for k, v in self.model_dump(exclude_none=True).items()
89
- if not isinstance(v, SecretStr)
90
- }
91
-
92
64
  @property
93
65
  def all_values(self) -> Dict[str, Any]:
94
66
  """Get all values as a dictionary.
@@ -643,34 +615,7 @@ class ServiceConnector(BaseModel, metaclass=ServiceConnectorMeta):
643
615
  ) from e
644
616
 
645
617
  # Unpack the authentication configuration
646
- config = model.configuration.copy()
647
- if isinstance(model, ServiceConnectorResponse) and model.secret_id:
648
- try:
649
- secret = Client().get_secret(model.secret_id)
650
- except KeyError as e:
651
- raise ValueError(
652
- f"could not fetch secret with ID '{model.secret_id}' "
653
- f"referenced in the connector configuration: {e}"
654
- ) from e
655
-
656
- if secret.has_missing_values:
657
- raise ValueError(
658
- f"secret with ID '{model.secret_id}' referenced in the "
659
- "connector configuration has missing values. This can "
660
- "happen for example if your user lacks the permissions "
661
- "required to access the secret."
662
- )
663
-
664
- config.update(secret.secret_values)
665
-
666
- if model.secrets:
667
- config.update(
668
- {
669
- k: v.get_secret_value()
670
- for k, v in model.secrets.items()
671
- if v
672
- }
673
- )
618
+ config = model.configuration.plain
674
619
 
675
620
  if method_spec.config_class is None:
676
621
  raise ValueError(
@@ -683,8 +628,15 @@ class ServiceConnector(BaseModel, metaclass=ServiceConnectorMeta):
683
628
  try:
684
629
  auth_config = method_spec.config_class(**config)
685
630
  except ValidationError as e:
631
+ hint = ""
632
+ if isinstance(model, ServiceConnectorResponse):
633
+ hint = (
634
+ "If the error is related to missing secret attributes, "
635
+ "you might be missing permissions to access the service "
636
+ "connector's secret values."
637
+ )
686
638
  raise ValueError(
687
- f"connector configuration is not valid: {e}"
639
+ f"connector configuration is not valid: {e}\n{hint}"
688
640
  ) from e
689
641
 
690
642
  assert isinstance(auth_config, AuthenticationConfig)
@@ -748,8 +700,7 @@ class ServiceConnector(BaseModel, metaclass=ServiceConnectorMeta):
748
700
  connector_type=spec,
749
701
  resource_types=self.resource_type,
750
702
  resource_id=self.resource_id,
751
- configuration=self.config.non_secret_values,
752
- secrets=self.config.secret_values, # type: ignore[arg-type]
703
+ configuration=self.config.all_values,
753
704
  )
754
705
 
755
706
  return model
@@ -815,8 +766,7 @@ class ServiceConnector(BaseModel, metaclass=ServiceConnectorMeta):
815
766
  connector_type=spec,
816
767
  resource_types=self.resource_type,
817
768
  resource_id=self.resource_id,
818
- configuration=self.config.non_secret_values,
819
- secrets=self.config.secret_values, # type: ignore[arg-type]
769
+ configuration=self.config.all_values,
820
770
  )
821
771
 
822
772
  return model
@@ -20,6 +20,7 @@ from zenml.client import Client
20
20
  from zenml.enums import StackComponentType
21
21
  from zenml.models import (
22
22
  ResourcesInfo,
23
+ ServiceConnectorConfiguration,
23
24
  ServiceConnectorInfo,
24
25
  ServiceConnectorRequest,
25
26
  ServiceConnectorResourcesInfo,
@@ -187,8 +188,9 @@ def get_resources_options_from_resource_model_for_full_stack(
187
188
  name="fake",
188
189
  connector_type=connector_details.type,
189
190
  auth_method=connector_details.auth_method,
190
- configuration=connector_details.configuration,
191
- secrets={},
191
+ configuration=ServiceConnectorConfiguration(
192
+ **connector_details.configuration
193
+ ),
192
194
  labels={},
193
195
  ),
194
196
  list_resources=True,
@@ -527,7 +527,7 @@ class StackComponent:
527
527
  )
528
528
 
529
529
  # Use the current config as a base
530
- settings_dict = self.config.model_dump()
530
+ settings_dict = self.config.model_dump(exclude_unset=True)
531
531
 
532
532
  if key in all_settings:
533
533
  settings_dict.update(dict(all_settings[key]))