fix(#2698): clamp isolated profile lookups to the pinned home

This commit is contained in:
Rod Boev 2026-06-19 19:45:57 -04:00 committed by nesquena-hermes
parent 41f2015a32
commit c7375c60c4
2 changed files with 24 additions and 4 deletions

View file

@ -376,10 +376,17 @@ def _resolve_profile_home_for_name(name: str) -> Path:
names fall back to the base home so traversal-shaped cookie values cannot
influence filesystem paths.
"""
# In isolated mode, the pinned profile name, including a literal
# "default", must resolve to the configured startup HERMES_HOME.
if _is_isolated_profile_mode() and name == _isolated_profile_name():
return Path(_INITIAL_HERMES_HOME).expanduser()
# In isolated mode, every logical profile lookup clamps to the configured
# startup HERMES_HOME so callers cannot resolve a foreign profile path.
if _is_isolated_profile_mode():
isolated_name = _isolated_profile_name()
isolated_home = Path(_INITIAL_HERMES_HOME).expanduser()
if name and not _profiles_match(name, isolated_name):
logger.warning(
"Ignoring profile lookup %r in isolated profile mode; using pinned profile %r",
name, isolated_name,
)
return isolated_home
if not name or _is_root_profile(name):
return _DEFAULT_HERMES_HOME
if not _PROFILE_ID_RE.fullmatch(name):

View file

@ -291,6 +291,19 @@ class TestIsolatedRuntimePinning:
assert get_hermes_home_for_profile("default") == isolated_default
assert get_hermes_home_for_profile("default") != temp_hermes_home
def test_explicit_foreign_profile_resolution_stays_on_isolated_home(self, temp_single_profile, monkeypatch):
"""Explicit profile lookups must not escape the isolated startup home."""
from api.profiles import get_hermes_home_for_profile, _resolve_profile_home_for_name
base_home = temp_single_profile.parent.parent
monkeypatch.setenv("HERMES_HOME", str(temp_single_profile))
monkeypatch.setenv("HERMES_BASE_HOME", "")
monkeypatch.setattr(_profiles_mod, "_DEFAULT_HERMES_HOME", base_home)
monkeypatch.setattr(_profiles_mod, "_INITIAL_HERMES_HOME", str(temp_single_profile))
assert _resolve_profile_home_for_name("other_profile") == temp_single_profile
assert get_hermes_home_for_profile("other_profile") == temp_single_profile
def test_list_profiles_prefers_matching_isolated_default_home(self, temp_hermes_home, monkeypatch):
"""The isolated profiles/default row must not collapse to the base-home row."""
isolated_default = temp_hermes_home / "profiles" / "default"