Skip to content
Open
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
57 changes: 57 additions & 0 deletions policies/README.md
Original file line number Diff line number Diff line change
@@ -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`.
9 changes: 9 additions & 0 deletions policies/engineer-base.Dockerfile
Original file line number Diff line number Diff line change
@@ -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
79 changes: 79 additions & 0 deletions policies/engineer.yaml
Original file line number Diff line number Diff line change
@@ -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
Loading