Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ Uses an **allow-only pattern** - all network access is denied by default.
- `network.deniedDomains` - Array of denied domains (checked first, takes precedence over allowedDomains). Same `:port` suffix, and a bare `*` (or `*:22`) is accepted for deny-all.
- `network.deniedDomainReasons` - Optional map from a `deniedDomains` entry (matched by exact string) to a model-facing reason that appears in the `<sandbox_violations>` line when that entry denies a connection — say what is blocked and the sanctioned alternative (e.g. `{"github.com:22": "SSH pushes to GitHub are blocked; use an https:// remote"}`). Entries without a reason report a generic one. For SSH destinations (port 22), the reason is also delivered in-band: an SSH client tunneled through a no-auth SOCKS ProxyCommand (e.g. BSD `nc -X 5`) receives a pre-key-exchange SSH disconnect whose description is the reason, which OpenSSH prints verbatim — keep such reasons under ~400 ASCII characters, imperative first, since OpenSSH truncates and escapes non-ASCII.
- `network.allowLocalBinding` - Allow binding to local ports (boolean, default: false)
- `network.exposeLoopbackPorts` - **Linux only.** Array of specific ports (e.g. `[3000]`) that the sandboxed process binds on `127.0.0.1` which the host should be able to reach through the bwrap network-namespace boundary (default: none). Each listed port gets its own scoped Unix-socket bridge — no general network access is granted, and any port not listed stays unreachable from outside the sandbox exactly as before. Use this when an unsandboxed parent process needs to poll/drive an HTTP (or other TCP) server that only exists inside the sandbox — e.g. spawning `myserver --port 4000` under `srt` and then health-checking `http://127.0.0.1:4000` from the launcher itself. Has no effect on macOS, where `--unshare-net` is never applied and `network.allowLocalBinding` already covers the equivalent case.

**TLS termination** (`network.tlsTerminate`, experimental): when set, HTTPS CONNECTs are terminated in-process so SRT can see (and filter, via `network.filterRequest`) the decrypted requests. The sandboxed process is pointed at a trust bundle containing the MITM CA (`caCertPath`/`caKeyPath`, or an ephemeral CA if omitted) plus the host's regular roots, so proxy-minted certificates and real upstream certificates both verify.

Expand Down Expand Up @@ -627,6 +628,8 @@ The sandbox runs HTTP and SOCKS5 proxy servers on the host machine that filter a

- **Windows**: A WFP `ALE_AUTH_CONNECT` filter blocks every outbound connect from the `srt-sandbox` account except loopback to the configured proxy port range. The proxies bind inside that range. Environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, …) point tools at the proxies, but the WFP filter is the boundary — a process that ignores or unsets them is still fenced.

**Reaching a server inside the sandbox (Linux, opt-in):** `--unshare-net` is otherwise all-or-nothing — there is no way for a process outside the sandbox to connect to a port a sandboxed process binds, since it lives in a different, fully isolated network namespace. `network.exposeLoopbackPorts` adds a narrowly-scoped exception for this one case, reusing the same Unix-socket-bridge mechanism in reverse: for each listed port, a host-side `socat` listens on `127.0.0.1:<port>` and forwards connections into a Unix socket; that socket is bind-mounted into the sandbox, where a matching in-sandbox `socat` forwards it to the sandboxed process's own `127.0.0.1:<port>` server. Only the exact ports listed are bridged — every other port, and all other outbound/inbound traffic, is governed by the domain allowlist and proxies exactly as described above.

**JVM tools (macOS/Linux):** the JVM ignores `HTTPS_PROXY`/`NO_PROXY` and has no environment variable for proxy credentials — proxy selection comes from the `https.proxyHost` system properties and the credential can only be supplied through `java.net.Authenticator`. So JVM-based tools (Bazel's gRPC remote cache, Gradle, Maven, …) would otherwise dial the target directly and fail, or reach the proxy without its token and get a 407. To close that gap srt injects a small `-javaagent` via `JAVA_TOOL_OPTIONS` (the env var carries only the jar path, the credential stays in `HTTPS_PROXY`). At JVM start the agent sets `http[s].proxyHost`/`Port` and `http.nonProxyHosts` from the proxy env vars, re-enables Basic auth for CONNECT tunnels, and installs an Authenticator for the proxy endpoint. Explicit `-D` proxy properties on the JVM command line still win, and any inherited `JAVA_TOOL_OPTIONS` is preserved (unless it is a denied credential env var). Every JVM prints a `Picked up JAVA_TOOL_OPTIONS: …` line to stderr as a result; a jlink'd runtime built without the `java.instrument` module cannot load agents and will refuse to start under the sandbox — unset `JAVA_TOOL_OPTIONS` in the command for such a tool. The jar ships in the npm package as `vendor/java-proxy-agent/srt-proxy-agent.jar` (source: `vendor/java-proxy-agent-src/`; built by the release workflow, or locally with `npm run build:java-agent` — needs a JDK ≥ 17). If it is not found, `JAVA_TOOL_OPTIONS` is left alone and JVMs behave as before; bundlers can point at their own copy with `javaAgentJarPath`.

### Filesystem Isolation
Expand Down
Loading