69 lines
3.6 KiB
Markdown
69 lines
3.6 KiB
Markdown
# Directory-constraint (`bwrap`) findings for the Daytona session path
|
|
|
|
## Summary
|
|
|
|
The Daytona provider ran an advisory `bubblewrap` (`bwrap`) wrapper around each
|
|
user command. The wrapper gave an agent real-time feedback when the agent wrote
|
|
to a directory that the ephemeral sandbox does not keep. The wrapper was
|
|
advisory only. It added no security boundary; the ephemeral sandbox is the only
|
|
boundary.
|
|
|
|
The provider now runs each user command plain, both on the persistent-session
|
|
path and on the one-shot fallback path. This note records why the provider drops
|
|
the directory-constraint goal for now, and what a future re-introduction needs.
|
|
|
|
## Why the goal is dropped for now
|
|
|
|
The session model runs one persistent shell per lease and feeds every command
|
|
into that shell. The plan aimed to enter the `bwrap` sandbox one time per session
|
|
and amortize its cost across every command in the session. A live validation
|
|
proved this aim is not reachable with the current Daytona session daemon.
|
|
|
|
- An `exec`-replace of the session shell with `bwrap` stops the session from
|
|
running any later command. A side-channel file proved the inner shell never
|
|
ran the next command. A repeat without `--new-session` gave the same result,
|
|
so `--new-session` is not the cause. The `exec`-replace itself breaks the
|
|
session daemon's per-command delivery.
|
|
- A per-command `bwrap` wrap works inside a session (separated `stdout` and
|
|
`stderr`, correct exit codes, the session stays alive), but it costs about
|
|
1.75 s per command. An un-wrapped session command takes about 0.29 s; a
|
|
`bwrap`-wrapped session command takes about 2.05 s. The wrap adds the full
|
|
cost back on every command, which removes the session model's speed win.
|
|
|
|
The wrapper was advisory, not a security boundary. The provider already ran a
|
|
command plain when the `bwrap` capability probe failed, so the plain path is an
|
|
accepted, shipped behavior. Dropping the wrapper drops only the advisory
|
|
feedback; it does not change the command's privilege or isolation. The command
|
|
runs as the unprivileged sandbox user (`daytona`) in both cases.
|
|
|
|
## Removal scope
|
|
|
|
- The session dispatch runs the plain login-shell script, wrapped in a subshell
|
|
so a top-level `exit` cannot end the persistent session shell.
|
|
- The one-shot fallback (used when the session model is off) also runs the plain
|
|
login-shell script.
|
|
- The provider removed the per-command `bwrap` apply, the `bwrap` capability
|
|
probe, the `bwrap` command builder, and the `bwrapAvailable` /
|
|
`sandboxUsername` lease metadata that only the removed path used.
|
|
- The provider keeps the advisory writable-directory set, which a sync operation
|
|
records from each `access: "rw"` mapping. Nothing reads the set today. It stays
|
|
in place so a future isolation wrapper can consume it without a new sync
|
|
change.
|
|
|
|
## What a future re-introduction needs
|
|
|
|
- A persistent-namespace approach needs its own spike. Two candidates are:
|
|
- Enter one namespace per session and route each command into it with
|
|
`nsenter`.
|
|
- Feed each command to the namespace shell through a FIFO instead of an
|
|
`exec`-replace.
|
|
- Both candidates need a live test against the Daytona session daemon, because
|
|
the `exec`-replace model is proven unreachable and the per-command wrap is too
|
|
slow.
|
|
- The re-introduction must keep the session speed win. It must not pay the full
|
|
`bwrap` setup cost on every command.
|
|
- The writable-directory set is already tracked per lease, so a new wrapper can
|
|
bind those directories read-write without a sync change.
|
|
- The wrapper stays advisory. It must not become a security boundary; the
|
|
ephemeral sandbox stays the only boundary.
|