Skip to content

feat(whatsapp): add WhatsApp channel support for sandbox onboarding#2025

Open
paritoshd-nv wants to merge 1 commit into
NVIDIA:mainfrom
paritoshd-nv:fix/support-whatsapp-channel
Open

feat(whatsapp): add WhatsApp channel support for sandbox onboarding#2025
paritoshd-nv wants to merge 1 commit into
NVIDIA:mainfrom
paritoshd-nv:fix/support-whatsapp-channel

Conversation

@paritoshd-nv
Copy link
Copy Markdown
Contributor

@paritoshd-nv paritoshd-nv commented Apr 17, 2026

Add WhatsApp as a messaging channel option during nemoclaw onboard. WhatsApp uses QR code pairing (no token), so the onboard flow skips the token prompt and prints pairing instructions in the summary.

Changes:

  • Add whatsapp.yaml network policy preset with security-hardened endpoints (3/8 access:full for WebSocket/Noise, 5/8 L7-enforced)
  • Add WhatsApp to onboard channel selector and policy auto-suggestion
  • Register WhatsApp plugin in sandbox image when channel is selected
  • Patch Baileys proxy agent in sandbox image for OpenClaw 2026.4.2 (fixed upstream in 2026.4.15+; patch self-skips after version bump)
  • Add whatsapp-bridge to sandbox destroy cleanup
  • Add regression tests for preset, tier, and cleanup

Closes #513

Summary

Related Issue

Changes

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

AI Disclosure

  • AI-assisted — tool:

Signed-off-by: Your Name your-email@example.com

Summary by CodeRabbit

  • New Features

    • Added WhatsApp as a messaging channel with QR-code pairing and dashboard pairing instructions; onboarding supports selecting WhatsApp and seeds matching policy presets
  • Chores

    • Build now conditionally includes WhatsApp support and optional HTTPS proxy handling for WhatsApp sessions
    • Sandbox cleanup now removes WhatsApp provider entries
    • Policy tiers updated to expose WhatsApp in the open tier
  • Tests

    • Updated/added tests to cover the new WhatsApp preset and provider cleanup behaviors

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds WhatsApp channel support: new policy preset and tier entry, onboarding QR-pairing flow and dashboard output, sandbox provider teardown update, Dockerfile build-time logic to enable and optionally patch OpenClaw’s WhatsApp plugin for HTTPS proxying, and corresponding tests and validations.

Changes

Cohort / File(s) Summary
Docker build
Dockerfile
Adds build-time conditional steps driven by base64 NEMOCLAW_MESSAGING_CHANNELS_B64 to enable the bundled OpenClaw WhatsApp plugin in ~/.openclaw/openclaw.json; as root optionally patches dist/session-*.js to inject HttpsProxyAgent usage guarded by process.env.HTTPS_PROXY; fails build if expected files/patterns missing; version-gated skip logic included.
Policy presets & tiers
nemoclaw-blueprint/policies/presets/whatsapp.yaml, nemoclaw-blueprint/policies/tiers.yaml
Adds whatsapp preset with network_policies.whatsapp endpoints (web.whatsapp.com, g.whatsapp.net:443/5222, mmg/media/static/pps hosts, explicit raw.githubusercontent.com GET) and allowed node binary paths; inserts whatsapp into open tier with read-write access.
Onboarding & dashboard
src/lib/onboard.ts
Adds whatsapp messaging channel (qrPairing: true, envKey), updates selection prompt range, skips token prompt for QR-pairing channels, ensures activeMessagingChannels includes whatsapp, seeds suggested presets from selected channels, and passes channels to printDashboard which prints QR pairing instructions.
Sandbox cleanup
src/nemoclaw.ts
Includes *-whatsapp-bridge in messaging-provider deletion during sandbox teardown.
Tests & validations
test/cli.test.ts, test/policies.test.ts, test/policy-tiers.test.ts, test/validate-blueprint.test.ts
Updates tests to expect WhatsApp provider deletion, increments expected preset count and includes whatsapp in preset/tier assertions; adds a validation suite asserting whatsapp preset structure and endpoint rules.

Sequence Diagram

sequenceDiagram
    actor User
    participant Onboard as Onboarding
    participant Policy as Policy Engine
    participant Docker as Docker Build
    participant OpenClaw as OpenClaw Runtime
    participant Proxy as Network/Proxy

    User->>Onboard: select "whatsapp" channel
    Onboard->>Policy: request suggested presets
    Policy-->>Onboard: include "whatsapp" preset
    Onboard->>User: show QR pairing instructions

    User->>Docker: build sandbox with WhatsApp enabled
    Docker->>OpenClaw: enable plugin path in openclaw.json
    Docker->>OpenClaw: (if root & target found) patch session-*.js to use HttpsProxyAgent when HTTPS_PROXY
    OpenClaw->>Proxy: initiate wss / noise / rest connections per policies
    Proxy-->>OpenClaw: proxy handshake (HTTP/1.1 required for WebSocket)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through code to open a gate,
