Skip to content
Closed
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
11 changes: 10 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ RUN npm ci && npm run build
# hadolint ignore=DL3006
FROM ${BASE_IMAGE}

COPY scripts/install-provider-tools.sh /usr/local/lib/nemoclaw/install-provider-tools.sh

# Harden: remove unnecessary build tools and network probes from base image (#830)
# Protect runtime tools before autoremove — the GHCR base may predate the
# procps/e2fsprogs additions, leaving ps/chattr absent or auto-marked. The
Expand Down Expand Up @@ -57,6 +59,11 @@ RUN set -eu; \
ps --version; \
command -v chattr >/dev/null

# Provider tools are installed in the base image, but this derived-image replay
# keeps local and CI builds usable while GHCR sandbox-base catches up. OpenShell
# provider approval still controls network and credential use at runtime.
RUN chmod 755 /usr/local/lib/nemoclaw/install-provider-tools.sh \
&& /usr/local/lib/nemoclaw/install-provider-tools.sh

# Copy built plugin and blueprint into the sandbox
COPY --from=builder /opt/nemoclaw/dist/ /opt/nemoclaw/dist/
Expand Down Expand Up @@ -244,6 +251,8 @@ RUN chmod 755 /usr/local/bin/nemoclaw-start /usr/local/bin/nemoclaw-codex-acp \
/usr/local/lib/nemoclaw/generate-openclaw-config.py \
/usr/local/lib/nemoclaw/seed-wechat-accounts.py \
&& if [ -d /usr/local/lib/nemoclaw/preloads ]; then find /usr/local/lib/nemoclaw/preloads -type f -name '*.js' -exec chmod 644 {} +; fi \
&& mkdir -p /usr/local/share/nemoclaw/openclaw-plugins/nemoclaw \
&& cp -a /opt/nemoclaw/. /usr/local/share/nemoclaw/openclaw-plugins/nemoclaw/ \
&& chmod 755 /usr/local/share/nemoclaw \
/usr/local/share/nemoclaw/openclaw-plugins \
&& find /usr/local/share/nemoclaw/openclaw-plugins -type d -exec chmod 755 {} + \
Expand Down Expand Up @@ -621,7 +630,7 @@ RUN chown root:root /sandbox/.nemoclaw \
&& chmod -R 755 /sandbox/.nemoclaw/blueprints \
&& mkdir -p /sandbox/.nemoclaw/state /sandbox/.nemoclaw/migration /sandbox/.nemoclaw/snapshots /sandbox/.nemoclaw/staging \
&& chown sandbox:sandbox /sandbox/.nemoclaw/state /sandbox/.nemoclaw/migration /sandbox/.nemoclaw/snapshots /sandbox/.nemoclaw/staging \
&& touch /sandbox/.nemoclaw/config.json \
&& printf '{}\n' > /sandbox/.nemoclaw/config.json \
&& chown sandbox:sandbox /sandbox/.nemoclaw/config.json

