#!/usr/bin/env python3 """Patch hermes-agent: sandbox isolation DISABLED (2026-05-09 emergency fix). The original patch had a CRITICAL indentation bug in the Popen hook: old_popen = "proc = subprocess.Popen(\n args," # no leading spaces new_popen = " # Hermes Bot patch: ...\n" # 8 leading spaces → str.replace doubled indentation (8+8=16 spaces) → IndentationError → local.py failed to import → terminal tool completely broken This no-op version preserves the file so start.sh doesn't error, but does NOT inject any code into local.py. Re-enable after rewriting with correct indentation matching (include leading spaces in old_popen to prevent double-indentation). """ import sys import os import glob def patch_file(filepath: str) -> bool: """No-op: sandbox isolation patch is disabled.""" # If previously patched, REMOVE the sandbox code to restore clean state with open(filepath, "r") as f: content = f.read() if "sandbox_wrap" not in content: print(f" [local.py] Clean (no sandbox code found)") return True # Remove the sandbox wrapper code block sandbox_start = content.find("# ── Hermes Bot patch: Sandbox isolation for dangerous commands ──") if sandbox_start < 0: sandbox_start = content.find("# Hermes Bot patch: Sandbox isolation for dangerous commands") if sandbox_start < 0: print(f" [local.py] sandbox_wrap found but no injection marker — manual cleanup needed") return True # Find the insertion point: the line before the sandbox block # Walk backwards to find the start of the injected block line_start = content.rfind("\n", 0, sandbox_start) if line_start < 0: line_start = 0 else: line_start += 1 # skip the \n # Find the end of the sandbox code block # The block ends with a blank line before the next original code # Look for the pattern that indicates end of injected code # The sandbox code block ends with the closing of should_sandbox function sandbox_end_markers = [ "\n\ndef _resolve_safe_cwd", # original function after injection point "\n\ndef _build_provider_env", # alternative "\n\nclass LocalEnvironment", # if injected before class ] sandbox_end = -1 for marker in sandbox_end_markers: pos = content.find(marker, sandbox_start) if pos > 0: sandbox_end = pos break if sandbox_end < 0: # Fallback: find the next top-level def or class after sandbox_start import re m = re.search(r'\n(def |class )', content[sandbox_start + 100:]) if m: sandbox_end = sandbox_start + 100 + m.start() else: print(f" [local.py] Could not find end of sandbox block — skipping cleanup") return False # Also remove the hook code from _run_bash if present hook_pattern = " # Hermes Bot patch: auto-sandbox dangerous commands\n" new_content = content[line_start:sandbox_end] new_content2 = new_content.replace(hook_pattern, "") if len(new_content2) < len(new_content): # Remove the if should_sandbox block too import re new_content2 = re.sub( r'\n if should_sandbox\(cmd_string\):\n.*?(?=\n proc = subprocess\.Popen)', '\n', new_content2, flags=re.DOTALL, ) content = content[:line_start] + new_content2 + content[sandbox_end:] print(f" [local.py] Removed sandbox hook from _run_bash") else: content = content[:line_start] + content[sandbox_end:] print(f" [local.py] Removed sandbox wrapper code block") with open(filepath, "w") as f: f.write(content) print(f" [local.py] Sandbox isolation REMOVED (emergency fix)") return True if __name__ == "__main__": print("Sandbox isolation patch: DISABLED (emergency fix 2026-05-09)") print(" Reason: indentation bug caused local.py IndentationError") candidates = [ "/app/hermes-agent/tools/environments/local.py", ] candidates.extend( glob.glob("/app/venv/lib/**/tools/environments/local.py", recursive=True) ) filepath = None for c in candidates: if os.path.isfile(c): filepath = c break if not filepath: print(" local.py not found — nothing to do") sys.exit(0) patch_file(filepath) print(" Terminal tool should now work normally")