QR moons glow for pairing late.
Plugins nudged and proxies set,
Bridges ready—no timeout yet.
Hop, scan, connect — then celebrate!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 accurately summarizes the main change: adding WhatsApp channel support during sandbox onboarding.
Linked Issues check ✅ Passed The PR addresses all key requirements from #513: fixes HTTP/2 proxy timeout by patching Baileys to use HTTP/1.1-compatible proxy agent, adds WhatsApp channel to onboarding flow, and implements policy-based endpoint controls.
Out of Scope Changes check ✅ Passed All changes directly support WhatsApp channel integration: Dockerfile patches, policy presets, onboarding updates, sandbox cleanup, and corresponding tests. No unrelated modifications detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile`:
- Around line 259-265: The current RUN block computes WA_ENABLED and, when
WhatsApp is selected, silently skips plugin registration if the bundled
extension path (WA_EXT) or its openclaw.plugin.json is missing; change the logic
so that when WA_ENABLED is 1 and the check [ -d "$WA_EXT" ] && [ -f
"$WA_EXT/openclaw.plugin.json" ] fails, the build exits non‑zero (e.g., echo an
error to stderr and run exit 1) instead of printing a benign message—update the
else branch in the WA_EXT existence check to fail the build and include the
path/filename (WA_EXT and openclaw.plugin.json) in the error for clarity.
- Around line 289-300: If WhatsApp is enabled (WA_ENABLED) and a chunk is found
(WA_CHUNK) but the patch verification after the sed command fails, the current
`|| echo "ERROR: Patch verification failed"` path still returns exit code 0 and
allows the image to build; change that to fail the build: after running the sed
and the grep verification (the lines referencing sed -i on "$WA_CHUNK" and grep
-q 'HttpsProxyAgent' "$WA_CHUNK"), ensure the failure path exits non‑zero (for
example replace the final `|| echo "ERROR: Patch verification failed"` with a
construct that writes the error to stderr and exits 1) so that when WA_ENABLED
is 1 and verification fails the Docker build layer fails.

In `@src/lib/onboard.ts`:
- Around line 3203-3210: The code currently adds "whatsapp" to
activeMessagingChannels but doesn't force a sandbox rebuild when an existing
sandbox was created without WhatsApp; modify the onboarding logic so that when
Array.isArray(enabledChannels) && enabledChannels.includes("whatsapp") &&
!activeMessagingChannels.includes("whatsapp") you not only push "whatsapp" onto
activeMessagingChannels but also set the flag that prevents reuse (e.g., set
reuseSandbox = false or set a needsRecreate variable) so the Dockerfile/patch
step runs; update both occurrences referenced (the block using
enabledChannels/activeMessagingChannels at lines around the shown diff and the
similar block at the other location) to ensure a recreate is forced when
WhatsApp is newly enabled.

In `@src/nemoclaw.ts`:
- Around line 1632-1633: The provider cleanup loop uses a hard-coded suffix list
in the for-loop where runOpenshell(["provider", "delete",
`${sandboxName}-${suffix}`], ...) is called; update that suffix list to match
the exact providers created during onboarding (including "slack-app" and any new
"whatsapp-bridge" if onboarding creates it) so the cleanup deletes
`${sandboxName}-slack-app` as well; locate the loop with runOpenshell and
sandboxName in src/nemoclaw.ts and adjust the array to include "slack-app" (and
remove any stale/mismatched entries) so all credential providers created by
src/lib/onboard.ts are cleaned up.

In `@test/validate-blueprint.test.ts`:
- Around line 355-356: The Endpoint type is missing the enforcement property
which causes a TS type mismatch when code accesses ep!.enforcement; update the
Endpoint type definition (symbol: Endpoint) to include enforcement?: string (or
the appropriate type used by whatsapp.yaml) so consumers like the code that
accesses ep!.enforcement compile under strict mode; ensure any other usages of
Endpoint accept the optional enforcement field and run type checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7245136f-0f1d-46f0-ada0-46786503227d

📥 Commits

Reviewing files that changed from the base of the PR and between 946c52b and a3acb9c.

📒 Files selected for processing (9)
  • Dockerfile
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml
  • nemoclaw-blueprint/policies/tiers.yaml
  • src/lib/onboard.ts
  • src/nemoclaw.ts
  • test/cli.test.ts
  • test/policies.test.ts
  • test/policy-tiers.test.ts
  • test/validate-blueprint.test.ts

Comment thread Dockerfile
Comment thread src/lib/onboard.ts
Comment thread src/nemoclaw.ts
Comment thread test/validate-blueprint.test.ts Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@paritoshd-nv paritoshd-nv marked this pull request as draft April 17, 2026 16:27
@paritoshd-nv paritoshd-nv force-pushed the fix/support-whatsapp-channel branch from a3acb9c to 7d0a027 Compare April 17, 2026 16:35
@paritoshd-nv paritoshd-nv marked this pull request as ready for review April 17, 2026 16:54
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/lib/onboard.ts (1)

3203-3210: ⚠️ Potential issue | 🟠 Major

WhatsApp enablement still does not force a rebuild when reusing an existing sandbox.

Adding WhatsApp to activeMessagingChannels here is too late for reuse cases. At Line 2977, reuse can still return early, so a sandbox created before WhatsApp support may be reused without Dockerfile/plugin updates.

💡 Proposed fix
@@
-    const needsProviderMigration =
+    const needsProviderMigration =
       hasMessagingTokens &&
       messagingTokenDefs.some(({ name, token }) => token && !providerExistsInGateway(name));
+
+    const recordedChannels = new Set(
+      Array.isArray(registry.getSandbox(sandboxName)?.messagingChannels)
+        ? registry.getSandbox(sandboxName).messagingChannels
+        : [],
+    );
+    const needsWhatsAppMigration =
+      Array.isArray(enabledChannels) &&
+      enabledChannels.includes("whatsapp") &&
+      !recordedChannels.has("whatsapp");
@@
-    if (!isRecreateSandbox() && !needsProviderMigration && !credentialRotation.changed) {
+    if (
+      !isRecreateSandbox() &&
+      !needsProviderMigration &&
+      !needsWhatsAppMigration &&
+      !credentialRotation.changed
+    ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard.ts` around lines 3203 - 3210, enabledChannels may include
"whatsapp" but adding it to activeMessagingChannels happens after the early
reuse check, so an existing sandbox can be reused without WhatsApp-related
rebuilds; move the logic that pushes "whatsapp" onto activeMessagingChannels
(the block that checks enabledChannels.includes("whatsapp")) to run before the
early reuse/return decision (the reuse-existing-sandbox check) or,
alternatively, ensure the reuse path also adds "whatsapp" and triggers a rebuild
by setting the same flag used to force Dockerfile/plugin regeneration; reference
the variables enabledChannels and activeMessagingChannels and the early reuse
branch so the sandbox build decision sees WhatsApp enabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile`:
- Around line 289-300: The WhatsApp proxy patch must be gated by an OpenClaw
version check: when WA_ENABLED is true, detect the OpenClaw version (e.g., by
reading OC_DIST/package.json or another included version token) and only allow a
missing WA_CHUNK to be treated as a non-fatal skip if the OpenClaw version is >=
2026.4.15; otherwise, if WA_CHUNK is empty or the grep patch pattern is not
found and version < 2026.4.15, fail the build (exit 1). Update the Dockerfile
logic around WA_CHUNK and the patch verification (the sed/grep block) to perform
this version comparison and change the current warning-only branch into a fatal
error for older versions while keeping the skip behavior for >= 2026.4.15.

In `@src/lib/onboard.ts`:
- Line 6130: printDashboard(...) can be called with an empty
selectedMessagingChannels on resume/reuse paths, which hides WhatsApp pairing
instructions; update the resume flow so that before calling
printDashboard(sandboxName, model, provider, nimContainer, agent,
selectedMessagingChannels) you populate selectedMessagingChannels when it's
empty by deriving channels from the existing nimContainer/agent (e.g., inspect
nimContainer.messagingChannels or agent.config to include "whatsapp" if enabled)
or by computing a fallback list based on the sandbox state, then pass that
non-empty array to printDashboard so WhatsApp pairing hints are shown on resume.

---

Duplicate comments:
In `@src/lib/onboard.ts`:
- Around line 3203-3210: enabledChannels may include "whatsapp" but adding it to
activeMessagingChannels happens after the early reuse check, so an existing
sandbox can be reused without WhatsApp-related rebuilds; move the logic that
pushes "whatsapp" onto activeMessagingChannels (the block that checks
enabledChannels.includes("whatsapp")) to run before the early reuse/return
decision (the reuse-existing-sandbox check) or, alternatively, ensure the reuse
path also adds "whatsapp" and triggers a rebuild by setting the same flag used
to force Dockerfile/plugin regeneration; reference the variables enabledChannels
and activeMessagingChannels and the early reuse branch so the sandbox build
decision sees WhatsApp enabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8e21a400-7925-46c4-b793-2b203f756c45

📥 Commits

Reviewing files that changed from the base of the PR and between a3acb9c and 7d0a027.

📒 Files selected for processing (9)
  • Dockerfile
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml
  • nemoclaw-blueprint/policies/tiers.yaml
  • src/lib/onboard.ts
  • src/nemoclaw.ts
  • test/cli.test.ts
  • test/policies.test.ts
  • test/policy-tiers.test.ts
  • test/validate-blueprint.test.ts
✅ Files skipped from review due to trivial changes (4)
  • src/nemoclaw.ts
  • nemoclaw-blueprint/policies/tiers.yaml
  • test/validate-blueprint.test.ts
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/policy-tiers.test.ts
  • test/policies.test.ts

Comment thread Dockerfile
Comment thread src/lib/onboard.ts Outdated
@paritoshd-nv paritoshd-nv force-pushed the fix/support-whatsapp-channel branch from 7d0a027 to 755f98b Compare April 17, 2026 17:03
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (4)
src/nemoclaw.ts (1)

1632-1634: ⚠️ Potential issue | 🟡 Minor

Provider cleanup still missing slack-app.

The addition of whatsapp-bridge is correct, but the cleanup loop still omits slack-app. According to previous review, onboarding creates ${sandboxName}-slack-app which would be left behind after destroy.

Proposed fix
-  for (const suffix of ["telegram-bridge", "discord-bridge", "slack-bridge", "whatsapp-bridge"]) {
+  for (const suffix of [
+    "telegram-bridge",
+    "discord-bridge",
+    "slack-bridge",
+    "slack-app",
+    "whatsapp-bridge",
+  ]) {
     runOpenshell(["provider", "delete", `${sandboxName}-${suffix}`], { ignoreError: true });
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/nemoclaw.ts` around lines 1632 - 1634, The provider cleanup loop omits
removing the `${sandboxName}-slack-app` provider so that resource is left
behind; update the for-loop that calls runOpenshell(["provider","delete",
`${sandboxName}-${suffix}`], { ignoreError: true }) to include "slack-app" in
the suffix list (alongside
"telegram-bridge","discord-bridge","slack-bridge","whatsapp-bridge") so the
`${sandboxName}-slack-app` provider is deleted during destroy.
Dockerfile (1)