# OpenShell 0.0.37's macOS VM backend currently remaps rootfs ownership to the
Expand Down
6 changes: 6 additions & 0 deletions Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,17 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
procps=2:4.0.4-9 \
e2fsprogs=1.47.2-3+b11 \
"dos2unix=7.5.2-1*" \
gh=2.46.0-3 \
glab=1.53.0-1+b3 \
jq=1.7.1-6+deb13u2 \
vim-tiny=2:9.1.1230-2 \
openssh-sftp-server=1:10.0p1-7+deb13u4 \
&& rm -rf /var/lib/apt/lists/*

COPY scripts/install-provider-tools.sh /usr/local/lib/nemoclaw/install-provider-tools.sh
RUN chmod 755 /usr/local/lib/nemoclaw/install-provider-tools.sh \
&& /usr/local/lib/nemoclaw/install-provider-tools.sh

# gosu for privilege separation (gateway vs sandbox user).
# Install from GitHub release with checksum verification instead of
# Debian's packaged gosu can lag upstream. Pinned to 1.19 (2025-09).
Expand Down
72 changes: 72 additions & 0 deletions docs/reference/nemoclaw-openshell-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# NemoClaw OpenShell Integration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required SPDX license header at the top of this page.

This new Markdown file is missing the required SPDX copyright and Apache-2.0 header.

As per coding guidelines, "**/*.{js,ts,tsx,jsx,sh,yaml,yml,json,md,mdx}: Every source file must include an SPDX license header for copyright and Apache-2.0 license".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/nemoclaw-openshell-integration.md` at line 1, Add the required
SPDX license header to the top of the Markdown file
docs/reference/nemoclaw-openshell-integration.md by inserting the SPDX copyright
and license lines as a header block (e.g., an HTML comment or plain text)
including "SPDX-FileCopyrightText: <YEAR> <OWNER>" and "SPDX-License-Identifier:
Apache-2.0" as the first lines of the file so the document complies with the
repository rule for *.{md,mdx} files.


```mermaid
flowchart LR
user["User"] --> agent["Agent runtime"]
agent --> adapter["NemoClaw agent adapter"]

subgraph adapters["Current adapters"]
openclaw["OpenClaw plugin"]
hermes["Hermes plugin"]
end

subgraph plugin_tools["NemoClaw access tools"]
list["list_resource_access_presets"]
request["request_resource_access"]
check["check_resource_access"]
end

adapter --> adapters
adapters --> plugin_tools
onboard["nemoclaw onboard"] --> profile_import["Import NemoClaw provider profiles"]
profile_import --> profiles["OpenShell provider profiles"]
list --> profiles
profiles --> presets["Provider-backed access presets"]
presets --> request

request --> policy_local["policy.local HTTP API"]
check --> policy_local

subgraph sandbox["OpenShell sandbox"]
policy_local
proxy["Sandbox HTTP proxy"]
policy_runtime["Sandbox policy runtime"]
end

policy_local --> proposals["OpenShell policy proposals"]
proposals --> review["Operator review"]
review --> approve["Approve or reject"]
approve --> merge["Policy merge and reload"]
merge --> policy_runtime
policy_runtime --> check

agent --> workload["Requested agent work"]
workload --> proxy
proxy --> policy_runtime
policy_runtime --> external["Approved external resources"]
```

## Flow

1. The agent asks NemoClaw for allowed resource presets with `list_resource_access_presets`.
2. During onboarding, NemoClaw imports its provider profiles into OpenShell for package registries, messaging platforms, Brave Search, Jira, Hugging Face, and local inference.
3. NemoClaw builds the agent-visible preset list from OpenShell provider profiles, with built-in presets as fallback coverage for older OpenShell versions.
4. The agent calls `request_resource_access` with a preset, access mode, reason, and optional wait timeout.
5. NemoClaw submits a least-privilege proposal to `policy.local`.
6. OpenShell surfaces the proposal for operator review.
7. After approval, OpenShell merges and reloads the sandbox policy.
8. The agent calls `check_resource_access`; NemoClaw reports `applied` only after OpenShell reports the policy reload is complete.

## Agent Tools

- `list_resource_access_presets`: discovers provider-backed preset ids.
- `request_resource_access`: submits a network access proposal through OpenShell.
- `check_resource_access`: polls an existing proposal until it is pending, denied, failed, or applied.

## Adapter Contract

Each agent adapter exposes the same tool names and response shape through the harness-native mechanism. OpenClaw uses its plugin API. Hermes uses its Python plugin API. Additional harnesses can implement the same contract without changing the OpenShell policy proposal flow.

## Provider Profiles

