tests: pin ink engine in _make_tui_argv npm-bootstrap tests (post-merge semantic fix)

Main's rewritten test_tui_npm_install.py tests call _make_tui_argv expecting
the Ink/npm flow unconditionally; with the dual-engine dispatch merged in,
_resolve_tui_engine() auto-selects opentui whenever ui-opentui/dist is built
in the repo, routing the call away from the path under test (first subprocess
became 'node --version' instead of 'npm run build'). Pin the engine to ink
via an autouse fixture, mirroring the existing pinning precedent in
test_tui_resume_flow.py.
This commit is contained in:
alt-glitch 2026-06-12 10:32:40 +05:30
parent ab37440ce6
commit e1067dbbe5
756 changed files with 79874 additions and 19585 deletions

View file

@ -4,6 +4,7 @@ import os
import json
import shutil
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch, MagicMock
import pytest
@ -1069,6 +1070,148 @@ class TestWebServerEndpoints:
assert "GATEWAY_PROXY_URL" not in managed
assert "GATEWAY_PROXY_URL" in _MESSAGING_KEYS_PAGE_KEYS
def test_model_set_requires_confirmation_for_expensive_model(self, monkeypatch):
monkeypatch.setattr(
"hermes_cli.model_cost_guard.expensive_model_warning",
lambda *_args, **_kwargs: SimpleNamespace(message="EXPENSIVE MODEL WARNING"),
)
resp = self.client.post(
"/api/model/set",
json={
"scope": "main",
"provider": "nous",
"model": "openai/gpt-5.5-pro",
},
)
assert resp.status_code == 200
data = resp.json()
assert data["ok"] is False
assert data["confirm_required"] is True
assert data["confirm_message"] == "EXPENSIVE MODEL WARNING"
confirmed = self.client.post(
"/api/model/set",
json={
"scope": "main",
"provider": "nous",
"model": "openai/gpt-5.5-pro",
"confirm_expensive_model": True,
},
)
assert confirmed.status_code == 200
assert confirmed.json()["ok"] is True
def test_model_set_normalizes_vendor_slug_for_native_provider(self, monkeypatch):
"""'Use as → Main' with an OpenRouter slug + native provider must not
persist the vendor-prefixed slug verbatim (it 400s against the native
API and reads as "changing models does nothing")."""
monkeypatch.setattr(
"hermes_cli.model_cost_guard.expensive_model_warning",
lambda *_args, **_kwargs: None,
)
resp = self.client.post(
"/api/model/set",
json={
"scope": "main",
"provider": "anthropic",
"model": "anthropic/claude-opus-4.6",
},
)
assert resp.status_code == 200
data = resp.json()
assert data["ok"] is True
assert data["provider"] == "anthropic"
# Vendor prefix stripped + dots→hyphens for the native Anthropic API.
assert data["model"] == "claude-opus-4-6"
from hermes_cli.config import load_config
cfg = load_config()
assert cfg["model"]["provider"] == "anthropic"
assert cfg["model"]["default"] == "claude-opus-4-6"
def test_model_set_maps_unknown_vendor_to_aggregator(self, monkeypatch):
"""A bare vendor name from analytics rows (no billing_provider) is not
a Hermes provider keep the user's aggregator instead of writing a
provider that can never resolve credentials."""
monkeypatch.setattr(
"hermes_cli.model_cost_guard.expensive_model_warning",
lambda *_args, **_kwargs: None,
)
from hermes_cli.config import load_config, save_config
cfg = load_config()
cfg["model"] = {"provider": "openrouter", "default": "openai/gpt-5.5"}
save_config(cfg)
resp = self.client.post(
"/api/model/set",
json={
"scope": "main",
"provider": "moonshotai", # vendor prefix, not a provider
"model": "moonshotai/kimi-k2.6",
},
)
assert resp.status_code == 200
data = resp.json()
assert data["ok"] is True
assert data["provider"] == "openrouter"
assert data["model"] == "moonshotai/kimi-k2.6"
def test_model_set_keeps_aggregator_slug_unchanged(self, monkeypatch):
"""The happy path (picker → openrouter + vendor/model) is untouched."""
monkeypatch.setattr(
"hermes_cli.model_cost_guard.expensive_model_warning",
lambda *_args, **_kwargs: None,
)
resp = self.client.post(
"/api/model/set",
json={
"scope": "main",
"provider": "openrouter",
"model": "anthropic/claude-sonnet-4.6",
},
)
assert resp.status_code == 200
data = resp.json()
assert data["ok"] is True
assert data["provider"] == "openrouter"
assert data["model"] == "anthropic/claude-sonnet-4.6"
def test_ops_import_passes_force_flag(self, tmp_path, monkeypatch):
"""force=True must append --force so the spawned non-interactive
`hermes import` doesn't auto-abort at the overwrite prompt."""
import hermes_cli.web_server as ws
archive = tmp_path / "backup.zip"
import zipfile
with zipfile.ZipFile(archive, "w") as zf:
zf.writestr("config.yaml", "model: {}\n")
captured = {}
def fake_spawn(subcommand, name):
captured["args"] = subcommand
captured["name"] = name
from types import SimpleNamespace as NS
return NS(pid=12345)
monkeypatch.setattr(ws, "_spawn_hermes_action", fake_spawn)
resp = self.client.post(
"/api/ops/import", json={"archive": str(archive), "force": True},
)
assert resp.status_code == 200
assert captured["args"] == ["import", str(archive), "--force"]
resp = self.client.post(
"/api/ops/import", json={"archive": str(archive)},
)
assert resp.status_code == 200
assert captured["args"] == ["import", str(archive)]
def test_reveal_env_var(self, tmp_path):
"""POST /api/env/reveal should return the real unredacted value."""
from hermes_cli.config import save_env_value
@ -1363,6 +1506,17 @@ class TestWebServerEndpoints:
}
monkeypatch.setattr(ws, "_telegram_onboarding_request_sync", fake_request)
ws._ACTION_PROCS.pop("gateway-restart", None)
restart_calls = []
class FakeRestartProc:
pid = 4242
def fake_spawn_action(subcommand, name):
restart_calls.append((subcommand, name))
return FakeRestartProc()
monkeypatch.setattr(ws, "_spawn_hermes_action", fake_spawn_action)
start = self.client.post("/api/messaging/telegram/onboarding/start", json={})
assert start.status_code == 200
@ -1384,13 +1538,138 @@ class TestWebServerEndpoints:
"ok": True,
"platform": "telegram",
"bot_username": "hermes_pair_ready_bot",
"needs_restart": True,
"needs_restart": False,
"restart_started": True,
"restart_action": "gateway-restart",
"restart_pid": 4242,
}
assert restart_calls == [(["gateway", "restart"], "gateway-restart")]
env = load_env()
assert env["TELEGRAM_BOT_TOKEN"] == "123456:SECRET"
assert env["TELEGRAM_ALLOWED_USERS"] == "123456789"
assert load_config()["platforms"]["telegram"]["enabled"] is True
def test_telegram_onboarding_apply_reports_restart_failure_after_save(
self, monkeypatch
):
import hermes_cli.web_server as ws
from hermes_cli.config import load_config, load_env
with ws._telegram_onboarding_lock:
ws._telegram_onboarding_pairings.clear()
def fake_request(method, path, *, body=None, bearer_token=None):
if method == "POST":
return {
"pairing_id": "pair-restart-fails",
"poll_token": "poll-secret",
"suggested_username": "hermes_pair_restart_fails_bot",
"deep_link": "https://t.me/newbot/HermesSetupBot/hermes_pair_restart_fails_bot",
"qr_payload": "https://t.me/newbot/HermesSetupBot/hermes_pair_restart_fails_bot",
"expires_at": "2027-05-18T00:00:00.000Z",
}
assert method == "GET"
assert path == "/v1/telegram/pairings/pair-restart-fails"
assert bearer_token == "poll-secret"
return {
"status": "ready",
"bot_username": "hermes_pair_restart_fails_bot",
"owner_user_id": 123456789,
"token": "123456:SECRET",
}
monkeypatch.setattr(ws, "_telegram_onboarding_request_sync", fake_request)
ws._ACTION_PROCS.pop("gateway-restart", None)
def fail_spawn_action(subcommand, name):
assert subcommand == ["gateway", "restart"]
assert name == "gateway-restart"
raise RuntimeError("supervisor unavailable")
monkeypatch.setattr(ws, "_spawn_hermes_action", fail_spawn_action)
start = self.client.post("/api/messaging/telegram/onboarding/start", json={})
assert start.status_code == 200
ready = self.client.get("/api/messaging/telegram/onboarding/pair-restart-fails")
assert ready.status_code == 200
assert ready.json()["status"] == "ready"
applied = self.client.post(
"/api/messaging/telegram/onboarding/pair-restart-fails/apply",
json={"allowed_user_ids": ["123456789"]},
)
assert applied.status_code == 200
applied_data = applied.json()
assert applied_data["ok"] is True
assert applied_data["needs_restart"] is True
assert applied_data["restart_started"] is False
assert "supervisor unavailable" in applied_data["restart_error"]
assert "token" not in applied_data
env = load_env()
assert env["TELEGRAM_BOT_TOKEN"] == "123456:SECRET"
assert env["TELEGRAM_ALLOWED_USERS"] == "123456789"
assert load_config()["platforms"]["telegram"]["enabled"] is True
def test_telegram_onboarding_apply_reuses_inflight_gateway_restart(
self, monkeypatch
):
"""A live in-flight gateway restart is reused instead of spawning a
second racing ``hermes gateway restart`` child (e.g. when a stale
cached frontend also fires its own restart call)."""
import hermes_cli.web_server as ws
with ws._telegram_onboarding_lock:
ws._telegram_onboarding_pairings.clear()
def fake_request(method, path, *, body=None, bearer_token=None):
if method == "POST":
return {
"pairing_id": "pair-reuse",
"poll_token": "poll-secret",
"suggested_username": "hermes_pair_reuse_bot",
"deep_link": "https://t.me/newbot/HermesSetupBot/hermes_pair_reuse_bot",
"qr_payload": "https://t.me/newbot/HermesSetupBot/hermes_pair_reuse_bot",
"expires_at": "2027-05-18T00:00:00.000Z",
}
return {
"status": "ready",
"bot_username": "hermes_pair_reuse_bot",
"owner_user_id": 123456789,
"token": "123456:SECRET",
}
monkeypatch.setattr(ws, "_telegram_onboarding_request_sync", fake_request)
class FakeRunningProc:
pid = 5151
def poll(self):
return None # still running
monkeypatch.setitem(ws._ACTION_PROCS, "gateway-restart", FakeRunningProc())
def fail_spawn_action(subcommand, name):
raise AssertionError("must not spawn a second concurrent restart")
monkeypatch.setattr(ws, "_spawn_hermes_action", fail_spawn_action)
start = self.client.post("/api/messaging/telegram/onboarding/start", json={})
assert start.status_code == 200
ready = self.client.get("/api/messaging/telegram/onboarding/pair-reuse")
assert ready.status_code == 200
applied = self.client.post(
"/api/messaging/telegram/onboarding/pair-reuse/apply",
json={"allowed_user_ids": ["123456789"]},
)
assert applied.status_code == 200
applied_data = applied.json()
assert applied_data["needs_restart"] is False
assert applied_data["restart_started"] is True
assert applied_data["restart_pid"] == 5151
def test_telegram_onboarding_apply_requires_ready_pairing(self, monkeypatch):
import hermes_cli.web_server as ws
@ -1601,6 +1880,28 @@ class TestWebServerEndpoints:
out = _apply_main_model_assignment("not-a-dict", "custom", "m", "http://x/v1")
assert out == {"provider": "custom", "default": "m", "base_url": "http://x/v1"}
# api_key follows the same lifecycle as base_url:
# supplied → persisted.
out = _apply_main_model_assignment(
{}, "custom", "m", "http://x/v1", "sk-secret"
)
assert out["api_key"] == "sk-secret"
# same provider, no new key → existing key preserved (re-picking a model
# on the same custom endpoint must not wipe the saved key).
out = _apply_main_model_assignment(
{"provider": "custom", "base_url": "http://x/v1", "api_key": "sk-keep"},
"custom",
"m2",
)
assert out["api_key"] == "sk-keep"
# switching providers without a new key → stale key cleared.
out = _apply_main_model_assignment(
{"provider": "custom", "api_key": "sk-old"}, "openrouter", "m"
)
assert out["api_key"] == ""
def test_parse_model_ids_handles_openai_and_bare_shapes(self):
"""Model discovery must tolerate the common /v1/models shapes and
never raise (so a slightly non-standard local endpoint still works)."""
@ -1657,6 +1958,45 @@ class TestWebServerEndpoints:
assert model_cfg["default"] == "llama-3.1-8b"
assert model_cfg["base_url"] == "http://127.0.0.1:8000/v1"
def test_set_model_main_custom_persists_api_key_and_registers_provider(self):
"""A custom endpoint that requires auth must persist model.api_key (where
the runtime reads it) AND register a named custom_providers entry so the
endpoint reappears as a ready row in the picker matching the
``hermes model`` custom flow. Regression for the desktop loop where a
keyed custom endpoint could never be configured from the GUI."""
from hermes_cli.config import load_config
resp = self.client.post(
"/api/model/set",
json={
"scope": "main",
"provider": "custom",
"model": "gpt-oss-120b",
"base_url": "https://text.example.com/v1",
"api_key": "sk-secret",
},
)
assert resp.status_code == 200
assert resp.json()["ok"] is True
cfg = load_config()
model_cfg = cfg.get("model")
assert isinstance(model_cfg, dict)
assert model_cfg["provider"] == "custom"
assert model_cfg["base_url"] == "https://text.example.com/v1"
assert model_cfg["api_key"] == "sk-secret"
# Registered in custom_providers (dedup by base_url) so the picker shows
# a proper ready row instead of the "needs setup" dead-end.
custom = cfg.get("custom_providers") or []
assert any(
isinstance(e, dict)
and e.get("base_url") == "https://text.example.com/v1"
and e.get("api_key") == "sk-secret"
and e.get("model") == "gpt-oss-120b"
for e in custom
)
def test_set_model_main_non_custom_clears_stale_base_url(self):
"""Switching to a hosted provider must clear a stale base_url so the
resolver picks that provider's own default endpoint."""
@ -2081,6 +2421,42 @@ class TestNewEndpoints:
resp = self.client.get("/api/cron/jobs/nonexistent-id")
assert resp.status_code == 404
# --- Automation Blueprints ---
def test_cron_blueprints_list(self):
resp = self.client.get("/api/cron/blueprints")
assert resp.status_code == 200
blueprints = resp.json()["blueprints"]
assert len(blueprints) >= 1
first = blueprints[0]
assert "fields" in first
assert first["command"].startswith("/blueprint")
assert first["appUrl"].startswith("hermes://")
def test_blueprint_instantiate_creates_job(self):
resp = self.client.post(
"/api/cron/blueprints/instantiate",
json={"blueprint": "morning-brief", "values": {"time": "07:30", "deliver": "local"}},
)
assert resp.status_code == 200
job = resp.json()
assert (job.get("schedule_display") or "").strip() == "30 7 * * *" or \
(job.get("schedule", {}) or {}).get("expr") == "30 7 * * *"
def test_blueprint_instantiate_unknown_404(self):
resp = self.client.post(
"/api/cron/blueprints/instantiate",
json={"blueprint": "does-not-exist", "values": {}},
)
assert resp.status_code == 404
def test_blueprint_instantiate_bad_value_422(self):
resp = self.client.post(
"/api/cron/blueprints/instantiate",
json={"blueprint": "morning-brief", "values": {"time": "99:99"}},
)
assert resp.status_code == 422
# --- Profiles ---
def test_profiles_list_includes_default(self):
@ -2253,6 +2629,83 @@ class TestNewEndpoints:
profiles = {p["name"]: p for p in self.client.get("/api/profiles").json()["profiles"]}
assert profiles["fresh"]["skill_count"] == 1
def test_profiles_create_builder_fields_model_mcp_and_keep_skills(self, monkeypatch):
"""Profile-builder create: model + MCP servers + keep-skills selection
all land in the NEW profile's config, and hub installs are spawned
scoped to that profile via ``-p <name>``."""
from hermes_constants import (
get_hermes_home,
set_hermes_home_override,
reset_hermes_home_override,
)
from hermes_cli.config import load_config
from hermes_cli.skills_config import get_disabled_skills
import hermes_cli.profiles as profiles_mod
import hermes_cli.web_server as web_server
monkeypatch.setattr(profiles_mod, "create_wrapper_script", lambda name: None)
# Seed two known skills so keep-skills "replace" has something to act on.
def fake_seed(profile_dir, quiet=False):
for skill in ("keep-me", "drop-me"):
d = profile_dir / "skills" / "custom" / skill
d.mkdir(parents=True)
(d / "SKILL.md").write_text(f"---\nname: {skill}\n---\n", encoding="utf-8")
return {"copied": ["keep-me", "drop-me"]}
monkeypatch.setattr(profiles_mod, "seed_profile_skills", fake_seed)
# Capture hub-install spawns instead of launching real subprocesses.
spawned = []
class _FakeProc:
pid = 4321
def fake_spawn(subcommand, name):
spawned.append((list(subcommand), name))
return _FakeProc()
monkeypatch.setattr(web_server, "_spawn_hermes_action", fake_spawn)
resp = self.client.post(
"/api/profiles",
json={
"name": "builder",
"provider": "openrouter",
"model": "anthropic/claude-sonnet-4.6",
"mcp_servers": [
{"name": "ctx7", "url": "https://mcp.context7.com/mcp"},
{"name": "bogus"}, # no url/command -> must be skipped, no 500
],
"keep_skills": ["keep-me"],
"hub_skills": ["someuser/some-skill"],
},
)
assert resp.status_code == 200
data = resp.json()
assert data["model_set"] is True
assert data["mcp_written"] == 1 # bogus skipped
assert data["skills_disabled"] == 1 # drop-me disabled, keep-me kept
assert data["hub_installs"] == [{"identifier": "someuser/some-skill", "pid": 4321}]
# Hub install was scoped to the new profile.
assert spawned == [(["-p", "builder", "skills", "install", "someuser/some-skill"], "skills-install")]
# Verify the writes landed in the NEW profile's config, not the root.
prof_dir = get_hermes_home() / "profiles" / "builder"
token = set_hermes_home_override(str(prof_dir))
try:
cfg = load_config()
assert cfg["model"]["default"] == "anthropic/claude-sonnet-4.6"
assert cfg["model"]["provider"] == "openrouter"
assert sorted((cfg.get("mcp_servers") or {}).keys()) == ["ctx7"]
disabled = get_disabled_skills(cfg)
assert "drop-me" in disabled
assert "keep-me" not in disabled
finally:
reset_hermes_home_override(token)
def test_profile_open_terminal_uses_macos_terminal(self, monkeypatch):
from hermes_constants import get_hermes_home
import hermes_cli.web_server as web_server
@ -4146,6 +4599,39 @@ class TestPtyWebSocket:
assert env["HERMES_TUI_INLINE"] == "1"
assert env["HERMES_TUI_DISABLE_MOUSE"] == "1"
def test_resolve_chat_argv_applies_terminal_backend_config(
self, monkeypatch, _isolate_hermes_home
):
import hermes_cli.main as main_mod
config_path = Path(os.environ["HERMES_HOME"]) / "config.yaml"
config_path.write_text(
"\n".join(
[
"terminal:",
" backend: docker",
" docker_image: example/hermes-tools:latest",
" docker_extra_args:",
" - --network=host",
]
),
encoding="utf-8",
)
monkeypatch.delenv("TERMINAL_ENV", raising=False)
monkeypatch.delenv("TERMINAL_DOCKER_IMAGE", raising=False)
monkeypatch.delenv("TERMINAL_DOCKER_EXTRA_ARGS", raising=False)
monkeypatch.setattr(
main_mod,
"_make_tui_argv",
lambda project_root, tui_dev=False: (["node", "dist/entry.js"], "/tmp/ui-tui"),
)
_argv, _cwd, env = self.ws_module._resolve_chat_argv()
assert env["TERMINAL_ENV"] == "docker"
assert env["TERMINAL_DOCKER_IMAGE"] == "example/hermes-tools:latest"
assert env["TERMINAL_DOCKER_EXTRA_ARGS"] == '["--network=host"]'
def test_rejects_when_embedded_chat_disabled(self, monkeypatch):
monkeypatch.setattr(self.ws_module, "_DASHBOARD_EMBEDDED_CHAT_ENABLED", False)
from starlette.websockets import WebSocketDisconnect
@ -4159,7 +4645,7 @@ class TestPtyWebSocket:
monkeypatch.setattr(
self.ws_module,
"_resolve_chat_argv",
lambda resume=None, sidecar_url=None: (["/bin/cat"], None, None),
lambda resume=None, sidecar_url=None, profile=None: (["/bin/cat"], None, None),
)
from starlette.websockets import WebSocketDisconnect
@ -4172,7 +4658,7 @@ class TestPtyWebSocket:
monkeypatch.setattr(
self.ws_module,
"_resolve_chat_argv",
lambda resume=None, sidecar_url=None: (["/bin/cat"], None, None),
lambda resume=None, sidecar_url=None, profile=None: (["/bin/cat"], None, None),
)
from starlette.websockets import WebSocketDisconnect
@ -4185,7 +4671,7 @@ class TestPtyWebSocket:
monkeypatch.setattr(
self.ws_module,
"_resolve_chat_argv",
lambda resume=None, sidecar_url=None: (
lambda resume=None, sidecar_url=None, profile=None: (
["/bin/sh", "-c", "printf hermes-ws-ok"],
None,
None,
@ -4215,7 +4701,7 @@ class TestPtyWebSocket:
monkeypatch.setattr(
self.ws_module,
"_resolve_chat_argv",
lambda resume=None, sidecar_url=None: (["/bin/cat"], None, None),
lambda resume=None, sidecar_url=None, profile=None: (["/bin/cat"], None, None),
)
with self.client.websocket_connect(self._url()) as conn:
conn.send_bytes(b"round-trip-payload\n")
@ -4248,7 +4734,7 @@ class TestPtyWebSocket:
self.ws_module,
"_resolve_chat_argv",
# sleep gives the test time to push the resize before the child reads the ioctl.
lambda resume=None, sidecar_url=None: (
lambda resume=None, sidecar_url=None, profile=None: (
[sys.executable, "-c", winsize_script],
None,
None,
@ -4284,7 +4770,7 @@ class TestPtyWebSocket:
monkeypatch.setattr(
self.ws_module,
"_resolve_chat_argv",
lambda resume=None, sidecar_url=None: (["/bin/cat"], None, None),
lambda resume=None, sidecar_url=None, profile=None: (["/bin/cat"], None, None),
)
# Patch PtyBridge.spawn at the web_server module's binding.
import hermes_cli.web_server as ws_mod
@ -4299,7 +4785,7 @@ class TestPtyWebSocket:
def test_resume_parameter_is_forwarded_to_argv(self, monkeypatch):
captured: dict = {}
def fake_resolve(resume=None, sidecar_url=None):
def fake_resolve(resume=None, sidecar_url=None, profile=None):
captured["resume"] = resume
return (["/bin/sh", "-c", "printf resume-arg-ok"], None, None)
@ -4319,7 +4805,7 @@ class TestPtyWebSocket:
same channel which is how tool events reach the dashboard sidebar."""
captured: dict = {}
def fake_resolve(resume=None, sidecar_url=None):
def fake_resolve(resume=None, sidecar_url=None, profile=None):
captured["sidecar_url"] = sidecar_url
return (["/bin/sh", "-c", "printf sidecar-ok"], None, None)
@ -4593,6 +5079,83 @@ class TestValidateProviderCredential:
data = self._post("OPENAI_API_KEY", " ").json()
assert data["ok"] is False
def test_local_endpoint_forwards_api_key_as_bearer(self, monkeypatch):
"""A custom endpoint that gates /v1/models behind auth must still
enumerate models: the optional api_key is sent as a Bearer header so the
probe doesn't come back empty (the desktop loop's root cause)."""
captured = {}
class _Resp:
status_code = 200
is_success = True
def json(self):
return {"data": [{"id": "gpt-oss-120b"}]}
class _Client:
def __init__(self, *a, **k):
pass
def __enter__(self):
return self
def __exit__(self, *a):
return False
def get(self, url, *a, headers=None, **k):
captured["url"] = url
captured["headers"] = headers
return _Resp()
monkeypatch.setattr("httpx.Client", _Client)
resp = self.client.post(
"/api/providers/validate",
json={
"key": "OPENAI_BASE_URL",
"value": "https://text.example.com/v1",
"api_key": "sk-secret",
},
)
data = resp.json()
assert data["ok"] is True and data["reachable"] is True
assert data["models"] == ["gpt-oss-120b"]
assert captured["url"] == "https://text.example.com/v1/models"
assert captured["headers"] == {"Authorization": "Bearer sk-secret"}
def test_local_endpoint_without_key_sends_no_auth_header(self, monkeypatch):
"""No key → no Authorization header (keyless local servers unaffected)."""
captured = {}
class _Resp:
status_code = 200
is_success = True
def json(self):
return {"data": []}
class _Client:
def __init__(self, *a, **k):
pass
def __enter__(self):
return self
def __exit__(self, *a):
return False
def get(self, url, *a, headers=None, **k):
captured["headers"] = headers
return _Resp()
monkeypatch.setattr("httpx.Client", _Client)
self.client.post(
"/api/providers/validate",
json={"key": "OPENAI_BASE_URL", "value": "http://127.0.0.1:8000/v1"},
)
assert captured["headers"] is None
class TestDesktopCronTicker:
"""The dashboard backend fires cron jobs itself only when desktop-spawned."""