Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 74 additions & 26 deletions sandboxes/base/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.4
# syntax=docker/dockerfile:1

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
Expand All @@ -20,9 +20,9 @@ ENV DEBIAN_FRONTEND=noninteractive \
WORKDIR /sandbox

# Core system dependencies
# python3.13 + pip: agent scripting and SDK usage (deadsnakes PPA for Noble)
# iproute2: network namespace management (ip netns, veth pairs)
# dnsutils: dig, nslookup
# Python is managed entirely by uv (see devtools stage).
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
Expand All @@ -33,16 +33,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
netcat-openbsd \
openssh-sftp-server \
procps \
software-properties-common \
traceroute \
&& add-apt-repository -y ppa:deadsnakes/ppa \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
python3.13 \
python3.13-venv \
&& curl -sS https://bootstrap.pypa.io/get-pip.py | python3.13 \
&& update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.13 1 \
&& update-alternatives --install /usr/bin/python python /usr/bin/python3.13 1 \
&& rm -rf /var/lib/apt/lists/*

# Create supervisor and sandbox users/groups
Expand All @@ -52,20 +43,36 @@ RUN groupadd -r supervisor && useradd -r -g supervisor -s /usr/sbin/nologin supe
# Developer tools
FROM system AS devtools

# Node.js 22 + build toolchain (needed by npm packages with native addons)
# Node.js 22 + build toolchain (needed by npm packages with native addons).
# Pin to a specific patch version for reproducible builds.
# CVE-2026-21637, CVE-2025-59466, CVE-2025-59465, CVE-2025-55131 affect
# Node.js <= 22.22.1. Update to 22.23.0+ when a patched release ships.
#
# npm is upgraded to v11 in the same layer to avoid caching the old npm.
# npm 11 ships tar@^7.5.9, fixing tar@6.2.1 vulns bundled in npm 10
# (GHSA-r6q2-hw4h-h46w, GHSA-8qq5-rm4j-mr97, GHSA-83g3-92jg-28cx,
# GHSA-34x7-hfp2-rc4v, GHSA-qffp-2rhf-9h96).
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
apt-get install -y --no-install-recommends \
build-essential \
git \
nodejs \
nodejs=22.22.1-1nodesource1 \
vim-tiny \
nano \
&& rm -rf /var/lib/apt/lists/*

# Fix transitive tar vulnerabilities (GHSA-qffp-2rhf-9h96,
# GHSA-9ppj-qmqm-q256, GHSA-8qq5-rm4j-mr97, GHSA-r6q2-hw4h-h46w,
# GHSA-34x7-hfp2-rc4v, GHSA-83g3-92jg-28cx).
RUN npm install -g tar@7.5.11
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g npm@11.11.0

# Global npm packages — pinned for reproducibility.
# tar + @hono/node-server: transitive vuln fixes
# (GHSA-qffp-2rhf-9h96, GHSA-9ppj-qmqm-q256, GHSA-8qq5-rm4j-mr97,
# GHSA-r6q2-hw4h-h46w, GHSA-34x7-hfp2-rc4v, GHSA-83g3-92jg-28cx,
# GHSA-wc8c-qw6v-h7f6).
# opencode-ai + @openai/codex: agent CLIs.
RUN npm install -g \
tar@7.5.11 \
@hono/node-server@1.19.11 \
opencode-ai@1.2.18 \
@openai/codex@0.111.0

# GitHub CLI
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
Expand All @@ -75,20 +82,61 @@ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
apt-get update && apt-get install -y --no-install-recommends gh && \
rm -rf /var/lib/apt/lists/*

# uv (Python package manager)
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
# Install Claude CLI via native installer (npm method is deprecated)
RUN curl -fsSL https://claude.ai/install.sh | bash \
&& cp /root/.local/bin/claude /usr/local/bin/claude \
&& chmod 755 /usr/local/bin/claude

# uv (Python package/project manager) — pinned for reproducibility.
# uv manages the Python toolchain; no system Python packages are needed.
COPY --from=ghcr.io/astral-sh/uv:0.10.8 /uv /usr/local/bin/uv
ENV UV_PYTHON_INSTALL_DIR="/sandbox/.uv/python"
RUN uv python install 3.13 && \
ln -s $(uv python find 3.13) /usr/local/bin/python3 && \
ln -s $(uv python find 3.13) /usr/local/bin/python && \
uv cache clean

# Final base image
FROM devtools AS final

# Ensure policy directory exists
RUN mkdir -p /etc/navigator
# Add venvs to PATH -- /sandbox/.venv (writable, user-installed packages)
# takes priority over system paths.
# VIRTUAL_ENV and UV_PYTHON_INSTALL_DIR are also exported in .bashrc
# so that login shell sessions (interactive and exec) see them.
ENV PATH="/sandbox/.venv/bin:/usr/local/bin:/usr/bin:/bin" \
VIRTUAL_ENV="/sandbox/.venv"

# Default sandbox network / filesystem policy
COPY policy.yaml /etc/navigator/policy.yaml

# Copy custom skills into the image.
# To add a skill, create a subdirectory under sandboxes/base/skills/
# with a SKILL.md file (and any supporting files). It will be installed into
# both ~/.claude/skills/ and ~/.agents/skills/ for agent discovery.
COPY skills/ /sandbox/.agents/skills/

# Set up sandbox user home directory
RUN mkdir -p /sandbox/.agents/skills && \
printf 'export PS1="\\u@\\h:\\w\\$ "\n' > /sandbox/.bashrc && \
RUN mkdir -p /sandbox/.claude/skills && \
# Create a writable venv using uv-managed Python 3.13.
# Sandbox users can `uv pip install` (or `pip install`) into
# this venv without touching the base image layer.
uv venv --python 3.13 --seed /sandbox/.venv && \
uv cache clean && \
chown -R sandbox:sandbox /sandbox/.venv && \
# Minimal shell init files so interactive and non-interactive shells
# get a sane PATH and prompt. Without these, bash sources nothing
# under /sandbox and tools like VS Code Remote-SSH may mis-detect
# the platform.
printf 'export PATH="/sandbox/.venv/bin:/usr/local/bin:/usr/bin:/bin"\nexport VIRTUAL_ENV="/sandbox/.venv"\nexport UV_PYTHON_INSTALL_DIR="/sandbox/.uv/python"\nexport PS1="\\u@\\h:\\w\\$ "\n' \
> /sandbox/.bashrc && \
printf '[ -f ~/.bashrc ] && . ~/.bashrc\n' > /sandbox/.profile && \
chown -R sandbox:sandbox /sandbox
chown sandbox:sandbox /sandbox/.bashrc /sandbox/.profile && \
# Symlink skills into agent discovery directories
for skill in /sandbox/.agents/skills/*/; do \
[ -d "$skill" ] || continue; \
ln -sf "$skill" "/sandbox/.claude/skills/$(basename "$skill")"; \
done && \
chown -R sandbox:sandbox /sandbox/.claude /sandbox/.agents /sandbox

