Skip to content

Sandbox-Backends (sandbox backends)

源码版本v2026.7.20

Verantwortung

Der Agent muss Befehle ausführen und Code laufen lassen, aber beliebige Befehle dürfen nicht direkt auf den Host durchschlagen. Das Terminal-Werkzeug (tool) von Hermes unterstützt 6 Ausführungs-Backends, gewählt nach Sicherheits-/Isolations-/Kosten-Trade-off: Local (direkt auf dem Host), Docker (Container-Isolation), SSH (entfernte Maschine), Singularity (HPC-Container), Modal (Cloud-Sandbox (sandbox), direct oder managed), Daytona (Cloud-Dev-Umgebung). Container-Härtung + Namespace-Isolation; gefährliche Befehle werden zudem von Approval-Callbacks abgefangen.

Designmotiv

Warum 6 statt 1? Die Ausführungsszenarien des Agenten spannen zu weit — bei der Entwicklung will man nur schnell lokal laufen, in Produktion für Batch brauchen wir Container-Isolation, HPC-Nutzer müssen in Singularity arbeiten (Docker geht nicht), in der Cloud unbeaufsichtigt braucht man einen sekundengenau abrechnenden Cloud-Sandkasten wie Modal. Kein einzelnes Backend deckt alles. Hermes abstrahiert «Ausführung» als einheitliche Schnittstelle; Backends werden nach Szenario zusammengesetzt; der Approval-Callback für gefährliche Befehle ist backend-übergreifend gleich. Das Docker-Backend prüft explizit, ob ein Bind Mount Host-Pfade freilegt, weil die Sicherheitsannahme der Container-Isolation lautet «Container sieht nicht nach draußen»; sobald docker run -v /:/host dabeistehn, ist das gebrochen. Modal unterscheidet direct (Credentials des Nutzers) und managed (vom Gateway (gateway) verwaltet), denn jenes läuft über die Nutzerrechnung, dieses über das Nous-Portal-Kontingent — Berechtigungs- und Abrechnungspfad sind völlig verschieden. Diese Prüflogik liegt nicht im Backend, sondern in tool_backend_helpers.py, sodass Backend-Wahl und Sicherheitsbewertung entkoppelt sind.

Schlüsseldateien

Datenfluss

  1. Der Agent will einen Befehl ausführen → tool_call terminaltools/terminal_tool.py.
  2. Das Backend wird gemäß Job-Konfiguration gewählt (local/docker/modal/ssh/singularity/daytona):
  3. Gefährliche Befehle werden von Approval-Callbacks abgefangen – die Hauptschleife nutzt interaktive Approval; Subagenten sind per Default auto-deny (tools/delegate_tool.py:75); Cron/Batch kann opt-in auto-approve aktivieren.
  4. Die Befehlsausgabe wird in die Hauptschleife zurückgefüllt; lange Tasks können in den Hintergrund ausgelagert werden (tools/daemon_pool.py).

Die Backend-Liste ist schlicht deklariert; im Kopf von terminal_tool.py steht ein Kommentar: «A terminal tool that executes commands in local, Docker, Modal, SSH, Singularity, and Daytona environments.»

Das Docker-Backend prüft, ob ein Bind Mount ein Host-Pfad ist, anhand des Spec-Präfix: beginnt er mit /, ~, ./, ../, oder ist (wie bei Windows-Laufwerken C:\) das zweite Zeichen ein Doppelpunkt, gilt er als Host-Pfad, has_host_access=True schlägt an und die Berechtigungen gehen in den strengeren Zweig:

python
def _docker_volume_uses_host_path(volume_spec: str) -> bool:
    """Return True when a docker volume spec bind-mounts a host path."""
    if not isinstance(volume_spec, str):
        return False
    vol = volume_spec.strip()
    return bool(vol) and (
        vol.startswith(("/", "~", "./", "../")) or
        (len(vol) >= 3 and vol[1] == ":" and vol[2] in ("/", "\\"))
    )

