π‘ unaiverse.utils.sandbox
What this module does π‘
Provides Docker-based sandboxing utilities that build an isolated image from project requirements and run agent code inside a container with mounted volumes and resource limits.
sandbox
¶
βββββ βββββ ββββββ βββββ βββββ βββββ βββββ ββββββββββ βββββββββββ βββββββββ ββββββββββ
βββββ βββββ ββββββββ βββββ βββββ βββββ βββββ ββββββββββββββββββββββββ ββββββββββββββββββββββ
ββββ ββββ ββββββββ ββββ ββββββ ββββ ββββ ββββ ββββ β β ββββ ββββ ββββ βββ ββββ β β
ββββ ββββ βββββββββββββ ββββββββ ββββ ββββ ββββ βββββββ βββββββββββ βββββββββββ βββββββ
ββββ ββββ ββββ ββββββββ βββββββ ββββ βββββ βββ βββββββ ββββββββββββ βββββββββββ βββββββ
ββββ ββββ ββββ βββββββ ββββββββ ββββ βββββββββ ββββ β β ββββ ββββ βββ ββββ ββββ β β
ββββββββββ βββββ βββββββββββββββββ βββββ βββββ ββββββββββ βββββ ββββββββββββββββ ββββββββββ
ββββββββ βββββ βββββ ββββββββ βββββ βββ ββββββββββ βββββ βββββ βββββββββ ββββββββββ
A Collectionless AI Project (https://collectionless.ai)
Registration/Login: https://unaiverse.io
Code Repositories: https://github.com/collectionlessai/
Main Developers: Stefano Melacci (Project Leader), Christian Di Maio, Tommaso Guidi
DOCKERFILE_CONTENT
module-attribute
¶
DOCKERFILE_CONTENT = '\n\n# Debian image, automatically guessed architecture\nFROM python:3.12-slim-bookworm\n\n# Installing Go compiler\nRUN apt-get update && apt-get install -y --no-install-recommends build-essential curl git\nRUN rm -rf /var/lib/apt/lists/*\nRUN ARCH=$(dpkg --print-architecture) && curl -LO https://go.dev/dl/go1.24.5.linux-${ARCH}.tar.gz\nRUN ARCH=$(dpkg --print-architecture) && tar -C /usr/local -xzf go1.24.5.linux-${ARCH}.tar.gz\nRUN ARCH=$(dpkg --print-architecture) && rm go1.24.5.linux-${ARCH}.tar.gz\n\n# Set Go environment variables\nENV PATH="/usr/local/go/bin:${PATH}"\nENV GOPATH="/go"\nRUN mkdir -p /go/bin /go/src /go/pkg\n\n# Setting the working directory inside the container\nWORKDIR /unaiverse\n\n# Dependencies\nRUN <create_requirements.txt>\nRUN pip install --no-cache-dir -r requirements.txt --break-system-packages\n'
parser
module-attribute
¶
parser = ArgumentParser(description='Run a Python script adding customizable read-only and writable paths.', formatter_class=RawTextHelpFormatter, epilog='\n Examples:\n python utils/sandbox.py my_script.py -r /home/user/data:/opt/app/data -p 1234\n python utils/sandbox.py another_script.py -w /tmp/output:/mnt/results\n python utils/sandbox.py script_with_both.py -r /input:/app/in -w /output:/app/out -p 8082\n ')
sandbox
¶
sandbox(file_to_run: str, read_only_paths: tuple[str] | list[str] | None = None, writable_paths: tuple[str] | list[str] | None = None) -> None
Run a Python script inside an isolated Docker sandbox.
Builds a fresh Docker image from an embedded Dockerfile (DOCKERFILE_CONTENT),
mounts the UNaIVERSE source tree as read-only together with any caller-supplied
paths, mounts writable paths, and executes file_to_run with python3 inside
the resulting container. Temporary Docker artifacts (the Dockerfile on disk, the
image, and the container) are created at the start and removed at the end, and also
cleaned up before the build starts so that stale leftovers from a previous failed
run cannot interfere.
The UNaIVERSE root directory is always mounted read-only. In addition, three
subdirectories (runners/, unaiverse/library/, and
unaiverse/networking/p2p/) are always mounted read-write to allow the sandboxed
script to write runtime state back to the host. The caller may extend both sets via
read_only_paths and writable_paths.
The path layout of this file (.../<pkg>/unaiverse/utils/sandbox.py) is asserted
at startup to detect tampering before any Docker command is executed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_to_run
|
str
|
Absolute or relative path to the Python script to execute inside the container. It is converted to an absolute path before being passed to Docker. |
required |
read_only_paths
|
tuple[str] | list[str] | None
|
Additional host filesystem paths to mount inside the container as read-only. Each path must be an existing directory. Defaults to None, meaning no extra read-only mounts are added. |
None
|
writable_paths
|
tuple[str] | list[str] | None
|
Additional host filesystem paths to mount inside the container with read-write access. Each path must be an existing directory. Defaults to None, meaning no extra writable mounts are added. |
None
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If the file's own path does not match the expected
|
SystemExit
|
If the Docker image build fails (exit code 1) or if the Docker container run fails (exit code 1). |
Source code in unaiverse/utils/sandbox.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | |
build_docker_image
¶
Build the Docker image from the Dockerfile located in where.
Invokes docker build -t <DOCKER_IMAGE_NAME> <where> as a subprocess and waits
for it to complete. Progress and errors from the Docker build are printed to stdout
by the subprocess itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
where
|
str
|
Absolute path to the directory containing the Dockerfile. This is
typically the UNaIVERSE source root, where the Dockerfile is written by
|
required |
Returns:
| Type | Description |
|---|---|
|
|
|
|
|
|
|
non-zero status code). |
Source code in unaiverse/utils/sandbox.py
cleanup_docker_artifacts
¶
Remove the generated Dockerfile, Docker image, and any running container.
Attempts, in order: stopping and removing the container whose name matches
CONTAINER_NAME, removing the DOCKER_IMAGE_NAME image, and deleting the
Dockerfile from where. Each step is performed independently so that a
failure in one step does not prevent the others from running. Errors encountered
while stopping or removing the container are caught and printed rather than raised.
Errors raised by docker rmi (a subprocess.CalledProcessError) are also
caught and printed.
This function is called both before the build (to remove stale artifacts from a previously interrupted run) and after a successful or failed run (final cleanup).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
where
|
str
|
Absolute path to the directory from which the Dockerfile should be removed. This is typically the UNaIVERSE source root. |
required |
Source code in unaiverse/utils/sandbox.py
run_in_docker
¶
run_in_docker(file_to_run: str, read_only_host_paths: list[str] = None, writable_host_paths: list[str] = None)
Run a Python script inside a Docker container with configurable volume mounts.
Builds a docker run command from the supplied parameters and executes it. The
container is started with --rm so it is automatically removed on exit.
PYTHONUNBUFFERED=1 and NODE_STARTING_PORT are forwarded from the host
environment so the subprocess behaves identically to a direct invocation.
Network configuration is platform-sensitive: on Linux, --net host is used so
the container shares the host network stack directly. On other platforms (macOS,
Windows), the four consecutive ports starting at NODE_STARTING_PORT are
published explicitly (TCP for the even offsets, UDP for the odd ones).
Every path in read_only_host_paths is mounted at the same absolute location
inside the container with :ro. Every path in writable_host_paths is mounted
at the same absolute location with read-write access. A path that does not exist or
is not a directory causes the function to return False immediately without
starting the container.
The container's stdout and stderr are streamed line-by-line to the caller's stdout
in real time. A KeyboardInterrupt during streaming is silently swallowed so the
caller can handle it at a higher level.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_to_run
|
str
|
Absolute path to the Python script to execute inside the
container. It is passed directly as the argument to |
required |
read_only_host_paths
|
list[str]
|
Host filesystem paths to mount read-only. Each path must be an existing directory; the mount point inside the container mirrors the host path exactly. Defaults to None. |
None
|
writable_host_paths
|
list[str]
|
Host filesystem paths to mount with read-write access. Each path must be an existing directory; the mount point inside the container mirrors the host path exactly. Defaults to None. |
None
|
Returns:
| Type | Description |
|---|---|
|
|
|
|
code), |
|
|
returns a non-zero status ( |
|
|
required host path does not exist. |
Source code in unaiverse/utils/sandbox.py
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | |