Skip to content

fix: pass Discord and Slack bot tokens via env vars into sandbox#601

Merged
kjw3 merged 5 commits into
mainfrom
fix/discord-token-immutable-config
Mar 21, 2026
Merged

fix: pass Discord and Slack bot tokens via env vars into sandbox#601
kjw3 merged 5 commits into
mainfrom
fix/discord-token-immutable-config

Conversation

@ericksoa

@ericksoa ericksoa commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Pass DISCORD_BOT_TOKEN and SLACK_BOT_TOKEN as env vars into the sandbox at creation time
  • Forward both tokens in the Brev/VM deploy path
  • Disable channels.defaults.configWrites in the build-time openclaw.json to prevent channel plugins from writing to the immutable config
  • Add Discord endpoints (discord.com, gateway.discord.gg, cdn.discordapp.com) to the default baseline sandbox policy

Context

PR #588 made openclaw.json immutable to prevent agent tampering with gateway auth tokens. Community users reported that OpenClaw's Discord integration fails because it tries to write the bot token to the now-immutable config.

OpenClaw already supports reading DISCORD_BOT_TOKEN from an environment variable and auto-enables the Discord channel when present. This PR passes the token through at sandbox creation time — the same pattern already used for NVIDIA_API_KEY and TELEGRAM_BOT_TOKEN.

Closes #599
Closes #606

Test plan

  • Unit tests pass (187/187)
  • Full E2E pass (17/17) — install, onboard, sandbox verification, live inference, cleanup
  • Set DISCORD_BOT_TOKEN env var, run onboard, verify token is available inside sandbox
  • Verify no EPERM errors in gateway logs from configWrites
  • Verify openclaw.json remains immutable (root:root, 444)

OpenClaw's Discord integration fails when it tries to write a
user-provided bot token to openclaw.json, which is now immutable
(root:root 444, Landlock read-only) after #588.

OpenClaw already supports reading DISCORD_BOT_TOKEN and
SLACK_BOT_TOKEN from environment variables, so we pass them through
at sandbox creation time — the same pattern used for NVIDIA_API_KEY
and TELEGRAM_BOT_TOKEN.

Also disables channels.defaults.configWrites in the build-time config
to prevent any channel plugin from attempting runtime writes to the
immutable config file.

Closes #599
@coderabbitai

coderabbitai Bot commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6cb666cc-f091-4b1f-921d-ace53819ecb5

📥 Commits

Reviewing files that changed from the base of the PR and between 685d3a0 and c15cbce.

📒 Files selected for processing (1)
  • nemoclaw-blueprint/policies/openclaw-sandbox.yaml

📝 Walkthrough

Walkthrough

Docker build now injects an extra channels.defaults.configWrites: False into generated openclaw.json. Sandbox and VM deployment paths were updated to pass Discord and Slack bot tokens as environment variables (resolved via getCredential() with env fallbacks) instead of relying on runtime writes to immutable config.

Changes

Cohort / File(s) Summary
Docker build config
Dockerfile
Inline Python that generates openclaw.json now adds channels: { defaults: { configWrites: False } }, making default channel config writes disabled in the built image.
Sandbox & onboarding runtime
bin/lib/onboard.js
createSandbox(gpu) now conditionally includes DISCORD_BOT_TOKEN and SLACK_BOT_TOKEN in envArgs, each from getCredential() with process.env fallback and shell-quoted when present.
VM deployment (.env) population
bin/nemoclaw.js
deploy(instanceName) now conditionally adds DISCORD_BOT_TOKEN and SLACK_BOT_TOKEN (via getCredential) to the generated Brev VM .env file when available.
Network policy additions
nemoclaw-blueprint/policies/openclaw-sandbox.yaml
Updated comment to reference Telegram and Discord; added network_policies.discord policy allowing HTTPS to discord.com, gateway.discord.gg, and cdn.discordapp.com (port 443) with tls: terminate, enforcement: enforce, and GET/POST to /**.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer/CLI
  participant Cred as Credential Store (getCredential)
  participant Docker as Docker build
  participant Sandbox as Sandbox (openshell)
  participant VM as Brev VM
  participant OpenClaw as OpenClaw runtime

  Dev->>Docker: build image (inline python -> openclaw.json)
  Docker-->>OpenClaw: image with configWrites: False

  Dev->>Cred: request DISCORD_BOT_TOKEN / SLACK_BOT_TOKEN
  Cred-->>Dev: token (if present)

  Dev->>Sandbox: createSandbox(...) with envArgs (include tokens)
  Sandbox->>OpenClaw: start runtime with env vars

  Dev->>VM: deploy(instance) -> generate .env (include tokens)
  VM->>OpenClaw: start service with .env environment
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit sniffed the locked-up file,
No scribble, no scratch, not even a style.
So I tucked tokens in envs that fly,
Through sandbox gates and VMs high,
Hopping safe where configs can’t cry. 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: passing Discord and Slack bot tokens as environment variables into the sandbox.
Linked Issues check ✅ Passed The PR addresses issue #599 by preventing OpenClaw from writing credentials to immutable openclaw.json and instead providing tokens via environment variables, aligning with the objective to restore Discord integration without compromising immutability protections.
Out of Scope Changes check ✅ Passed All changes are directly related to passing bot tokens via environment variables and disabling channel configuration writes, which are in scope for issue #599.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/discord-token-immutable-config

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://NVIDIA.github.io/NemoClaw/pr-preview/pr-601/

Built to branch gh-pages at 2026-03-21 19:31 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Comment thread README.md
| **Static** | Edit `openclaw-sandbox.yaml` and re-run `nemoclaw onboard`. | Persists across restarts. |
| **Dynamic** | Run `openshell policy set <policy-file>` on a running sandbox. | Session only; resets on restart. |

NemoClaw includes preset policy files for common integrations such as PyPI, Docker Hub, Slack, and Jira in `nemoclaw-blueprint/policies/presets/`. Apply a preset as-is or use it as a starting template.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Technically outside this diff, but should we add the Discord preset here as well? I realize there may be a fair bit of churn in that area right now.

(At least I assume there is a preset, based on #585 which might do well with another look with this merged)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point, thx for flagging

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added discord support to the PR as well.

@ericksoa ericksoa marked this pull request as ready for review March 21, 2026 19:47
Keep main's shellQuote usage for Telegram token, mkdtempSync for temp
files, and "default policy" wording in README. Add Discord/Slack token
passthrough on top.
Add discord.com, gateway.discord.gg, and cdn.discordapp.com to the
baseline sandbox policy so Discord integration works without needing
the preset applied separately.
@kjw3 kjw3 self-assigned this Mar 21, 2026
@kjw3

kjw3 commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

Reviewed the latest rebase and validated the end-to-end path locally.

What I checked:

  • The fix direction is correct for #599: instead of reopening writes to immutable openclaw.json, this passes DISCORD_BOT_TOKEN / SLACK_BOT_TOKEN through env at sandbox creation and VM deploy time.
  • The build-time config change is aligned with that model. Setting channels.defaults.configWrites: false avoids channel plugins trying to mutate immutable config at runtime.
  • The default sandbox policy now includes the Discord endpoints, and that matches the existing Discord preset shape rather than inventing a new policy variant.

Validation status:

  • CI is green.
  • E2E validation passed locally.

Net: this preserves the immutability hardening from #588 while restoring the broken Discord integration path. Looks ready.

Let it rip 🤙

@kjw3 kjw3 merged commit 255e606 into main Mar 21, 2026
6 checks passed
@kjw3 kjw3 deleted the fix/discord-token-immutable-config branch March 21, 2026 20:47
@heartsiddharth1

heartsiddharth1 commented Mar 21, 2026

Copy link
Copy Markdown

@ericksoa @kjw3 any chance if the below error be fixed for all so that everthig works please help why i am getting this error

◇ Configure Discord channels access?
│ Yes

◇ Discord channels access
│ Open (allow all channels)

◇ Selected channels ────────────────────────────────────────────╮
│ │
│ Discord — very well supported right now. Docs: │
│ discord │
│ │
├────────────────────────────────────────────────────────────────╯
Error: EACCES: permission denied, copyfile '/sandbox/.openclaw/openclaw.json.1509.28a46635-f655-4913-862a-39cf98c21765.tmp' -> '/sandbox/.openclaw/openclaw.json'

this is inside the sandbox

@ericksoa

Copy link
Copy Markdown
Contributor Author

@heartsiddharth1 This fix is already merged, but it changes how you set up Discord. Instead of configuring it inside the sandbox via openclaw onboard, set the token on the host before creating the sandbox:

export DISCORD_BOT_TOKEN=your-token-here
nemoclaw onboard

The token gets passed into the sandbox as an environment variable and OpenClaw picks it up automatically. Running openclaw onboard inside the sandbox to configure Discord won't work because the config file is intentionally locked down.

To change the token later, you'll need to recreate the sandbox with the new token set. We know that's not ideal — tracking a better workflow for runtime credential updates as a follow-up.

ericksoa added a commit that referenced this pull request Mar 22, 2026
RISKY CHANGE — migration path to standardize messaging configuration.

When messaging tokens (Telegram, Discord, Slack) are detected at
onboard completion, automatically start the host-side bridges via
start-services.sh. This seamlessly migrates users from the in-sandbox
OpenClaw plugin path (#601) to the host-side bridge architecture.

Discord and Slack enforce single gateway connections per token, so
the host bridge naturally takes over from the in-sandbox plugin.
The env var passthrough is kept for backwards compatibility during
this transition.
kagura-agent pushed a commit to kagura-agent/NemoClaw that referenced this pull request Mar 22, 2026
…ixes NVIDIA#606)

openclaw.json is locked (root:root 444) at build time to prevent agent
tampering (NVIDIA#514, NVIDIA#588).  However, users legitimately need to modify
config at runtime — e.g. running `openclaw onboard` to add a Discord
bot token.  The atomic write (tmp → copyfile → rename) in OpenClaw's
config writer fails with EACCES against the immutable file.

PR NVIDIA#601 addressed the env-var path (passing DISCORD_BOT_TOKEN into the
sandbox), but the underlying issue remains: any `openclaw onboard` or
`/config` write inside the sandbox hits the same EACCES error.

Fix: at sandbox startup, copy the immutable openclaw.json to the
writable state directory (~/.openclaw-data/) and set
OPENCLAW_CONFIG_PATH to redirect all OpenClaw config reads/writes to
the copy.  The original immutable file stays intact as a read-only
reference; the Landlock policy on /sandbox/.openclaw continues to
protect it.

Changes:
- nemoclaw-start.sh: add prepare_writable_config() that copies the
  locked config to ~/.openclaw-data/openclaw.json and exports
  OPENCLAW_CONFIG_PATH; update print_dashboard_urls to respect the
  env var
- e2e-test.sh: add test 11 verifying writable overlay works and
  immutable original stays untouched
Ryuketsukami pushed a commit to Ryuketsukami/NemoClaw that referenced this pull request Mar 24, 2026
…DIA#601)

* docs: add community feedback invitation for policy presets

* docs: link baseline policy reference to the YAML file on GitHub

* fix: pass Discord and Slack bot tokens via env vars into sandbox

OpenClaw's Discord integration fails when it tries to write a
user-provided bot token to openclaw.json, which is now immutable
(root:root 444, Landlock read-only) after NVIDIA#588.

OpenClaw already supports reading DISCORD_BOT_TOKEN and
SLACK_BOT_TOKEN from environment variables, so we pass them through
at sandbox creation time — the same pattern used for NVIDIA_API_KEY
and TELEGRAM_BOT_TOKEN.

Also disables channels.defaults.configWrites in the build-time config
to prevent any channel plugin from attempting runtime writes to the
immutable config file.

Closes NVIDIA#599

* fix: add Discord endpoints to default sandbox policy

Add discord.com, gateway.discord.gg, and cdn.discordapp.com to the
baseline sandbox policy so Discord integration works without needing
the preset applied separately.
jessesanford pushed a commit to jessesanford/NemoClaw that referenced this pull request Mar 24, 2026
…DIA#601)

* docs: add community feedback invitation for policy presets

* docs: link baseline policy reference to the YAML file on GitHub

* fix: pass Discord and Slack bot tokens via env vars into sandbox

OpenClaw's Discord integration fails when it tries to write a
user-provided bot token to openclaw.json, which is now immutable
(root:root 444, Landlock read-only) after NVIDIA#588.

OpenClaw already supports reading DISCORD_BOT_TOKEN and
SLACK_BOT_TOKEN from environment variables, so we pass them through
at sandbox creation time — the same pattern used for NVIDIA_API_KEY
and TELEGRAM_BOT_TOKEN.

Also disables channels.defaults.configWrites in the build-time config
to prevent any channel plugin from attempting runtime writes to the
immutable config file.

Closes NVIDIA#599

* fix: add Discord endpoints to default sandbox policy

Add discord.com, gateway.discord.gg, and cdn.discordapp.com to the
baseline sandbox policy so Discord integration works without needing
the preset applied separately.
@wscurran wscurran added the bug-fix PR fixes a bug or regression label Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression

Projects

None yet

5 participants