289-302: ⚠️ Potential issue | 🟠 Major

Version-gate the WhatsApp proxy patch to fail on vulnerable OpenClaw builds.

Line 301 treats a missing patch target as a warning-only skip. On vulnerable OpenClaw builds < 2026.4.15, this would ship an image where WhatsApp pairing regresses to the 408 timeout (the issue this PR fixes). Per line 286's comment, the fix is only upstream in 2026.4.15+.

The patch should fail the build if the target is missing and OpenClaw < 2026.4.15; only skip safely if >= 2026.4.15.

Proposed fix with version check
 RUN WA_ENABLED="$(echo "$NEMOCLAW_MESSAGING_CHANNELS_B64" | base64 -d 2>/dev/null | grep -q '"whatsapp"' && echo 1 || echo 0)" \
     && if [ "$WA_ENABLED" = "1" ]; then \
+         OPENCLAW_VERSION="$(node -p "require('/usr/local/lib/node_modules/openclaw/package.json').version")" \
          OC_DIST="/usr/local/lib/node_modules/openclaw/dist" \
          && WA_CHUNK="$(grep -rl 'async function createWaSocket' "$OC_DIST"/session-*.js 2>/dev/null | head -1)" \
          && echo "Patching WhatsApp proxy agent in: ${WA_CHUNK:-NOT FOUND}" \
          && if [ -n "$WA_CHUNK" ] && grep -q 'markOnlineOnConnect: false' "$WA_CHUNK"; then \
               sed -i 's|markOnlineOnConnect: false|markOnlineOnConnect: false, agent: process.env.HTTPS_PROXY ? new (__require("https-proxy-agent").HttpsProxyAgent)(process.env.HTTPS_PROXY) : undefined|' "$WA_CHUNK"; \
               if grep -q 'HttpsProxyAgent' "$WA_CHUNK"; then \
                 echo "Patch applied successfully"; \
               else \
                 echo "ERROR: Patch verification failed" >&2; exit 1; \
               fi; \
