mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-26 06:52:57 +08:00
Closes #34 ## Summary - Add `nav ssh-proxy` name mode (`--cluster`/`--name`) and `nav sandbox ssh-config` for VS Code Remote-SSH integration - Fix VS Code Remote-SSH platform misdetection (was defaulting to Windows/PowerShell) - Fix sandbox network policy for VS Code server connectivity - Fix sandbox user shell configuration ## Problem VS Code Remote-SSH was failing to connect to Navigator sandboxes due to three issues: 1. **Platform misdetection**: VS Code sends `uname -rsv` after a `ready:` marker and expects a response within ~1ms. Forced PTY allocation in `shell_request`, interactive bash (`-i`), and leaked supervisor env vars added enough latency that VS Code timed out and defaulted to "Platform: windows", then tried `powershell`. 2. **Broken network policy**: The `vscode` entry in `dev-sandbox-policy.yaml` was at the YAML top-level instead of nested under `network_policies:` (indentation bug). The VS Code server binary also needed a glob entry. 3. **No login shell**: The sandbox user had `/usr/sbin/nologin` as its shell. ## Changes | File | Change | |------|--------| | `crates/navigator-sandbox/src/ssh.rs` | Remove forced PTY in `shell_request`, remove `-i` flag from pipe exec, add `env_clear()` + explicit `SHELL`/`PATH` to both shell spawn paths | | `deploy/docker/sandbox/Dockerfile.base` | Change sandbox user shell to `/bin/bash`, set home to `/sandbox`, add `.bashrc`/`.profile` | | `dev-sandbox-policy.yaml` | Fix `vscode:` indentation under `network_policies:`, add `/sandbox/.vscode-server/*` binary glob | | `crates/navigator-cli/src/main.rs` | Add `--cluster`/`--name` to `SshProxy`, add `SshConfig`/`Policy`/`Logs` subcommands (rebase merge) | | `crates/navigator-cli/src/ssh.rs` | Update `print_ssh_config` to use `--cluster` flag | | `examples/vscode-remote-sandbox.md` | User-facing example and docs | ## How to use ```bash # Create a persistent sandbox nav sandbox create --keep my-sandbox # Generate SSH config nav sandbox ssh-config my-sandbox >> ~/.ssh/config # Open VS Code code --remote ssh-remote+nav-my-sandbox /sandbox ``` ## Testing - All 307 tests pass - Clippy clean on modified crates
172 lines
7.6 KiB
Docker
172 lines
7.6 KiB
Docker
# syntax=docker/dockerfile:1.4
|
|
# Supervisor container for navigator
|
|
# 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
|
|
|
|
# Install build dependencies
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
cmake g++ make protobuf-compiler && rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install cross-compilation toolchain + Rust target (no-ops for native builds)
|
|
COPY deploy/docker/cross-build.sh /usr/local/bin/
|
|
RUN . cross-build.sh && install_cross_toolchain && add_rust_target
|
|
|
|
WORKDIR /build
|
|
COPY Cargo.toml Cargo.lock ./
|
|
COPY crates/ crates/
|
|
COPY proto/ proto/
|
|
COPY dev-sandbox-policy.rego ./
|
|
|
|
# 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},sharing=locked,target=/build/target \
|
|
. 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)
|
|
FROM python:3.12-slim 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:latest /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
|
|
RUN uv pip install --python /app/.venv/bin/python --no-cache-dir cloudpickle grpcio protobuf openai
|
|
|
|
# Stage 4: Coding agents layer
|
|
FROM base AS coding-agents
|
|
|
|
# Install Node.js 22 via NodeSource (required by OpenClaw and other 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.
|
|
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \
|
|
apt-get install -y --no-install-recommends build-essential git nodejs build-essential python3 vim-tiny 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
|
|
|
|
# Install OpenClaw CLI via npm (the native installer uses npm under the hood;
|
|
# installing directly avoids TTY and onboarding issues in Docker builds)
|
|
RUN npm install -g openclaw@2026.2.9
|
|
|
|
# Install OpenCode CLI and Codex CLI (OpenAI)
|
|
RUN npm install -g opencode-ai @openai/codex
|
|
|
|
# Install GitHub CLI (gh) via official Debian repository
|
|
RUN mkdir -p -m 755 /etc/apt/keyrings && \
|
|
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
|
-o /etc/apt/keyrings/githubcli-archive-keyring.gpg && \
|
|
chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg && \
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/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 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 venv to PATH
|
|
ENV PATH="/app/.venv/bin:$PATH"
|
|
|
|
# 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/.openclaw/skills/
|
|
|
|
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 && \
|
|
# 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="/app/.venv/bin:$PATH"\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/.openclaw /sandbox/.claude /sandbox/.agents
|
|
|
|
# OpenClaw startup helper for environments without systemd (e.g. sandboxes).
|
|
# Usage: nav sandbox create --forward 18789 -- openclaw-start
|
|
COPY deploy/docker/openclaw-start.sh /usr/local/bin/openclaw-start
|
|
RUN chmod +x /usr/local/bin/openclaw-start
|
|
|
|
ENTRYPOINT ["navigator-sandbox"]
|