diff --git a/sandboxes/droid/Dockerfile b/sandboxes/droid/Dockerfile new file mode 100644 index 00000000..b40e16e5 --- /dev/null +++ b/sandboxes/droid/Dockerfile @@ -0,0 +1,29 @@ +# syntax=docker/dockerfile:1.4 + +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +# Factory Droid sandbox image for OpenShell +# +# Builds on the community base sandbox and adds Factory's Droid CLI. +# Build: docker build -t openshell-droid --build-arg BASE_IMAGE=openshell-base . +# Run: openshell sandbox create --from droid + +ARG BASE_IMAGE=ghcr.io/nvidia/openshell-community/sandboxes/base:latest +FROM ${BASE_IMAGE} + +USER root + +# Install Droid CLI (pinned for reproducibility) +RUN npm install -g droid@0.90.0 + +# Copy sandbox policy +COPY policy.yaml /etc/openshell/policy.yaml + +# Create Droid config directory +RUN mkdir -p /sandbox/.factory && \ + chown sandbox:sandbox /sandbox/.factory + +USER sandbox + +ENTRYPOINT ["/bin/bash"] diff --git a/sandboxes/droid/README.md b/sandboxes/droid/README.md new file mode 100644 index 00000000..7f92d681 --- /dev/null +++ b/sandboxes/droid/README.md @@ -0,0 +1,28 @@ +# Factory Droid Sandbox + +OpenShell sandbox image pre-configured with [Factory Droid CLI](https://docs.factory.ai/) for AI-powered software engineering. + +## What's Included + +- **Droid CLI** (`droid@0.90.0`) — Factory's AI coding agent +- Everything from the [base sandbox](../base/README.md) + +## Build + +```bash +docker build -t openshell-droid . +``` + +To build against a specific base image: + +```bash +docker build -t openshell-droid --build-arg BASE_IMAGE=ghcr.io/nvidia/openshell-community/sandboxes/base:latest . +``` + +## Usage + +### Create a sandbox + +```bash +openshell sandbox create --from droid +``` diff --git a/sandboxes/droid/policy.yaml b/sandboxes/droid/policy.yaml new file mode 100644 index 00000000..7b48020c --- /dev/null +++ b/sandboxes/droid/policy.yaml @@ -0,0 +1,141 @@ +# 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: + + # --- Factory Droid core infrastructure --- + droid: + name: droid + endpoints: + # Main API / LLM proxy + - { host: api.factory.ai, port: 443 } + # Auth, OAuth callbacks, CLI updates + - { host: app.factory.ai, port: 443 } + # WorkOS authentication (device code / OAuth login flow) + - { host: api.workos.com, port: 443 } + # Droid Computers relay (HTTPS + WSS) + - { host: relay.factory.ai, port: 443 } + # CLI auto-update CDN + - { host: downloads.factory.ai, port: 443 } + # Documentation / changelog + - { host: docs.factory.ai, port: 443 } + # Customer OTEL telemetry + - { host: "*.run.app", port: 443 } + # Error tracking + - { host: "*.ingest.us.sentry.io", port: 443 } + - { host: "*.ingest.sentry.io", port: 443 } + binaries: + - { path: "/usr/lib/node_modules/droid/**" } + - { path: /usr/bin/droid } + - { path: /usr/bin/node } + + # --- BYOK: direct model provider access --- + droid_byok: + name: droid-byok + endpoints: + - { host: api.anthropic.com, port: 443 } + - { host: api.openai.com, port: 443 } + - { host: generativelanguage.googleapis.com, port: 443 } + - { host: "*.googleapis.com", port: 443 } + - { host: api.groq.com, port: 443 } + - { host: api.fireworks.ai, port: 443 } + - { host: api.deepinfra.com, port: 443 } + - { host: openrouter.ai, port: 443 } + - { host: api-inference.huggingface.co, port: 443 } + binaries: + - { path: "/usr/lib/node_modules/droid/**" } + - { path: /usr/bin/droid } + - { path: /usr/bin/node } + + # --- GitHub (full read + write access) --- + github: + name: github + endpoints: + - host: github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + rules: + - allow: + method: GET + path: "/**/info/refs*" + - allow: + method: POST + path: "/**/git-upload-pack" + - allow: + method: POST + path: "/**/git-receive-pack" + - host: api.github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + access: read-only + binaries: + - { path: /usr/bin/git } + - { path: /usr/bin/gh } + - { path: "/usr/lib/node_modules/droid/**" } + - { path: /usr/bin/node } + + # --- npm registry (MCP server installs) --- + npm: + name: npm + endpoints: + - { host: registry.npmjs.org, port: 443 } + binaries: + - { path: /usr/bin/node } + - { path: /usr/local/bin/npm } + + # --- PyPI (Python package installs) --- + pypi: + name: pypi + endpoints: + - { host: pypi.org, port: 443 } + - { host: files.pythonhosted.org, port: 443 } + - { host: github.com, port: 443 } + - { host: objects.githubusercontent.com, port: 443 } + - { 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 } + - { path: "/sandbox/.uv/python/**" }