Skip to content

feat(sandbox): support gated host mounts through driver_config #1760

Description

@elezar

Problem Statement

OpenShell sandboxes currently have no first-class way to request live host
filesystem mounts through the driver-specific sandbox configuration path. The
existing sandbox upload and sandbox download flows are copy-based, which is
safe and portable but does not cover long-running workflows that need a live,
read-only view of host data such as repositories, local reference data,
diagnostic artifacts, or operator-provided shared directories.

Historically, host mounts have been rejected or deferred because they are
security-sensitive and driver-specific. That concern still applies. The new
SandboxTemplate.driver_config passthrough proposal gives us a better boundary:
the public API can stay generic, the gateway can remain driver-agnostic, and
each compute driver can own validation and rendering for its own runtime.

The missing design is a common, safe-by-default host_mounts schema under
driver_config, with driver-level admin gates, allowlisted host prefixes, and
read-only behavior by default.

Proposed Design

Add a driver-owned host_mounts schema under the active driver's
containers.agent config:

{
  "kubernetes": {
    "containers": {
      "agent": {
        "host_mounts": [{
          "name": "shared-data",
          "host_path": "/var/lib/openshell/shared",
          "mount_path": "/mnt/shared",
          "type": "Directory"
        }]
      }
    }
  },
  "docker": {
    "containers": {
      "agent": {
        "host_mounts": [{
          "name": "shared-data",
          "host_path": "/var/lib/openshell/shared",
          "mount_path": "/mnt/shared"
        }]
      }
    }
  },
  "podman": {
    "containers": {
      "agent": {
        "host_mounts": [{
          "name": "shared-data",
          "host_path": "/var/lib/openshell/shared",
          "mount_path": "/mnt/shared"
        }]
      }
    }
  }
}

Field semantics:

  • name: required logical name, valid for the active driver and unique within
    the request.
  • host_path: required absolute path on the compute host.
  • mount_path: required absolute path inside the agent workload.
  • read_write: optional, defaults to false. Omit it for read-only mounts.
    read_write: true should be rejected in the first implementation unless the
    active driver has an explicit read-write admin gate.
  • type: optional and driver-specific. Kubernetes maps this to
    hostPath.type; Docker and Podman should reject non-empty values initially
    unless they implement equivalent validation.

Add driver config gates:

[openshell.drivers.kubernetes]
allow_host_path_mounts = false
host_path_mount_allowed_prefixes = ["/var/lib/openshell/shared"]

[openshell.drivers.docker]
allow_host_path_mounts = false
host_path_mount_allowed_prefixes = ["/var/lib/openshell/shared"]

[openshell.drivers.podman]
allow_host_path_mounts = false
host_path_mount_allowed_prefixes = ["/var/lib/openshell/shared"]

First-pass behavior:

  • Reject host_mounts unless the active driver has
    allow_host_path_mounts = true.
  • Reject all paths if the active driver's allowed-prefix list is empty.
  • Match allowed prefixes on path components, not raw string prefixes.
  • Render mounts read-only by default.
  • Reject read_write: true unless a future explicit
    allow_read_write_host_path_mounts gate is added.
  • Validate and fail fast during ValidateSandboxCreate and again before
    rendering during CreateSandbox.

Driver rendering:

  • Kubernetes: render accepted mounts as hostPath volumes plus volumeMounts
    on the agent container. Set readOnly: !read_write.
  • Docker: render accepted mounts through HostConfig.binds, following the
    existing internal bind style for read-only mounts.
  • Podman: render accepted mounts through the existing mounts array as bind
    mounts with ["ro", "rbind"], plus z when SELinux is enabled.
  • VM: reject driver_config.vm.containers.agent.host_mounts for now with a
    clear unsupported message. VM support needs a separate transport decision
    such as virtiofs, 9p, or an extra block image, plus guest init integration.

Validation should reject:

  • malformed host_mounts;
  • duplicate mount names or target paths;
  • non-absolute or non-normalized host_path / mount_path;
  • host paths outside allowed prefixes;
  • reserved OpenShell mount targets such as /sandbox,
    /var/run/secrets/openshell, /run/netns, TLS mount directories, and
    supervisor mount directories;
  • unsupported driver-specific type values;
  • read_write: true until writable mounts have a separate security design.

Documentation should cover Docker Desktop and Podman machine path-resolution
semantics: paths are resolved by the daemon/VM host, not necessarily the
gateway process filesystem.

Alternatives Considered

  • Public typed protobuf mount fields: rejected for the first pass because host
    mounts are driver-specific and should not force a lowest-common-denominator
    API.
  • Provider-driven mounts: rejected because providers are credential/config
    records, not filesystem access grants.
  • Arbitrary pod/container spec passthrough: rejected because it makes security
    review and validation too broad.
  • sandbox upload / sandbox download: safe and portable, but copy-based and
    not a live filesystem view.
  • VM virtiofs support now: useful, but it requires separate VM runtime and
    guest-init design. This proposal should reject VM host mounts until that work
    is intentionally designed.

