mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-04 12:33:08 +00:00
fix(config): accept placeholder base_url in custom provider validation
_normalize_custom_provider_entry() ran urlparse() on base_url and dropped
any entry whose value was an un-expanded placeholder, so a caller reaching
the normalizer with raw config (e.g. the Dockerized gateway path) silently
skipped the provider with a 'not a valid URL' warning. Skip URL validation
when the candidate contains a placeholder token — both ${ENV_VAR} env-refs
and bare {region}-style templates — since those are expanded at runtime.
Closes #14457
This commit is contained in:
parent
b34771fc06
commit
16192103f4
2 changed files with 54 additions and 0 deletions
|
|
@ -4269,6 +4269,14 @@ def _normalize_custom_provider_entry(
|
|||
raw_url = entry.get(url_key)
|
||||
if isinstance(raw_url, str) and raw_url.strip():
|
||||
candidate = raw_url.strip()
|
||||
# Accept URLs containing unresolved placeholder tokens — both
|
||||
# ``${ENV_VAR}`` env-refs and bare ``{region}``-style templates —
|
||||
# without URL validation. They are expanded at runtime, so a
|
||||
# caller reaching this normalizer with raw (un-expanded) config
|
||||
# would otherwise see the provider silently dropped (#14457).
|
||||
if re.search(r"\{[^}]+\}", candidate):
|
||||
base_url = candidate
|
||||
break
|
||||
parsed = urlparse(candidate)
|
||||
if parsed.scheme and parsed.netloc:
|
||||
base_url = candidate
|
||||
|
|
|
|||
|
|
@ -191,3 +191,49 @@ class TestNormalizeCustomProviderEntry:
|
|||
result = _normalize_custom_provider_entry(entry)
|
||||
assert result is not None
|
||||
assert "models" not in result
|
||||
|
||||
def test_env_var_placeholder_in_base_url_not_rejected(self):
|
||||
"""A base_url that is an un-expanded ${ENV_VAR} placeholder must not be
|
||||
rejected as an invalid URL — it is expanded at runtime, so a caller
|
||||
reaching this normalizer with raw config would otherwise see the
|
||||
provider silently dropped. Regression test for #14457."""
|
||||
entry = {
|
||||
"name": "PROVIDER_A",
|
||||
"base_url": "${PROVIDER_A_BASE_URL}",
|
||||
"key_env": "PROVIDER_A_API_KEY",
|
||||
}
|
||||
result = _normalize_custom_provider_entry(entry, provider_key="PROVIDER_A")
|
||||
assert result is not None
|
||||
assert result["base_url"] == "${PROVIDER_A_BASE_URL}"
|
||||
|
||||
def test_multiple_env_vars_in_base_url(self):
|
||||
"""base_url with multiple ${VAR} placeholders is accepted verbatim."""
|
||||
entry = {
|
||||
"name": "multi-var-provider",
|
||||
"base_url": "${SCHEME}://${HOST}:${PORT}/v1",
|
||||
}
|
||||
result = _normalize_custom_provider_entry(entry)
|
||||
assert result is not None
|
||||
assert result["base_url"] == "${SCHEME}://${HOST}:${PORT}/v1"
|
||||
|
||||
def test_bare_brace_region_placeholder_accepted(self):
|
||||
"""A bare {region}-style template token (not an env-ref) is also
|
||||
accepted without validation, supporting region-substitution URLs."""
|
||||
entry = {
|
||||
"name": "regional",
|
||||
"base_url": "https://{region}.api.example.com/v1",
|
||||
}
|
||||
result = _normalize_custom_provider_entry(entry, provider_key="regional")
|
||||
assert result is not None
|
||||
assert result["base_url"] == "https://{region}.api.example.com/v1"
|
||||
|
||||
def test_invalid_url_without_placeholder_still_rejected(self):
|
||||
"""A malformed URL with no scheme/host AND no placeholder token is
|
||||
still rejected — the placeholder bypass must not weaken validation of
|
||||
ordinary literal URLs."""
|
||||
entry = {
|
||||
"name": "bad",
|
||||
"base_url": "not-a-url",
|
||||
}
|
||||
result = _normalize_custom_provider_entry(entry, provider_key="bad")
|
||||
assert result is None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue