Spaces:
Running
Running
| """Sandbox network download cap — socket-level, injected via sitecustomize.""" | |
| from __future__ import annotations | |
| import os | |
| from typing import Any | |
| DEFAULT_CAP_KB = 64 * 1024 | |
| GUARD_DIR = "/tmp/mh_net_guard" | |
| GUARD_FILE = f"{GUARD_DIR}/sitecustomize.py" | |
| # The in-sandbox guard. Idempotent (``_mh_net_guarded`` flag) so the | |
| # kernel-preamble variant can re-run it safely in a persistent Jupyter | |
| # kernel. Pure stdlib; every counter operation is fail-open — telemetry | |
| # must never break working agent code. | |
| SITECUSTOMIZE_SOURCE = '''\ | |
| # frontier_agent sandbox network guard (auto-injected; do not edit) | |
| import os as _mh_os | |
| def _mh_install_net_guard(): | |
| try: | |
| _cap = int(_mh_os.environ.get("FRONTIER_AGENT_NET_DOWNLOAD_CAP_BYTES", "0")) | |
| except ValueError: | |
| _cap = 0 | |
| if _cap <= 0: | |
| return | |
| import socket as _socket | |
| import ssl as _ssl | |
| import weakref as _weakref | |
| if getattr(_socket, "_mh_net_guarded", False): | |
| return | |
| _socket._mh_net_guarded = True | |
| _rx = _weakref.WeakKeyDictionary() | |
| _len = len | |
| _msg = ( | |
| "[frontier_agent] per-connection download cap exceeded (%d MB). " | |
| "Downloading large datasets/archives/packages in the sandbox is " | |
| "not allowed. Use aggregate/count API endpoints, sample a few " | |
| "records, or stream + filter and keep only the small subset you " | |
| "need." % max(1, _cap // (1024 * 1024)) | |
| ) | |
| def _bump(sock, n): | |
| try: | |
| total = _rx.get(sock, 0) + n | |
| _rx[sock] = total | |
| except TypeError: | |
| return | |
| if total > _cap: | |
| raise OSError(_msg) | |
| _orig_recv = _socket.socket.recv | |
| _orig_recv_into = _socket.socket.recv_into | |
| def _recv(self, *args, **kwargs): | |
| data = _orig_recv(self, *args, **kwargs) | |
| _bump(self, _len(data)) | |
| return data | |
| def _recv_into(self, *args, **kwargs): | |
| n = _orig_recv_into(self, *args, **kwargs) | |
| _bump(self, int(n or 0)) | |
| return n | |
| _socket.socket.recv = _recv | |
| _socket.socket.recv_into = _recv_into | |
| _orig_ssl_read = _ssl.SSLSocket.read | |
| def _ssl_read(self, *args, **kwargs): | |
| result = _orig_ssl_read(self, *args, **kwargs) | |
| buffer = kwargs.get("buffer") if "buffer" in kwargs else ( | |
| args[1] if _len(args) > 1 else None | |
| ) | |
| if buffer is not None: | |
| _bump(self, int(result or 0)) | |
| else: | |
| _bump(self, _len(result)) | |
| return result | |
| _ssl.SSLSocket.read = _ssl_read | |
| try: | |
| _mh_install_net_guard() | |
| except Exception: | |
| pass | |
| ''' | |
| def cap_bytes() -> int: | |
| """Per-connection cap in bytes from host env; 0 = guard disabled.""" | |
| raw = (os.getenv("SANDBOX_NET_DOWNLOAD_CAP_KB") or "").strip() | |
| if raw: | |
| try: | |
| kb = int(raw) | |
| return max(0, kb) * 1024 | |
| except ValueError: | |
| pass | |
| return DEFAULT_CAP_KB * 1024 | |
| def guard_env_prefix() -> str: | |
| """Shell env prefix arming the guard for a ``python3 file`` exec. | |
| Empty string when disabled. The ``VAR=x VAR2=y command`` form scopes | |
| the env to the exec'd process tree without mutating the sandbox | |
| shell, matching the ``_OFFLINE_DOWNLOAD_ENV`` convention in | |
| ``run_python_code.py``. | |
| """ | |
| cap = cap_bytes() | |
| if cap <= 0: | |
| return "" | |
| return ( | |
| f"FRONTIER_AGENT_NET_DOWNLOAD_CAP_BYTES={cap} " | |
| f'PYTHONPATH="{GUARD_DIR}:${{PYTHONPATH:-}}" ' | |
| ) | |
| def kernel_preamble() -> str: | |
| """Guard source for persistent-kernel execs (``Sandbox.run_code``). | |
| There is no per-process startup to hook in a long-lived Jupyter | |
| kernel, so the guard is prepended to the submitted code instead. | |
| Idempotent across calls via the ``_mh_net_guarded`` flag. Empty when | |
| disabled. | |
| """ | |
| cap = cap_bytes() | |
| if cap <= 0: | |
| return "" | |
| return ( | |
| f'import os as _mh_os\n' | |
| f'_mh_os.environ.setdefault(' | |
| f'"FRONTIER_AGENT_NET_DOWNLOAD_CAP_BYTES", "{cap}")\n' | |
| f"{SITECUSTOMIZE_SOURCE}\n" | |
| ) | |
| _guard_installed_sandboxes: set[int] = set() | |
| async def ensure_guard_file(sandbox: Any) -> None: | |
| """Write the sitecustomize into the sandbox once per sandbox object. | |
| Remote sandboxes (E2B/Docker) pay one file-write round-trip on first | |
| exec only; local sandboxes write to host ``/tmp``. Failures are | |
| swallowed — the guard is defence-in-depth, never a reason to fail an | |
| exec (and ``guard_env_prefix`` pointing at a missing file is a | |
| harmless no-op: python ignores absent PYTHONPATH entries). | |
| """ | |
| import asyncio | |
| from pathlib import Path | |
| if cap_bytes() <= 0: | |
| return | |
| key = id(sandbox) | |
| if key in _guard_installed_sandboxes: | |
| return | |
| try: | |
| if hasattr(sandbox, "files"): | |
| await asyncio.to_thread( | |
| sandbox.files.write, GUARD_FILE, SITECUSTOMIZE_SOURCE, | |
| ) | |
| else: | |
| def _write_local() -> None: | |
| Path(GUARD_DIR).mkdir(parents=True, exist_ok=True) | |
| Path(GUARD_FILE).write_text(SITECUSTOMIZE_SOURCE) | |
| await asyncio.to_thread(_write_local) | |
| _guard_installed_sandboxes.add(key) | |
| except Exception: | |
| pass | |
| __all__ = [ | |
| "DEFAULT_CAP_KB", | |
| "GUARD_DIR", | |
| "GUARD_FILE", | |
| "SITECUSTOMIZE_SOURCE", | |
| "cap_bytes", | |
| "ensure_guard_file", | |
| "guard_env_prefix", | |
| "kernel_preamble", | |
| ] | |