#5153: MoA gateway fail-closed routing
This commit is contained in:
parent
651c45614e
commit
36643867f4
2 changed files with 81 additions and 11 deletions
|
|
@ -19367,11 +19367,15 @@ def _handle_chat_start(handler, body, diag=None):
|
|||
if "model_provider" in body
|
||||
else getattr(s, "model_provider", None)
|
||||
)
|
||||
<<<<<<< ours
|
||||
_pp_provider, _pp_default, _pp_cfg = _read_profile_model_config(s, requested_provider)
|
||||
=======
|
||||
>>>>>>> theirs
|
||||
explicit_model_pick = bool(body.get("explicit_model_pick"))
|
||||
moa_config = None
|
||||
gateway_chat_enabled = webui_gateway_chat_enabled(get_config())
|
||||
if body.get("moa_config"):
|
||||
if webui_gateway_chat_enabled(get_config()):
|
||||
if gateway_chat_enabled:
|
||||
return bad(handler, "MoA override is unavailable on gateway-backed sessions", 409)
|
||||
from api.commands import resolve_moa_config
|
||||
|
||||
|
|
@ -19379,6 +19383,7 @@ def _handle_chat_start(handler, body, diag=None):
|
|||
moa_config = resolve_moa_config()
|
||||
except RuntimeError as e:
|
||||
return bad(handler, str(e), 503)
|
||||
_pp_provider, _pp_default = _read_profile_model_config(s, requested_provider)
|
||||
diag.stage("resolve_model_provider") if diag else None
|
||||
model, model_provider, normalized_model = _resolve_compatible_session_model_state(
|
||||
requested_model,
|
||||
|
|
@ -19401,18 +19406,22 @@ def _handle_chat_start(handler, body, diag=None):
|
|||
# with start_session_turn so both entry points behave identically
|
||||
# under runtime_adapter_enabled() / runtime_adapter_runner_enabled()
|
||||
# — Q-2979-A2 / Copilot discussion_r3305864087/r3305864173).
|
||||
start_run_kwargs = {
|
||||
"msg": msg,
|
||||
"attachments": attachments,
|
||||
"workspace": workspace,
|
||||
"model": model,
|
||||
"model_provider": model_provider,
|
||||
"normalized_model": normalized_model,
|
||||
"source": "webui",
|
||||
"route": "/api/chat/start",
|
||||
"diag": diag,
|
||||
}
|
||||
if not gateway_chat_enabled and moa_config is not None:
|
||||
start_run_kwargs["moa_config"] = moa_config
|
||||
response = _start_run(
|
||||
s,
|
||||
msg=msg,
|
||||
attachments=attachments,
|
||||
workspace=workspace,
|
||||
model=model,
|
||||
model_provider=model_provider,
|
||||
normalized_model=normalized_model,
|
||||
source="webui",
|
||||
route="/api/chat/start",
|
||||
diag=diag,
|
||||
moa_config=moa_config,
|
||||
**start_run_kwargs,
|
||||
)
|
||||
# Map adapter-selection NotImplementedError (501) onto the legacy
|
||||
# bad-request response shape that this route exposed historically
|
||||
|
|
|
|||
|
|
@ -127,3 +127,64 @@ def test_moa_config_is_per_turn_not_persisted():
|
|||
js_source = js_path.read_text(encoding="utf-8")
|
||||
assert "moa_config:_pendingMoaConfig?true:undefined" in js_source
|
||||
assert "_pendingMoaConfig=null" in js_source
|
||||
|
||||
|
||||
def test_moa_gateway_chat_start_fails_closed(monkeypatch, tmp_path):
|
||||
"""Gateway-backed WebUI sessions must reject /moa until the gateway consumes runtime overrides."""
|
||||
import api.commands as commands
|
||||
import api.routes as routes
|
||||
|
||||
class _Handler:
|
||||
def __init__(self):
|
||||
import io
|
||||
|
||||
self.status = None
|
||||
self.response_headers = []
|
||||
self.wfile = io.BytesIO()
|
||||
|
||||
def send_response(self, status):
|
||||
self.status = status
|
||||
|
||||
def send_header(self, key, value):
|
||||
self.response_headers.append((key, value))
|
||||
|
||||
def end_headers(self):
|
||||
self.response_headers.append(("__end__", ""))
|
||||
|
||||
class _Session:
|
||||
session_id = "sess-moa-gateway"
|
||||
workspace = str(tmp_path)
|
||||
model = "gpt-5.5"
|
||||
model_provider = "openai-codex"
|
||||
profile = "default"
|
||||
messages = []
|
||||
context_messages = []
|
||||
pending_user_message = None
|
||||
|
||||
def start_run(*_args, **_kwargs): # pragma: no cover - should fail before run start
|
||||
raise AssertionError("gateway-backed /moa must fail closed before starting a run")
|
||||
|
||||
def resolve_moa_config(): # pragma: no cover - should fail before resolving MoA
|
||||
raise AssertionError("gateway-backed /moa must fail before resolving MoA config")
|
||||
|
||||
monkeypatch.setattr(routes, "get_session", lambda _sid: _Session())
|
||||
monkeypatch.setattr(routes, "_resolve_chat_workspace_with_recovery", lambda _s, _w: str(tmp_path))
|
||||
monkeypatch.setattr(routes, "_start_run", start_run)
|
||||
monkeypatch.setattr(routes, "get_config", lambda: {"chat_backend": "gateway"})
|
||||
monkeypatch.setattr(routes, "webui_gateway_chat_enabled", lambda _cfg: True)
|
||||
monkeypatch.setattr(commands, "resolve_moa_config", resolve_moa_config)
|
||||
|
||||
handler = _Handler()
|
||||
routes._handle_chat_start(
|
||||
handler,
|
||||
{
|
||||
"session_id": "sess-moa-gateway",
|
||||
"message": "diagnose issue",
|
||||
"workspace": str(tmp_path),
|
||||
"moa_config": True,
|
||||
},
|
||||
)
|
||||
|
||||
body = json.loads(handler.wfile.getvalue().decode("utf-8"))
|
||||
assert handler.status == 409
|
||||
assert body["error"] == "MoA override is unavailable on gateway-backed sessions"
|
||||
|
|
|
|||
Loading…
Reference in a new issue