fix(auth): user provider plugin owns its aliases and display name in the auth registry
register_plugin_provider setdefault-ed aliases regardless of provenance, so a
$HERMES_HOME plugin alias colliding with an existing row kept resolving to the
old row while providers.get_provider_profile already followed the user profile;
override_registry_row left the display name untouched on a same-name
replacement. mirror_aliases applies the provider_source ownership rule that
e5e7fbcd27 introduced for endpoints.
Fixes #116668
This commit is contained in:
@@ -60,16 +60,42 @@ def register_plugin_provider(pp: Any) -> None:
|
||||
pconfig = ProviderConfig(pp.name, pp.display_name or pp.name, pp.auth_type, inference_base_url=pp.base_url)
|
||||
PROVIDER_REGISTRY[pp.name] = pconfig
|
||||
PLUGIN_MIRRORED_PROVIDERS.add(pp.name)
|
||||
for alias in pp.aliases: # so resolve_provider() resolves them too
|
||||
PROVIDER_REGISTRY.setdefault(alias, pconfig)
|
||||
mirror_aliases(pconfig, pp)
|
||||
|
||||
|
||||
def _user_owns_alias(pp: Any, alias: str) -> bool:
|
||||
"""True when *alias* resolves to the ``$HERMES_HOME`` plugin *pp* in the ``providers`` layer."""
|
||||
try:
|
||||
from providers import get_provider_profile, provider_source
|
||||
except Exception:
|
||||
return False
|
||||
owner = get_provider_profile(alias)
|
||||
return owner is not None and owner.name == pp.name and provider_source(pp.name) == "user"
|
||||
|
||||
|
||||
def mirror_aliases(pconfig: Any, pp: Any) -> None:
|
||||
"""Point ``pp.aliases`` at *pconfig* so ``resolve_provider()`` resolves them too.
|
||||
|
||||
A bundled plugin never steals an alias another row already holds; a ``$HERMES_HOME`` plugin
|
||||
whose alias the ``providers`` layer already resolves to it does — the same ownership rule as
|
||||
:func:`override_registry_row`, otherwise the alias kept resolving to the built-in row while
|
||||
``providers.get_provider_profile`` followed the user's profile (#116668).
|
||||
"""
|
||||
from hermes_cli.auth import PROVIDER_REGISTRY
|
||||
|
||||
for alias in pp.aliases:
|
||||
if alias not in PROVIDER_REGISTRY or _user_owns_alias(pp, alias):
|
||||
PROVIDER_REGISTRY[alias] = pconfig
|
||||
|
||||
|
||||
def override_registry_row(pconfig: Any, pp: Any) -> None:
|
||||
"""A ``$HERMES_HOME`` plugin re-registering a name that already has a row wins for the fields
|
||||
it declares — ``base_url`` and, on api-key rows, ``env_vars`` (#48450). ``register_provider()``
|
||||
it declares — ``display_name``, ``base_url`` and, on api-key rows, ``env_vars`` (#48450, #116668). ``register_provider()``
|
||||
is last-writer-wins for the profile; without this the runtime kept reading the built-in
|
||||
endpoint. In place, so alias rows sharing the object follow; idempotent, so re-sync is free.
|
||||
"""
|
||||
if pp.display_name:
|
||||
pconfig.name = pp.display_name
|
||||
if pp.base_url:
|
||||
pconfig.inference_base_url = pp.base_url
|
||||
if pp.auth_type == "api_key" == pconfig.auth_type and pp.env_vars:
|
||||
@@ -104,6 +130,7 @@ def sync_plugin_provider_registry() -> int:
|
||||
core_row = pp.name in BUILTIN_PROVIDER_IDS or pp.name in PLUGIN_MIRRORED_PROVIDERS
|
||||
if core_row and pp.name not in _REGISTRY_PLUGIN_SKIP and provider_source(pp.name) == "user":
|
||||
override_registry_row(PROVIDER_REGISTRY[pp.name], pp)
|
||||
mirror_aliases(PROVIDER_REGISTRY[pp.name], pp)
|
||||
continue
|
||||
register_plugin_provider(pp)
|
||||
added += pp.name in PROVIDER_REGISTRY
|
||||
|
||||
@@ -173,3 +173,45 @@ def test_post_discovery_registration_is_mirrored(_isolated_registries, monkeypat
|
||||
)
|
||||
assert LATE in auth_mod.PROVIDER_REGISTRY
|
||||
assert auth_mod.PROVIDER_REGISTRY[LATE_ALIAS] is auth_mod.PROVIDER_REGISTRY[LATE]
|
||||
|
||||
|
||||
def test_user_plugin_alias_repoints_and_display_name_follows(_isolated_registries, monkeypatch, tmp_path):
|
||||
"""A $HERMES_HOME plugin owns the aliases it declares and the display name of a same-name row.
|
||||
|
||||
Ownership split (#116668): ``providers.get_provider_profile`` already followed the user's
|
||||
profile for the alias, while the auth registry kept the alias on whichever row got there first
|
||||
and kept the bundled display name on a same-name replacement.
|
||||
"""
|
||||
monkeypatch.setattr(providers, "_discover_entry_point_providers", lambda: None)
|
||||
monkeypatch.setattr(providers, "_BUNDLED_PLUGINS_DIR", tmp_path)
|
||||
monkeypatch.setattr(providers, "_user_plugins_dir", lambda: None)
|
||||
monkeypatch.setattr(providers, "_installed_plugins_dir", lambda: None)
|
||||
providers._discover_providers()
|
||||
|
||||
taken_alias = "probe-116668-alias"
|
||||
monkeypatch.setattr(providers, "_current_source", "bundled")
|
||||
providers.register_provider(ProviderProfile(
|
||||
name="probe-116668-bundled", display_name="Bundled", base_url="https://bundled.example/v1",
|
||||
env_vars=("PROBE_116668_BUNDLED_KEY",), aliases=(taken_alias,)))
|
||||
bundled_row = auth_mod.PROVIDER_REGISTRY["probe-116668-bundled"]
|
||||
assert auth_mod.PROVIDER_REGISTRY[taken_alias] is bundled_row
|
||||
|
||||
# A second bundled plugin claiming the same alias does not steal it.
|
||||
providers.register_provider(ProviderProfile(
|
||||
name="probe-116668-other", display_name="Other", base_url="https://other.example/v1",
|
||||
env_vars=("PROBE_116668_OTHER_KEY",), aliases=(taken_alias,)))
|
||||
assert auth_mod.PROVIDER_REGISTRY[taken_alias] is bundled_row
|
||||
|
||||
# The user's plugin does, and its same-name replacement rewrites the display name in place.
|
||||
monkeypatch.setattr(providers, "_current_source", "user")
|
||||
providers.register_provider(ProviderProfile(
|
||||
name="probe-116668-user", display_name="Mine", base_url="https://mine.example/v1",
|
||||
env_vars=("PROBE_116668_USER_KEY",), aliases=(taken_alias,)))
|
||||
assert auth_mod.PROVIDER_REGISTRY[taken_alias] is auth_mod.PROVIDER_REGISTRY["probe-116668-user"]
|
||||
|
||||
providers.register_provider(ProviderProfile(
|
||||
name="probe-116668-bundled", display_name="Bundled (mine)", base_url="https://mine.example/v2",
|
||||
env_vars=("PROBE_116668_BUNDLED_KEY",), aliases=(taken_alias,)))
|
||||
assert bundled_row.name == "Bundled (mine)"
|
||||
assert bundled_row.inference_base_url == "https://mine.example/v2"
|
||||
assert auth_mod.PROVIDER_REGISTRY[taken_alias] is bundled_row
|
||||
|
||||
Reference in New Issue
Block a user