fix(image_gen): resolve OpenAI and Meta image base URLs through the secret scope
Sibling sites of #119986's class: the openai and meta-ai image backends resolved their API key through get_secret but the base URL through os.environ, so on a multiplexed gateway a routed profile's key was sent to the launch profile's endpoint. Both fields now come from the same scope (get_secret_str, like the DeepInfra video backend after #119986).
This commit is contained in:
@@ -6,10 +6,9 @@ Selection: ``model`` kwarg → ``META_IMAGE_MODEL`` → ``image_gen.meta-ai.mode
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from agent.secret_scope import get_secret
|
||||
from agent.secret_scope import get_secret, get_secret_str
|
||||
from agent.image_gen_provider import (
|
||||
DEFAULT_ASPECT_RATIO, resolve_aspect_ratio, save_b64_image, save_url_image, success_response)
|
||||
from plugins.image_gen._common import (
|
||||
@@ -32,7 +31,9 @@ def _resolve_api_key() -> Optional[str]:
|
||||
|
||||
|
||||
def _resolve_base_url() -> str:
|
||||
return (os.environ.get(BASE_URL_ENV) or "").strip() or DEFAULT_BASE_URL
|
||||
# Through the secret scope like the key: under multiplexing os.environ holds the launch profile's
|
||||
# endpoint, and a routed profile's key must never be sent to another profile's base URL.
|
||||
return get_secret_str(BASE_URL_ENV).strip() or DEFAULT_BASE_URL
|
||||
|
||||
|
||||
# Model ids are sent verbatim to ``/v1/images/generations``.
|
||||
|
||||
@@ -12,7 +12,7 @@ import logging
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from agent.secret_scope import get_secret
|
||||
from agent.secret_scope import get_secret, get_secret_str
|
||||
from agent.image_gen_provider import DEFAULT_ASPECT_RATIO, resolve_aspect_ratio, success_response
|
||||
from plugins.image_gen._common import (
|
||||
GPT_IMAGE_2_API_MODEL as API_MODEL, GPT_IMAGE_2_DEFAULT as DEFAULT_MODEL, GPT_IMAGE_2_TIERS,
|
||||
@@ -70,7 +70,7 @@ def _resolve_endpoint() -> Tuple[str, str]:
|
||||
named = str(cfg.get("provider") or "").strip()
|
||||
named_base, named_key = _named_endpoint(named) if named else ("", "")
|
||||
base_url = (str(cfg.get("base_url") or "").strip().rstrip("/") or named_base
|
||||
or os.environ.get("OPENAI_BASE_URL", "").strip())
|
||||
or get_secret_str("OPENAI_BASE_URL").strip())
|
||||
key_env = str(cfg.get("key_env") or "").strip()
|
||||
api_key = (get_secret(key_env) if key_env else None) or named_key or get_secret("OPENAI_API_KEY") or ""
|
||||
return base_url, api_key
|
||||
|
||||
@@ -109,6 +109,24 @@ class TestResolution:
|
||||
monkeypatch.setenv("META_BASE_URL", "https://proxy.internal/v1")
|
||||
assert meta_plugin._resolve_base_url() == "https://proxy.internal/v1"
|
||||
|
||||
def test_base_url_follows_the_profile_secret_scope(self, monkeypatch):
|
||||
"""Under multiplexing os.environ is the launch profile's: a routed profile's key must go to
|
||||
ITS base URL, and a profile without an override gets the default — never the launch URL."""
|
||||
from agent.secret_scope import reset_secret_scope, set_multiplex_active, set_secret_scope
|
||||
|
||||
monkeypatch.setenv("META_BASE_URL", "https://launch.example/v1")
|
||||
set_multiplex_active(True)
|
||||
try:
|
||||
for scope, expected in (({"META_BASE_URL": "https://profile-b.example/v1"}, "https://profile-b.example/v1"),
|
||||
({}, "https://api.meta.ai/v1")):
|
||||
token = set_secret_scope(scope)
|
||||
try:
|
||||
assert meta_plugin._resolve_base_url() == expected
|
||||
finally:
|
||||
reset_secret_scope(token)
|
||||
finally:
|
||||
set_multiplex_active(False)
|
||||
|
||||
|
||||
# ── Model resolution ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user