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
19 changes: 15 additions & 4 deletions sandboxes/openclaw/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

# OpenClaw sandbox image for OpenShell
#
# Builds on the community base sandbox and adds OpenClaw.
# Builds on the community base sandbox and adds OpenClaw with Slack
# Socket Mode support (WebSocket proxy patch) and expanded network policies.
#
# Build: docker build -t openshell-openclaw --build-arg BASE_IMAGE=openshell-base .
# Run: openshell sandbox create --from openclaw

Expand All @@ -14,13 +16,22 @@ FROM ${BASE_IMAGE}

USER root

# Install OpenClaw CLI (pinned to fix GHSA-rchv-x836-w7xp, GHSA-6mgf-v5j7-45cr,
# GHSA-5wcw-8jjv-m286)
RUN npm install -g openclaw@2026.3.11
# Install OpenClaw CLI
RUN npm install -g openclaw@latest

# Copy sandbox policy
COPY policy.yaml /etc/openshell/policy.yaml

# Copy the WebSocket proxy patch (required for Slack Socket Mode behind
# the OpenShell CONNECT proxy — see README.md for details)
COPY openclaw-ws-proxy-patch.js /sandbox/openclaw-ws-proxy-patch.js

# Copy the Slack app manifest for one-click app creation
COPY openclaw-slack-manifest.yaml /sandbox/openclaw-slack-manifest.yaml

# Auto-load the WS proxy patch in every Node.js process
ENV NODE_OPTIONS="--require /sandbox/openclaw-ws-proxy-patch.js"

