unsloth/.github
danielhanchen db76fc27e5 Studio: OS-level sandbox for python and terminal tool execution (bubblewrap + Seatbelt)
Wrap the Studio backend's python and terminal tool subprocesses in an
OS-level sandbox: bubblewrap on Linux, Seatbelt (sandbox-exec) on macOS. This
confines LLM-driven tool execution to the per-session workdir with a read-only
view of the OS and interpreter, a fresh /tmp, and no network, instead of
running with the full privileges of the Studio user.

This ports the sandbox core from PR #5468 onto current main and redoes the
integration against today's tool-execution path. The existing in-process guard
(code-safety AST scan, command blocklist, credential-free env, rlimits, /proc
environ hardening) is unchanged and becomes a defense-in-depth layer: the OS
sandbox is the primary boundary when available, and execution falls back to the
existing guarded path (with a warning) when it is not.

core/inference/sandbox.py (new):
- sandbox_available(): cached, thread-safe, three-way probe (ok / fail /
  transient-timeout) that confirms the primitive can actually apply in this
  process context, not just that the binary exists. A transient timeout is not
  cached, so a one-off slow probe does not disable the sandbox for the whole
  process lifetime.
- build_sandbox_argv(inner_argv, workdir): the Linux bwrap argv (--unshare-all,
  fresh /proc /dev /tmp, read-only OS + interpreter binds, rw workdir bind,
  narrowed /etc) or the macOS Seatbelt profile (deny default, narrow read allow,
  deny network, deny Keychain / LaunchServices browser-escape). NPROC is
  reapplied inside the Linux user namespace by a small inner wrapper.

core/inference/tools.py:
- _python_exec / _bash_exec wrap the interpreter / shell argv with
  build_sandbox_argv when sandbox_available() and not Bypass Permissions.
- _sandbox_preexec is split into _sandbox_preexec_impl(apply_no_new_privs,
  apply_nproc); the Linux bwrap path uses _sandbox_preexec_for_bwrap, which
  skips PR_SET_NO_NEW_PRIVS (breaks the setuid bwrap helper) and the
  per-real-UID RLIMIT_NPROC (can EAGAIN bwrap's fork on busy hosts). macOS keeps
  the full pre-exec.
- _get_workdir canonicalizes the workdir with realpath so the child's cwd and
  the bwrap bind always match on symlinked-$HOME hosts.
- UNSLOTH_STUDIO_SANDBOX_STRICT=1 (opt-in) makes execution fail closed when the
  sandbox cannot be applied; the default stays fail-open so locked-down installs
  keep working.

run.py warms the availability probe at startup. install.sh installs bubblewrap
best-effort on Linux (never fatal; missing bwrap only downgrades to the
in-process guard). CI installs bubblewrap, relaxes the Ubuntu 24.04 userns
AppArmor restriction, and gates the enforcement tests on a probe so they run
where the sandbox applies and skip (green) where it cannot.

Co-authored-by: Nilay <118994073+NilayYadav@users.noreply.github.com>
2026-07-13 10:23:20 +00:00
..
ISSUE_TEMPLATE Update issue template 2026-03-23 10:10:15 +05:30
scripts unsloth start: add --persist to keep and reopen agent sessions (#7014) 2026-07-09 11:47:59 +02:00
workflows Studio: OS-level sandbox for python and terminal tool execution (bubblewrap + Seatbelt) 2026-07-13 10:23:20 +00:00
CODEOWNERS Update CODEOWNERS 2026-06-10 11:09:16 -07:00
dependabot.yml security: NOT affected by Mini Shai-Hulud (May-12 wave) -- forward-looking hardening only (#5397) 2026-05-13 04:58:12 -07:00
FUNDING.yml Update FUNDING.yml (#3792) 2025-12-28 19:57:43 -08:00