feat: --volume bind mounts with auto userns-remap on rootless podman#2
Merged
Conversation
Register a repeatable `--volume <HOST>:<CONTAINER>[:ro]` clap arg on `SandboxCommands::Create`. Adds an `#[allow(clippy::large_enum_variant)]` to suppress the size-difference lint that fires now that Create has multiple Vec fields. The new field is destructured as `_volumes` in the dispatch match arm; plumbing through the create flow is deferred to a follow-up task.
…y allow
- Replace dead openshell_bin() fallback with env!("CARGO_BIN_EXE_openshell")
so a missing binary fails at compile time rather than panicking at runtime
with a space-in-path exec error.
- Strengthen the three parse-acceptance tests: assert exit code == 1 (no
gateway configured) rather than != 2, pinning the exact failure mode and
ruling out silent success (exit 0) as well as clap errors (exit 2).
- Drop OPENSHELL_ENDPOINT env var from parse tests; the "No active gateway"
runtime check fires first (exit 1) before any network I/O.
- Add module-level doc comment explaining why subprocess is retained over
in-process (Cli is private; run::sandbox_create bypasses clap).
- Verify large_enum_variant clippy allow: lint fires at 297 bytes (Create)
vs 78 bytes (next variant). Update comment to cite actual sizes instead
of "by design".
Introduces volume_spec module with BindVolumeSpec, VolumeParseError, and parse_volume_spec, validated by 7 unit tests covering both happy paths and all error variants (bad field count, bad ro token, non-absolute/missing host, non-absolute container).
Add BindVolume message to openshell.proto (SandboxSpec.volumes = 11) and compute_driver.proto (DriverSandboxSpec.volumes = 11). Wire parsed BindVolumeSpec entries from the CLI handler through run::sandbox_create into the CreateSandboxRequest, and map them to DriverBindVolume in driver_sandbox_spec_from_public on the server side. Fix the docker driver test fixture and integration test call sites for the updated sandbox_create signature.
…sent Append a libpod bind-mount entry for each DriverSandboxSpec.volume, and set userns=keep-id:uid=N,gid=N (from the image USER directive) when any volumes are present. Falls back to uid/gid 1000660000 for unset or non-numeric USER directives.
…BOX_UID Extract the magic number 1_000_660_000 into a named pub constant COMMUNITY_SANDBOX_UID so all four usage sites share a single source of truth with a doc-comment linking to the Dockerfile origin. Fix a split-uid bug in image_user: when Config.User is ":1000", the uid field is "" which fails to parse as u32. Previously gid was still extracted from parts[1], producing a mismatched (1_000_660_000, 1000) pair. Now the function returns the fallback pair immediately on any uid parse failure, matching the documented contract. Expand the image_user doc-comment to cover the uid=0/root case (keep-id:uid=0,gid=0 is harmless on rootless Podman), the empty-user case, and the non-numeric-user case. Add an rbind/read-write assertion on bind_mounts[0] in the existing build_container_spec_emits_bind_mount_entries test.
Extend DockerDriver's build_binds to append user-declared bind volumes from sandbox.spec.volumes using host:container[:ro] format. Extend validate_vm_sandbox to reject requests that carry any volumes with Status::invalid_argument.
Add two e2e tests for `openshell sandbox create --volume` (rw round-trip and ro write-block) gated behind the new `e2e` Cargo feature. Add bind-volume section to the podman driver README documenting auto userns-remap. Add `--volume` flag documentation and userns-remap note to the user-facing manage-sandboxes page and the compute-runtimes architecture doc.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
openshell sandbox create --volume <HOST>:<CONTAINER>[:ro]for bind mounts. Repeatable flag. Driver coverage: podman (libpod bind mounts + auto userns-remap), docker (-vpassthrough), vm (early reject with clear error).Auto userns-remap on rootless podman: when any
--volumeis set, the driver inspects the sandbox image'sConfig.Userdirective (fallback to community-image default1000660000) and setsuserns: keep-id:uid=N,gid=N, so bind file ownership is bidirectional between host caller and container sandbox user.This is the fork-side prerequisite for openlock v0.6.0 (mount system v2). Ship as fork v0.4.0 via coordinated Pattern B RC cycle with openlock v0.6.0.
Related Issue
Closes the fork-side scope of the openlock-driven mount system v2 feature. See openlock spec
docs/superpowers/specs/2026-05-21-bind-mount-design.mdand Plan Adocs/superpowers/plans/2026-05-21-bind-mount-fork.md(both in the openlock repo).Changes
crates/openshell-cli/:--volumeclap arg,volume_spec.rsparser, plumbed throughrun::sandbox_createto the gRPCSandboxSpec.volumesfield.proto/openshell.proto+proto/compute_driver.proto: newBindVolumemessage;SandboxSpec.volumes(tag 11) andDriverSandboxSpec.volumes(tag 11).crates/openshell-server/src/compute/mod.rs: maps publicBindVolumeto driverBindVolumeindriver_sandbox_spec_from_public.crates/openshell-driver-podman/: emits libpod bind mount entries; newPodmanClient::image_userinspects imageConfig.User; autouserns: keep-id:uid=N,gid=Nwhen volumes present.pub const COMMUNITY_SANDBOX_UID: u32 = 1_000_660_000.crates/openshell-driver-docker/: extendsbuild_bindswith user volumes (host:container[:ro], no,zSELinux suffix).crates/openshell-driver-vm/: rejects bind volumes early viavalidate_vm_sandbox.Testing
crates/openshell-cli/tests/sandbox_create_volume_e2e.rs(gated behind--features e2e) covers host-bind round trip + ro write rejection. Requires a live podman daemon; not run in unit CI.mise run pre-commitpasses (fmt, clippy, license, helm, markdown all green).python:prototask skipped — pre-existing env issue (missing grpc_tools in venv), unrelated to this change.Checklist
mise run pre-commitpasses (Rust checks: fmt, clippy, license — all clean)sandbox_create_volume_e2e.rs, gated behind--features e2e)architecture/compute-runtimes.md,crates/openshell-driver-podman/README.md,docs/sandboxes/manage-sandboxes.mdx)