diff --git a/agent/file_safety.py b/agent/file_safety.py index 7a70f9641..0d71400c8 100644 --- a/agent/file_safety.py +++ b/agent/file_safety.py @@ -77,15 +77,21 @@ def build_write_denied_prefixes(home: str) -> list[str]: ] -def get_safe_write_root() -> Optional[str]: - """Return the resolved HERMES_WRITE_SAFE_ROOT path, or None if unset.""" - root = os.getenv("HERMES_WRITE_SAFE_ROOT", "") - if not root: - return None - try: - return os.path.realpath(os.path.expanduser(root)) - except Exception: - return None +def get_safe_write_roots() -> set[str]: + """Return resolved HERMES_WRITE_SAFE_ROOT paths. Supports multiple directories + separated by ':' (Unix PATH-style). E.g., '/opt/data:/var/www/html'.""" + env = os.getenv("HERMES_WRITE_SAFE_ROOT", "") + if not env: + return set() + roots: set[str] = set() + for path in env.split(":"): + if path: + try: + resolved = os.path.realpath(os.path.expanduser(path)) + roots.add(resolved) + except Exception: + continue + return roots def is_write_denied(path: str) -> bool: @@ -124,9 +130,16 @@ def is_write_denied(path: str) -> bool: except Exception: pass - safe_root = get_safe_write_root() - if safe_root and not (resolved == safe_root or resolved.startswith(safe_root + os.sep)): - return True + safe_roots = get_safe_write_roots() + if safe_roots: + # Allow write if path is under ANY of the safe roots + allowed = False + for safe_root in safe_roots: + if resolved == safe_root or resolved.startswith(safe_root + os.sep): + allowed = True + break + if not allowed: + return True return False