NemoClaw imports OpenShell provider profiles for its policy presets during onboarding. Existing OpenShell profiles are left untouched, and already-imported NemoClaw profiles are skipped so repeated onboarding remains idempotent. If the OpenShell gateway does not support provider-profile import, NemoClaw continues with local fallback presets.
18 changes: 11 additions & 7 deletions nemoclaw-blueprint/policies/presets/github.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,13 @@
# selects this preset during `nemoclaw onboard` (or applies it later via
# `openshell policy set`).
#
# The `gh` CLI was also whitelisted here historically (alongside `git`),
# but the sandbox base image (Dockerfile.base) only apt-installs `git`,
# not `gh`. Users selecting this preset and running `gh api …` would hit
# `bash: gh: command not found`. Dropping `/usr/bin/gh` from the binaries
# list and from the description keeps the preset surface honest about
# what's actually usable in the shipped image. Closes #2179.
# The sandbox image ships the provider tools used by the GitHub provider
# profile, so preset policy exposes the same usable surface. Credential
# injection is still governed by OpenShell provider approval.

preset:
name: github
description: "GitHub.com and GitHub API access (git)"
description: "GitHub.com and GitHub API access (gh, git, curl)"

network_policies:
github:
Expand All @@ -33,4 +30,11 @@ network_policies:
port: 443
access: full
binaries:
- { path: /usr/bin/gh }
- { path: /usr/local/bin/gh }
- { path: /usr/bin/git }
- { path: /usr/local/bin/git }
- { path: /usr/bin/curl }
- { path: /usr/local/bin/curl }
- { path: /usr/bin/node }
- { path: /usr/local/bin/node }
19 changes: 19 additions & 0 deletions nemoclaw-blueprint/provider-profiles/brave.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

id: brave
display_name: Brave Search
description: Brave Search API access
category: knowledge
endpoints:
- host: api.search.brave.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
binaries:
- /usr/local/bin/node
- /usr/bin/node
- /usr/bin/curl
38 changes: 38 additions & 0 deletions nemoclaw-blueprint/provider-profiles/brew.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

id: brew
display_name: Homebrew
description: Homebrew (Linuxbrew) package manager access
category: data
endpoints:
- host: formulae.brew.sh
port: 443
access: full
tls: skip
- host: github.com
port: 443
access: full
tls: skip
- host: ghcr.io
port: 443
access: full
tls: skip
- host: pkg-containers.githubusercontent.com
port: 443
access: full
tls: skip
- host: objects.githubusercontent.com
port: 443
access: full
tls: skip
- host: raw.githubusercontent.com
port: 443
access: full
tls: skip
Comment on lines +12 to +32

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not skip TLS verification on public endpoints.

Using tls: skip across public hosts weakens transport security and policy guarantees. Please require normal TLS verification unless there is a narrowly justified exception.

Suggested change
   - host: formulae.brew.sh
     port: 443
     access: full
-    tls: skip
   - host: github.com
     port: 443
     access: full
-    tls: skip
   - host: ghcr.io
     port: 443
     access: full
-    tls: skip
   - host: pkg-containers.githubusercontent.com
     port: 443
     access: full
-    tls: skip
   - host: objects.githubusercontent.com
     port: 443
     access: full
-    tls: skip
   - host: raw.githubusercontent.com
     port: 443
     access: full
