Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions gateway/platforms/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ def is_host_excluded_by_no_proxy(hostname: str, no_proxy_value: str | None = Non

from gateway.config import Platform, PlatformConfig
from gateway.session import SessionSource, build_session_key
from hermes_constants import get_hermes_dir, get_hermes_home
from hermes_constants import get_default_hermes_root, get_hermes_dir, get_hermes_home


GATEWAY_SECRET_CAPTURE_UNSUPPORTED_MESSAGE = (
Expand Down Expand Up @@ -827,6 +827,7 @@ def cache_video_from_bytes(data: bytes, ext: str = ".mp4") -> str:
DOCUMENT_CACHE_DIR = get_hermes_dir("cache/documents", "document_cache")
SCREENSHOT_CACHE_DIR = get_hermes_dir("cache/screenshots", "browser_screenshots")
_HERMES_HOME = get_hermes_home()
_HERMES_ROOT = get_default_hermes_root()
MEDIA_DELIVERY_ALLOW_DIRS_ENV = "HERMES_MEDIA_ALLOW_DIRS"
MEDIA_DELIVERY_TRUST_RECENT_ENV = "HERMES_MEDIA_TRUST_RECENT_FILES"
MEDIA_DELIVERY_TRUST_RECENT_SECONDS_ENV = "HERMES_MEDIA_TRUST_RECENT_SECONDS"
Expand Down Expand Up @@ -954,13 +955,14 @@ def _media_delivery_denied_paths() -> List[Path]:
home = Path(os.path.expanduser("~"))
for sub in _MEDIA_DELIVERY_DENIED_HOME_SUBPATHS:
denied.append(home / sub)
# The Hermes home itself contains credentials (auth.json, .env) and
# configuration (config.yaml) — only the cache subdirectories under it
# are explicitly allowlisted above.
denied.append(_HERMES_HOME / ".env")
denied.append(_HERMES_HOME / "auth.json")
denied.append(_HERMES_HOME / "credentials")
denied.append(_HERMES_HOME / "config.yaml")
# The active Hermes profile and shared Hermes root both contain control
# files and credentials. Only cache subdirectories under them are
# explicitly allowlisted above.
for hermes_root in (_HERMES_HOME, _HERMES_ROOT):
denied.append(hermes_root / ".env")
denied.append(hermes_root / "auth.json")
denied.append(hermes_root / "credentials")
denied.append(hermes_root / "config.yaml")
return denied


Expand Down
39 changes: 39 additions & 0 deletions tests/gateway/test_platform_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,45 @@ def test_denylist_blocks_hermes_credentials(self, tmp_path, monkeypatch):

assert BasePlatformAdapter.validate_media_delivery_path(str(env_file)) is None

def test_denylist_blocks_hermes_config_in_active_profile(self, tmp_path, monkeypatch):
"""The active profile config stays blocked in default mode."""
self._patch_roots(monkeypatch)

fake_home = tmp_path / "home"
hermes_dir = fake_home / ".hermes"
hermes_dir.mkdir(parents=True)
config_file = hermes_dir / "config.yaml"
config_file.write_text("model:\n provider: openai\n")
monkeypatch.setenv("HOME", str(fake_home))
monkeypatch.setattr(
"gateway.platforms.base._HERMES_HOME",
hermes_dir,
)

assert BasePlatformAdapter.validate_media_delivery_path(str(config_file)) is None

def test_denylist_blocks_shared_hermes_root_config_for_profiles(self, tmp_path, monkeypatch):
"""Profile-mode gateways must still block the shared Hermes root config."""
self._patch_roots(monkeypatch)

fake_home = tmp_path / "home"
profile_home = fake_home / ".hermes" / "profiles" / "work"
profile_home.mkdir(parents=True)
hermes_root = fake_home / ".hermes"
config_file = hermes_root / "config.yaml"
config_file.write_text("profiles:\n active: work\n")
monkeypatch.setenv("HOME", str(fake_home))
monkeypatch.setattr(
"gateway.platforms.base._HERMES_HOME",
profile_home,
)
monkeypatch.setattr(
"gateway.platforms.base._HERMES_ROOT",
hermes_root,
)

assert BasePlatformAdapter.validate_media_delivery_path(str(config_file)) is None

def test_strict_mode_envvar_restores_legacy_behavior(self, tmp_path, monkeypatch):
"""Setting HERMES_MEDIA_DELIVERY_STRICT=1 reactivates the older
allowlist+recency logic. A stale file outside the allowlist is
Expand Down
Loading