Support rootless container toolchains under workspace-write
#5359
sennadevos
started this conversation in
Ideas
Replies: 1 comment
|
Hello, I am developing a plugin to add support for running agent tools such as shell commands in Podman containers. It uses distribution images (Arch Linux, Ubuntu and Alpine for starters) and builds additional images using the distribution's package manager. I am in the finals steps of polishing the first version and I will release it soon, so it could solve your problem, as long as you can mount a rootless Podman socket ( Note that I am documenting how to run dsh in Podman too, but it would also work to run dsh independently. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Summary
On an atomic (image-based) Linux host, development toolchains live in rootless
containers. That is the supported way to have a toolchain when the base system
is immutable and layering packages means a reboot. Under
workspace-write,rootless
podmancannot run at all, so the agent has no toolchain available.This is not a matter of allow-listing a binary, and it is also not fixed by
making more paths writable. I tested both Linux sandbox backends: bwrap's nested
user namespace breaks rootless container UID mapping regardless of the writable
set.
The practical outcome is that the only usable mode on such a host is
danger-full-access, which removes confinement entirely. Someone who wantssome confinement while working with containers has nothing to select.
Environment
0.1.1-rc.2bwrappresent at/usr/bin/bwrap, so thesandbox selects the bwrap rung
Reproduction
Running dsh's own
workspace-writeprofile directly, as built bybwrapProfileArgsin@deepseek-ai/dsh-sandbox-local:1. The profile itself works as intended. Writes inside the workspace
succeed:
2. Rootless podman fails on its runtime state:
3. Granting the container roots is not sufficient. This is the key result.
Adding
--bind /run/user/1000 …,--bind ~/.local/share/containers …and--bind /dev/shm …to the same profile moves the failure to UID mapping:bwrap has already created an unprivileged user namespace, so the setuid
newuidmaphelper cannot establish the multi-ID mapping rootless podman needs.4. The Landlock backend gets further but also fails. Using the bundled
landlock-runwith equivalent grants (filesystem-only confinement, no namespacenesting):
Filesystem confinement itself still works there (
touch ~/.cache/xgivesPermission denied), so this is specifically about rootless containers ratherthan about the grants being wrong.
All four behave as above consistently; unsandboxed
podman imageson the samehost works fine.
Why this matters
On an atomic host, containers are not a stylistic preference. They are the
mechanism for having a toolchain at all, because the base image is read-only and
layering packages requires a reboot. A mode that cannot run containers therefore
is not "restrictive" for these users, it is empty: there is no work it can do.
Per-call escalation does work, and podman's first failure does match bwrap's
"read-only file system"denial signature, so the escalation hint is offered.But the only escalation target is
danger-full-access. For a workflow wheremost commands touch a container, that means running unconfined almost always,
which is the situation
workspace-writeexists to avoid.What is currently configurable
As far as I can tell from the shipped packages, there is no combination of
settings that expresses "confined, but containers work":
@deepseek-ai/dsh-permission-presetsmakes the preset table fullyconfigurable, but a preset is only a
(sandbox mode, approval policy)pair,so it cannot change what a mode permits.
SANDBOX_MODESis a closed union with exhaustiveness throws, so a deploymentcannot define a fourth mode.
writableRoots()in@deepseek-ai/dsh-sandboxreturns[workspaceRoot, '/tmp', tmpdir()]with no configuration path. This isacknowledged in
dsh-sandbox-policy's own README: "One primary workspace rootper session … extra writable roots are not part of
SandboxExecutionPolicy."runnerCommandindsh-sandbox-localis a genuine escape hatch, but it isnot a declarative one. The configured command is prepended and the
hardcoded profile args are appended after it, so
runnerCommand: ['bwrap', '--bind', '/data', '/data']yieldsbwrap --bind /data /data --ro-bind / / … -- bash -c cmd, where the later--ro-bind / /overmounts the bind. Widening paths this way requiresshipping a wrapper binary that parses and rewrites its own argv, and per the
README that wrapper also skips the functional probes and becomes an
unverified operator assertion.
packages contain no
process.envreads at all, and the CLI grammar has nosandbox option.
$DSH_HOME/cordis.patch.ymland--patchoverlays are realconfig layers, but none of the rows they can reach carries a writable-root
key.
Suggestions
To be clear about scope: I am not asking dsh to run the agent inside a
container.
dsh-sandbox's README already defers that ("containers, microVMs,and remote execution require replacing capability implementations rather than
adding a provider here"), and that is a different problem. This is about the
sandbox not breaking the container tooling the user already has.
Points 3 and 4 above mean container support needs both of the first two, not
either one alone:
Configurable additional writable roots on the sandbox policy, so a
container runtime's state directories can be reached. The plumbing already
exists at both layers:
bwrapProfileArgsemits--bindper root,landlockProfileArgsemits--rwper root, and the bundledlandlock-runbinary's public API is already{ readOnly?: string[], readWrite?: string[] }.dsh-sandbox-localsimplyhardcodes
["/tmp", workspaceRoot]into that list. The gap looks likeSandboxExecutionPolicycarrying a singleworkspaceRoot: stringwhere aroot list would do.
A confinement option that does not nest a user namespace, so rootless
containers can still set up their ID mapping. The Landlock rung is already
close in spirit, since it confines the filesystem without creating
namespaces; point 4 suggests it needs a little more than filesystem grants to
get there.
Document the limitation in the mode descriptions in the meantime. Right
now the failure surfaces as a podman error, and it takes a while to work out
that the sandbox is the cause rather than a broken container setup.
Happy to test patches on an atomic host, since that is the environment where
this bites hardest and it is easy for me to reproduce.
Quick disclosure: this was written by Claude (Anthropic), which also ran the
tests above on my machine. I read the whole thing before posting and the
symptoms match what I actually hit day to day, but the suggestions and the code
references are its work rather than mine. I don't know your codebase, so treat
that part as a starting point rather than a considered proposal.
All reactions