mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-25 12:01:04 +02:00
fix: masked secret saves
This commit is contained in:
parent
d383729f50
commit
eb09aea6ca
8 changed files with 143 additions and 19 deletions
|
|
@ -244,7 +244,10 @@ def merge_ai_model_configuration_v2_secrets(
|
|||
existing_dograh = existing_dict.get("dograh") or {}
|
||||
incoming_key = incoming_dograh.get("api_key")
|
||||
existing_key = existing_dograh.get("api_key")
|
||||
if incoming_key and existing_key and contains_masked_key(incoming_key):
|
||||
if incoming_key and existing_key and contains_masked_key(
|
||||
incoming_key,
|
||||
existing_key,
|
||||
):
|
||||
incoming_dograh["api_key"] = resolve_masked_api_keys(
|
||||
incoming_key,
|
||||
existing_key,
|
||||
|
|
@ -258,9 +261,13 @@ def merge_ai_model_configuration_v2_secrets(
|
|||
|
||||
def check_for_masked_keys_in_ai_model_configuration_v2(
|
||||
configuration: OrganizationAIModelConfigurationV2,
|
||||
existing: OrganizationAIModelConfigurationV2 | None = None,
|
||||
) -> None:
|
||||
data = configuration.model_dump(mode="json", exclude_none=True)
|
||||
_raise_if_masked_secret(data)
|
||||
existing_data = (
|
||||
existing.model_dump(mode="json", exclude_none=True) if existing else None
|
||||
)
|
||||
_raise_if_masked_secret(data, existing_data)
|
||||
|
||||
|
||||
def mask_ai_model_configuration_v2(
|
||||
|
|
@ -381,22 +388,26 @@ def _merge_service_secret_fields(incoming: dict, existing: dict):
|
|||
existing_secret = existing[secret_field]
|
||||
if incoming_secret is None:
|
||||
incoming[secret_field] = existing_secret
|
||||
elif contains_masked_key(incoming_secret):
|
||||
elif contains_masked_key(incoming_secret, existing_secret):
|
||||
incoming[secret_field] = resolve_masked_api_keys(
|
||||
incoming_secret,
|
||||
existing_secret,
|
||||
)
|
||||
|
||||
|
||||
def _raise_if_masked_secret(value):
|
||||
def _raise_if_masked_secret(value, existing=None):
|
||||
if isinstance(value, dict):
|
||||
for key, nested in value.items():
|
||||
if key in SERVICE_SECRET_FIELDS and contains_masked_key(nested):
|
||||
existing_nested = existing.get(key) if isinstance(existing, dict) else None
|
||||
if key in SERVICE_SECRET_FIELDS and contains_masked_key(
|
||||
nested,
|
||||
existing_nested,
|
||||
):
|
||||
raise ValueError(
|
||||
f"The {key} appears to be masked. Please provide the actual "
|
||||
"value, not the masked value."
|
||||
)
|
||||
_raise_if_masked_secret(nested)
|
||||
_raise_if_masked_secret(nested, existing_nested)
|
||||
elif isinstance(value, list):
|
||||
for item in value:
|
||||
_raise_if_masked_secret(item)
|
||||
|
|
|
|||
|
|
@ -23,12 +23,23 @@ SERVICE_SECRET_FIELDS = ("api_key", "credentials", "aws_access_key", "aws_secret
|
|||
MODEL_OVERRIDE_FIELDS = ("llm", "tts", "stt", "realtime")
|
||||
|
||||
|
||||
def contains_masked_key(value: str | list[str] | None) -> bool:
|
||||
def contains_masked_key(
|
||||
value: str | list[str] | None,
|
||||
existing: str | list[str] | None = None,
|
||||
) -> bool:
|
||||
"""Return True if *value* looks like a masked placeholder."""
|
||||
if value is None:
|
||||
return False
|
||||
keys = value if isinstance(value, list) else [value]
|
||||
return any(MASK_MARKER in k or _matches_mask_shape(k) for k in keys)
|
||||
if existing is None:
|
||||
return any(MASK_MARKER in k for k in keys)
|
||||
|
||||
existing_keys = existing if isinstance(existing, list) else [existing]
|
||||
return any(
|
||||
MASK_MARKER in key
|
||||
or any(_matches_existing_mask(key, real_key) for real_key in existing_keys)
|
||||
for key in keys
|
||||
)
|
||||
|
||||
|
||||
def _matches_mask_shape(key: str) -> bool:
|
||||
|
|
@ -43,20 +54,39 @@ def _matches_mask_shape(key: str) -> bool:
|
|||
return key[:masked_prefix_length] == MASK_CHAR * masked_prefix_length
|
||||
|
||||
|
||||
def check_for_masked_keys(config: "EffectiveAIModelConfiguration") -> None:
|
||||
def _matches_existing_mask(key: str, existing: str | None) -> bool:
|
||||
return bool(existing) and _matches_mask_shape(key) and is_mask_of(key, existing)
|
||||
|
||||
|
||||
def check_for_masked_keys(
|
||||
config: "EffectiveAIModelConfiguration",
|
||||
existing: "EffectiveAIModelConfiguration | None" = None,
|
||||
) -> None:
|
||||
"""Raise ValueError if any service in *config* still has a masked secret."""
|
||||
for field in ("llm", "tts", "stt", "embeddings", "realtime"):
|
||||
service = getattr(config, field, None)
|
||||
if service is None:
|
||||
continue
|
||||
existing_service = getattr(existing, field, None) if existing else None
|
||||
for secret_field in SERVICE_SECRET_FIELDS:
|
||||
if not hasattr(service, secret_field):
|
||||
continue
|
||||
if secret_field == "api_key" and hasattr(service, "get_all_api_keys"):
|
||||
secret_value = service.get_all_api_keys()
|
||||
existing_secret_value = (
|
||||
existing_service.get_all_api_keys()
|
||||
if existing_service
|
||||
and hasattr(existing_service, "get_all_api_keys")
|
||||
else None
|
||||
)
|
||||
else:
|
||||
secret_value = getattr(service, secret_field, None)
|
||||
if contains_masked_key(secret_value):
|
||||
existing_secret_value = (
|
||||
getattr(existing_service, secret_field, None)
|
||||
if existing_service and hasattr(existing_service, secret_field)
|
||||
else None
|
||||
)
|
||||
if contains_masked_key(secret_value, existing_secret_value):
|
||||
raise ValueError(
|
||||
f"The {field} {secret_field} appears to be masked. "
|
||||
"Please provide the actual value, not the masked value."
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ def _merge_service_secret_fields(
|
|||
incoming_secret = incoming_cfg.get(secret_field)
|
||||
existing_secret = existing_cfg[secret_field]
|
||||
if incoming_secret is not None:
|
||||
if contains_masked_key(incoming_secret):
|
||||
if contains_masked_key(incoming_secret, existing_secret):
|
||||
incoming_cfg[secret_field] = (
|
||||
existing_secret
|
||||
if masked_value_preserves_full_secret
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue