orchestrator-core 4.0.4__py3-none-any.whl → 4.1.0rc1__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.
orchestrator/__init__.py CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  """This is the orchestrator workflow engine."""
15
15
 
16
- __version__ = "4.0.4"
16
+ __version__ = "4.1.0rc1"
17
17
 
18
18
  from orchestrator.app import OrchestratorCore
19
19
  from orchestrator.settings import app_settings
@@ -22,11 +22,17 @@ from sqlalchemy.exc import SQLAlchemyError
22
22
  from oauth2_lib.fastapi import OIDCUserModel
23
23
  from orchestrator.api.error_handling import raise_status
24
24
  from orchestrator.db import EngineSettingsTable
25
- from orchestrator.schemas import EngineSettingsBaseSchema, EngineSettingsSchema, WorkerStatus
25
+ from orchestrator.schemas import (
26
+ EngineSettingsBaseSchema,
27
+ EngineSettingsSchema,
28
+ WorkerStatus,
29
+ )
26
30
  from orchestrator.security import authenticate
27
31
  from orchestrator.services import processes, settings
28
32
  from orchestrator.services.settings import generate_engine_global_status
33
+ from orchestrator.services.settings_env_variables import get_all_exposed_settings
29
34
  from orchestrator.settings import ExecutorType, app_settings
35
+ from orchestrator.utils.expose_settings import SettingsExposedSchema
30
36
  from orchestrator.utils.json import json_dumps
31
37
  from orchestrator.utils.redis import delete_keys_matching_pattern
32
38
  from orchestrator.utils.redis_client import create_redis_asyncio_client
@@ -169,3 +175,8 @@ def generate_engine_status_response(
169
175
  result = EngineSettingsSchema.model_validate(engine_settings)
170
176
  result.global_status = generate_engine_global_status(engine_settings)
171
177
  return result
178
+
179
+
180
+ @router.get("/overview", response_model=list[SettingsExposedSchema])
181
+ def get_exposed_settings() -> list[SettingsExposedSchema]:
182
+ return get_all_exposed_settings()
@@ -0,0 +1,68 @@
1
+ # Copyright 2019-2025 SURF.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
14
+ from typing import Any, Dict, Type
15
+
16
+ from pydantic import SecretStr as PydanticSecretStr
17
+ from pydantic_core import MultiHostUrl
18
+ from pydantic_settings import BaseSettings
19
+
20
+ from orchestrator.utils.expose_settings import SecretStr as OrchSecretStr
21
+ from orchestrator.utils.expose_settings import SettingsEnvVariablesSchema, SettingsExposedSchema
22
+
23
+ EXPOSED_ENV_SETTINGS_REGISTRY: Dict[str, Type[BaseSettings]] = {}
24
+ MASK = "**********"
25
+
26
+
27
+ def expose_settings(settings_name: str, base_settings: Type[BaseSettings]) -> Type[BaseSettings]:
28
+ """Decorator to register settings classes."""
29
+ EXPOSED_ENV_SETTINGS_REGISTRY[settings_name] = base_settings
30
+ return base_settings
31
+
32
+
33
+ def mask_value(key: str, value: Any) -> Any:
34
+ key_lower = key.lower()
35
+
36
+ if "secret" in key_lower or "password" in key_lower:
37
+ # Mask sensitive information
38
+ return MASK
39
+
40
+ if isinstance(value, PydanticSecretStr):
41
+ # Need to convert SecretStr to str for serialization
42
+ return str(value)
43
+
44
+ if isinstance(value, OrchSecretStr):
45
+ return MASK
46
+
47
+ # PostgresDsn is just MultiHostUrl with extra metadata (annotations)
48
+ if isinstance(value, MultiHostUrl):
49
+ # Convert PostgresDsn to str for serialization
50
+ return MASK
51
+
52
+ return value
53
+
54
+
55
+ def get_all_exposed_settings() -> list[SettingsExposedSchema]:
56
+ """Return all registered settings as dicts."""
57
+
58
+ def _get_settings_env_variables(base_settings: Type[BaseSettings]) -> list[SettingsEnvVariablesSchema]:
59
+ """Get environment variables from settings."""
60
+ return [
61
+ SettingsEnvVariablesSchema(env_name=key, env_value=mask_value(key, value))
62
+ for key, value in base_settings.model_dump().items() # type: ignore
63
+ ]
64
+
65
+ return [
66
+ SettingsExposedSchema(name=name, variables=_get_settings_env_variables(base_settings))
67
+ for name, base_settings in EXPOSED_ENV_SETTINGS_REGISTRY.items()
68
+ ]
orchestrator/settings.py CHANGED
@@ -20,6 +20,8 @@ from pydantic import Field, NonNegativeInt, PostgresDsn, RedisDsn
20
20
  from pydantic_settings import BaseSettings
21
21
 
22
22
  from oauth2_lib.settings import oauth2lib_settings
23
+ from orchestrator.services.settings_env_variables import expose_settings
24
+ from orchestrator.utils.expose_settings import SecretStr as OrchSecretStr
23
25
  from pydantic_forms.types import strEnum
24
26
 
25
27
 
@@ -30,7 +32,7 @@ class ExecutorType(strEnum):
30
32
 
31
33
  class AppSettings(BaseSettings):
32
34
  TESTING: bool = True
33
- SESSION_SECRET: str = "".join(secrets.choice(string.ascii_letters) for i in range(16)) # noqa: S311
35
+ SESSION_SECRET: OrchSecretStr = "".join(secrets.choice(string.ascii_letters) for i in range(16)) # type: ignore
34
36
  CORS_ORIGINS: str = "*"
35
37
  CORS_ALLOW_METHODS: list[str] = ["GET", "PUT", "PATCH", "POST", "DELETE", "OPTIONS", "HEAD"]
36
38
  CORS_ALLOW_HEADERS: list[str] = ["If-None-Match", "Authorization", "If-Match", "Content-Type"]
@@ -55,7 +57,7 @@ class AppSettings(BaseSettings):
55
57
  MAIL_PORT: int = 25
56
58
  MAIL_STARTTLS: bool = False
57
59
  CACHE_URI: RedisDsn = "redis://localhost:6379/0" # type: ignore
58
- CACHE_HMAC_SECRET: str | None = None # HMAC signing key, used when pickling results in the cache
60
+ CACHE_HMAC_SECRET: OrchSecretStr | None = None # HMAC signing key, used when pickling results in the cache
59
61
  REDIS_RETRY_COUNT: NonNegativeInt = Field(
60
62
  2, description="Number of retries for redis connection errors/timeouts, 0 to disable"
61
63
  ) # More info: https://redis-py.readthedocs.io/en/stable/retry.html
@@ -87,6 +89,8 @@ class AppSettings(BaseSettings):
87
89
  ENABLE_PROMETHEUS_METRICS_ENDPOINT: bool = False
88
90
  VALIDATE_OUT_OF_SYNC_SUBSCRIPTIONS: bool = False
89
91
  FILTER_BY_MODE: Literal["partial", "exact"] = "exact"
92
+ EXPOSE_SETTINGS: bool = False
93
+ EXPOSE_OAUTH_SETTINGS: bool = False
90
94
 
91
95
 
92
96
  app_settings = AppSettings()
@@ -94,3 +98,8 @@ app_settings = AppSettings()
94
98
  # Set oauth2lib_settings variables to the same (default) value of settings
95
99
  oauth2lib_settings.SERVICE_NAME = app_settings.SERVICE_NAME
96
100
  oauth2lib_settings.ENVIRONMENT = app_settings.ENVIRONMENT
101
+
102
+ if app_settings.EXPOSE_SETTINGS:
103
+ expose_settings("app_settings", app_settings) # type: ignore
104
+ if app_settings.EXPOSE_OAUTH_SETTINGS:
105
+ expose_settings("oauth2lib_settings", oauth2lib_settings) # type: ignore
@@ -0,0 +1,45 @@
1
+ # Copyright 2019-2025 SURF.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ """Utility module for exposing settings in a structured format.
14
+
15
+ Unfortunately, this module needs to be imported from the utils and cannot be added to the schemas folder.
16
+ This is due to circular import issues with the combination of schemas/settings.
17
+ """
18
+
19
+ from typing import Any
20
+
21
+ from pydantic import BaseModel
22
+ from pydantic_core import core_schema
23
+
24
+
25
+ class SecretStr(str):
26
+ """A string that is treated as a secret, for example, passwords or API keys.
27
+
28
+ This class is used to indicate that the string should not be logged or displayed in plaintext.
29
+ """
30
+
31
+ @classmethod
32
+ def __get_pydantic_core_schema__(cls, source_type, handler): # type: ignore
33
+ # This method is used to define how the SecretStr type should be handled by Pydantic.
34
+ # With this implementation, it will fail validation.
35
+ return core_schema.no_info_plain_validator_function(cls)
36
+
37
+
38
+ class SettingsEnvVariablesSchema(BaseModel):
39
+ env_name: str
40
+ env_value: Any
41
+
42
+
43
+ class SettingsExposedSchema(BaseModel):
44
+ name: str
45
+ variables: list[SettingsEnvVariablesSchema]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orchestrator-core
3
- Version: 4.0.4
3
+ Version: 4.1.0rc1
4
4
  Summary: This is the orchestrator workflow engine.
5
5
  Requires-Python: >=3.11,<3.14
6
6
  Classifier: Intended Audience :: Information Technology
@@ -1,10 +1,10 @@
1
- orchestrator/__init__.py,sha256=YVe09WczpF4MK2XPRNEAfLMjIE3YCIBlDRgfibiP9U8,1063
1
+ orchestrator/__init__.py,sha256=tOY8a4U2sGqlMaBFFS05G5fpTsG5MQWrMraMt7i-SW0,1066
2
2
  orchestrator/app.py,sha256=7UrXKjBKNSEaSSXAd5ww_RdMFhFqE4yvfj8faS2MzAA,12089
3
3
  orchestrator/exception_handlers.py,sha256=UsW3dw8q0QQlNLcV359bIotah8DYjMsj2Ts1LfX4ClY,1268
4
4
  orchestrator/log_config.py,sha256=1tPRX5q65e57a6a_zEii_PFK8SzWT0mnA5w2sKg4hh8,1853
5
5
  orchestrator/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  orchestrator/security.py,sha256=iXFxGxab54aav7oHEKLAVkTgrQMJGHy6IYLojEnD7gI,2422
7
- orchestrator/settings.py,sha256=ep4RXOIZfYb5ws4qT_E_iiANMQR91pvOhQQCv1t8osw,3879
7
+ orchestrator/settings.py,sha256=TFIv09JIKY-lXqd04lH_XEcijEEyheaz3zTcgeG8DEI,4339
8
8
  orchestrator/targets.py,sha256=WizBgnp8hWX9YLFUIju7ewSubiwQqinCvyiYNcXHbHI,802
9
9
  orchestrator/types.py,sha256=qzs7xx5AYRmKbpYRyJJP3wuDb0W0bcAzefCN0RWLAco,15459
10
10
  orchestrator/version.py,sha256=b58e08lxs47wUNXv0jXFO_ykpksmytuzEXD4La4W-NQ,1366
@@ -21,7 +21,7 @@ orchestrator/api/api_v1/endpoints/processes.py,sha256=i5GRoszvdmpZqOxSqON83DNuc0
21
21
  orchestrator/api/api_v1/endpoints/product_blocks.py,sha256=kZ6ywIOsS_S2qGq7RvZ4KzjvaS1LmwbGWR37AKRvWOw,2146
22
22
  orchestrator/api/api_v1/endpoints/products.py,sha256=BfFtwu9dZXEQbtKxYj9icc73GKGvAGMR5ytyf41nQlQ,3081
23
23
  orchestrator/api/api_v1/endpoints/resource_types.py,sha256=gGyuaDyOD0TAVoeFGaGmjDGnQ8eQQArOxKrrk4MaDzA,2145
24
- orchestrator/api/api_v1/endpoints/settings.py,sha256=orcwFqGiQ3Ala3mLm_27ChXPkUFoGUeGNaDZnEIk2Ak,5848
24
+ orchestrator/api/api_v1/endpoints/settings.py,sha256=5s-k169podZjgGHUbVDmSQwpY_3Cs_Bbf2PPtZIkBcw,6184
25
25
  orchestrator/api/api_v1/endpoints/subscription_customer_descriptions.py,sha256=1_6LtgQleoq3M6z_W-Qz__Bj3OFUweoPrUqHMwSH6AM,3288
26
26
  orchestrator/api/api_v1/endpoints/subscriptions.py,sha256=V-ebvjtFEKlALx8SKX42SiNPM-GAgSMWbuaimyktUQQ,8758
27
27
  orchestrator/api/api_v1/endpoints/translations.py,sha256=dIWh_fCnZZUxJoGiNeJ49DK_xpf75IpR_0EIMSvzIvY,963
@@ -268,6 +268,7 @@ orchestrator/services/processes.py,sha256=rTH6zLNsun3qDCPguz2LYS87MQR_LJREIPrgkG
268
268
  orchestrator/services/products.py,sha256=BP4KyE8zO-8z7Trrs5T6zKBOw53S9BfBJnHWI3p6u5Y,1943
269
269
  orchestrator/services/resource_types.py,sha256=_QBy_JOW_X3aSTqH0CuLrq4zBJL0p7Q-UDJUcuK2_qc,884
270
270
  orchestrator/services/settings.py,sha256=HEWfFulgoEDwgfxGEO__QTr5fDiwNBEj1UhAeTAdbLQ,3159
271
+ orchestrator/services/settings_env_variables.py,sha256=U2xz0h3bOAE8wWQF2iCp5jf-2v0NUOOCTecNTouB1jY,2496
271
272
  orchestrator/services/subscription_relations.py,sha256=9C126TUfFvyBe7y4x007kH_dvxJ9pZ1zSnaWeH6HC5k,12261
272
273
  orchestrator/services/subscriptions.py,sha256=nr2HI89nC0lYjzTh2j-lEQ5cPQK43LNZv3gvP6jbepw,27189
273
274
  orchestrator/services/tasks.py,sha256=NjPkuauQoh9UJDcjA7OcKFgPk0i6NoKdDO7HlpGbBJ8,6575
@@ -280,6 +281,7 @@ orchestrator/utils/deprecation_logger.py,sha256=oqju7ecJcB_r7cMnldaOAA79QUZYS_h6
280
281
  orchestrator/utils/docs.py,sha256=GbyD61oKn1yVYaphUKHCBvrWEWJDTQfRc_VEbVb-zgU,6172
281
282
  orchestrator/utils/enrich_process.py,sha256=o_QSy5Q4wn1SMHhzVOw6bp7uhDXr7GhAIWRDDMWUVO4,4699
282
283
  orchestrator/utils/errors.py,sha256=6FxvXrITmRjP5bYnJJ3CxjAwA5meNjRAVYouz4TWKkU,4653
284
+ orchestrator/utils/expose_settings.py,sha256=0NOjLBifQy4k2zUYJ31QjGQCaXEQ1zB4UtCle7XglAM,1640
283
285
  orchestrator/utils/fixed_inputs.py,sha256=pnL6I_19VMp_Bny8SYjSzVFNvTFDyeCxFFOWGhTnDiQ,2665
284
286
  orchestrator/utils/functional.py,sha256=X1MDNwHmkU3-8mFb21m31HGlcfc5TygliXR0sXN3-rU,8304
285
287
  orchestrator/utils/get_subscription_dict.py,sha256=hctkFvD3U6LpygNwz2uesRMdnXSY-PaohBqPATsi9r4,694
@@ -307,7 +309,7 @@ orchestrator/workflows/tasks/resume_workflows.py,sha256=MzJqlSXUvKStkT7NGzxZyRlf
307
309
  orchestrator/workflows/tasks/validate_product_type.py,sha256=paG-NAY1bdde3Adt8zItkcBKf5Pxw6f5ngGW6an6dYU,3192
308
310
  orchestrator/workflows/tasks/validate_products.py,sha256=GZJBoFF-WMphS7ghMs2-gqvV2iL1F0POhk0uSNt93n0,8510
309
311
  orchestrator/workflows/translations/en-GB.json,sha256=ST53HxkphFLTMjFHonykDBOZ7-P_KxksktZU3GbxLt0,846
310
- orchestrator_core-4.0.4.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
311
- orchestrator_core-4.0.4.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
312
- orchestrator_core-4.0.4.dist-info/METADATA,sha256=EDGeOW4AxLgPbD6ZQDojlTPd8H3j4GOpD1vfWg-MgKA,5070
313
- orchestrator_core-4.0.4.dist-info/RECORD,,
312
+ orchestrator_core-4.1.0rc1.dist-info/licenses/LICENSE,sha256=b-aA5OZQuuBATmLKo_mln8CQrDPPhg3ghLzjPjLn4Tg,11409
313
+ orchestrator_core-4.1.0rc1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
314
+ orchestrator_core-4.1.0rc1.dist-info/METADATA,sha256=hyIGgttPRSo2gjx2V1kbbpd5MvEbnCttnUJ2LzZEyP4,5073
315
+ orchestrator_core-4.1.0rc1.dist-info/RECORD,,