-    tls: skip
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoclaw-blueprint/provider-profiles/brew.yaml` around lines 12 - 32, The
entries for public hosts (host: github.com, ghcr.io,
pkg-containers.githubusercontent.com, objects.githubusercontent.com,
raw.githubusercontent.com) currently set tls: skip; remove or change those tls
settings so normal TLS verification is enforced (e.g., delete the tls: skip
lines or set tls: verify) for each listed host in the provider profile to
restore proper transport security and policy guarantees.

binaries:
- /usr/bin/curl
- /usr/bin/git
- /home/linuxbrew/.linuxbrew/bin/brew
- /home/linuxbrew/.linuxbrew/bin/*
- /home/linuxbrew/.linuxbrew/Homebrew/bin/*
42 changes: 42 additions & 0 deletions nemoclaw-blueprint/provider-profiles/discord.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

id: discord
display_name: Discord
description: Discord API, gateway, and CDN access
category: messaging
endpoints:
- host: discord.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
- allow: { method: PUT, path: "/**" }
- allow: { method: PATCH, path: "/**" }
- allow: { method: DELETE, path: "/api/v*/channels/*/messages/*" }
- allow: { method: DELETE, path: "/api/v*/channels/*/messages/*/reactions/*/*" }
- host: gateway.discord.gg
port: 443
protocol: websocket
enforcement: enforce
websocket_credential_rewrite: true
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: WEBSOCKET_TEXT, path: "/**" }
- host: cdn.discordapp.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- host: media.discordapp.net
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
binaries:
- /usr/local/bin/node
- /usr/bin/node
30 changes: 30 additions & 0 deletions nemoclaw-blueprint/provider-profiles/huggingface.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

id: huggingface
display_name: Hugging Face
description: Hugging Face Hub, LFS, and Inference API access
category: knowledge
endpoints:
- host: huggingface.co
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- host: cdn-lfs.huggingface.co
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- host: router.huggingface.co
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
binaries:
- /usr/local/bin/python3
- /usr/local/bin/node
31 changes: 31 additions & 0 deletions nemoclaw-blueprint/provider-profiles/jira.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

id: jira
display_name: Jira
description: Jira and Atlassian Cloud access
category: data
endpoints:
- host: "*.atlassian.net"
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
- host: auth.atlassian.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
- host: api.atlassian.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
binaries:
- /usr/local/bin/node
47 changes: 47 additions & 0 deletions nemoclaw-blueprint/provider-profiles/local-inference.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

id: local-inference
display_name: Local Inference
description: Local inference access (Ollama, vLLM) via host gateway
category: inference
endpoints:
- host: host.openshell.internal
port: 11434
protocol: rest
enforcement: enforce
allowed_ips:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
- host: host.openshell.internal
port: 11435
protocol: rest
enforcement: enforce
allowed_ips:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
- host: host.openshell.internal
port: 8000
protocol: rest
enforcement: enforce
allowed_ips:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
rules:
- allow: { method: GET, path: "/**" }
- allow: { method: POST, path: "/**" }
binaries:
- /usr/local/bin/openclaw
- /usr/local/bin/node
- /usr/bin/node
- /usr/bin/curl
- /usr/bin/python3
23 changes: 23 additions & 0 deletions nemoclaw-blueprint/provider-profiles/npm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

id: npm
display_name: npm
description: npm and Yarn registry access
category: data
endpoints:
- host: registry.npmjs.org
port: 443
access: full
tls: skip
- host: registry.yarnpkg.com
port: 443
access: full
tls: skip
Comment on lines +11 to +16

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid tls: skip for package registry traffic.

This disables TLS verification for external registries and weakens secure-by-default behavior. Please keep TLS verification enabled.

Suggested change
   - host: registry.npmjs.org
     port: 443
     access: full
-    tls: skip
   - host: registry.yarnpkg.com
     port: 443
     access: full
-    tls: skip
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
access: full
tls: skip
- host: registry.yarnpkg.com
port: 443
access: full
tls: skip
access: full
- host: registry.yarnpkg.com
port: 443
access: full
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nemoclaw-blueprint/provider-profiles/npm.yaml` around lines 11 - 16, Replace
the insecure "tls: skip" setting for the external registry entry (the block
containing host: registry.yarnpkg.com and tls: skip) so TLS verification is
enabled by default; remove the tls: skip line or change it to an affirmative
verification setting (e.g., tls: verify or tls: true) in the provider profile
that contains the npm registry configuration to ensure package registry traffic
performs TLS certificate validation.

binaries:
- /usr/local/bin/npm*
- /usr/local/bin/npx*
- /usr/local/bin/node*
- /usr/local/bin/yarn*
- /usr/bin/npm*
- /usr/bin/node*
Loading
Loading