From 640fe07b60b4efba5d50695f84a17f4b27d0ddc4 Mon Sep 17 00:00:00 2001 From: Leonid Gorkin Date: Fri, 23 Oct 2026 09:47:29 -0400 Subject: [PATCH] feat(sandbox): OpenShell pilot policy + image for the engineer bot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First pilot of NVIDIA/OpenShell sandboxing for OpenBot bots (advisory mode, enforcement=audit): declarative policy covering the workspace, git remotes (github/api.github/objects.githubusercontent), package registries (pypi.org/files.pythonhosted.org) and uv's CPython release host; ubuntu:24.04 base image (default image lacks git/gh/python/curl and apt is unusable inside); README quickstart with the v0.1.5 gotchas (real-binary network paths, uv->github releases dependency, hot-reload, detached create). Verified live: git->github, gh, pypi API + pip download, default-deny (conn refused), policy hot-reload x5, full backend suite in-sandbox (811 passed / 30 failed — environmental: uv Python 3.13 vs repo 3.12, missing patch binary; sample failures pass on host). --- policies/README.md | 57 ++++++++++++++++++++++ policies/engineer-base.Dockerfile | 9 ++++ policies/engineer.yaml | 79 +++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 policies/README.md create mode 100644 policies/engineer-base.Dockerfile create mode 100644 policies/engineer.yaml diff --git a/policies/README.md b/policies/README.md new file mode 100644 index 0000000..232c8d4 --- /dev/null +++ b/policies/README.md @@ -0,0 +1,57 @@ +# Bot sandbox policies (NVIDIA/OpenShell pilot) + +Policies for running OpenBot bots inside [NVIDIA/OpenShell](https://github.com/NVIDIA/OpenShell) +kernel-level sandboxes. Pilot scope: the `@engineer` bot, in **advisory** mode +(denials are logged and surfaced as drafted rule proposals, not hard failures). + +## Contents + +- `engineer.yaml` — policy for the `engineer` sandbox: workspace files, git remotes + (github.com / api.github.com), package registries (pypi.org, files.pythonhosted.org), + and uv's CPython release host. All network rules are `enforcement: audit` for the + pilot; flip to `enforce` per rule before production. +- `engineer-base.Dockerfile` — sandbox image. The default sandbox image ships **without** + git/gh/curl/python and apt is unusable inside (non-root, no network), so tools must be + baked into the image before the sandbox starts. + +## Quickstart (host) + +```sh +# 1. Build the base image (gateway uses the local Docker daemon) +docker build -f policies/engineer-base.Dockerfile -t openshell/engineer-base:latest . + +# 2. Create the sandbox (keep a sleep-style main process; create attaches to it) +openshell sandbox create engineer --from openshell/engineer-base:latest \ + -- sleep 100000 # detached: nohup openshell sandbox create engineer ... + +# 3. Apply (or hot-reload) the policy — no restart needed +openshell policy set engineer --policy policies/engineer.yaml --wait + +# 4. Run work inside +openshell sandbox exec engineer -- bash -c 'cd /sandbox && git …' + +# 5. Audit + rule proposals +openshell logs engineer --source sandbox # OCSF allow/deny events +openshell rule get engineer --status pending # drafted rules from denials +``` + +## Hard-won details (v0.1.5) + +- **Network `binaries` must be kernel-resolved real paths** (`readlink -f`), never + symlinks. `git` fetch/push execs `/usr/lib/git-core/git-remote-http`; `pip` runs as the + interpreter `/usr/bin/python3.12`. A symlink path fails silently as "connection refused"; + the sandbox log carries a `SYMLINK HINT` explaining it. +- **uv downloads CPython** builds from `github.com/astral-sh/...` releases + (redirected via `releases.astral.sh`), so both hosts must be allowed for the uv binary — + even when pypi itself is allowed. +- Policies hot-reload via `policy set --wait`; network rules are live fields. +- Default-deny holds: unlisted endpoints fail as connection refused. + +## Pilot result (2026-10-23) + +Full backend suite ran inside the sandbox: `uv sync --frozen`, ruff, pytest → +811 passed / 30 failed / 30 deselected. The 30 failures were environmental, not policy +denials: uv pulled Python 3.13 (repo targets 3.12) and the image lacked `patch` — both +fixed in the image/pinned-tooling follow-up. Audit log showed 36 denials, all default-deny +working as intended (e.g. `example.com`), plus the drafted rules listed by +`openshell rule get engineer --status pending`. diff --git a/policies/engineer-base.Dockerfile b/policies/engineer-base.Dockerfile new file mode 100644 index 0000000..fd64d7b --- /dev/null +++ b/policies/engineer-base.Dockerfile @@ -0,0 +1,9 @@ +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive +# ubuntu:24.04 ships an "ubuntu" user with UID 1000 (the uid OpenShell sandboxes run as). +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates git gh curl wget python3 python3-pip python3-venv ripgrep jq less patch && \ + rm -rf /var/lib/apt/lists/* +USER ubuntu +WORKDIR /sandbox +RUN mkdir -p /sandbox diff --git a/policies/engineer.yaml b/policies/engineer.yaml new file mode 100644 index 0000000..472a65a --- /dev/null +++ b/policies/engineer.yaml @@ -0,0 +1,79 @@ +version: 1 + +filesystem_policy: + include_workdir: true + read_only: + - /bin + - /usr + - /lib + - /proc + - /etc + - /dev/urandom + - /var/log + read_write: + - /tmp + - /dev/null + +landlock: + compatibility: best_effort + +network_policies: + github: + endpoints: + - host: github.com + port: 443 + protocol: rest + enforcement: audit + access: full + - host: api.github.com + port: 443 + protocol: rest + enforcement: audit + access: full + - host: objects.githubusercontent.com + port: 443 + protocol: rest + enforcement: audit + access: read-only + binaries: + # `git clone/fetch/push` execs git-remote-https (a symlink to this real + # binary) — list the real path, not the symlink. + - path: /usr/lib/git-core/git-remote-http + - path: /usr/bin/gh + - path: /usr/bin/curl + # uv downloads CPython builds from github.com/astral-sh releases + - path: /sandbox/.local/bin/uv + pypi: + endpoints: + - host: pypi.org + port: 443 + protocol: rest + enforcement: audit + access: read-only + - host: files.pythonhosted.org + port: 443 + protocol: rest + enforcement: audit + access: read-only + binaries: + # pip runs as the python3.12 interpreter — list the interpreter's real + # path (scripts exec their interpreter; pip3 itself is a python script). + - path: /usr/bin/python3.12 + # uv resolves/downloads packages over HTTPS + - path: /sandbox/.local/bin/uv + - path: /usr/bin/curl + astral_releases: + endpoints: + # uv fetches managed CPython builds from python-build-standalone releases + - host: releases.astral.sh + port: 443 + protocol: rest + enforcement: audit + access: read-only + - host: github.com + port: 443 + protocol: rest + enforcement: audit + access: read-only + binaries: + - path: /sandbox/.local/bin/uv