From d5073c36aab3b729d2f038aca84dff7f2fc10fbc Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Thu, 12 Mar 2026 16:56:34 -0700 Subject: [PATCH 1/2] chore: align sandbox tooling and policies with upstream OpenShell Add missing coding agents (Claude CLI, OpenCode, Codex), pin versions for reproducibility (Node.js 22.22.1, npm 11.11.0, uv 0.10.8), create a writable /sandbox/.venv overlay, set PATH/VIRTUAL_ENV/UV_PYTHON_INSTALL_DIR env vars, and bake the GitHub REST-only skill into the base image. Align openclaw and nemoclaw network policies with upstream: add pypi, cursor, and opencode policies; fix vscode wildcard endpoints that silently fail with OPA exact-match; replace hardcoded repo-specific write rules with generic read-only access; normalize policy names to use hyphens. --- sandboxes/base/Dockerfile | 71 ++++- sandboxes/base/README.md | 18 +- sandboxes/base/skills/github/SKILL.md | 379 ++++++++++++++++++++++++++ sandboxes/nemoclaw/policy.yaml | 114 ++++---- sandboxes/openclaw/policy.yaml | 113 ++++---- 5 files changed, 588 insertions(+), 107 deletions(-) create mode 100644 sandboxes/base/skills/github/SKILL.md diff --git a/sandboxes/base/Dockerfile b/sandboxes/base/Dockerfile index a555500..56ec386 100644 --- a/sandboxes/base/Dockerfile +++ b/sandboxes/base/Dockerfile @@ -40,6 +40,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \ python3.13 \ python3.13-venv \ + python3.13-dev \ && curl -sS https://bootstrap.pypa.io/get-pip.py | python3.13 \ && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.13 1 \ && update-alternatives --install /usr/bin/python python /usr/bin/python3.13 1 \ @@ -52,20 +53,29 @@ RUN groupadd -r supervisor && useradd -r -g supervisor -s /usr/sbin/nologin supe # Developer tools FROM system AS devtools -# Node.js 22 + build toolchain (needed by npm packages with native addons) +# Node.js 22 + build toolchain (needed by npm packages with native addons). +# 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 \ + nodejs=22.22.1-1nodesource1 \ vim-tiny \ nano \ && rm -rf /var/lib/apt/lists/* -# Fix transitive tar vulnerabilities (GHSA-qffp-2rhf-9h96, -# GHSA-9ppj-qmqm-q256, GHSA-8qq5-rm4j-mr97, GHSA-r6q2-hw4h-h46w, -# GHSA-34x7-hfp2-rc4v, GHSA-83g3-92jg-28cx). -RUN npm install -g tar@7.5.11 +# 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 + +# Fix transitive tar and @hono/node-server vulnerabilities +# (GHSA-qffp-2rhf-9h96, GHSA-9ppj-qmqm-q256, GHSA-8qq5-rm4j-mr97, +# GHSA-r6q2-hw4h-h46w, GHSA-34x7-hfp2-rc4v, GHSA-83g3-92jg-28cx, +# GHSA-wc8c-qw6v-h7f6). +RUN npm install -g tar@7.5.11 @hono/node-server@1.19.11 # GitHub CLI RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ @@ -75,20 +85,59 @@ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ apt-get update && apt-get install -y --no-install-recommends gh && \ rm -rf /var/lib/apt/lists/* -# uv (Python package manager) -COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv +# 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 OpenCode CLI and Codex CLI (OpenAI) with pinned versions for +# reproducible builds. +RUN npm install -g opencode-ai@1.2.18 @openai/codex@0.111.0 + +# uv (Python package manager) — pinned for reproducibility +COPY --from=ghcr.io/astral-sh/uv:0.10.8 /uv /usr/local/bin/uv # Final base image FROM devtools AS final +# Add venvs to PATH -- /sandbox/.venv (writable, user-installed packages) +# takes priority over system paths. +# 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:/usr/local/bin:/usr/bin:/bin" \ + VIRTUAL_ENV="/sandbox/.venv" \ + UV_PYTHON_INSTALL_DIR="/sandbox/.uv/python" + # Ensure policy directory exists RUN mkdir -p /etc/navigator +# Copy custom skills into the image. +# To add a skill, create a subdirectory under sandboxes/base/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 skills/ /sandbox/.agents/skills/ + # Set up sandbox user home directory -RUN mkdir -p /sandbox/.agents/skills && \ - printf 'export PS1="\\u@\\h:\\w\\$ "\n' > /sandbox/.bashrc && \ +RUN mkdir -p /sandbox/.agents/skills /sandbox/.claude/skills && \ + # Create a writable venv that inherits all system packages. + # Sandbox users can `pip install` or `uv pip install` into + # this venv without touching the base image layer. + uv venv --python /usr/bin/python3.13 --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:/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 -R sandbox:sandbox /sandbox + chown sandbox:sandbox /sandbox/.bashrc /sandbox/.profile && \ + # Symlink skills into agent discovery directories + for skill in /sandbox/.agents/skills/*/; do \ + [ -d "$skill" ] || continue; \ + ln -sf "$skill" "/sandbox/.claude/skills/$(basename "$skill")"; \ + done && \ + chown -R sandbox:sandbox /sandbox/.claude /sandbox/.agents /sandbox USER sandbox diff --git a/sandboxes/base/README.md b/sandboxes/base/README.md index 94ecb11..5fb4156 100644 --- a/sandboxes/base/README.md +++ b/sandboxes/base/README.md @@ -7,8 +7,10 @@ The foundational sandbox image that all other OpenShell Community sandbox images | Category | Tools | |----------|-------| | OS | Ubuntu 24.04 | -| Language | `python3`, `node` (22) | -| Developer | `gh`, `git`, `vim`, `nano`, `uv` | +| Languages | `python3` (3.13), `node` (22.22.1) | +| Package managers | `npm` (11.11.0), `uv` (0.10.8), `pip` | +| Coding agents | `claude`, `opencode`, `codex` | +| Developer | `gh`, `git`, `vim`, `nano` | | Networking | `ping`, `dig`, `nslookup`, `nc`, `traceroute`, `netstat`, `curl` | ### Users @@ -22,10 +24,20 @@ The foundational sandbox image that all other OpenShell Community sandbox images ``` /sandbox/ # Home directory (sandbox user) - .bashrc, .profile # Shell init + .bashrc, .profile # Shell init (PATH, VIRTUAL_ENV, UV_PYTHON_INSTALL_DIR) + .venv/ # Writable Python venv (pip install, uv pip install) .agents/skills/ # Agent skill discovery + .claude/skills/ # Claude skill discovery (symlinked from .agents/skills) ``` +### Skills + +The base image ships with the following agent skills: + +| Skill | Description | +|-------|-------------| +| `github` | REST-only GitHub CLI usage guide (GraphQL is blocked in sandboxes) | + ## Build ```bash diff --git a/sandboxes/base/skills/github/SKILL.md b/sandboxes/base/skills/github/SKILL.md new file mode 100644 index 0000000..b3c9137 --- /dev/null +++ b/sandboxes/base/skills/github/SKILL.md @@ -0,0 +1,379 @@ +--- +name: github +description: Interact with GitHub using the gh CLI restricted to REST API only (no GraphQL). Use when the user wants to work with GitHub issues, pull requests, repos, releases, or Actions — especially in sandboxed environments where the GraphQL endpoint may be blocked. Trigger keywords - github, gh, pull request, PR, github issue, github actions, workflow, release, gh api. +--- + +Always prefer using the github cli. do not use git for any operations except cloning. + +# GitHub via REST API + +Work with GitHub using `gh api` and REST-only subcommands. Many `gh` subcommands (`gh pr list`, `gh issue list`, `gh issue view`, `gh pr view`, etc.) use GraphQL internally and **will fail** if the sandbox blocks `api.github.com/graphql`. Always prefer `gh api` hitting REST endpoints. + +## Shell Permissions + +Use `required_permissions: ["full_network"]` for all `gh` commands (they need to reach `api.github.com`). + +## Key Constraint + +| Endpoint | Status | +| --------------------------------- | ---------------------- | +| `api.github.com/graphql` | **Blocked** in sandbox | +| `api.github.com/repos/...` (REST) | Allowed | + +**Rule:** Never use `gh` subcommands that call GraphQL. When in doubt, use `gh api` with an explicit REST path. + +### Commands known to use GraphQL (avoid these) + +- `gh pr list`, `gh pr view`, `gh pr status`, `gh pr checks` +- `gh issue list`, `gh issue view`, `gh issue status` +- `gh project` (all subcommands) +- `gh search` (all subcommands) +- `gh label list` + +### Commands that are REST-safe + +- `gh api ` — always REST when given a path (not `graphql`) +- `gh pr create` — uses REST +- `gh pr merge` — uses REST +- `gh release *` — uses REST +- `gh run *` — uses REST +- `gh workflow *` — uses REST +- `gh auth status` — local/REST +- `gh repo clone` / `gh repo view --json` — may use GraphQL; prefer `gh api` + +## Authentication Check + +```bash +gh auth status +``` + +If not authenticated, instruct the user to run `gh auth login`. + +## Repositories + +### Get repo info + +```bash +gh api repos/{owner}/{repo} +``` + +### List repos for a user or org + +```bash +gh api "users/{username}/repos?per_page=30&sort=updated" +gh api "orgs/{org}/repos?per_page=30&sort=updated" +``` + +## Issues + +### List issues + +```bash +gh api "repos/{owner}/{repo}/issues?state=open&per_page=30" \ + | jq '.[] | {number, title, state, user: .user.login, labels: [.labels[].name]}' +``` + +Filter options (query params): `state` (open/closed/all), `labels` (comma-separated), `assignee`, `creator`, `milestone`, `sort` (created/updated/comments), `direction` (asc/desc), `since` (ISO 8601), `per_page`, `page`. + +### Get a single issue + +```bash +gh api repos/{owner}/{repo}/issues/{number} +``` + +### Create an issue + +```bash +gh api repos/{owner}/{repo}/issues \ + -f title="Issue title" \ + -f body="Issue description" \ + -f "labels[]=bug" \ + -f "assignees[]={username}" +``` + +### Comment on an issue + +```bash +gh api repos/{owner}/{repo}/issues/{number}/comments \ + -f body="Comment text" +``` + +### Close an issue + +```bash +gh api repos/{owner}/{repo}/issues/{number} -X PATCH -f state=closed +``` + +### Reopen an issue + +```bash +gh api repos/{owner}/{repo}/issues/{number} -X PATCH -f state=open +``` + +### Add labels + +```bash +gh api repos/{owner}/{repo}/issues/{number}/labels \ + -f "labels[]=bug" -f "labels[]=priority-high" +``` + +## Pull Requests + +### List PRs + +```bash +gh api "repos/{owner}/{repo}/pulls?state=open&per_page=30" \ + | jq '.[] | {number, title, state, user: .user.login, head: .head.ref, base: .base.ref}' +``` + +Filter options: `state` (open/closed/all), `head` (filter by head user/org and branch: `user:ref-name`), `base` (filter by base branch), `sort` (created/updated/popularity/long-running), `direction`, `per_page`, `page`. + +### Get a single PR + +```bash +gh api repos/{owner}/{repo}/pulls/{number} \ + | jq '{number, title, state, body, user: .user.login, head: .head.ref, base: .base.ref, mergeable: .mergeable, merged: .merged}' +``` + +### Get PR diff + +```bash +gh api repos/{owner}/{repo}/pulls/{number} \ + -H "Accept: application/vnd.github.diff" +``` + +### Get PR files changed + +```bash +gh api "repos/{owner}/{repo}/pulls/{number}/files?per_page=100" \ + | jq '.[] | {filename, status, additions, deletions, changes}' +``` + +### Create a PR (REST-safe alternative) + +`gh pr create` is REST-safe and the easiest way: + +```bash +gh pr create --title "PR title" --body "PR description" --base main --head feature-branch +``` + +Or via `gh api`: + +```bash +gh api repos/{owner}/{repo}/pulls \ + -f title="PR title" \ + -f body="PR description" \ + -f head="feature-branch" \ + -f base="main" +``` + +### Merge a PR + +```bash +gh pr merge {number} --squash # REST-safe +``` + +Or via `gh api`: + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/merge \ + -X PUT -f merge_method=squash +``` + +### Request reviewers + +```bash +gh api repos/{owner}/{repo}/pulls/{number}/requested_reviewers \ + -f "reviewers[]={username}" +``` + +### List PR reviews + +```bash +gh api "repos/{owner}/{repo}/pulls/{number}/reviews" \ + | jq '.[] | {user: .user.login, state, body}' +``` + +### List PR review comments + +```bash +gh api "repos/{owner}/{repo}/pulls/{number}/comments" \ + | jq '.[] | {user: .user.login, path, body, line}' +``` + +### Comment on a PR + +PRs use the issues comments endpoint: + +```bash +gh api repos/{owner}/{repo}/issues/{number}/comments \ + -f body="Comment text" +``` + +## Commits & Branches + +### List branches + +```bash +gh api "repos/{owner}/{repo}/branches?per_page=30" \ + | jq '.[].name' +``` + +### Get a commit + +```bash +gh api repos/{owner}/{repo}/commits/{sha} \ + | jq '{sha, message: .commit.message, author: .commit.author.name, date: .commit.author.date}' +``` + +### Compare two refs + +```bash +gh api "repos/{owner}/{repo}/compare/{base}...{head}" \ + | jq '{ahead_by, behind_by, total_commits, files: [.files[] | {filename, status, additions, deletions}]}' +``` + +### List commits on a branch + +```bash +gh api "repos/{owner}/{repo}/commits?sha={branch}&per_page=20" \ + | jq '.[] | {sha: .sha[:8], message: (.commit.message | split("\n")[0]), date: .commit.author.date}' +``` + +## GitHub Actions + +### List workflow runs + +```bash +gh run list --limit 10 # REST-safe +``` + +Or via `gh api`: + +```bash +gh api "repos/{owner}/{repo}/actions/runs?per_page=10" \ + | jq '.workflow_runs[] | {id, name, status, conclusion, head_branch, created_at}' +``` + +### Get a specific run + +```bash +gh api repos/{owner}/{repo}/actions/runs/{run_id} \ + | jq '{id, name, status, conclusion, head_branch, html_url}' +``` + +### List jobs for a run + +```bash +gh api "repos/{owner}/{repo}/actions/runs/{run_id}/jobs" \ + | jq '.jobs[] | {id, name, status, conclusion, started_at, completed_at}' +``` + +### Download job logs + +```bash +gh run view {run_id} --log # REST-safe +``` + +### Re-run a workflow + +```bash +gh api repos/{owner}/{repo}/actions/runs/{run_id}/rerun -X POST +``` + +### Re-run failed jobs only + +```bash +gh api repos/{owner}/{repo}/actions/runs/{run_id}/rerun-failed-jobs -X POST +``` + +### List workflows + +```bash +gh api "repos/{owner}/{repo}/actions/workflows" \ + | jq '.workflows[] | {id, name, state, path}' +``` + +### Trigger a workflow dispatch + +```bash +gh api repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches \ + -f ref=main -f "inputs[key]=value" +``` + +## Releases + +### List releases + +```bash +gh api "repos/{owner}/{repo}/releases?per_page=10" \ + | jq '.[] | {tag_name, name, draft, prerelease, published_at}' +``` + +### Get latest release + +```bash +gh api repos/{owner}/{repo}/releases/latest \ + | jq '{tag_name, name, body, published_at, assets: [.assets[] | {name, download_count, browser_download_url}]}' +``` + +### Create a release + +```bash +gh api repos/{owner}/{repo}/releases \ + -f tag_name="v1.0.0" \ + -f name="Release v1.0.0" \ + -f body="Release notes here" \ + -F draft=false \ + -F prerelease=false +``` + +## Check Runs & Statuses (CI) + +### List check runs for a ref + +```bash +gh api "repos/{owner}/{repo}/commits/{ref}/check-runs" \ + | jq '.check_runs[] | {name, status, conclusion, html_url}' +``` + +### Get combined status for a ref + +```bash +gh api "repos/{owner}/{repo}/commits/{ref}/status" \ + | jq '{state, total_count, statuses: [.statuses[] | {context, state, description}]}' +``` + +## Pagination + +GitHub REST API returns at most 100 items per page. Use `per_page` and `page` query params: + +```bash +gh api "repos/{owner}/{repo}/issues?state=all&per_page=100&page=1" +gh api "repos/{owner}/{repo}/issues?state=all&per_page=100&page=2" +``` + +Or use `--paginate` to auto-follow `Link` headers (returns all pages concatenated): + +```bash +gh api "repos/{owner}/{repo}/issues?state=all&per_page=100" --paginate \ + | jq '.[] | {number, title}' +``` + +## Resolving Owner/Repo + +If the user doesn't specify a repo, infer from the current git remote: + +```bash +gh api repos/:owner/:repo +``` + +`gh api` resolves `:owner` and `:repo` from the current git remote automatically. + +## Error Handling + +- **401 Unauthorized** — run `gh auth status`; may need `gh auth login` +- **403 Forbidden** — rate limit or insufficient permissions; check `gh api rate_limit` +- **404 Not Found** — wrong owner/repo/number or private repo without access +- **422 Unprocessable** — invalid payload; check field names and types +- **Network error / timeout** — if you see connection refused on the graphql endpoint, you're hitting the sandbox restriction; switch to a REST endpoint diff --git a/sandboxes/nemoclaw/policy.yaml b/sandboxes/nemoclaw/policy.yaml index 397971a..37fba14 100644 --- a/sandboxes/nemoclaw/policy.yaml +++ b/sandboxes/nemoclaw/policy.yaml @@ -8,7 +8,6 @@ version: 1 filesystem_policy: include_workdir: true read_only: - # read_write: - /usr - /lib - /proc @@ -37,7 +36,7 @@ process: network_policies: claude_code: - name: claude_code + name: claude-code endpoints: - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate } - { host: statsig.anthropic.com, port: 443 } @@ -47,6 +46,7 @@ network_policies: binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/node } + gitlab: name: gitlab endpoints: @@ -54,8 +54,9 @@ network_policies: - { host: gitlab.mycorp.com, port: 443 } binaries: - { path: /usr/bin/glab } - github: - name: github + + github_ssh_over_https: + name: github-ssh-over-https endpoints: - host: github.com port: 443 @@ -72,90 +73,109 @@ network_policies: - allow: method: POST path: "/**/git-upload-pack" - # Data transfer for writes (alpha-claw only) - - allow: - method: POST - path: "/johntmyers/alpha-claw*/git-receive-pack" + # Data transfer for writes + # - allow: + # method: POST + # path: "/**/git-receive-pack" binaries: - { path: /usr/bin/git } - nvidia: - name: nvidia + + nvidia_inference: + name: nvidia-inference endpoints: - { host: integrate.api.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - { path: /bin/bash } - { path: /usr/local/bin/opencode } + nvidia_web: - name: nvidia_web + name: nvidia-web endpoints: - { host: nvidia.com, port: 443 } - { host: www.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - # --- GitHub repo-scoped policy (L7, TLS-terminated) --- - # Combined policy for api.github.com to avoid OPA complete-rule conflict. - # - johntmyers/alpha-claw: full access (all methods including DELETE) - # - johntmyers/bravo-claw: read-only + create/edit issues - github_repos: - name: github_repos + # --- GitHub REST API (read-only) --- + github_rest_api: + name: github-rest-api endpoints: - host: api.github.com port: 443 protocol: rest tls: terminate enforcement: enforce - rules: - # Read-only access to all GitHub API paths - - allow: - method: GET - path: "/**" - - allow: - method: HEAD - path: "/**" - - allow: - method: OPTIONS - path: "/**" - # GraphQL API (used by gh CLI for most operations) - # - allow: - # method: POST - # path: "/graphql" - # alpha-claw: full write access - - allow: - method: "*" - path: "/repos/johntmyers/alpha-claw/**" - # bravo-claw: create + edit issues - - allow: - method: POST - path: "/repos/johntmyers/bravo-claw/issues" - - allow: - method: PATCH - path: "/repos/johntmyers/bravo-claw/issues/*" + access: read-only binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/gh } + pypi: + name: pypi + endpoints: + - { host: pypi.org, port: 443 } + - { host: files.pythonhosted.org, port: 443 } + # uv python install downloads from python-build-standalone on GitHub + - { host: github.com, port: 443 } + - { host: objects.githubusercontent.com, port: 443 } + # uv resolves python-build-standalone release metadata via the GitHub API + - { 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: /usr/local/bin/uv } + # Managed Python installations from uv python install + - { path: "/sandbox/.uv/python/**" } + vscode: name: vscode endpoints: - { host: update.code.visualstudio.com, port: 443 } - - { host: "*.vo.msecnd.net", port: 443 } + # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. + - { host: az764295.vo.msecnd.net, port: 443 } - { host: vscode.download.prss.microsoft.com, port: 443 } - { host: marketplace.visualstudio.com, port: 443 } - - { host: "*.gallerycdn.vsassets.io", port: 443 } + - { host: gallerycdn.vsassets.io, port: 443 } binaries: - { path: /usr/bin/curl } - { path: /usr/bin/wget } - { path: "/sandbox/.vscode-server/**" } - { path: "/sandbox/.vscode-remote-containers/**" } - # --- Private network access (allowed_ips demo) --- + cursor: + name: cursor + endpoints: + - { host: cursor.blob.core.windows.net, port: 443 } + # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. + - { host: api2.cursor.sh, port: 443 } + - { host: repo.cursor.sh, port: 443 } + - { host: download.cursor.sh, port: 443 } + - { host: cursor.download.prss.microsoft.com, port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /usr/bin/wget } + - { path: "/sandbox/.cursor-server/**" } + + opencode: + name: opencode + endpoints: + - { host: registry.npmjs.org, port: 443 } + - { host: opencode.ai, port: 443 } + - { host: integrate.api.nvidia.com, port: 443 } + binaries: + - { path: /usr/lib/node_modules/opencode-ai/bin/.opencode } + - { path: /usr/bin/node } + - { path: /usr/local/bin/opencode } + + # --- Private network access (allowed_ips) --- # Allows any binary to reach services on the k3s cluster pod network # (10.42.0.0/16). Without allowed_ips, the proxy's SSRF check blocks # all connections to private RFC 1918 addresses. cluster_pods: - name: cluster_pods + name: cluster-pods endpoints: - port: 8080 allowed_ips: diff --git a/sandboxes/openclaw/policy.yaml b/sandboxes/openclaw/policy.yaml index 92d9a41..336fdab 100644 --- a/sandboxes/openclaw/policy.yaml +++ b/sandboxes/openclaw/policy.yaml @@ -36,7 +36,7 @@ process: network_policies: claude_code: - name: claude_code + name: claude-code endpoints: - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate } - { host: statsig.anthropic.com, port: 443 } @@ -46,6 +46,7 @@ network_policies: binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/node } + gitlab: name: gitlab endpoints: @@ -53,8 +54,9 @@ network_policies: - { host: gitlab.mycorp.com, port: 443 } binaries: - { path: /usr/bin/glab } - github: - name: github + + github_ssh_over_https: + name: github-ssh-over-https endpoints: - host: github.com port: 443 @@ -71,90 +73,109 @@ network_policies: - allow: method: POST path: "/**/git-upload-pack" - # Data transfer for writes (alpha-claw only) - - allow: - method: POST - path: "/johntmyers/alpha-claw*/git-receive-pack" + # Data transfer for writes + # - allow: + # method: POST + # path: "/**/git-receive-pack" binaries: - { path: /usr/bin/git } - nvidia: - name: nvidia + + nvidia_inference: + name: nvidia-inference endpoints: - { host: integrate.api.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - { path: /bin/bash } - { path: /usr/local/bin/opencode } + nvidia_web: - name: nvidia_web + name: nvidia-web endpoints: - { host: nvidia.com, port: 443 } - { host: www.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - # --- GitHub repo-scoped policy (L7, TLS-terminated) --- - # Combined policy for api.github.com to avoid OPA complete-rule conflict. - # - johntmyers/alpha-claw: full access (all methods including DELETE) - # - johntmyers/bravo-claw: read-only + create/edit issues - github_repos: - name: github_repos + # --- GitHub REST API (read-only) --- + github_rest_api: + name: github-rest-api endpoints: - host: api.github.com port: 443 protocol: rest tls: terminate enforcement: enforce - rules: - # Read-only access to all GitHub API paths - - allow: - method: GET - path: "/**" - - allow: - method: HEAD - path: "/**" - - allow: - method: OPTIONS - path: "/**" - # GraphQL API (used by gh CLI for most operations) - # - allow: - # method: POST - # path: "/graphql" - # alpha-claw: full write access - - allow: - method: "*" - path: "/repos/johntmyers/alpha-claw/**" - # bravo-claw: create + edit issues - - allow: - method: POST - path: "/repos/johntmyers/bravo-claw/issues" - - allow: - method: PATCH - path: "/repos/johntmyers/bravo-claw/issues/*" + access: read-only binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/gh } + pypi: + name: pypi + endpoints: + - { host: pypi.org, port: 443 } + - { host: files.pythonhosted.org, port: 443 } + # uv python install downloads from python-build-standalone on GitHub + - { host: github.com, port: 443 } + - { host: objects.githubusercontent.com, port: 443 } + # uv resolves python-build-standalone release metadata via the GitHub API + - { 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: /usr/local/bin/uv } + # Managed Python installations from uv python install + - { path: "/sandbox/.uv/python/**" } + vscode: name: vscode endpoints: - { host: update.code.visualstudio.com, port: 443 } - - { host: "*.vo.msecnd.net", port: 443 } + # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. + - { host: az764295.vo.msecnd.net, port: 443 } - { host: vscode.download.prss.microsoft.com, port: 443 } - { host: marketplace.visualstudio.com, port: 443 } - - { host: "*.gallerycdn.vsassets.io", port: 443 } + - { host: gallerycdn.vsassets.io, port: 443 } binaries: - { path: /usr/bin/curl } - { path: /usr/bin/wget } - { path: "/sandbox/.vscode-server/**" } - { path: "/sandbox/.vscode-remote-containers/**" } - # --- Private network access (allowed_ips demo) --- + cursor: + name: cursor + endpoints: + - { host: cursor.blob.core.windows.net, port: 443 } + # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. + - { host: api2.cursor.sh, port: 443 } + - { host: repo.cursor.sh, port: 443 } + - { host: download.cursor.sh, port: 443 } + - { host: cursor.download.prss.microsoft.com, port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /usr/bin/wget } + - { path: "/sandbox/.cursor-server/**" } + + opencode: + name: opencode + endpoints: + - { host: registry.npmjs.org, port: 443 } + - { host: opencode.ai, port: 443 } + - { host: integrate.api.nvidia.com, port: 443 } + binaries: + - { path: /usr/lib/node_modules/opencode-ai/bin/.opencode } + - { path: /usr/bin/node } + - { path: /usr/local/bin/opencode } + + # --- Private network access (allowed_ips) --- # Allows any binary to reach services on the k3s cluster pod network # (10.42.0.0/16). Without allowed_ips, the proxy's SSRF check blocks # all connections to private RFC 1918 addresses. cluster_pods: - name: cluster_pods + name: cluster-pods endpoints: - port: 8080 allowed_ips: From 0d6d02745950b04508852a94f243f65dd550ee8f Mon Sep 17 00:00:00 2001 From: Drew Newberry Date: Thu, 12 Mar 2026 18:38:40 -0700 Subject: [PATCH 2/2] chore: use uv for Python management, consolidate Dockerfile layers, and clean up policies - Remove deadsnakes PPA, apt Python packages, and pip bootstrap; let uv manage the full Python 3.13 toolchain - Merge Node.js install + npm upgrade into a single RUN layer - Merge all npm global installs (vuln fixes + CLI tools) into one call - Add uv cache clean after python install and venv creation - Copy base policy.yaml into the image instead of just creating the dir - Remove duplicate UV_PYTHON_INSTALL_DIR ENV and redundant mkdir - Update syntax directive from dockerfile:1.4 to dockerfile:1 - Revert nemoclaw/openclaw policies to main and replace repo-specific rules (johntmyers/alpha-claw, bravo-claw) with generic placeholders --- sandboxes/base/Dockerfile | 73 ++++++++------- sandboxes/base/policy.yaml | 161 +++++++++++++++++++++++++++++++++ sandboxes/nemoclaw/policy.yaml | 117 +++++++----------------- sandboxes/openclaw/policy.yaml | 115 ++++++----------------- 4 files changed, 258 insertions(+), 208 deletions(-) create mode 100644 sandboxes/base/policy.yaml diff --git a/sandboxes/base/Dockerfile b/sandboxes/base/Dockerfile index 56ec386..7d47635 100644 --- a/sandboxes/base/Dockerfile +++ b/sandboxes/base/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.4 +# syntax=docker/dockerfile:1 # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 @@ -20,9 +20,9 @@ ENV DEBIAN_FRONTEND=noninteractive \ WORKDIR /sandbox # Core system dependencies -# python3.13 + pip: agent scripting and SDK usage (deadsnakes PPA for Noble) # iproute2: network namespace management (ip netns, veth pairs) # dnsutils: dig, nslookup +# Python is managed entirely by uv (see devtools stage). RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ @@ -33,17 +33,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ netcat-openbsd \ openssh-sftp-server \ procps \ - software-properties-common \ traceroute \ - && add-apt-repository -y ppa:deadsnakes/ppa \ - && apt-get update \ - && apt-get install -y --no-install-recommends \ - python3.13 \ - python3.13-venv \ - python3.13-dev \ - && curl -sS https://bootstrap.pypa.io/get-pip.py | python3.13 \ - && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.13 1 \ - && update-alternatives --install /usr/bin/python python /usr/bin/python3.13 1 \ && rm -rf /var/lib/apt/lists/* # Create supervisor and sandbox users/groups @@ -57,6 +47,11 @@ FROM system AS devtools # 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. +# +# npm is upgraded to v11 in the same layer to avoid caching the old npm. +# npm 11 ships tar@^7.5.9, fixing 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 curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ apt-get install -y --no-install-recommends \ build-essential \ @@ -64,18 +59,20 @@ RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \ nodejs=22.22.1-1nodesource1 \ vim-tiny \ nano \ - && rm -rf /var/lib/apt/lists/* - -# 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 - -# Fix transitive tar and @hono/node-server vulnerabilities -# (GHSA-qffp-2rhf-9h96, GHSA-9ppj-qmqm-q256, GHSA-8qq5-rm4j-mr97, -# GHSA-r6q2-hw4h-h46w, GHSA-34x7-hfp2-rc4v, GHSA-83g3-92jg-28cx, -# GHSA-wc8c-qw6v-h7f6). -RUN npm install -g tar@7.5.11 @hono/node-server@1.19.11 + && rm -rf /var/lib/apt/lists/* \ + && npm install -g npm@11.11.0 + +# Global npm packages — pinned for reproducibility. +# tar + @hono/node-server: transitive vuln fixes +# (GHSA-qffp-2rhf-9h96, GHSA-9ppj-qmqm-q256, GHSA-8qq5-rm4j-mr97, +# GHSA-r6q2-hw4h-h46w, GHSA-34x7-hfp2-rc4v, GHSA-83g3-92jg-28cx, +# GHSA-wc8c-qw6v-h7f6). +# opencode-ai + @openai/codex: agent CLIs. +RUN npm install -g \ + tar@7.5.11 \ + @hono/node-server@1.19.11 \ + opencode-ai@1.2.18 \ + @openai/codex@0.111.0 # GitHub CLI RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ @@ -90,12 +87,14 @@ 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 OpenCode CLI and Codex CLI (OpenAI) with pinned versions for -# reproducible builds. -RUN npm install -g opencode-ai@1.2.18 @openai/codex@0.111.0 - -# uv (Python package manager) — pinned for reproducibility +# uv (Python package/project manager) — pinned for reproducibility. +# uv manages the Python toolchain; no system Python packages are needed. COPY --from=ghcr.io/astral-sh/uv:0.10.8 /uv /usr/local/bin/uv +ENV UV_PYTHON_INSTALL_DIR="/sandbox/.uv/python" +RUN uv python install 3.13 && \ + ln -s $(uv python find 3.13) /usr/local/bin/python3 && \ + ln -s $(uv python find 3.13) /usr/local/bin/python && \ + uv cache clean # Final base image FROM devtools AS final @@ -105,11 +104,10 @@ FROM devtools AS final # 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:/usr/local/bin:/usr/bin:/bin" \ - VIRTUAL_ENV="/sandbox/.venv" \ - UV_PYTHON_INSTALL_DIR="/sandbox/.uv/python" + VIRTUAL_ENV="/sandbox/.venv" -# Ensure policy directory exists -RUN mkdir -p /etc/navigator +# Default sandbox network / filesystem policy +COPY policy.yaml /etc/navigator/policy.yaml # Copy custom skills into the image. # To add a skill, create a subdirectory under sandboxes/base/skills/ @@ -118,11 +116,12 @@ RUN mkdir -p /etc/navigator COPY skills/ /sandbox/.agents/skills/ # Set up sandbox user home directory -RUN mkdir -p /sandbox/.agents/skills /sandbox/.claude/skills && \ - # Create a writable venv that inherits all system packages. - # Sandbox users can `pip install` or `uv pip install` into +RUN mkdir -p /sandbox/.claude/skills && \ + # Create a writable venv using uv-managed Python 3.13. + # Sandbox users can `uv pip install` (or `pip install`) into # this venv without touching the base image layer. - uv venv --python /usr/bin/python3.13 --seed --system-site-packages /sandbox/.venv && \ + uv venv --python 3.13 --seed /sandbox/.venv && \ + uv cache clean && \ 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 diff --git a/sandboxes/base/policy.yaml b/sandboxes/base/policy.yaml new file mode 100644 index 0000000..02ef4b1 --- /dev/null +++ b/sandboxes/base/policy.yaml @@ -0,0 +1,161 @@ +# 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: + claude_code: + name: claude-code + endpoints: + - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate } + - { host: statsig.anthropic.com, port: 443 } + - { host: sentry.io, port: 443 } + - { host: raw.githubusercontent.com, port: 443 } + - { host: platform.claude.com, port: 443 } + binaries: + - { path: /usr/local/bin/claude } + - { path: /usr/bin/node } + + github_ssh_over_https: + name: github-ssh-over-https + endpoints: + - host: github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + rules: + # Git Smart HTTP read-only: allow clone, fetch, pull + # Discovery (query string is included in path matching) + - allow: + method: GET + path: "/**/info/refs*" + # Data transfer for reads (all repos) + - allow: + method: POST + path: "/**/git-upload-pack" + # Data transfer for writes + # - allow: + # method: POST + # path: "/**/git-receive-pack" + binaries: + - { path: /usr/bin/git } + + nvidia_inference: + name: nvidia-inference + endpoints: + - { host: integrate.api.nvidia.com, port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /bin/bash } + - { path: /usr/local/bin/opencode } + + # --- GitHub REST API (read-only) --- + github_rest_api: + name: github-rest-api + endpoints: + - host: api.github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + access: read-only + binaries: + - { path: /usr/local/bin/claude } + - { path: /usr/bin/gh } + + pypi: + name: pypi + endpoints: + - { host: pypi.org, port: 443 } + - { host: files.pythonhosted.org, port: 443 } + # uv python install downloads from python-build-standalone on GitHub + - { host: github.com, port: 443 } + - { host: objects.githubusercontent.com, port: 443 } + # uv resolves python-build-standalone release metadata via the GitHub API + - { 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 } + # Managed Python installations from uv python install + - { path: "/sandbox/.uv/python/**" } + + vscode: + name: vscode + endpoints: + - { host: update.code.visualstudio.com, port: 443 } + # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. + - { host: az764295.vo.msecnd.net, port: 443 } + - { host: vscode.download.prss.microsoft.com, port: 443 } + - { host: marketplace.visualstudio.com, port: 443 } + - { host: gallerycdn.vsassets.io, port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /usr/bin/wget } + - { path: "/sandbox/.vscode-server/**" } + - { path: "/sandbox/.vscode-remote-containers/**" } + + cursor: + name: cursor + endpoints: + - { host: cursor.blob.core.windows.net, port: 443 } + # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. + - { host: api2.cursor.sh, port: 443 } + - { host: repo.cursor.sh, port: 443 } + - { host: download.cursor.sh, port: 443 } + - { host: cursor.download.prss.microsoft.com, port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /usr/bin/wget } + - { path: "/sandbox/.cursor-server/**" } + + opencode: + name: opencode + endpoints: + - host: registry.npmjs.org + port: 443 + - host: opencode.ai + port: 443 + - host: integrate.api.nvidia.com + port: 443 + binaries: + - path: /usr/lib/node_modules/opencode-ai/bin/.opencode + - path: /usr/bin/node + - path: /usr/local/bin/opencode diff --git a/sandboxes/nemoclaw/policy.yaml b/sandboxes/nemoclaw/policy.yaml index 37fba14..3a1422e 100644 --- a/sandboxes/nemoclaw/policy.yaml +++ b/sandboxes/nemoclaw/policy.yaml @@ -8,6 +8,7 @@ version: 1 filesystem_policy: include_workdir: true read_only: + # read_write: - /usr - /lib - /proc @@ -36,7 +37,7 @@ process: network_policies: claude_code: - name: claude-code + name: claude_code endpoints: - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate } - { host: statsig.anthropic.com, port: 443 } @@ -46,7 +47,6 @@ network_policies: binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/node } - gitlab: name: gitlab endpoints: @@ -54,9 +54,8 @@ network_policies: - { host: gitlab.mycorp.com, port: 443 } binaries: - { path: /usr/bin/glab } - - github_ssh_over_https: - name: github-ssh-over-https + github: + name: github endpoints: - host: github.com port: 443 @@ -73,31 +72,30 @@ network_policies: - allow: method: POST path: "/**/git-upload-pack" - # Data transfer for writes + # Data transfer for writes (uncomment and scope to specific repos) # - allow: - # method: POST - # path: "/**/git-receive-pack" + # method: POST + # path: "///git-receive-pack" binaries: - { path: /usr/bin/git } - - nvidia_inference: - name: nvidia-inference + nvidia: + name: nvidia endpoints: - { host: integrate.api.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - { path: /bin/bash } - { path: /usr/local/bin/opencode } - nvidia_web: - name: nvidia-web + name: nvidia_web endpoints: - { host: nvidia.com, port: 443 } - { host: www.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - # --- GitHub REST API (read-only) --- + # --- GitHub REST API (L7, TLS-terminated) --- + # Read-only by default. Uncomment and scope write rules to specific repos. github_rest_api: name: github-rest-api endpoints: @@ -106,79 +104,26 @@ network_policies: protocol: rest tls: terminate enforcement: enforce - access: read-only + rules: + # Read-only access to all GitHub API paths + - allow: + method: GET + path: "/**" + - allow: + method: HEAD + path: "/**" + - allow: + method: OPTIONS + path: "/**" + # GraphQL API (used by gh CLI for most operations) + # - allow: + # method: POST + # path: "/graphql" + # Per-repo write access (uncomment and replace /) + # - allow: + # method: "*" + # path: "/repos///**" binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/gh } - pypi: - name: pypi - endpoints: - - { host: pypi.org, port: 443 } - - { host: files.pythonhosted.org, port: 443 } - # uv python install downloads from python-build-standalone on GitHub - - { host: github.com, port: 443 } - - { host: objects.githubusercontent.com, port: 443 } - # uv resolves python-build-standalone release metadata via the GitHub API - - { 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: /usr/local/bin/uv } - # Managed Python installations from uv python install - - { path: "/sandbox/.uv/python/**" } - - vscode: - name: vscode - endpoints: - - { host: update.code.visualstudio.com, port: 443 } - # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. - - { host: az764295.vo.msecnd.net, port: 443 } - - { host: vscode.download.prss.microsoft.com, port: 443 } - - { host: marketplace.visualstudio.com, port: 443 } - - { host: gallerycdn.vsassets.io, port: 443 } - binaries: - - { path: /usr/bin/curl } - - { path: /usr/bin/wget } - - { path: "/sandbox/.vscode-server/**" } - - { path: "/sandbox/.vscode-remote-containers/**" } - - cursor: - name: cursor - endpoints: - - { host: cursor.blob.core.windows.net, port: 443 } - # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. - - { host: api2.cursor.sh, port: 443 } - - { host: repo.cursor.sh, port: 443 } - - { host: download.cursor.sh, port: 443 } - - { host: cursor.download.prss.microsoft.com, port: 443 } - binaries: - - { path: /usr/bin/curl } - - { path: /usr/bin/wget } - - { path: "/sandbox/.cursor-server/**" } - - opencode: - name: opencode - endpoints: - - { host: registry.npmjs.org, port: 443 } - - { host: opencode.ai, port: 443 } - - { host: integrate.api.nvidia.com, port: 443 } - binaries: - - { path: /usr/lib/node_modules/opencode-ai/bin/.opencode } - - { path: /usr/bin/node } - - { path: /usr/local/bin/opencode } - - # --- Private network access (allowed_ips) --- - # Allows any binary to reach services on the k3s cluster pod network - # (10.42.0.0/16). Without allowed_ips, the proxy's SSRF check blocks - # all connections to private RFC 1918 addresses. - cluster_pods: - name: cluster-pods - endpoints: - - port: 8080 - allowed_ips: - - "10.42.0.0/16" - binaries: - - { path: "/**" } diff --git a/sandboxes/openclaw/policy.yaml b/sandboxes/openclaw/policy.yaml index 336fdab..9e2ef78 100644 --- a/sandboxes/openclaw/policy.yaml +++ b/sandboxes/openclaw/policy.yaml @@ -36,7 +36,7 @@ process: network_policies: claude_code: - name: claude-code + name: claude_code endpoints: - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate } - { host: statsig.anthropic.com, port: 443 } @@ -46,7 +46,6 @@ network_policies: binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/node } - gitlab: name: gitlab endpoints: @@ -54,9 +53,8 @@ network_policies: - { host: gitlab.mycorp.com, port: 443 } binaries: - { path: /usr/bin/glab } - - github_ssh_over_https: - name: github-ssh-over-https + github: + name: github endpoints: - host: github.com port: 443 @@ -73,31 +71,30 @@ network_policies: - allow: method: POST path: "/**/git-upload-pack" - # Data transfer for writes + # Data transfer for writes (uncomment and scope to specific repos) # - allow: - # method: POST - # path: "/**/git-receive-pack" + # method: POST + # path: "///git-receive-pack" binaries: - { path: /usr/bin/git } - - nvidia_inference: - name: nvidia-inference + nvidia: + name: nvidia endpoints: - { host: integrate.api.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - { path: /bin/bash } - { path: /usr/local/bin/opencode } - nvidia_web: - name: nvidia-web + name: nvidia_web endpoints: - { host: nvidia.com, port: 443 } - { host: www.nvidia.com, port: 443 } binaries: - { path: /usr/bin/curl } - # --- GitHub REST API (read-only) --- + # --- GitHub REST API (L7, TLS-terminated) --- + # Read-only by default. Uncomment and scope write rules to specific repos. github_rest_api: name: github-rest-api endpoints: @@ -106,82 +103,30 @@ network_policies: protocol: rest tls: terminate enforcement: enforce - access: read-only + rules: + # Read-only access to all GitHub API paths + - allow: + method: GET + path: "/**" + - allow: + method: HEAD + path: "/**" + - allow: + method: OPTIONS + path: "/**" + # GraphQL API (used by gh CLI for most operations) + # - allow: + # method: POST + # path: "/graphql" + # Per-repo write access (uncomment and replace /) + # - allow: + # method: "*" + # path: "/repos///**" binaries: - { path: /usr/local/bin/claude } - { path: /usr/bin/gh } - pypi: - name: pypi - endpoints: - - { host: pypi.org, port: 443 } - - { host: files.pythonhosted.org, port: 443 } - # uv python install downloads from python-build-standalone on GitHub - - { host: github.com, port: 443 } - - { host: objects.githubusercontent.com, port: 443 } - # uv resolves python-build-standalone release metadata via the GitHub API - - { 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: /usr/local/bin/uv } - # Managed Python installations from uv python install - - { path: "/sandbox/.uv/python/**" } - vscode: - name: vscode - endpoints: - - { host: update.code.visualstudio.com, port: 443 } - # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. - - { host: az764295.vo.msecnd.net, port: 443 } - - { host: vscode.download.prss.microsoft.com, port: 443 } - - { host: marketplace.visualstudio.com, port: 443 } - - { host: gallerycdn.vsassets.io, port: 443 } - binaries: - - { path: /usr/bin/curl } - - { path: /usr/bin/wget } - - { path: "/sandbox/.vscode-server/**" } - - { path: "/sandbox/.vscode-remote-containers/**" } - - cursor: - name: cursor - endpoints: - - { host: cursor.blob.core.windows.net, port: 443 } - # NOTE: OPA host matching uses exact equality, not glob — list hosts explicitly. - - { host: api2.cursor.sh, port: 443 } - - { host: repo.cursor.sh, port: 443 } - - { host: download.cursor.sh, port: 443 } - - { host: cursor.download.prss.microsoft.com, port: 443 } - binaries: - - { path: /usr/bin/curl } - - { path: /usr/bin/wget } - - { path: "/sandbox/.cursor-server/**" } - - opencode: - name: opencode - endpoints: - - { host: registry.npmjs.org, port: 443 } - - { host: opencode.ai, port: 443 } - - { host: integrate.api.nvidia.com, port: 443 } - binaries: - - { path: /usr/lib/node_modules/opencode-ai/bin/.opencode } - - { path: /usr/bin/node } - - { path: /usr/local/bin/opencode } - - # --- Private network access (allowed_ips) --- - # Allows any binary to reach services on the k3s cluster pod network - # (10.42.0.0/16). Without allowed_ips, the proxy's SSRF check blocks - # all connections to private RFC 1918 addresses. - cluster_pods: - name: cluster-pods - endpoints: - - port: 8080 - allowed_ips: - - "10.42.0.0/16" - binaries: - - { path: "/**" } inference: allowed_routes: