Summary
On Linux systems where /dev/fd is a symlink to a directory (/proc/self/fd) — e.g. Fedora — every shell_command / exec_command fails at the process-spawn level with:
failed to spawn process: Invalid argument (os error 22)
…even echo test. File tools (read/write/edit) and MCP servers work fine — because MCP servers are spawned outside the bwrap sandbox, whereas shell/exec tools are wrapped by it.
Environment
- Devo Desktop (Electron) + CLI
devo v0.1.32, Fedora (kernel 6.19).
bwrap (bubblewrap) 0.11.0, installed and working standalone (bwrap --dev-bind / / /bin/echo ok → ok).
/dev/fd -> /proc/self/fd (i.e. a directory), which is the default on modern Linux.
Root cause (from devo-server log)
Every failing shell attempt is preceded by:
WARN devo_sandbox::profiles: crates/sandbox/src/profiles.rs:314:
Could not allow device file path="/dev/fd" error=Expected a file but got a directory: /dev/fd
/dev/fd is in the sandbox's DEVICE_FILES list, but on this system it is a directory (symlink → /proc/self/fd). The device-file allow fails, the resulting bwrap invocation is malformed, and the kernel rejects the spawn with EINVAL. It should be handled like the DEVICE_DIRS entries (e.g. /dev/pts), or resolved through the symlink / skipped when is_dir().
Reproduction (CLI)
mkdir -p repro/.devo && cd repro
# A sandboxing profile -> EINVAL:
printf '[permission]\nsandbox_profile="workspace"\n' > .devo/config.toml
devo prompt "Use your shell tool to run exactly: echo test"
# -> failed to spawn process: Invalid argument (os error 22)
# sandbox off -> works:
printf '[permission]\nsandbox_profile="off"\n' > .devo/config.toml
devo prompt "Use your shell tool to run exactly: echo test"
# -> test
Secondary issue: Desktop server ignores the global sandbox setting
The Desktop devo server does not honor the global [permission].sandbox_profile = "off" — only a per-project override works:
[projects."/abs/path/to/repo"]
sandbox_profile = "off"
The CLI devo prompt honors the global key; the Desktop server appears to resolve the sandbox per-project and fall back to a sandboxing default when a project has no entry. Users who set the global key to off still get sandboxed shell failures in Desktop. (Env DEVO_SANDBOX_LAUNCHER=none, a top-level sandbox_profile, and permission_preset="full-access" do not disable it.)
Suggested fix
- In
crates/sandbox/src/profiles.rs, classify /dev/fd as a device directory (or realpath it, or skip when is_dir()), so the bwrap invocation is well-formed where /dev/fd is a directory symlink.
- Have the Desktop server honor the global
[permission].sandbox_profile default, consistent with the CLI.
Happy to test a patch build.
Summary
On Linux systems where
/dev/fdis a symlink to a directory (/proc/self/fd) — e.g. Fedora — everyshell_command/exec_commandfails at the process-spawn level with:…even
echo test. File tools (read/write/edit) and MCP servers work fine — because MCP servers are spawned outside thebwrapsandbox, whereas shell/exec tools are wrapped by it.Environment
devov0.1.32, Fedora (kernel 6.19).bwrap(bubblewrap) 0.11.0, installed and working standalone (bwrap --dev-bind / / /bin/echo ok→ok)./dev/fd -> /proc/self/fd(i.e. a directory), which is the default on modern Linux.Root cause (from
devo-serverlog)Every failing shell attempt is preceded by:
/dev/fdis in the sandbox'sDEVICE_FILESlist, but on this system it is a directory (symlink →/proc/self/fd). The device-file allow fails, the resultingbwrapinvocation is malformed, and the kernel rejects the spawn with EINVAL. It should be handled like theDEVICE_DIRSentries (e.g./dev/pts), or resolved through the symlink / skipped whenis_dir().Reproduction (CLI)
Secondary issue: Desktop server ignores the global sandbox setting
The Desktop
devo serverdoes not honor the global[permission].sandbox_profile = "off"— only a per-project override works:The CLI
devo prompthonors the global key; the Desktop server appears to resolve the sandbox per-project and fall back to a sandboxing default when a project has no entry. Users who set the global key tooffstill get sandboxed shell failures in Desktop. (EnvDEVO_SANDBOX_LAUNCHER=none, a top-levelsandbox_profile, andpermission_preset="full-access"do not disable it.)Suggested fix
crates/sandbox/src/profiles.rs, classify/dev/fdas a device directory (orrealpathit, or skip whenis_dir()), so thebwrapinvocation is well-formed where/dev/fdis a directory symlink.[permission].sandbox_profiledefault, consistent with the CLI.Happy to test a patch build.