-            else echo "WARNING: Pattern not found or chunk missing — skipping WhatsApp proxy patch"; fi; \
+            elif dpkg --compare-versions "$OPENCLAW_VERSION" ge "2026.4.15"; then \
+              echo "OpenClaw ${OPENCLAW_VERSION} already contains the upstream fix — skipping WhatsApp proxy patch"; \
+            else \
+              echo "ERROR: WhatsApp proxy patch target not found in vulnerable OpenClaw ${OPENCLAW_VERSION}" >&2; exit 1; \
+            fi; \
        else echo "WhatsApp not selected — skipping proxy patch"; fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 289 - 302, The Dockerfile currently treats a missing
WhatsApp proxy patch (WA_CHUNK) as a warning, which must instead fail for
vulnerable OpenClaw builds; update the patching block so it reads OpenClaw's
version (e.g., from OC_DIST/package.json or another version file under OC_DIST),
compare it against "2026.4.15", and if WA_CHUNK is missing and the detected
OpenClaw version is less than 2026.4.15 then exit with an error (non-zero)
rather than printing a warning; only allow skipping (warning) when the detected
version is >= 2026.4.15. Use the existing variables WA_ENABLED, OC_DIST and
WA_CHUNK to locate the files and fail the build path accordingly, and ensure the
error message includes the discovered OpenClaw version and that the patch target
was not found.
src/lib/onboard.ts (2)

