fix(dashboard): map the default root to profile name "default" in _scope_profile_name
Launched from a named profile (HERMES_HOME=<root>/profiles/<name>), the
default root is not the process home, so _scope_profile_name fell through to
path.name and handed the root directory's basename (".hermes" or a custom
root) to _config_profile_scope, which 404s "Profile '<basename>' does not
exist" -- or, if that basename happens to match a real profile, scopes and
writes the wrong one. PUT /api/profiles/default/model and the TUI gateway's
_pin_profile_model both reach this helper.
Return "default" when the path resolves to get_default_hermes_root() before
the path.name fallback; _config_profile_scope("default") already resolves to
the root and builds its secret scope. The second invariant test is reshaped
to the named-profile-launch -> default-target case: 404 before, 200 after,
with the ROOT's .env credential (not the launch profile's) reaching the
validator and only the root config.yaml updated.
This commit is contained in:
@@ -103,9 +103,17 @@ def _profile_setup_command(name: str) -> str:
|
||||
|
||||
def _scope_profile_name(path: Path) -> Optional[str]:
|
||||
"""Map a profile directory onto the query name ``_config_profile_scope`` expects: None for
|
||||
the process home (current-profile semantics: launch secret scope, no home override), the
|
||||
the process home (current-profile semantics: launch secret scope, no home override),
|
||||
``"default"`` for the default root (its basename -- ``.hermes`` or a custom root -- is not a
|
||||
profile name; launched from ``profiles/<name>`` the root is a *different* profile), the
|
||||
directory name for ``profiles/<name>``."""
|
||||
return None if path.resolve() == get_process_hermes_home().resolve() else path.name
|
||||
from hermes_constants import get_default_hermes_root
|
||||
resolved = path.resolve()
|
||||
if resolved == get_process_hermes_home().resolve():
|
||||
return None
|
||||
if resolved == get_default_hermes_root().resolve():
|
||||
return "default"
|
||||
return path.name
|
||||
|
||||
|
||||
def _write_profile_model(profile_dir: Path, provider: str, model: str, validate_in: Optional[Path] = None) -> None:
|
||||
|
||||
@@ -89,19 +89,26 @@ def test_model_pick_resolves_key_env_from_profile_scope(client, homes, probe):
|
||||
assert (load_config().get("model") or {}).get("default") == "acme/mini"
|
||||
|
||||
|
||||
def test_model_pick_for_process_home_uses_launch_scope(client, homes, probe):
|
||||
"""The dashboard's own profile maps to None (current-profile semantics) and still
|
||||
validates through the launch scope once multiplexing is active."""
|
||||
secret_scope.set_multiplex_active(True)
|
||||
try:
|
||||
def test_model_pick_for_default_from_named_profile_launch(homes, probe, monkeypatch):
|
||||
"""Dashboard launched from ``profiles/demo``: targeting ``default`` must scope the ROOT
|
||||
(name ``default``), not the root directory's basename, which is not a profile name."""
|
||||
root, demo = homes
|
||||
monkeypatch.setenv("HERMES_HOME", str(demo))
|
||||
(root / ".env").write_text("ACME_RELAY_KEY=root-key\n", encoding="utf-8")
|
||||
from hermes_cli.config import invalidate_env_cache, load_config
|
||||
from hermes_cli.web_server_profiles import _hermes_home_scope
|
||||
invalidate_env_cache()
|
||||
from hermes_cli import web_server
|
||||
|
||||
with TestClient(web_server.app, raise_server_exceptions=False) as client:
|
||||
client.headers["Authorization"] = f"Bearer {web_server._SESSION_TOKEN}"
|
||||
resp = client.put(
|
||||
"/api/profiles/default/model",
|
||||
json={"provider": "acme", "model": "acme/mini"},
|
||||
"/api/profiles/default/model", json={"provider": "acme", "model": "acme/mini"}
|
||||
)
|
||||
finally:
|
||||
secret_scope.set_multiplex_active(False)
|
||||
|
||||
assert resp.status_code == 200, resp.text
|
||||
# Launch scope: live process env while single-profile... frozen at activation once
|
||||
# multiplexed — the dashboard home's value, resolved through get_secret, not a raise.
|
||||
assert probe["api_key"] == "dashboard-home-key"
|
||||
assert probe["api_key"] == "root-key" # the root's .env, not the launch profile's
|
||||
with _hermes_home_scope(root):
|
||||
assert (load_config().get("model") or {}).get("default") == "acme/mini"
|
||||
with _hermes_home_scope(demo):
|
||||
assert (load_config().get("model") or {}).get("default") is None
|
||||
|
||||
Reference in New Issue
Block a user