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.
- zenml/VERSION +1 -1
- zenml/cli/base.py +3 -2
- zenml/cli/service_connectors.py +5 -12
- zenml/cli/stack.py +1 -5
- zenml/cli/utils.py +8 -52
- zenml/client.py +40 -42
- zenml/integrations/aws/container_registries/aws_container_registry.py +3 -1
- zenml/integrations/aws/flavors/sagemaker_orchestrator_flavor.py +1 -1
- zenml/integrations/databricks/orchestrators/databricks_orchestrator_entrypoint_config.py +8 -3
- zenml/integrations/integration.py +23 -58
- zenml/models/__init__.py +2 -0
- zenml/models/v2/core/pipeline_run.py +1 -0
- zenml/models/v2/core/service_connector.py +178 -108
- zenml/service_connectors/service_connector.py +11 -61
- zenml/service_connectors/service_connector_utils.py +4 -2
- zenml/stack/stack_component.py +1 -1
- zenml/utils/package_utils.py +111 -1
- zenml/zen_server/routers/service_connectors_endpoints.py +7 -22
- zenml/zen_stores/migrations/versions/5bb25e95849c_add_internal_secrets.py +62 -0
- zenml/zen_stores/rest_zen_store.py +57 -4
- zenml/zen_stores/schemas/pipeline_run_schemas.py +10 -10
- zenml/zen_stores/schemas/secret_schemas.py +5 -0
- zenml/zen_stores/schemas/service_connector_schemas.py +16 -14
- zenml/zen_stores/schemas/step_run_schemas.py +44 -14
- zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +4 -1
- zenml/zen_stores/sql_zen_store.py +238 -122
- zenml/zen_stores/zen_store_interface.py +9 -1
- {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/METADATA +1 -1
- {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/RECORD +32 -32
- zenml/utils/integration_utils.py +0 -34
- {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.83.1.dev20250625.dist-info → zenml_nightly-0.83.1.dev20250627.dist-info}/WHEEL +0 -0
- {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,
|
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
|
-
|
3041
|
-
|
3042
|
-
|
3043
|
-
|
3044
|
-
|
3045
|
-
|
3046
|
-
|
3047
|
-
|
3048
|
-
|
3049
|
-
|
3050
|
-
|
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
|
-
|
5336
|
-
|
5337
|
-
|
5338
|
-
|
5339
|
-
|
5340
|
-
|
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 =
|
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
|
-
|
6791
|
-
|
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(
|
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(
|
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(
|
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
|
-
|
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,
|
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`
|
7528
|
-
|
7529
|
-
|
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
|
7635
|
-
#
|
7636
|
-
#
|
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
|
-
|
7648
|
-
|
7649
|
-
|
7650
|
-
|
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.
|
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:
|
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 =
|
7733
|
-
|
7734
|
-
name
|
7831
|
+
existing_secrets = session.exec(
|
7832
|
+
select(SecretSchema).where(
|
7833
|
+
SecretSchema.name == secret_name,
|
7735
7834
|
)
|
7736
|
-
)
|
7737
|
-
if not existing_secrets
|
7835
|
+
).all()
|
7836
|
+
if not existing_secrets:
|
7738
7837
|
try:
|
7739
|
-
return self.
|
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
|
-
|
7815
|
-
|
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
|
-
|
7825
|
-
secret.
|
7826
|
-
|
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
|
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
|
-
|
7851
|
-
|
7852
|
-
|
7853
|
-
|
7854
|
-
|
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(
|
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(
|
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(
|
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=
|
8262
|
+
configuration=ServiceConnectorConfiguration(
|
8263
|
+
**connector_config
|
8264
|
+
)
|
8153
8265
|
),
|
8154
8266
|
)
|
8155
8267
|
service_connectors.append(
|
8156
|
-
self.get_service_connector(
|
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=
|
8286
|
+
configuration=ServiceConnectorConfiguration(
|
8287
|
+
**connector_config
|
8288
|
+
),
|
8173
8289
|
labels={
|
8174
8290
|
k: str(v)
|
8175
8291
|
for k, v in stack.labels.items()
|