import type { SandboxPolicy } from "../types"; import type { SandboxPolicyEnforcer } from "../contracts/policy_enforcer"; type SrtConfig = { filesystem: Record; network?: Record; /** SRT's Linux mandatory-deny scan depth is session-level. */ mandatoryDenySearchDepth?: number; git?: { safeDirectories: string[]; }; /** Top-level and session-level: SRT reads this from the config `initialize()` stored, not per call. */ enableWeakerNestedSandbox?: boolean; bwrapPath?: string; socatPath?: string; }; /** * The sole ADK-to-SRT translation point. Keep the upstream type behind this local firewall. * * @remarks * `runtime` carries ADAPTER-level settings that are deliberately absent from `SandboxPolicy`. That * type is ADK-owned, SRT-neutral vocabulary — naming an SRT feature in it would make the firewall * nominal and leave a non-SRT enforcer unable to implement the contract — so an SRT-specific switch * belongs on the adapter's own options, exactly as `binShell` already does. */ declare const mapPolicy: (policy: SandboxPolicy, runtime?: { enableWeakerNestedSandbox?: boolean; bwrapPath?: string; socatPath?: string; }) => SrtConfig; /** * Relinquish this module's ownership marker. * * @remarks * TEST SEAM, and a narrow one. The marker exists because upstream's `isSandboxingEnabled()` is * `config !== undefined` and `reset()` never clears `config` — so after the first `initialize()` the * flag is permanently `true` and cannot by itself distinguish *"a session we established"* from * *"somebody else's"*. Ownership therefore persists for the life of the module, which is correct in * production (a process that initialised once keeps re-initialising its own session) but makes the * ADOPTION branch unreachable in a test file that has already constructed an owned enforcer. * * Production code has no reason to call this: relinquishing ownership while a session we established * is still live would make the next construction adopt it and refuse to re-initialise. */ export declare const releaseSrtOwnershipForTests: () => void; /** Construction options for {@link srtEnforcer}. */ export type SrtEnforcerOptions = { /** * Absolute path to the POSIX shell used to invoke wrapped commands. Defaults to `/bin/bash`. * * @remarks * Validated at construction in TWO checks, both required: it must be ABSOLUTE (a bare `bash` passes * any basename test while remaining `PATH`-dependent — the exact hazard the absolute default * avoids), and its basename must be on the allow-list (`sh`, `bash`, `dash`, `zsh`, `ksh`) — the * shells whose quoting the single escaper is correct for. An allow-list rather than a deny-list is * deliberate: `fish` and `nu` are POSIX-ish enough to look safe and different enough to break * single-quote escaping, so an unverified shell must fail closed. */ binShell?: string; /** * The ADK-owned policy to enforce. * * @remarks * Mapped to SRT's config inside this module and nowhere else. The derived baseline is captured * immediately after `initialize()`, because `SandboxManager` is a process-global singleton whose * SECOND `initialize()` is a no-op — a later call with a different policy silently keeps the first. */ policy: SandboxPolicy; /** * Host environment variable NAMES a sandboxed child may inherit. Defaults to `['PATH']`. * * @remarks * The child inherits NOTHING from the host beyond these names. That default is deliberate: a model * that can direct the shell's argv can run `env`, so anything inherited is readable back into its * context — and no filesystem or network policy stops it, because the value arrives in the tool * result rather than over the wire. * * **This REPLACES the default, it does not extend it.** A caller who needs `CARGO_HOME` and still * wants binaries to resolve must pass BOTH: `['PATH', 'CARGO_HOME']`. Passing `['CARGO_HOME']` alone * drops `PATH`, which breaks `search_files` on any host where `rg` lives outside `/usr/bin`. * * An entry that is not a valid POSIX environment-variable name throws `E_INVALID_SANDBOX_CONFIG` at * construction rather than being skipped, so a typo surfaces as a startup error instead of a * variable that silently never arrives. */ envAllowList?: readonly string[]; /** * Pass the ENTIRE host environment to sandboxed children. Defaults to `false`. * * @remarks * The escape hatch for a deployment that genuinely needs ambient configuration, and it is worth * being blunt about what it re-opens: **every secret in the host process becomes readable by the * model**, because `run_shell_command` exists precisely to run commands the model chose and `env` is * one of them. Prefer naming what you need in `envAllowList`. */ inheritHostEnv?: boolean; /** * Absolute path to a Linux bubblewrap wrapper or binary. SRT reads it from the config passed to * `initialize()`; on the Linux launch path it becomes argv[0] of the bwrap command * (`linux-sandbox-utils.js:1539`). A wrapper script placed at this path therefore receives every * bwrap argument and can strip or rewrite options such as `--unshare-net`. On Linux a nonexistent * path fails in SRT's `initialize()`; on macOS it is neither validated nor used. */ bwrapPath?: string; /** * Absolute path to a Linux socat binary or wrapper. SRT passes it to `initializeLinuxNetworkBridge` * on Linux. A nonexistent path fails in SRT's `initialize()`; on macOS it is neither validated nor * used. */ socatPath?: string; /** * Enable SRT's weaker nested-sandbox mode, for running inside an unprivileged container. * * @remarks * Bubblewrap cannot mount a fresh `/proc` inside an unprivileged container, so the sandbox fails to * start at all — the symptom is `apply-seccomp: write /proc/self/uid_map: Operation not permitted` * with exit 1, an empty stdout and NO diagnostics, which is indistinguishable from a policy denial. * This flag makes the inner sandbox bind-mount the container's EXISTING `/proc` instead. * * **It considerably weakens the boundary**, in upstream's own words: the bind-mounted `/proc` * exposes process information a fresh mount would hide. Only enable it when the OUTER container * already provides the isolation you need — it trades inner isolation for the sandbox running at all. * * Session-level: SRT reads it from the config given to `initialize()`, never per call. */ enableWeakerNestedSandbox?: boolean; }; /** * Construct the SRT-backed policy enforcer — the OS boundary. * * @remarks * REFUSES rather than degrades on an unsupported platform: native `win32` throws * `E_SANDBOX_UNSUPPORTED_ENV` naming WSL2, because Windows folds all four filesystem-policy lists * case-insensitively and throws on per-exec allows. A half-built branch there would be a DIVERGENT * boundary rather than a limited one, so there is deliberately no native-Windows evaluator. * * `run()` resolves on SPAWN with live streams plus a separate `completed` promise, never a settled * exit code. That split is not stylistic: one promise cannot both hand over unread child streams AND * carry an exit code, because settling requires the streams to have ended and they cannot end before * someone drains them. A caller MUST drain both concurrently — pipe buffers are per-fd, so draining * one to completion first can block the other and hang the child. * * @param options - Shell and policy configuration. * @returns An enforcer whose derived baseline is already captured. */ export declare const srtEnforcer: (options: SrtEnforcerOptions) => Promise; export { mapPolicy };