mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-11-12 11:33:51 +08:00
npm 11 does not support `npm dedupe -g` in global mode, causing the sandbox container build to fail with error code EDEDUPEGLOBAL. The dedupe was intended to remove nested copies of vulnerable dependencies, but npm 11 already handles global package installation differently. The force-upgrade of tar and @hono/node-server already ensures the patched versions are installed.
234 lines
12 KiB
Docker
234 lines
12 KiB
Docker
# syntax=docker/dockerfile:1.4
|
|
|
|
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# Supervisor container for NemoClaw
|
|
# Multi-stage build with cross-compilation support for multi-arch
|
|
|
|
# Stage 1: Rust builder (runs on build platform, cross-compiles for target)
|
|
FROM --platform=$BUILDPLATFORM rust:1.88-slim AS rust-builder
|
|
ARG RUST_BUILD_PROFILE=debug
|
|
ARG TARGETARCH
|
|
ARG BUILDARCH
|
|
ARG CARGO_TARGET_CACHE_SCOPE=default
|
|
|
|
# Install build dependencies
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
cmake g++ make protobuf-compiler curl && rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install cross-compilation toolchain, sccache, + Rust target (no-ops for native builds)
|
|
COPY deploy/docker/cross-build.sh /usr/local/bin/
|
|
RUN . cross-build.sh && install_cross_toolchain && install_sccache && add_rust_target
|
|
|
|
ARG SCCACHE_MEMCACHED_ENDPOINT
|
|
|
|
WORKDIR /build
|
|
|
|
# Copy dependency manifests first for better caching
|
|
COPY Cargo.toml Cargo.lock ./
|
|
COPY crates/navigator-cli/Cargo.toml crates/navigator-cli/Cargo.toml
|
|
COPY crates/navigator-core/Cargo.toml crates/navigator-core/Cargo.toml
|
|
COPY crates/navigator-policy/Cargo.toml crates/navigator-policy/Cargo.toml
|
|
COPY crates/navigator-providers/Cargo.toml crates/navigator-providers/Cargo.toml
|
|
COPY crates/navigator-router/Cargo.toml crates/navigator-router/Cargo.toml
|
|
COPY crates/navigator-sandbox/Cargo.toml crates/navigator-sandbox/Cargo.toml
|
|
COPY crates/navigator-server/Cargo.toml crates/navigator-server/Cargo.toml
|
|
COPY crates/navigator-bootstrap/Cargo.toml crates/navigator-bootstrap/Cargo.toml
|
|
|
|
# Create dummy source files to build dependencies
|
|
RUN mkdir -p crates/navigator-cli/src crates/navigator-core/src crates/navigator-policy/src crates/navigator-providers/src crates/navigator-router/src crates/navigator-sandbox/src crates/navigator-server/src crates/navigator-bootstrap/src && \
|
|
echo "fn main() {}" > crates/navigator-cli/src/main.rs && \
|
|
echo "fn main() {}" > crates/navigator-sandbox/src/main.rs && \
|
|
echo "fn main() {}" > crates/navigator-server/src/main.rs && \
|
|
touch crates/navigator-core/src/lib.rs && \
|
|
touch crates/navigator-policy/src/lib.rs && \
|
|
touch crates/navigator-providers/src/lib.rs && \
|
|
touch crates/navigator-router/src/lib.rs && \
|
|
touch crates/navigator-bootstrap/src/lib.rs
|
|
|
|
# Copy proto files needed for build
|
|
COPY proto/ proto/
|
|
COPY crates/navigator-sandbox/data/sandbox-policy.rego ./crates/navigator-sandbox/data/
|
|
COPY deploy/docker/sandbox/dev-sandbox-policy.yaml ./deploy/docker/sandbox/
|
|
|
|
# Build dependencies only (cached unless Cargo.toml/lock changes).
|
|
# sccache uses memcached in CI or the local disk cache mount for local dev.
|
|
# The cargo-target mount gives cargo a persistent target/ dir for incremental rebuilds.
|
|
RUN --mount=type=cache,id=cargo-registry-sandbox-${TARGETARCH},sharing=locked,target=/usr/local/cargo/registry \
|
|
--mount=type=cache,id=cargo-target-sandbox-${TARGETARCH}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \
|
|
--mount=type=cache,id=sccache-sandbox-${TARGETARCH},sharing=locked,target=/tmp/sccache \
|
|
. cross-build.sh && cargo_cross_build -p navigator-sandbox 2>/dev/null || true
|
|
|
|
# Copy actual source code
|
|
COPY crates/ crates/
|
|
|
|
# Touch source files to ensure they're rebuilt (not the cached dummy).
|
|
# Touch build.rs and proto files to force proto code regeneration when the
|
|
# cargo target cache mount retains stale OUT_DIR artifacts from prior builds.
|
|
RUN touch crates/navigator-sandbox/src/main.rs \
|
|
crates/navigator-core/build.rs \
|
|
proto/*.proto
|
|
|
|
# Build with cross-compilation support.
|
|
# Cache mounts are keyed by TARGETARCH so parallel multi-platform builds
|
|
# don't corrupt each other's cargo registry or build artifacts.
|
|
RUN --mount=type=cache,id=cargo-registry-sandbox-${TARGETARCH},sharing=locked,target=/usr/local/cargo/registry \
|
|
--mount=type=cache,id=cargo-target-sandbox-${TARGETARCH}-${CARGO_TARGET_CACHE_SCOPE},sharing=locked,target=/build/target \
|
|
--mount=type=cache,id=sccache-sandbox-${TARGETARCH},sharing=locked,target=/tmp/sccache \
|
|
. cross-build.sh && \
|
|
if [ "$RUST_BUILD_PROFILE" = "release" ]; then \
|
|
cargo_cross_build --release -p navigator-sandbox; \
|
|
else \
|
|
cargo_cross_build -p navigator-sandbox; \
|
|
fi && \
|
|
mkdir -p /build/out && \
|
|
cp "$(cross_output_dir "$RUST_BUILD_PROFILE")/navigator-sandbox" /build/out/
|
|
|
|
# Stage 2: Python base (uses target platform)
|
|
# Pin to specific Python patch + Debian release for reproducible builds.
|
|
# CVE-2025-13836 (stdlib urllib Content-Length OOM) affects Python <= 3.12.13;
|
|
# update to python:3.12.14-slim-bookworm (or later) when released.
|
|
FROM python:3.12.13-slim-bookworm AS base
|
|
|
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
PYTHONUNBUFFERED=1
|
|
|
|
WORKDIR /sandbox
|
|
|
|
# Install system dependencies
|
|
# iproute2 is needed for network namespace management (ip netns, veth pairs)
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
curl dnsutils iproute2 iputils-ping \
|
|
net-tools netcat-openbsd traceroute \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Create supervisor and sandbox users/groups
|
|
RUN groupadd -r supervisor && useradd -r -g supervisor -s /usr/sbin/nologin supervisor && \
|
|
groupadd -r sandbox && useradd -r -g sandbox -d /sandbox -s /bin/bash sandbox
|
|
|
|
# Stage 3: Python dependencies builder
|
|
FROM base AS builder
|
|
|
|
COPY --from=ghcr.io/astral-sh/uv:0.10.8 /uv /usr/local/bin/uv
|
|
|
|
# Copy project files for dependency resolution
|
|
COPY pyproject.toml uv.lock ./
|
|
|
|
# Install dependencies into a virtual environment
|
|
RUN uv venv /app/.venv && \
|
|
uv sync --frozen --no-dev --no-install-project 2>/dev/null || \
|
|
uv sync --no-dev --no-install-project 2>/dev/null || true
|
|
|
|
# Install navigator SDK dependencies and pip (uv venvs don't include pip by
|
|
# default, and sandbox users need it for `pip install` inside the sandbox).
|
|
RUN uv pip install --python /app/.venv/bin/python --no-cache-dir cloudpickle grpcio protobuf openai pip
|
|
|
|
# Stage 4: Coding agents layer
|
|
FROM base AS coding-agents
|
|
|
|
# Install Node.js 22 via NodeSource (required by coding agents).
|
|
# build-essential & python3 are needed for npm packages with native addons (node-gyp).
|
|
# Include a minimal native toolchain so npm can compile optional native
|
|
# dependencies on platforms where prebuilt artifacts are unavailable.
|
|
# 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.
|
|
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
|
|
apt-get install -y --no-install-recommends build-essential git nodejs=22.22.1-1nodesource1 python3 nano && \
|
|
rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install GitHub CLI (gh) from the official apt repository
|
|
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
|
-o /usr/share/keyrings/githubcli-archive-keyring.gpg && \
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
|
|
> /etc/apt/sources.list.d/github-cli.list && \
|
|
apt-get update && apt-get install -y --no-install-recommends gh && \
|
|
rm -rf /var/lib/apt/lists/*
|
|
|
|
# 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
|
|
|
|
# Upgrade npm to v11 which ships tar@^7.5.9 (fixes 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 npm install -g npm@11.11.0
|
|
|
|
# Install OpenCode CLI and Codex CLI (OpenAI) with pinned versions for
|
|
# reproducible builds. Force-upgrade tar and @hono/node-server afterward to
|
|
# resolve transitive dependency vulnerabilities (GHSA-wc8c-qw6v-h7f6,
|
|
# GHSA-r6q2-hw4h-h46w, GHSA-qffp-2rhf-9h96, GHSA-8qq5-rm4j-mr97,
|
|
# GHSA-83g3-92jg-28cx, GHSA-34x7-hfp2-rc4v).
|
|
RUN npm install -g opencode-ai@1.2.18 @openai/codex@0.111.0 && \
|
|
npm install -g tar@7.5.11 @hono/node-server@1.19.11
|
|
|
|
# Install ai-pim-utils (NVIDIA PIM CLI tools: outlook, calendar, transcripts, etc.)
|
|
# The install script auto-detects Debian and installs via .deb package to /usr/bin.
|
|
# Skills are installed to /usr/share/ai-pim-utils/skills and symlinked to ~/.claude/skills.
|
|
# RUN curl -fsSL https://outlook-cli-80d21a.gitlab-master-pages.nvidia.com/install.sh | bash
|
|
|
|
# Stage 5: Final image
|
|
FROM coding-agents AS final
|
|
ARG RUST_BUILD_PROFILE=debug
|
|
|
|
COPY --from=builder /app/.venv /app/.venv
|
|
COPY --from=builder /usr/local/bin/uv /usr/local/bin/uv
|
|
COPY --from=rust-builder /build/out/navigator-sandbox /usr/local/bin/
|
|
|
|
# Copy navigator Python SDK into the virtual environment
|
|
COPY python/navigator/ /app/.venv/lib/python3.12/site-packages/navigator/
|
|
|
|
# Add venvs to PATH -- /sandbox/.venv (writable, user-installed packages)
|
|
# takes priority over /app/.venv (read-only, build-time packages).
|
|
# ssh.rs inherits PATH at runtime so it stays in sync with this layout.
|
|
# 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:/app/.venv/bin:/usr/local/bin:/usr/bin:/bin" \
|
|
VIRTUAL_ENV="/sandbox/.venv" \
|
|
UV_PYTHON_INSTALL_DIR="/sandbox/.uv/python"
|
|
|
|
# Copy custom navigator skills into the image
|
|
# To add a skill, create a subdirectory under deploy/docker/sandbox/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 deploy/docker/sandbox/skills/ /sandbox/.agents/skills/
|
|
|
|
# Bake the default sandbox policy into the image so that sandboxes without an
|
|
# explicit policy from the gateway can discover it on disk.
|
|
COPY deploy/docker/sandbox/dev-sandbox-policy.yaml /etc/navigator/policy.yaml
|
|
|
|
RUN mkdir -p /var/navigator /sandbox /var/log && \
|
|
touch /var/log/navigator.log && \
|
|
chown supervisor:supervisor /var/log/navigator.log && \
|
|
chmod 0664 /var/log/navigator.log && \
|
|
chown sandbox:sandbox /sandbox && \
|
|
# Create a writable venv that inherits all packages from the read-only
|
|
# /app/.venv. Sandbox users can `pip install` or `uv pip install` into
|
|
# this venv without touching the base image layer.
|
|
uv venv --python /app/.venv/bin/python --seed --system-site-packages /sandbox/.venv && \
|
|
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:/app/.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 sandbox:sandbox /sandbox/.bashrc /sandbox/.profile && \
|
|
# Install agent skills into the sandbox user's home directory
|
|
# so Claude and other agents can discover them at runtime.
|
|
# Sources: ai-pim-utils (.deb) and custom navigator skills.
|
|
mkdir -p /sandbox/.claude/skills /sandbox/.agents/skills && \
|
|
for src in /usr/share/ai-pim-utils/skills /usr/share/navigator/skills; do \
|
|
[ -d "$src" ] || continue; \
|
|
find "$src" -mindepth 1 -maxdepth 1 -type d | while read -r skill; do \
|
|
ln -sf "$skill" "/sandbox/.claude/skills/$(basename "$skill")"; \
|
|
ln -sf "$skill" "/sandbox/.agents/skills/$(basename "$skill")"; \
|
|
done; \
|
|
done && \
|
|
chown -R sandbox:sandbox /sandbox/.claude /sandbox/.agents
|
|
|
|
ENTRYPOINT ["navigator-sandbox"]
|