Modal-Auflösung hat drei Stufen: direct (eigene Modal-Credentials), managed (Nous-Portal-verwaltet), auto (Default; fällt auf direct zurück, wenn managed nicht verfügbar). resolve_modal_backend_state zentralisiert das an einer Stelle; wählt es kein Backend, gibt es None zurück. has_direct_modal_credentials schaut gleichzeitig auf die Umgebungsvariablen MODAL_TOKEN_ID/MODAL_TOKEN_SECRET und auf die Datei ~/.modal.toml; fehlen beide, ist direct nicht verfügbar. managed_nous_tools_enabled geht über eine Nous-Portal-Kontoabfrage und fail-closed bei Fehler; ein Abfragefehler schaltet nicht versehentlich den managed-Pfad frei.

Singularity ist das HPC-Sonderexistenz — Nutzer können Docker nicht installieren, nur Apptainer/Singularity. _find_singularity_executable sucht zuerst apptainer, dann singularity; fehlen beide, wird mit Installationshinweis gemeldet. Das Scratch-Verzeichnis bevorzugt /scratch (Standard-Mount auf HPC-Clustern), sonst fällt es auf get_sandbox_dir() / "singularity" zurück. Der Container läuft mit --containall --no-home plus Capability-Dropping — auf einem geteilten HPC-Cluster zwingend, sonst sähe man in die Heimatverzeichnisse anderer Nutzer.

Grenzen und Fehler

  • Docker-Bind-Mount-Fehlurteil: Die Prüffunktion wertet Spec-Anfänge mit /, ~, ./, ../ als Host-Pfad; ein Named Volume (z. B. mydata:/data) wird jedoch durchgewunken. Hat das Named Volume einen Custom-Driver, der einen Host-Pfad bindet, sieht _docker_has_host_access das nicht und stuft es fälschlich als niedriges Risiko ein.
  • Modal-managed-Fehlschlag und Fallback (fallback): Im auto-Modus fällt managed-nicht-verfügbar auf direct zurück; hat der Nutzer aber nur managed und keine direct-Credentials, wird selected_backend zu None; die Backend-Wahl scheitert erst zur Laufzeit, beim Anlegen des Terminals ist der Fehler möglicherweise unklar.
  • Singularity-SIF-Cache wächst: SIF-Images sind oft mehrere 100 MB bis GB; ohne Rotationsstrategie für das Scratch-Verzeichnis sprengt es die Platte; /scratch auf HPC-Knoten hat meist eine clusterweite Aufräum-Strategie; passen beide nicht zusammen, kann der Cache vom Cluster weggeräumt werden, während der Agent noch denkt, das SIF sei da.
  • Remote-Backend-Netzschwankung: SSH-/Daytona-Befehl-Ausführung geht über das Netz; bricht die Verbindung, ist die Ausgabe des laufenden Kindprozesses weg. Die Rückfüllung nimmt eine einzelne synchrone Rückgabe an; ein Reconnect mit Fortsetzung gibt es nicht — lange Tasks sind auf Remote-Backends am riskantesten.
  • Timeout und OOM: local/docker haben script_timeout, aber Remote-Backends müssen sich selbst killen; der lokale Scheduler wartet auf eine Antwort, hängt oder wird vom Lease-TTL von _run_job_script_with_claim_heartbeat fälschlich als tot eingestuft.

Zusammenfassung

Die Sandbox-Schicht ist «Ausführungs-Isolation + Kontrolle gefährlicher Befehle»: 6 Backends decken Host bis HPC bis Cloud ab; Docker prüft Bind-Mounts gegen Rechteausweitung; Modal unterscheidet direct-/managed-Anmeldedaten; gefährliche Befehle laufen einheitlich über Approval-Callbacks. Subagenten und Cron laufen über den nicht-interaktiven Pfad auto-deny/auto-approve.

Inoffizielle Community-Lernseite. Basiert auf dem MIT-lizenzierten NousResearch/hermes-agent-Quellcode.