fix(config): invalidate fields with missing env refs
This commit is contained in:
@@ -121,15 +121,18 @@ def resolve_env_refs(value: str) -> str:
|
||||
"""Resolve ``${VAR}`` references in a single string, leniently.
|
||||
|
||||
Unlike :func:`resolve_config_env_vars` (which walks a whole ``Config`` and
|
||||
raises on a missing variable), this resolves one value and substitutes an
|
||||
empty string for any unset reference. It is meant for individual, lazily
|
||||
consumed secret fields — e.g. a transcription provider's ``api_key`` — so a
|
||||
missing variable degrades to "not configured" instead of sending the literal
|
||||
``${VAR}`` text to the provider. Non-string input is returned unchanged.
|
||||
raises on a missing variable), this resolves one value and returns an empty
|
||||
string if any reference is unset. It is meant for individual, lazily consumed
|
||||
fields — e.g. a transcription provider's ``api_key`` or ``api_base`` — so a
|
||||
missing variable degrades to "not configured" instead of producing a partial
|
||||
value. Non-string input is returned unchanged.
|
||||
"""
|
||||
if not isinstance(value, str):
|
||||
return value
|
||||
return _ENV_REF_PATTERN.sub(lambda m: os.environ.get(m.group(1), ""), value)
|
||||
names = _ENV_REF_PATTERN.findall(value)
|
||||
if any(name not in os.environ for name in names):
|
||||
return ""
|
||||
return _ENV_REF_PATTERN.sub(lambda m: os.environ[m.group(1)], value)
|
||||
|
||||
|
||||
def _resolve_in_place(obj: Any) -> Any:
|
||||
|
||||
@@ -185,6 +185,18 @@ def test_resolver_env_ref_missing_var_degrades_to_not_configured() -> None:
|
||||
assert resolved.configured is False
|
||||
|
||||
|
||||
def test_resolver_missing_embedded_api_key_ref_degrades_to_not_configured() -> None:
|
||||
config = Config()
|
||||
config.transcription.provider = "groq"
|
||||
config.providers.groq.api_key = "Bearer ${MISSING_GROQ_KEY}"
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
resolved = resolve_transcription_config(config)
|
||||
|
||||
assert not resolved.api_key
|
||||
assert resolved.configured is False
|
||||
|
||||
|
||||
def test_resolver_interpolates_env_ref_in_api_base() -> None:
|
||||
config = Config()
|
||||
config.transcription.provider = "groq"
|
||||
@@ -197,6 +209,18 @@ def test_resolver_interpolates_env_ref_in_api_base() -> None:
|
||||
assert resolved.api_base == "https://groq.example/v1"
|
||||
|
||||
|
||||
def test_resolver_missing_embedded_api_base_ref_uses_provider_default() -> None:
|
||||
config = Config()
|
||||
config.transcription.provider = "groq"
|
||||
config.providers.groq.api_key = "gsk-test"
|
||||
config.providers.groq.api_base = "https://${MISSING_GROQ_HOST}/openai/v1"
|
||||
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
resolved = resolve_transcription_config(config)
|
||||
|
||||
assert resolved.api_base == "https://api.groq.com/openai/v1"
|
||||
|
||||
|
||||
def test_resolver_supports_xiaomi_mimo_transcription_provider() -> None:
|
||||
config = Config()
|
||||
config.transcription.provider = "xiaomi_mimo"
|
||||
|
||||
Reference in New Issue
Block a user