# Copy the OpenClaw startup helper
COPY openclaw-start.sh /usr/local/bin/openclaw-start
RUN chmod +x /usr/local/bin/openclaw-start
Expand Down
101 changes: 86 additions & 15 deletions sandboxes/openclaw/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ OpenShell sandbox image pre-configured with [OpenClaw](https://github.com/opencl

## What's Included

- **OpenClaw CLI** -- Agent orchestration and gateway management
- **OpenClaw Gateway** -- Local gateway for agent-to-tool communication
- **Node.js 22** -- Runtime required by the OpenClaw gateway
- **openclaw-start** -- Helper script that onboards and starts the gateway automatically
| File | Purpose |
|---|---|
| `Dockerfile` | Builds the sandbox image with OpenClaw + WS proxy patch |
| `policy.yaml` | Network policies for 12 services (LLMs, Slack, GitHub, …) |
| `openclaw-ws-proxy-patch.js` | Monkey-patches `ws` to tunnel Slack WebSockets through the CONNECT proxy |
| `openclaw-slack-manifest.yaml` | One-click Slack app manifest with all 23 scopes and 12 events |
| `openclaw-start.sh` | Gateway lifecycle manager (start / stop / status / logs / pair) |

## Build

Expand All @@ -18,40 +21,108 @@ docker build -t openshell-openclaw .
To build against a specific base image:

```bash
docker build -t openshell-openclaw --build-arg BASE_IMAGE=ghcr.io/nvidia/openshell-community/sandboxes/base:latest .
docker build -t openshell-openclaw \
--build-arg BASE_IMAGE=ghcr.io/nvidia/openshell-community/sandboxes/base:latest .
```

## Usage

### Create a sandbox

```bash
openshell sandbox create --from openclaw
```

### With port forwarding (to access the OpenClaw UI)

```bash
openshell sandbox create --from openclaw --forward 18789 -- openclaw-start
```

This runs the `openclaw-start` helper which:
This runs `openclaw-start` which:

1. Runs `openclaw onboard` to configure the environment
2. Starts the OpenClaw gateway in the background
2. Starts the OpenClaw gateway under `nohup` (survives SSH disconnects)
3. Prints the gateway URL (with auth token if available)

Access the UI at `http://127.0.0.1:18789/`.

### Manual startup
### Gateway management

If you prefer to start OpenClaw manually inside the sandbox:
Once inside the sandbox:

```bash
openclaw-start # start (or restart) the gateway
openclaw-start stop # stop the gateway
openclaw-start status # check if running
openclaw-start logs # tail the gateway log
openclaw-start pair CODE # approve a Slack/Telegram pairing request
```

### Manual startup

```bash
openclaw onboard
openclaw gateway run
```

## Network Policy Coverage

The included `policy.yaml` covers:

| Category | Services |
|---|---|
| **LLM providers** | Anthropic, OpenAI, Google (Gemini/Vertex) |
| **Messaging** | Telegram, Slack REST API, Slack Socket Mode (WebSocket) |
| **Code** | GitHub (git + REST API), npm, PyPI |
| **Search** | Brave Search, OpenRouter |
| **Web** | LinkedIn |

All policies default to `enforcement: audit` except Slack WebSocket which uses `enforcement: enforce`.

### Slack wildcard gotcha

Do **not** add a `*.slack.com` wildcard to the `slack` policy. On OpenShell ≤ 0.0.15, a wildcard match takes priority over the `slack_websocket` policy's `tls: skip` setting, causing the L7 proxy to intercept the TLS handshake and break Socket Mode.

## WebSocket Proxy Patch

OpenShell routes all outbound traffic through an HTTP CONNECT proxy. The Slack SDK's `ws` library does not natively support CONNECT proxies for WebSocket connections. The `openclaw-ws-proxy-patch.js` file monkey-patches the `ws` module to:

1. Detect connections to `wss-primary.slack.com` and `wss-backup.slack.com`
2. Establish a CONNECT tunnel through the proxy
3. Perform TLS over the tunnel

The patch is auto-loaded via `NODE_OPTIONS="--require /sandbox/openclaw-ws-proxy-patch.js"` set in the Dockerfile.

> **Related:** [OpenShell #387](https://github.com/NVIDIA/OpenShell-Community/issues/387) — feature request for native WebSocket proxy support.

## Slack Setup

1. Go to [api.slack.com/apps](https://api.slack.com/apps)
2. Click **Create New App** → **From an app manifest**
3. Paste `openclaw-slack-manifest.yaml`
4. Generate an **App-Level Token** with `connections:write` scope
5. Install to your workspace and copy the **Bot User OAuth Token**
6. Pass both tokens during `openclaw onboard`

## Troubleshooting

### DNS resolution fails inside the sandbox

OpenShell's CoreDNS may not forward external queries by default. Patch the Corefile to add `forward . 8.8.8.8 8.8.4.4`:

```bash
openshell doctor exec -- kubectl patch configmap coredns -n kube-system \
--type merge -p '{"data":{"Corefile":"...<see setup script>..."}}'
openshell doctor exec -- kubectl rollout restart deployment coredns -n kube-system
```

### Slack Socket Mode disconnects or times out

- Verify `tls: skip` is set on `wss-primary.slack.com` and `wss-backup.slack.com` in `policy.yaml`
- Confirm `NODE_OPTIONS` includes `--require /sandbox/openclaw-ws-proxy-patch.js`
- Check logs: `openclaw-start logs | grep ws-proxy-patch`

### Gateway won't start

- Run `openclaw-start status` to check for zombie processes
- Run `openclaw-start stop` then `openclaw-start` to restart cleanly
- Inspect the log: `cat /sandbox/.openclaw/gateway.log`

## Configuration

OpenClaw stores its configuration in `~/.openclaw/openclaw.json` inside the sandbox. The config is generated during `openclaw onboard`.
99 changes: 99 additions & 0 deletions sandboxes/openclaw/openclaw-slack-manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# Slack App Manifest for OpenClaw
#
# This manifest configures all scopes, events, and settings required
# for OpenClaw's Slack integration with Socket Mode.
#
# Usage:
# 1. Go to https://api.slack.com/apps
# 2. Click "Create New App" > "From an app manifest"
# 3. Select your workspace
# 4. Paste this YAML and confirm
# 5. After creation, generate an App-Level Token with connections:write scope
# 6. Install to workspace and copy the Bot User OAuth Token
#
# To update an existing app:
# 1. Go to https://api.slack.com/apps > select your app
# 2. Click "App Manifest" in the left sidebar
# 3. Paste this YAML and save

_metadata:
major_version: 1
minor_version: 1

display_information:
name: OpenClaw Agent
description: Autonomous AI agent powered by OpenClaw, running inside an OpenShell sandbox.
background_color: "#1a1a2e"

features:
app_home:
home_tab_enabled: true
messages_tab_enabled: true
messages_tab_read_only_enabled: false
bot_user:
display_name: openclaw-agent
always_online: true

oauth_config:
scopes:
bot:
# Core messaging
- chat:write
- chat:write.customize
- im:history
- im:read
- im:write

# Channel access
- channels:history
- channels:read
- groups:history
- groups:read

# Group DMs
- mpim:history
- mpim:read
- mpim:write

# Mentions & reactions
- app_mentions:read
- reactions:read
- reactions:write

# Files
- files:read
- files:write

# Pins
- pins:read
- pins:write

# Other
- assistant:write
- commands
- emoji:read
- users:read

settings:
event_subscriptions:
bot_events:
- app_mention
- message.channels
- message.groups
- message.im
- message.mpim
- reaction_added
- reaction_removed
- member_joined_channel
- member_left_channel
- channel_rename
- pin_added
- pin_removed
interactivity:
is_enabled: true
org_deploy_enabled: false
socket_mode_enabled: true
token_rotation_enabled: false
Loading