Agent Investigation

Local codebase findings:

  • SandboxTemplate.driver_config exists on the public API and is forwarded as
    the selected driver block to DriverSandboxTemplate.driver_config.
  • crates/openshell-server/src/compute/mod.rs selects the active driver block
    and keeps the gateway out of nested schema validation.
  • crates/openshell-driver-kubernetes/src/driver.rs already decodes
    driver-local config for pod scheduling and agent resources, and already
    renders managed volumes/mounts for TLS, ServiceAccount bootstrap, supervisor
    sideloading, and workspace persistence.
  • crates/openshell-driver-docker/src/lib.rs already builds driver-owned bind
    mounts for the supervisor binary, TLS files, and sandbox token through
    HostConfig.binds.
  • crates/openshell-driver-podman/src/container.rs already renders bind mounts
    for TLS/token files and has SELinux-aware mount options.
  • crates/openshell-driver-vm/src/driver.rs currently rejects
    platform_config; VM host sharing needs a transport and guest mount design
    before support can be claimed.

Related issues and PRs:

Definition of Done

  • Add driver config gates and allowlists for Kubernetes, Docker, and Podman.
  • Add typed host-mount parsing/validation for Kubernetes, Docker, and
    Podman driver config.
  • Render read-only host mounts for Kubernetes, Docker, and Podman.
  • Reject VM host mount config with a clear unsupported error.
  • Add unit tests for success, disabled gates, disallowed prefixes,
    duplicate names/targets, reserved targets, unsupported types, read-write
    rejection, and VM unsupported behavior.
  • Update driver READMEs and reference docs.
  • Update Helm values/rendering/tests for the Kubernetes gate.

Activity

  1. randybias commented on Jun 8, 2026

    @randybias

    I need this capability right now. My use case is agents running on top of a shared GitOps-style substrate, that is used as the system of record. Copying in and out of the container is messy. The git repo itself is contained and there is little or no risk as any agent-initiated changes can be rolled back.

  2. github-actions commented on Jun 23, 2026

    @github-actions

    This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.

  3. elezar commented on Jun 25, 2026

    @elezar
    MemberAuthor

    @randybias we have landed initial support for specifying mounts in k8s, Docker, and Podman. See #1744 and #1785.

    In terms of this issue, we don't yet have a mechansims to limit the mounts, but that could be added in the context of #1927.

  4. randybias commented on Jun 25, 2026

    @randybias

    Awesome. Will take it for a test drive soon. 🙏

  5. ittayd commented on Jul 14, 2026

    @ittayd

    On the rootless Podman/Docker driver, a read_write host mount writes files owned by a subuid, not the user who started the sandbox.

    Concretely (rootless Podman 5.8.4, kernel 6.17): the agent runs as uid 1000 in the sandbox, writes to a bind-mounted host dir, and on the host the file ends up owned by 100999:100999. So read_write: true mounts work, but you can't cleanly edit or commit those files as yourself afterward — which defeats the main use case of live-editing your own repo in place.

    Could host_mounts include an opt-in idmap flag? When set, id-map the mount so the sandbox uid maps to the host owner, and writes land owned by the host user (like Podman's -v src:dst:idmap). Default off, so nothing changes unless you ask for it.

    The capability already exists in-tree — the Kubernetes driver does user namespaces + ID-mapped mounts (enable_user_namespaces). This would bring the same idmap to the podman/docker bind path. Rootless idmap bind mounts work on recent kernels (verified: podman run -v dir:/mnt:idmap … gives correct 1000:1000 ownership, no EPERM on 6.17).

    Without it, read_write host mounts are really only usable rootful (where container uid 1000 == host uid 1000); rootless users get subuid-owned files.

  6. randybias commented on Jul 14, 2026

    @randybias

    I agree that would be useful. My initial tests with Docker were positive, but this would definitely make it easier to use.

  7. ittayd commented on Jul 14, 2026

    @ittayd

    Setting the sandbox's user namespace to keep-id in the podman driver's create spec fixes it — the agent's writes to read_write host mounts land owned by the host user (1000) instead of a subuid. Verified on rootless Podman 5.8.4.

    // crates/openshell-driver-podman/src/container.rs — ContainerSpec create spec
    userns: std::env::var("OPENSHELL_SANDBOX_USERNS") // e.g. "keep-id"
    .ok().filter(|s| !s.is_empty())
    .map(|nsmode| UserNS { nsmode }),

  8. sandys commented on Jul 15, 2026

    @sandys

    would this also include FUSE ? we have been struggling to get a FUSE-based cloud filesystem (like s3fs) to run inside openshell. i think the architecture prevents a fuse daemon to run and mount filesystems before the rest of the openshell kicks in.

    a lot of us use agents with fuse based filesystems to access data.

  9. github-actions commented on Aug 28, 2026

    @github-actions

    This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:staleInactive item at risk of automatic closure.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions