mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-04-02 17:32:39 +00:00
Allow users to wrap shell commands in a sandbox (e.g. bubblewrap,
firejail, nsjail) via config, without nanobot baking in any sandbox
backend. The template supports {command} and {cwd} placeholders with
plain string replacement.
87 lines
2.9 KiB
Markdown
87 lines
2.9 KiB
Markdown
# Exec Tool Sandbox (`commandWrapper`)
|
|
|
|
The `tools.exec.commandWrapper` config option wraps every shell command in a user-defined template before execution. This allows you to add a sandbox layer (e.g. bubblewrap, firejail, nsjail) without any code changes to nanobot.
|
|
|
|
## Configuration
|
|
|
|
```json
|
|
{
|
|
"tools": {
|
|
"exec": {
|
|
"commandWrapper": "<template>"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Leave empty (the default) to run commands directly with no wrapper.
|
|
|
|
## Placeholders
|
|
|
|
Two placeholders are available in the template:
|
|
|
|
| Placeholder | Value |
|
|
|---|---|
|
|
| `{command}` | The original shell command generated by the LLM |
|
|
| `{cwd}` | Absolute path of the working directory |
|
|
|
|
nanobot performs plain string replacement — it does not parse, validate, or shell-escape the values. The wrapper template is trusted configuration.
|
|
|
|
## Examples
|
|
|
|
### bubblewrap
|
|
|
|
```json
|
|
{
|
|
"tools": {
|
|
"exec": {
|
|
"commandWrapper": "bwrap --ro-bind /usr /usr --ro-bind-try /bin /bin --ro-bind-try /lib /lib --ro-bind-try /lib64 /lib64 --proc /proc --dev /dev --tmpfs /tmp --bind {cwd} {cwd} --chdir {cwd} -- sh -c \"{command}\""
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Requires: `apt install bubblewrap` (or equivalent for your distro).
|
|
|
|
### firejail
|
|
|
|
```json
|
|
{
|
|
"tools": {
|
|
"exec": {
|
|
"commandWrapper": "firejail --noprofile --private={cwd} -- {command}"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### nsjail
|
|
|
|
```json
|
|
{
|
|
"tools": {
|
|
"exec": {
|
|
"commandWrapper": "nsjail -Mo --chroot /sandbox --cwd {cwd} -- {command}"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Caveats
|
|
|
|
> [!WARNING]
|
|
> **Do not wrap `{command}` in shell quotes.** If the original command contains the same quote character, the shell will break the quoting context. For example, `sh -c '{command}'` will fail on any command that contains single quotes.
|
|
|
|
This is an inherent limitation of the template approach — nanobot substitutes `{command}` as a raw string and cannot safely shell-quote it (the command may contain compound syntax like `&&`, `|`, `;` that must be preserved for the inner shell).
|
|
|
|
### Interaction with `create_subprocess_shell`
|
|
|
|
nanobot executes the wrapped command via `create_subprocess_shell`, which adds an outer shell layer. Keep this in mind when designing your template:
|
|
|
|
- **Without `sh -c`** (e.g. `firejail ... -- {command}`): The outer shell parses `{command}` directly. Compound commands with `&&` and `|` work as expected because they are parsed by the outer shell before the sandbox tool receives them.
|
|
- **With `sh -c`** (e.g. `bwrap ... -- sh -c "{command}"`): The command is passed through two shell layers. This is only needed if the sandbox tool requires a single command argument but you want to support compound syntax.
|
|
|
|
### `restrict_to_workspace` is independent
|
|
|
|
The `tools.restrictToWorkspace` setting and `commandWrapper` are orthogonal features. The workspace restriction guards against path traversal in the original command (before wrapping). The sandbox wrapper provides OS-level isolation. You can use either or both — they address different threat models.
|