fix(codex): send catalog/image credentials only to their own route
Follow-up to the two contributor commits for #121486. The picker, the image plugin and the auxiliary Codex client still composed a pooled gateway key with a base re-read from ambient state (HERMES_CODEX_BASE_URL or the chatgpt.com default), so a model.base_url-only gateway (env unset) still sent its key to chatgpt.com. - auth_codex: resolve_codex_runtime_credentials reports the host a pooled credential actually routes to (runtime_provider._pool_entry_mode_and_url: env > model.base_url while the row is canonical > row URL) instead of the ambient default; get_codex_auth_status carries the same bound base_url. - picker: get_codex_model_ids(access_token, base_url=) now receives the base resolved with the token from hermes_cli/models.py, the CLI default-model swap (self.base_url) and the `hermes model` Codex flow. - aux/image: _resolve_codex_credential_and_base() returns (token, base) from one pool selection; the image plugin, _build_codex_client and the raw Codex client use it (profile-scoped override from #121497 still wins). - model_metadata: the non-JWT refusal now applies only when the target is chatgpt.com; a gateway key may probe its own gateway's /models. Adversarial regressions: model.base_url with env unset, env/route mismatch, opaque + JWT gateway keys, pool-selected credential, pool row with its own gateway URL, direct-ChatGPT positive control. Addresses @andrexibiza's review on #121508.
This commit is contained in:
@@ -55,7 +55,12 @@ def provider(monkeypatch):
|
||||
def codex_backend(monkeypatch):
|
||||
"""Route the plugin's ``httpx.Client`` at a fake Codex images backend; returns the request log
|
||||
and lets a test swap the response via ``state["respond"]``."""
|
||||
# Seed the auth.json token below the credential/base resolver so generate() exercises the real
|
||||
# (token, base_url) binding; no pool present.
|
||||
from agent import auxiliary_client
|
||||
monkeypatch.setattr(codex_plugin, "_read_codex_access_token", lambda: "codex-token")
|
||||
monkeypatch.setattr(auxiliary_client, "_select_pool_entry", lambda provider: (False, None))
|
||||
monkeypatch.setattr(auxiliary_client, "_read_codex_singleton_token", lambda: "codex-token")
|
||||
state = {"requests": [], "respond": None}
|
||||
|
||||
def _default(request):
|
||||
@@ -181,7 +186,10 @@ class TestGenerate:
|
||||
assert request.url.host == "images.example.test"
|
||||
|
||||
def test_returns_auth_error_without_codex_token(self, provider, monkeypatch):
|
||||
from agent import auxiliary_client
|
||||
monkeypatch.setattr(codex_plugin, "_read_codex_access_token", lambda: None)
|
||||
monkeypatch.setattr(auxiliary_client, "_select_pool_entry", lambda provider: (False, None))
|
||||
monkeypatch.setattr(auxiliary_client, "_read_codex_singleton_token", lambda: None)
|
||||
result = provider.generate("a cat")
|
||||
assert result["success"] is False
|
||||
assert result["error_type"] == "auth_required"
|
||||
|
||||
Reference in New Issue
Block a user