6130-6130: ⚠️ Potential issue | 🟡 Minor

Use persisted channels as fallback before printing dashboard pairing hints.

On resume/reuse paths, selectedMessagingChannels can still be empty, so WhatsApp pairing instructions may be hidden even when the sandbox has WhatsApp enabled.

💡 Proposed fix
-    printDashboard(sandboxName, model, provider, nimContainer, agent, selectedMessagingChannels);
+    const dashboardChannels =
+      selectedMessagingChannels.length > 0
+        ? selectedMessagingChannels
+        : (
+            registry.getSandbox(sandboxName)?.messagingChannels ||
+            session?.messagingChannels ||
+            []
+          );
+    printDashboard(sandboxName, model, provider, nimContainer, agent, dashboardChannels);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard.ts` at line 6130, selectedMessagingChannels can be empty on
resume/reuse, causing WhatsApp pairing hints to be hidden; before calling
printDashboard(sandboxName, model, provider, nimContainer, agent,
selectedMessagingChannels) populate selectedMessagingChannels from persisted
storage if it's empty (e.g. load persisted messaging channels/state used
elsewhere in onboarding) so printDashboard receives the restored channels;
update the call site that prepares selectedMessagingChannels (or add a small
guard right before printDashboard) to merge persisted channels as a fallback
when selectedMessagingChannels.length === 0.

3203-3210: ⚠️ Potential issue | 🟠 Major

Force recreation when WhatsApp is newly enabled on an existing sandbox.

activeMessagingChannels.push("whatsapp") is correct, but the reuse gate (Line 2977) still skips recreate when WhatsApp was not present in the originally built sandbox. That can reuse an image without WhatsApp plugin/patching and produce a broken pairing flow.

💡 Proposed fix
@@
   if (liveExists) {
     const existingSandboxState = getSandboxReuseState(sandboxName);
+    const recordedChannels = new Set(
+      Array.isArray(registry.getSandbox(sandboxName)?.messagingChannels)
+        ? registry.getSandbox(sandboxName).messagingChannels
+        : [],
+    );
+    const needsMessagingChannelMigration =
+      Array.isArray(enabledChannels) &&
+      enabledChannels.some((name) => !recordedChannels.has(name));
@@
-    if (!isRecreateSandbox() && !needsProviderMigration && !credentialRotation.changed) {
+    if (
+      !isRecreateSandbox() &&
+      !needsProviderMigration &&
+      !needsMessagingChannelMigration &&
+      !credentialRotation.changed
+    ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard.ts` around lines 3203 - 3210, When WhatsApp is newly appended
to activeMessagingChannels (enabledChannels.includes("whatsapp") case), also
force the sandbox/image to be recreated by flipping the reuse gate used earlier
in the onboarding logic to prevent reusing an image without the WhatsApp plugin;
after activeMessagingChannels.push("whatsapp") set the same boolean/flag that
the reuse-gate checks (the boolean used to skip recreation) to false (or set a
dedicated forceRecreateSandbox = true) so the build/recreate path runs when
WhatsApp was not present originally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Dockerfile`:
- Around line 289-302: The Dockerfile currently treats a missing WhatsApp proxy
patch (WA_CHUNK) as a warning, which must instead fail for vulnerable OpenClaw
builds; update the patching block so it reads OpenClaw's version (e.g., from
OC_DIST/package.json or another version file under OC_DIST), compare it against
"2026.4.15", and if WA_CHUNK is missing and the detected OpenClaw version is
less than 2026.4.15 then exit with an error (non-zero) rather than printing a
warning; only allow skipping (warning) when the detected version is >=
2026.4.15. Use the existing variables WA_ENABLED, OC_DIST and WA_CHUNK to locate
the files and fail the build path accordingly, and ensure the error message
includes the discovered OpenClaw version and that the patch target was not
found.

In `@src/lib/onboard.ts`:
- Line 6130: selectedMessagingChannels can be empty on resume/reuse, causing
WhatsApp pairing hints to be hidden; before calling printDashboard(sandboxName,
model, provider, nimContainer, agent, selectedMessagingChannels) populate
selectedMessagingChannels from persisted storage if it's empty (e.g. load
persisted messaging channels/state used elsewhere in onboarding) so
printDashboard receives the restored channels; update the call site that
prepares selectedMessagingChannels (or add a small guard right before
printDashboard) to merge persisted channels as a fallback when
selectedMessagingChannels.length === 0.
- Around line 3203-3210: When WhatsApp is newly appended to
activeMessagingChannels (enabledChannels.includes("whatsapp") case), also force
the sandbox/image to be recreated by flipping the reuse gate used earlier in the
onboarding logic to prevent reusing an image without the WhatsApp plugin; after
activeMessagingChannels.push("whatsapp") set the same boolean/flag that the
reuse-gate checks (the boolean used to skip recreation) to false (or set a
dedicated forceRecreateSandbox = true) so the build/recreate path runs when
WhatsApp was not present originally.

In `@src/nemoclaw.ts`:
- Around line 1632-1634: The provider cleanup loop omits removing the
`${sandboxName}-slack-app` provider so that resource is left behind; update the
for-loop that calls runOpenshell(["provider","delete",
`${sandboxName}-${suffix}`], { ignoreError: true }) to include "slack-app" in
the suffix list (alongside
"telegram-bridge","discord-bridge","slack-bridge","whatsapp-bridge") so the
`${sandboxName}-slack-app` provider is deleted during destroy.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8679cf48-fffc-4768-908f-b273f79786b4

📥 Commits

Reviewing files that changed from the base of the PR and between 7d0a027 and 755f98b.

📒 Files selected for processing (9)
  • Dockerfile
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml
  • nemoclaw-blueprint/policies/tiers.yaml
  • src/lib/onboard.ts
  • src/nemoclaw.ts
  • test/cli.test.ts
  • test/policies.test.ts
  • test/policy-tiers.test.ts
  • test/validate-blueprint.test.ts
✅ Files skipped from review due to trivial changes (4)
  • test/policy-tiers.test.ts
  • test/cli.test.ts
  • test/policies.test.ts
  • nemoclaw-blueprint/policies/tiers.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/validate-blueprint.test.ts
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml

@paritoshd-nv paritoshd-nv force-pushed the fix/support-whatsapp-channel branch from 755f98b to 7b2678b Compare April 17, 2026 17:12
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/nemoclaw.ts (1)

1632-1633: ⚠️ Potential issue | 🟠 Major

Cleanup is still incomplete: slack-app provider is not deleted.

Line 1632 adds WhatsApp cleanup, but destroy still omits ${sandboxName}-slack-app (created during onboarding), so a provider can be left behind after sandbox teardown.

Proposed fix
-  for (const suffix of ["telegram-bridge", "discord-bridge", "slack-bridge", "whatsapp-bridge"]) {
+  for (const suffix of [
+    "telegram-bridge",
+    "discord-bridge",
+    "slack-bridge",
+    "slack-app",
+    "whatsapp-bridge",
+  ]) {
     runOpenshell(["provider", "delete", `${sandboxName}-${suffix}`], { ignoreError: true });
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/nemoclaw.ts` around lines 1632 - 1633, The cleanup loop in runOpenshell
that deletes providers omits the `${sandboxName}-slack-app` provider; update the
array of suffixes in the for loop (the one iterating over ["telegram-bridge",
"discord-bridge", "slack-bridge", "whatsapp-bridge"]) to include "slack-app" so
runOpenshell(["provider", "delete", `${sandboxName}-slack-app`], { ignoreError:
true }) is executed for that provider as well; keep the same ignoreError
behavior and use the existing sandboxName variable and runOpenshell call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile`:
- Around line 301-302: The patch gate currently compares versions
lexicographically in the Node one-liner (node -e "const
v=require('/usr/local/lib/node_modules/openclaw/package.json').version;process.exit(v>='2026.4.15'?0:1)"),
which misclassifies versions like 2026.4.9 and 2026.10.0; change the check to a
proper semantic comparison by invoking Node's semver comparison (e.g.,
require('semver').gte(v, '2026.4.15')) or by splitting and numerically comparing
major/minor/patch segments, and use the same method when printing the version in
the echo branch (the two node -e invocations referencing
require('/usr/local/lib/node_modules/openclaw/package.json').version). Ensure
the command exits 0 only when semver.gte(...) returns true.

---

Duplicate comments:
In `@src/nemoclaw.ts`:
- Around line 1632-1633: The cleanup loop in runOpenshell that deletes providers
omits the `${sandboxName}-slack-app` provider; update the array of suffixes in
the for loop (the one iterating over ["telegram-bridge", "discord-bridge",
"slack-bridge", "whatsapp-bridge"]) to include "slack-app" so
runOpenshell(["provider", "delete", `${sandboxName}-slack-app`], { ignoreError:
true }) is executed for that provider as well; keep the same ignoreError
behavior and use the existing sandboxName variable and runOpenshell call.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 45e403a5-5848-401a-8fb4-7c9d21c3a76c

📥 Commits

Reviewing files that changed from the base of the PR and between 755f98b and 7b2678b.

📒 Files selected for processing (9)
  • Dockerfile
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml
  • nemoclaw-blueprint/policies/tiers.yaml
  • src/lib/onboard.ts
  • src/nemoclaw.ts
  • test/cli.test.ts
  • test/policies.test.ts
  • test/policy-tiers.test.ts
  • test/validate-blueprint.test.ts
✅ Files skipped from review due to trivial changes (3)
  • test/policy-tiers.test.ts
  • nemoclaw-blueprint/policies/tiers.yaml
  • test/policies.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/cli.test.ts
  • test/validate-blueprint.test.ts
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml
  • src/lib/onboard.ts

Comment thread Dockerfile
Comment on lines +301 to +302
elif node -e "const v=require('/usr/local/lib/node_modules/openclaw/package.json').version;process.exit(v>='2026.4.15'?0:1)"; then \
echo "OpenClaw $(node -e "process.stdout.write(require('/usr/local/lib/node_modules/openclaw/package.json').version)") has upstream proxy fix — skipping patch"; \
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

node <<'NODE'
const threshold = '2026.4.15';
for (const v of ['2026.4.9', '2026.4.15', '2026.10.0']) {
  const lexicographic = v >= threshold;
  const [y, m, p] = v.split('.').map(Number);
  const numeric = (y > 2026) || (y === 2026 && (m > 4 || (m === 4 && p >= 15)));
  console.log(`${v}: current=${lexicographic} expected=${numeric}`);
}
NODE

Repository: NVIDIA/NemoClaw

Length of output: 173


Use a semantic version check for the patch gate.

The current code uses lexicographic string comparison (v >= '2026.4.15'), which incorrectly classifies versions: 2026.4.9 evaluates as fixed (true when it should be false) and 2026.10.0 evaluates as older (false when it should be true). This can skip the proxy patch on vulnerable builds or unnecessarily patch safe newer versions.

Suggested fix
-            elif node -e "const v=require('/usr/local/lib/node_modules/openclaw/package.json').version;process.exit(v>='2026.4.15'?0:1)"; then \
+            elif node -e "const [y,m,p]=require('/usr/local/lib/node_modules/openclaw/package.json').version.split('.').map(Number); process.exit((y > 2026 || (y === 2026 && (m > 4 || (m === 4 && p >= 15)))) ? 0 : 1)"; then \
               echo "OpenClaw $(node -e "process.stdout.write(require('/usr/local/lib/node_modules/openclaw/package.json').version)") has upstream proxy fix — skipping patch"; \
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 301 - 302, The patch gate currently compares
versions lexicographically in the Node one-liner (node -e "const
v=require('/usr/local/lib/node_modules/openclaw/package.json').version;process.exit(v>='2026.4.15'?0:1)"),
which misclassifies versions like 2026.4.9 and 2026.10.0; change the check to a
proper semantic comparison by invoking Node's semver comparison (e.g.,
require('semver').gte(v, '2026.4.15')) or by splitting and numerically comparing
major/minor/patch segments, and use the same method when printing the version in
the echo branch (the two node -e invocations referencing
require('/usr/local/lib/node_modules/openclaw/package.json').version). Ensure
the command exits 0 only when semver.gte(...) returns true.

Add WhatsApp as a messaging channel option during nemoclaw onboard.
WhatsApp uses QR code pairing (no token), so the onboard flow skips
the token prompt and prints pairing instructions in the summary.

Changes:
- Add whatsapp.yaml network policy preset with security-hardened
  endpoints (3/8 access:full for WebSocket/Noise, 5/8 L7-enforced)
- Add WhatsApp to onboard channel selector and policy auto-suggestion
- Register WhatsApp plugin in sandbox image when channel is selected
- Patch Baileys proxy agent in sandbox image for OpenClaw 2026.4.2
  (fixed upstream in 2026.4.15+; patch self-skips after version bump)
- Add whatsapp-bridge to sandbox destroy cleanup
- Add regression tests for preset, tier, and cleanup

Closes NVIDIA#513

Signed-off-by: Paritosh Dixit <paritoshd@nvidia.com>
@paritoshd-nv paritoshd-nv force-pushed the fix/support-whatsapp-channel branch from 7b2678b to ebf2751 Compare April 17, 2026 17:29
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
nemoclaw-blueprint/policies/presets/whatsapp.yaml (1)

65-70: Consider future-proofing against potential default branch changes in WhiskeySockets/Baileys.

Line 70 currently hardcodes /master/ in the allowed path, which is the current default branch. However, if the upstream repository were to change its default branch to main or another name, this hardcoded path would fail and cause pairing behavior to regress. To make the policy more resilient, consider allowing multiple path variants (e.g., both /master/ and /main/ depending on your Baileys version pin), or document this as a maintenance point if you monitor Baileys branch updates.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nemoclaw-blueprint/policies/presets/whatsapp.yaml` around lines 65 - 70, The
allowed path currently hardcodes
"/WhiskeySockets/Baileys/master/src/Defaults/index.ts" which will break if the
repo's default branch changes; update the policy rules (the allow entry under
rules for host raw.githubusercontent.com) to accept both branch variants (e.g.,
add an additional allow rule for
"/WhiskeySockets/Baileys/main/src/Defaults/index.ts" or replace with a
branch-agnostic pattern/wildcard/regex if supported) or add a comment
documenting that the entry must be updated when Baileys changes its default
branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@nemoclaw-blueprint/policies/presets/whatsapp.yaml`:
- Around line 65-70: The allowed path currently hardcodes
"/WhiskeySockets/Baileys/master/src/Defaults/index.ts" which will break if the
repo's default branch changes; update the policy rules (the allow entry under
rules for host raw.githubusercontent.com) to accept both branch variants (e.g.,
add an additional allow rule for
"/WhiskeySockets/Baileys/main/src/Defaults/index.ts" or replace with a
branch-agnostic pattern/wildcard/regex if supported) or add a comment
documenting that the entry must be updated when Baileys changes its default
branch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e377021-de5b-42a9-82bc-00dfad1d5947

📥 Commits

Reviewing files that changed from the base of the PR and between 7b2678b and ebf2751.

📒 Files selected for processing (9)
  • Dockerfile
  • nemoclaw-blueprint/policies/presets/whatsapp.yaml
  • nemoclaw-blueprint/policies/tiers.yaml
  • src/lib/onboard.ts
  • src/nemoclaw.ts
  • test/cli.test.ts
  • test/policies.test.ts
  • test/policy-tiers.test.ts
  • test/validate-blueprint.test.ts
✅ Files skipped from review due to trivial changes (4)
  • nemoclaw-blueprint/policies/tiers.yaml
  • test/policies.test.ts
  • test/validate-blueprint.test.ts
  • src/nemoclaw.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/policy-tiers.test.ts
  • test/cli.test.ts
  • src/lib/onboard.ts
  • Dockerfile

@wscurran wscurran added NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. integration: whatsapp WhatsApp integration or channel behavior labels Apr 20, 2026
@wscurran
Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this PR that proposes a new feature to add WhatsApp channel support for sandbox onboarding, which could help expand the capabilities of NemoClaw.


Possibly related open issues:

@wscurran wscurran added the priority: high Important issue that should be resolved in the next release label Apr 21, 2026
@clonardo
Copy link
Copy Markdown

@paritoshd-nv any chance this PR can be updated to resolve conflicts? would be great to have first-class Whatsapp support in onboarding. Thanks!

@cv cv closed this May 12, 2026
@cv cv reopened this May 12, 2026
@cv cv added v0.0.51 Release target v0.0.52 Release target v0.0.53 Release target and removed v0.0.51 Release target v0.0.52 Release target labels May 24, 2026
@ericksoa ericksoa added v0.0.55 and removed v0.0.53 Release target labels May 27, 2026
@jyaunches jyaunches added R1 v0.0.56 Release target and removed v0.0.55 labels May 29, 2026
@cv cv added whatsapp and removed whatsapp labels May 30, 2026
@sandl99 sandl99 added the enhancement: messaging Enhancements related to messing support including Slack, Telegram, Discord and WhatsApp. label Jun 1, 2026
@cv cv added v0.0.57 Release target and removed v0.0.56 Release target labels Jun 1, 2026
@cv cv self-assigned this Jun 2, 2026
@cv cv added v0.0.58 Release target and removed v0.0.57 Release target labels Jun 3, 2026
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output area: messaging Messaging channels, bridges, manifests, or channel lifecycle feature PR adds or expands user-visible functionality and removed priority: high Important issue that should be resolved in the next release labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output area: messaging Messaging channels, bridges, manifests, or channel lifecycle enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. enhancement: messaging Enhancements related to messing support including Slack, Telegram, Discord and WhatsApp. feature PR adds or expands user-visible functionality integration: whatsapp WhatsApp integration or channel behavior NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). v0.0.58 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WhatsApp login fails in OpenShell sandbox - WebSocket timeout due to HTTP/2 proxy

7 participants