"""Credential ownership for ``providers:`` entries whose pool slug is also a built-in's pool id. ``providers.deepseek`` pools under the slug ``deepseek``, which ``load_pool`` also seeds from the built-in DeepSeek provider's env vars and auth files. Those rows are the built-in's accounts. Every acquisition of a pool for the custom entry's runtime (main, frozen and auxiliary resolution, a URL-matched bare ``custom`` route, restoring the primary after a fallback, a delegated child's pool) takes the entry-scoped view from here, so the built-in's account never stands in for the entry's declared credential. The built-in provider itself still loads, and persists, the whole pool. """ from __future__ import annotations from typing import Any, Callable, Optional _DECLARED_CREDENTIAL_KEYS = ("api_key", "key_env", "api_key_env", "key_cmd") # The ``_primary_runtime`` field holding the owning entry's provenance (``runtime_entry_owner``). SNAPSHOT_OWNER_KEY = "custom_entry" def entry_declares_credential(entry: Any) -> bool: """Whether a custom entry names its own credential (``api_key`` / ``key_env`` / ``key_cmd``). A snapshot's provenance carries the verdict itself, since it never copies an inline secret.""" if isinstance(entry, dict) and "declares_credential" in entry: return bool(entry["declares_credential"]) return isinstance(entry, dict) and any(str(entry.get(k) or "").strip() for k in _DECLARED_CREDENTIAL_KEYS) def row_owned_by_entry(row: Any, entry: Any) -> bool: """Ownership by provenance: ``hermes auth add`` (manual) rows, and rows seeded from the entry's own ``key_env``. Rows the built-in seeded from its registry env vars or auth files are foreign.""" from agent.credential_pool import _is_manual_source source = str(getattr(row, "source", "") or "").strip() own_env = {f"env:{name}" for name in (str(entry.get(k) or "").strip() for k in ("key_env", "api_key_env")) if name} return _is_manual_source(source) or source in own_env def entry_scoped_pool(pool: Any, pool_key: str, entry: Optional[dict[str, Any]]) -> Any: """The rows of ``pool`` the custom ``entry`` owns: the pool itself when it owns them all, else a view of them, or None when it owns none. ``custom:`` pools are seeded from the entry's own config and stay whole; so does any pool for an entry that declares no credential (as before). The view shares the loaded rows and token baselines, so persisting it merges into the stored pool under its lock and leaves the built-in's omitted rows on disk. """ from agent.credential_pool import CUSTOM_POOL_PREFIX, CredentialPool if pool is None or str(pool_key or "").startswith(CUSTOM_POOL_PREFIX) or not entry_declares_credential(entry): return pool rows = pool.entries() owned = [row for row in rows if row_owned_by_entry(row, entry)] if len(owned) == len(rows): return pool if not owned: return None view = CredentialPool(pool.provider, owned) view._persisted_token_pairs = pool._persisted_token_pairs return view def custom_entry_for_endpoint( base_url: Optional[str], provider_name: Optional[str] = None, config: Optional[dict] = None, ) -> Optional[tuple[str, dict[str, Any]]]: """``(normalized_name, entry)`` of the configured custom entry that owns ``base_url``: by name first (a named entry's pool never serves another URL), else by URL. ``config`` is a frozen route's config, whose entry owns the endpoint even after a live edit.""" from agent import credential_pool as cp if not base_url: return None url = cp._norm_url(base_url) if (named := named_custom_entry(provider_name, config)) is not None: entry_url = cp._norm_url(named[1].get("base_url")) return None if entry_url and entry_url != url else named return next(((n, e) for n, e in cp._iter_custom_providers(config) if url and cp._norm_url(e.get("base_url")) == url), None) def named_custom_entry(provider_name: Optional[str], config: Optional[dict] = None) -> Optional[tuple[str, dict[str, Any]]]: """``(normalized_name, entry)`` of the configured custom entry ``provider_name`` names, else None.""" from agent import credential_pool as cp aliases = cp._requested_custom_name_aliases(provider_name) if provider_name else set() return next(((n, e) for n, e in cp._iter_custom_providers(config) if aliases & cp._custom_entry_name_aliases(n, e)), None) if aliases else None def pool_for_aux_provider(provider: Optional[str], pool_key: str, load: Callable[[str], Any]) -> Any: """``load(pool_key)`` for an auxiliary pool read (the key peek, credential recovery). A pinned ``custom:`` normalizes to its entry's slug, which may also be a same-named built-in's pool, so it gets the entry-scoped view; a bare built-in name keeps its whole pool.""" pool = load(pool_key) if pool is None or not str(provider or "").strip().lower().startswith("custom:"): return pool match = named_custom_entry(provider) return entry_scoped_pool(pool, pool_key, match[1] if match else None) def _custom_identity(provider: Optional[str], requested_provider: Optional[str]) -> tuple[bool, Optional[str]]: """``(is_custom, custom: or None)`` for a runtime's provider / requested_provider pair.""" from agent.credential_pool import CUSTOM_POOL_PREFIX identities = [str(v or "").strip().lower() for v in (provider, requested_provider)] custom = any(v == "custom" or v.startswith(CUSTOM_POOL_PREFIX) for v in identities) return custom, next((v for v in identities if v.startswith(CUSTOM_POOL_PREFIX)), None) def runtime_entry_owner(provider: Optional[str], requested_provider: Optional[str], base_url: Optional[str]) -> Optional[dict[str, Any]]: """Credential provenance of the entry that owns a custom runtime, for its ``_primary_runtime`` snapshot: matched in the config the route runs on (the frozen scope, else the profile's), the way resolution matched it. Names only, never a secret. None for a built-in or an unowned endpoint.""" custom, name = _custom_identity(provider, requested_provider) if not custom or (match := custom_entry_for_endpoint(base_url, name)) is None: return None norm_name, entry = match provenance = {k: entry.get(k) for k in ("provider_key", "base_url", "key_env", "api_key_env")} return {"name": norm_name, **provenance, "declares_credential": entry_declares_credential(entry)} def load_runtime_pool( provider: Optional[str], base_url: Optional[str], requested_provider: Optional[str] = None, snapshot: Optional[dict[str, Any]] = None, ) -> Any: """The pool for a runtime snapshot's identity. A custom runtime (``custom`` or ``custom:``) is the entry's, so it gets the entry-scoped view; a built-in identity loads its whole pool. Ownership and the pool key come from the runtime identity, never from the pool slug, which both share: a ``custom:`` identity keys on its own entry, not the first entry on its URL. ``snapshot`` is the ``_primary_runtime`` being restored: the owner it recorded wins over live config, so an edit can't reassign the endpoint or drop the entry's declared credential. A named identity whose snapshot recorded no owner gets None and keeps the snapshot's own credential.""" from agent.credential_pool import _pool_keys_for_custom_entry, load_pool, resolve_runtime_pool_key custom, name = _custom_identity(provider, requested_provider) if not custom: key = resolve_runtime_pool_key(provider, base_url) return load_pool(key) if key else None owner = (snapshot or {}).get(SNAPSHOT_OWNER_KEY) if snapshot is not None and name and not owner: return None match = (owner["name"], owner) if owner else custom_entry_for_endpoint(base_url, name) key = (_pool_keys_for_custom_entry(*match) or [""])[0] if match and (name or owner) else resolve_runtime_pool_key(provider, base_url) return entry_scoped_pool(load_pool(key), key, match[1] if match else None) if key else None