diff --git a/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md b/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md index 1d762085a3..07eeb9acee 100644 --- a/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md +++ b/packages/plugins/sandbox-providers/SANDBOX-REQUIREMENTS.md @@ -6,6 +6,32 @@ exec time. The environment is a requirement, not a build step. This document states requirements. It does not state build steps. +## bwrap prerequisites (advisory, optional) + +A sandbox provider can wrap a command with an advisory bubblewrap (`bwrap`) +wrapper. The wrapper is advisory, best-effort, and automatic. It adds no +security. The ephemeral sandbox model stays the only security posture. A missing +prerequisite degrades to the plain command. It never fails the lease. Daytona is +the current provider with bwrap support. + +The wrapper needs three run-time prerequisites. Each prerequisite is a fact of +the image or snapshot, not a fact of the runtime code. The runtime does not +build the image or snapshot. The runtime only probes for the capability and +degrades when the capability is absent. So each prerequisite is an owner +responsibility under the requirement-not-build contract above: + +- The `bubblewrap` package is installed, and the `bwrap` binary is on the PATH + (normally `/usr/bin/bwrap`). +- A passwordless `sudo` rule lets the sandbox user run `bwrap` as root. +- The host and kernel allow an unprivileged user namespace. + +The owner supplies these prerequisites through the image or snapshot. The +provider README states the distro-specific install commands, the exact sudoers +rule, the user-namespace setting, and the verification command. The install and +the sudoers change are environment provisioning at the image or snapshot layer. +Route them to DevOps through the board. Do not add a provisioning script to the +repository. + ## Required on PATH - `node` must be installed and on the PATH. diff --git a/packages/plugins/sandbox-providers/daytona/README.md b/packages/plugins/sandbox-providers/daytona/README.md index f2762feef1..84cfac9ad9 100644 --- a/packages/plugins/sandbox-providers/daytona/README.md +++ b/packages/plugins/sandbox-providers/daytona/README.md @@ -40,6 +40,93 @@ The driver wraps a sandbox command with an advisory bubblewrap (`bwrap`) wrapper - **The writable set is the workspace plus the read-write sync destinations.** The wrapper binds the workspace directory read-write as the baseline; the workspace is always durable. It adds the read-write sync destinations that a sync-in recorded for the same lease. The set deduplicates the directories. The baseline keeps a safe result even when the collected set is empty. - **The wrapper runs at execute time when the capability is present.** The driver wraps the command only when the lease reports `bwrapAvailable: true` and a uid/gid pair is known. It binds the workspace and the read-write sync destinations, keeps the root read-only for feedback, and re-binds the stdin file after the fresh `/tmp`. It runs the plain command when the capability or the uid/gid is missing. A wrap without a uid/gid would run as root and give the agent's files root ownership, so the driver keeps the plain command in that case. +## Operator enablement (advisory bwrap) + +The advisory `bwrap` wrapper needs three run-time prerequisites on the image or +snapshot. The repository does not build the Daytona image or snapshot. It +references an external `image` or `snapshot`. So the three prerequisites are +image facts, not code facts. The runtime only probes for the capability and +degrades when the capability is absent. + +The wrapper is advisory, best-effort, and automatic. It adds no security. The +ephemeral sandbox model stays the only security posture. A missing prerequisite +degrades to the plain command. It never fails the lease. So the enablement below +is optional. It gives the agent real-time feedback on a non-durable write. It +does not change the security posture. + +The install and the sudoers change are environment provisioning at the image or +snapshot layer. Route them to DevOps through the board. Do not run the steps +from the runtime and do not commit a provisioning script to the repository. + +### 1. Install the `bubblewrap` package + +The repository does not state the Daytona base distribution. Confirm the +distribution on the referenced image or snapshot first, then run the matching +command: + +```bash +# Debian/Ubuntu +apt-get install -y bubblewrap +# Alpine +apk add bubblewrap +# Fedora/RHEL +dnf install -y bubblewrap +``` + +Confirm the binary path is `/usr/bin/bwrap` after the install. + +### 2. Add the passwordless sudoers rule + +The wrapper runs `bwrap` as root with `sudo -n`. Add this exact sudoers line. +Use the real sandbox user name and the real `bwrap` path: + +```text + ALL=(root) NOPASSWD: /usr/bin/bwrap +``` + +The `` is the account name that `id -un` returns inside the +sandbox. Use the account name, not a numeric id, in the sudoers line. The probe +reads the numeric user id and group id with `id -u` and `id -g`. The driver +resolves the sandbox work directory first, then the user home directory. It uses +`/home/daytona` only as a fallback default when both are empty. Confirm the real +home directory for your image or snapshot. Install the `sudo` package in the +image or snapshot if it is absent. + +### 3. Allow user namespaces + +The `bwrap` wrapper creates a user namespace. The kernel must support user +namespaces for the wrapper to run. Confirm the kernel allows them: + +```bash +sysctl user.max_user_namespaces +``` + +A value greater than zero means the kernel supports user namespaces. This value +is the requirement for the wrapper. + +The wrapper runs `bwrap` as root with `sudo -n`. Root creates the user namespace +directly, so the Debian/Ubuntu `kernel.unprivileged_userns_clone` setting does +not apply here. That setting only limits an unprivileged process. A managed +sandbox that denies `sysctl kernel.unprivileged_userns_clone=1` still runs the +wrapper when `user.max_user_namespaces` is greater than zero. + +### 4. Verify the three prerequisites + +Run this exact command as the sandbox user: + +```bash +sudo -n bwrap --unshare-user --uid 0 --gid 0 --ro-bind / / -- true +``` + +A zero exit code means all three prerequisites are met. A non-zero exit code +means one prerequisite is missing. The wrapper then stays off and runs the plain +command. + +The `--uid 0` and `--gid 0` flags map the check to root inside the test +namespace. This command is only a capability check. It does not need to match +the sandbox user id. The live wrapper maps to the real sandbox user id and group +id. + ## Local development ```bash