USER sandbox

Expand Down
18 changes: 15 additions & 3 deletions sandboxes/base/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ The foundational sandbox image that all other OpenShell Community sandbox images
| Category | Tools |
|----------|-------|
| OS | Ubuntu 24.04 |
| Language | `python3`, `node` (22) |
| Developer | `gh`, `git`, `vim`, `nano`, `uv` |
| Languages | `python3` (3.13), `node` (22.22.1) |
| Package managers | `npm` (11.11.0), `uv` (0.10.8), `pip` |
| Coding agents | `claude`, `opencode`, `codex` |
| Developer | `gh`, `git`, `vim`, `nano` |
| Networking | `ping`, `dig`, `nslookup`, `nc`, `traceroute`, `netstat`, `curl` |

### Users
Expand All @@ -22,10 +24,20 @@ The foundational sandbox image that all other OpenShell Community sandbox images

```
/sandbox/ # Home directory (sandbox user)
.bashrc, .profile # Shell init
.bashrc, .profile # Shell init (PATH, VIRTUAL_ENV, UV_PYTHON_INSTALL_DIR)
.venv/ # Writable Python venv (pip install, uv pip install)
.agents/skills/ # Agent skill discovery
.claude/skills/ # Claude skill discovery (symlinked from .agents/skills)
```

### Skills

The base image ships with the following agent skills:

| Skill | Description |
|-------|-------------|
| `github` | REST-only GitHub CLI usage guide (GraphQL is blocked in sandboxes) |

## Build

