README.md
  1  # Host Volume Mount Example
  2  
  3  This example demonstrates how to mount host directories into sandbox containers using the OpenSandbox Volume API. Host volume mounts enable bidirectional file sharing between the host machine and sandbox environments — ideal for sharing datasets, model checkpoints, configuration files, or collecting sandbox outputs.
  4  
  5  ## Scenarios
  6  
  7  | # | Scenario | Description |
  8  |---|----------|-------------|
  9  | 1 | **Read-write mount** | Mount a host directory for bidirectional file exchange |
 10  | 2 | **Read-only mount** | Provide shared data that sandboxes cannot modify |
 11  | 3 | **SubPath mount** | Mount a specific subdirectory from the host path |
 12  
 13  ## Prerequisites
 14  
 15  ### 1. Start OpenSandbox Server
 16  
 17  ```shell
 18  git clone git@github.com:alibaba/OpenSandbox.git
 19  cd OpenSandbox/server
 20  cp opensandbox_server/examples/example.config.toml ~/.sandbox.toml
 21  uv sync && uv run python -m opensandbox_server.main
 22  ```
 23  
 24  ### 2. Configure Allowed Host Paths
 25  
 26  For security, the server restricts which host paths can be mounted. Add a `[storage]` section to `~/.sandbox.toml`:
 27  
 28  ```toml
 29  [storage]
 30  # Allowlist of host path prefixes permitted for bind mounts.
 31  # Only paths under these prefixes can be mounted into sandboxes.
 32  # If empty, all host paths are allowed (not recommended for production).
 33  allowed_host_paths = ["/tmp/opensandbox-data", "/data/shared"]
 34  ```
 35  
 36  > **Security note**: In production, always set explicit `allowed_host_paths` to prevent sandboxes from accessing sensitive host directories. An empty list allows all paths, which is convenient for local development but not safe for shared environments.
 37  
 38  ### 3. Create Host Directories
 39  
 40  ```shell
 41  # Create a directory to share with sandboxes
 42  mkdir -p /tmp/opensandbox-data
 43  echo "hello-from-host" > /tmp/opensandbox-data/marker.txt
 44  
 45  # Create a subdirectory for the subpath demo
 46  mkdir -p /tmp/opensandbox-data/datasets/train
 47  echo -e "id,value\n1,100\n2,200\n3,300" > /tmp/opensandbox-data/datasets/train/data.csv
 48  ```
 49  
 50  ### 4. Install SDK from Source
 51  
 52  Volume support requires the latest SDK built from source (not yet available in the released package):
 53  
 54  ```shell
 55  # From the project root (recommended: use uv)
 56  uv pip install -e sdks/sandbox/python
 57  
 58  # Or use pip inside a virtual environment
 59  # python3 -m venv .venv && source .venv/bin/activate
 60  # pip install -e sdks/sandbox/python
 61  ```
 62  
 63  ### 5. Pull the Sandbox Image
 64  
 65  ```shell
 66  docker pull ubuntu:latest
 67  ```
 68  
 69  ## Run
 70  
 71  ```shell
 72  HOST_VOLUME_PATH=/tmp/opensandbox-data uv run python examples/host-volume-mount/main.py
 73  ```
 74  
 75  ## Expected Output
 76  
 77  ```text
 78  Using HOST_VOLUME_PATH: /tmp/opensandbox-data
 79  
 80  OpenSandbox server : localhost:8080
 81  Sandbox image      : ubuntu
 82  Host volume path   : /tmp/opensandbox-data
 83  
 84  ============================================================
 85  Scenario 1: Read-Write Host Volume Mount
 86  ============================================================
 87    Host path : /tmp/opensandbox-data
 88    Mount path: /mnt/shared
 89  
 90    [1] Listing files visible from inside the sandbox:
 91    total 12
 92    drwxrwxrwx 3 root root 4096 ... .
 93    drwxr-xr-x 1 root root 4096 ... ..
 94    -rw-r--r-- 1 root root   16 ... marker.txt
 95    drwxr-xr-x 3 root root 4096 ... datasets
 96  
 97    [2] Writing a file from inside the sandbox:
 98    -> Written: /mnt/shared/sandbox-greeting.txt
 99  
100    [3] Reading back the file:
101    Hello from sandbox!
102  
103    [4] Verified on host: /tmp/opensandbox-data/sandbox-greeting.txt
104        Content: Hello from sandbox!
105  
106    Scenario 1 completed.
107  
108  ============================================================
109  Scenario 2: Read-Only Host Volume Mount
110  ============================================================
111    Host path : /tmp/opensandbox-data
112    Mount path: /mnt/readonly
113  
114    [1] Reading files from read-only mount:
115    ...
116  
117    [2] Reading marker.txt:
118    hello-from-host
119  
120    [3] Attempting to write (should fail):
121    Write denied (expected)
122  
123    Scenario 2 completed.
124  
125  ============================================================
126  Scenario 3: SubPath Host Volume Mount
127  ============================================================
128    Host path : /tmp/opensandbox-data
129    SubPath   : datasets/train
130    Mount path: /mnt/training-data
131  
132    [1] Listing mounted subpath content:
133    ...
134    -rw-r--r-- 1 root root   28 ... data.csv
135  
136    [2] Reading data.csv:
137    id,value
138    1,100
139    2,200
140    3,300
141  
142    Scenario 3 completed.
143  
144  ============================================================
145  All scenarios completed successfully!
146  ============================================================
147  ```
148  
149  ## SDK Usage Quick Reference
150  
151  ### Python (async)
152  
153  ```python
154  from opensandbox import Sandbox
155  from opensandbox.models.sandboxes import Host, Volume
156  
157  sandbox = await Sandbox.create(
158      image="ubuntu",
159      volumes=[
160          Volume(
161              name="my-data",
162              host=Host(path="/data/shared"),
163              mountPath="/mnt/data",
164              readOnly=False,       # optional, default is False
165              subPath="subdir",     # optional, mount a subdirectory
166          ),
167      ],
168  )
169  ```
170  
171  ### Python (sync)
172  
173  ```python
174  from opensandbox import SandboxSync
175  from opensandbox.models.sandboxes import Host, Volume
176  
177  sandbox = SandboxSync.create(
178      image="ubuntu",
179      volumes=[
180          Volume(
181              name="my-data",
182              host=Host(path="/data/shared"),
183              mountPath="/mnt/data",
184          ),
185      ],
186  )
187  ```
188  
189  ### JavaScript / TypeScript
190  
191  ```typescript
192  import { Sandbox } from "@alibaba-group/opensandbox";
193  
194  const sandbox = await Sandbox.create({
195    image: "ubuntu",
196    volumes: [
197      {
198        name: "my-data",
199        host: { path: "/data/shared" },
200        mountPath: "/mnt/data",
201        readOnly: false,
202      },
203    ],
204  });
205  ```
206  
207  ### Java / Kotlin
208  
209  ```java
210  Volume volume = Volume.builder()
211      .name("my-data")
212      .host(Host.of("/data/shared"))
213      .mountPath("/mnt/data")
214      .readOnly(false)
215      .build();
216  
217  Sandbox sandbox = Sandbox.builder()
218      .image("ubuntu")
219      .volume(volume)
220      .build();
221  ```
222  
223  ## References
224  
225  - [OSEP-0003: Volume and VolumeBinding Support](../../oseps/0003-volume-and-volumebinding-support.md) — Design proposal
226  - [Sandbox Lifecycle API Spec](../../specs/sandbox-lifecycle.yml) — OpenAPI schema for volume definitions
227  - [Server Configuration](../../server/example.config.toml) — `[storage]` section for `allowed_host_paths`