```bash
Expand Down
161 changes: 161 additions & 0 deletions sandboxes/base/policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

version: 1

# --- Sandbox setup configuration (queried once at startup) ---

filesystem_policy:
include_workdir: true
read_only:
- /usr
- /lib
- /proc
- /dev/urandom
- /app
- /etc
- /var/log
read_write:
- /sandbox
- /tmp
- /dev/null

landlock:
compatibility: best_effort

process:
run_as_user: sandbox
run_as_group: sandbox

# --- Network policies (queried per-CONNECT request) ---
#
# Each named policy maps a set of allowed (binary, endpoint) pairs.
# Binary identity is resolved via /proc/net/tcp inode lookup + /proc/{pid}/exe.
# Ancestors (/proc/{pid}/status PPid walk) and cmdline paths are also matched.
# SHA256 integrity is enforced in Rust via trust-on-first-use, not here.

network_policies:
claude_code:
name: claude-code
endpoints:
- { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate }
- { host: statsig.anthropic.com, port: 443 }
- { host: sentry.io, port: 443 }
- { host: raw.githubusercontent.com, port: 443 }
- { host: platform.claude.com, port: 443 }
binaries:
- { path: /usr/local/bin/claude }
- { path: /usr/bin/node }

github_ssh_over_https:
name: github-ssh-over-https
endpoints:
- host: github.com
port: 443
protocol: rest
tls: terminate
enforcement: enforce
rules:
# Git Smart HTTP read-only: allow clone, fetch, pull
# Discovery (query string is included in path matching)
- allow:
method: GET
path: "/**/info/refs*"
# Data transfer for reads (all repos)
- allow:
method: POST
path: "/**/git-upload-pack"
# Data transfer for writes
# - allow:
# method: POST
# path: "/**/git-receive-pack"
binaries:
- { path: /usr/bin/git }

nvidia_inference:
name: nvidia-inference
endpoints:
- { host: integrate.api.nvidia.com, port: 443 }
binaries:
- { path: /usr/bin/curl }
- { path: /bin/bash }
- { path: /usr/local/bin/opencode }

# --- GitHub REST API (read-only) ---
github_rest_api:
name: github-rest-api
endpoints:
- host: api.github.com
port: 443
protocol: rest
tls: terminate
enforcement: enforce
access: read-only
binaries:
- { path: /usr/local/bin/claude }
- { path: /usr/bin/gh }

pypi:
name: pypi
endpoints:
- { host: pypi.org, port: 443 }
- { host: files.pythonhosted.org, port: 443 }
# uv python install downloads from python-build-standalone on GitHub
- { host: github.com, port: 443 }
- { host: objects.githubusercontent.com, port: 443 }
# uv resolves python-build-standalone release metadata via the GitHub API
- { host: api.github.com, port: 443 }
- { host: downloads.python.org, port: 443 }
binaries:
- { path: /sandbox/.venv/bin/python }
- { path: /sandbox/.venv/bin/python3 }
- { path: /sandbox/.venv/bin/pip }
- { path: /app/.venv/bin/python }
- { path: /app/.venv/bin/python3 }
- { path: /app/.venv/bin/pip }
- { path: /usr/local/bin/uv }
# Managed Python installations from uv python install
- { path: "/sandbox/.uv/python/**" }

vscode:
name: vscode
endpoints:
- { host: update.code.visualstudio.com, port: 443 }
# NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly.
- { host: az764295.vo.msecnd.net, port: 443 }
- { host: vscode.download.prss.microsoft.com, port: 443 }
- { host: marketplace.visualstudio.com, port: 443 }
- { host: gallerycdn.vsassets.io, port: 443 }
binaries:
- { path: /usr/bin/curl }
- { path: /usr/bin/wget }
- { path: "/sandbox/.vscode-server/**" }
- { path: "/sandbox/.vscode-remote-containers/**" }

cursor:
name: cursor
endpoints:
- { host: cursor.blob.core.windows.net, port: 443 }
# NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly.
- { host: api2.cursor.sh, port: 443 }
- { host: repo.cursor.sh, port: 443 }
- { host: download.cursor.sh, port: 443 }
- { host: cursor.download.prss.microsoft.com, port: 443 }
binaries:
- { path: /usr/bin/curl }
- { path: /usr/bin/wget }
- { path: "/sandbox/.cursor-server/**" }

opencode:
name: opencode
endpoints:
- host: registry.npmjs.org
port: 443
- host: opencode.ai
port: 443
- host: integrate.api.nvidia.com
port: 443
binaries:
- path: /usr/lib/node_modules/opencode-ai/bin/.opencode
- path: /usr/bin/node
- path: /usr/local/bin/opencode
Loading
Loading