Skip to content

fix(whatsapp): revert post-pair gateway restart#6571

Closed
sandl99 wants to merge 5 commits into
mainfrom
revert/6496-whatsapp-postpair-reconcile
Closed

fix(whatsapp): revert post-pair gateway restart#6571
sandl99 wants to merge 5 commits into
mainfrom
revert/6496-whatsapp-postpair-reconcile

Conversation

@sandl99

@sandl99 sandl99 commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR reverts PR #6496 because manual validation shows the original WhatsApp issue still persists after the change. It also removes the DGX Spark and DGX Station regression that reports: NemoClaw rejected a conflicting gateway trust anchor, and the ambient gateway token could not be cleared.

Related Issue

Reopens #6413

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)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — focused gateway/runtime coverage remains in test/nemoclaw-start-gateway-ws-host.test.ts.
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — this is a targeted revert of PR fix(whatsapp): reconcile post-pair gateway restart without operator.admin #6496 because it does not fix fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 and regresses DGX Spark / DGX Station by rejecting the gateway trust anchor.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — npx vitest run --project integration test/nemoclaw-start-gateway-ws-host.test.ts passed, 9 tests.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only) — npm run docs passed with 0 errors and 2 existing warnings.
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Additional validation

  • npx prek run shfmt --files scripts/nemoclaw-start.sh passed.
  • npx prek run shellcheck --files scripts/nemoclaw-start.sh passed.
  • Documentation writer review found no additional docs changes needed beyond the reverted docs.

Signed-off-by: San Dang sdang@nvidia.com

Summary by CodeRabbit

  • Documentation

    • Streamlined WhatsApp (experimental) OpenClaw sandbox setup/troubleshooting guidance, preserving QR pairing validation and 1008 close-code recovery steps.
  • Refactor

    • Simplified the WhatsApp sandbox login flow by narrowing accepted login arguments, removing post-login reconcile/restart behavior, and tightening gateway token handling so caller-selected WhatsApp gateways don’t receive ambient tokens.
  • Tests

    • Updated harness runtime environment and centralized timeout configuration.
    • Added coverage to ensure tokens are withheld for WhatsApp gateway overrides.
    • Removed outdated regression coverage for the prior WhatsApp post-pair restart logic.

Reverts PR #6496 / merge commit 1ff8855.

Reason 1: Manual validation shows PR #6496 does not fix the issue; it still reproduces.

Reason 2: It regresses DGX Spark and DGX Station.

Observed error: NemoClaw rejected a conflicting gateway trust anchor.

The ambient gateway token could not be cleared.

Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99 sandl99 self-assigned this Jul 9, 2026
@github-code-quality

github-code-quality Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage remains at 96%, unchanged from the branch.

TypeScript / code-coverage/cli

The overall coverage in the branch remains at 77%, unchanged from the branch.

Show a code coverage summary of the most impacted files.
File 0d2aca4 110bfcf +/-
src/lib/actions...-add-restart.ts 19% 14% -5%
src/lib/shields/index.ts 60% 60% 0%
src/lib/policy/index.ts 67% 67% 0%
src/lib/actions...ateway-state.ts 72% 72% 0%
src/lib/inferen...board-probes.ts 84% 86% +2%
src/lib/actions...ridge-policy.ts 62% 64% +2%
src/lib/actions...lution-probe.ts 88% 94% +6%
src/lib/actions...e-validation.ts 81% 90% +9%
src/lib/actions...x/mcp-bridge.ts 35% 44% +9%
src/lib/actions...ence-gateway.ts 50% 83% +33%

Updated July 09, 2026 13:31 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR removes the WhatsApp post-pair restart path, drops the trusted gateway URL anchor guard, updates related shell tests and harness timeouts, and shortens the WhatsApp sandbox documentation.

Changes

WhatsApp login and runtime cleanup

Layer / File(s) Summary
Remove trusted gateway anchor
scripts/nemoclaw-start.sh, test/nemoclaw-start-gateway-ws-host.test.ts
Removes the readonly trusted gateway URL anchor logic from the runtime shell env script and updates the runtime-env tests to stop asserting trust-anchor output while keeping the other environment assertions.
Simplify WhatsApp login flow
scripts/nemoclaw-start.sh
Removes the WhatsApp gateway-token and post-pair restart helpers, drops --account parsing state, keeps dedicated --channel handling, changes WhatsApp login execution to conditionally add preload options, and deletes the post-login reconcile branch.
Update harness timeouts and docs
src/lib/actions/sandbox/mcp-bridge-status-resolution.test.ts, docs/manage-sandboxes/messaging-channels.mdx
Adds harness process timeout plumbing to the bridge-status test, applies the new timeout settings to both describe blocks, and shortens the WhatsApp sandbox documentation to the revised pairing and troubleshooting guidance.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested labels: area: messaging, area: sandbox, area: docs

Suggested reviewers: jyaunches, cv

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR removes the post-pair restart fix instead of restoring a working gateway-session recovery path required by #6413. Implement a bounded post-pair gateway reload/restart path or add a clear host-side recovery flow, while preserving gateway-token isolation.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main change: reverting WhatsApp post-pair gateway restart behavior.
Out of Scope Changes check ✅ Passed The docs, runtime, and test changes all relate to the WhatsApp restart revert and its supporting behavior.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch revert/6496-whatsapp-postpair-reconcile

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

@sandl99 sandl99 added bug-fix PR fixes a bug or regression v0.0.79 Release target labels Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Informational

Merge posture: Informational / low confidence
Primary next action: Resolve or justify PRA-1: PR review advisor unavailable.
Open items: 0 required · 1 warning · 0 suggestions · 1 test follow-up
Top item: PR review advisor unavailable

Action checklist

  • PRA-1 Resolve or justify: PR review advisor unavailable
  • PRA-T1 Add or justify test follow-up: Runtime validation

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify correctness Re-run the PR Review Advisor or perform a manual review.
Review findings by urgency: 0 required fixes, 1 item to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — PR review advisor unavailable

  • Location: not file-specific
  • Category: correctness
  • Problem: The automated advisor could not complete: PR review advisor SDK execution failed: session: scope-risk-map must call pr_review_update_ledger exactly once (observed 5 starts); scope-risk-map must finish pr_review_update_ledger successfully exactly once (observed 1 successful of 5 total completions); turn: scope-risk-map: scope-risk-map must call pr_review_update_ledger exactly once (observed 5 starts); scope-risk-map must finish pr_review_update_ledger successfully exactly once (observed 1 successful of 5 total completions)
  • Impact: Automated review evidence is incomplete, so human review must cover the changed code manually.
  • Recommended action: Re-run the PR Review Advisor or perform a manual review.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the workflow logs and raw advisor artifact for the execution failure.
  • Missing regression test: No regression test recommendation is available because the advisor did not complete.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the workflow logs and raw advisor artifact for the execution failure.
  • Evidence: PR review advisor SDK execution failed: session: scope-risk-map must call pr_review_update_ledger exactly once (observed 5 starts); scope-risk-map must finish pr_review_update_ledger successfully exactly once (observed 1 successful of 5 total completions); turn: scope-risk-map: scope-risk-map must call pr_review_update_ledger exactly once (observed 5 starts); scope-risk-map must finish pr_review_update_ledger successfully exactly once (observed 1 successful of 5 total completions)

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Add or identify targeted runtime/integration validation for the changed behavior; do not report external E2E job pass/fail here.. Runtime/sandbox/infrastructure paths need behavioral runtime validation: docs/manage-sandboxes/messaging-channels.mdx, scripts/nemoclaw-start.sh.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: full-e2e, messaging-providers, issue-4462-scope-upgrade-approval
Optional E2E: whatsapp-qr-compact-e2e, openshell-gateway-auth-contract, test-e2e-gateway-isolation

Dispatch hint: full-e2e,messaging-providers,issue-4462-scope-upgrade-approval

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • full-e2e (high): Required because the PR changes the core sandbox startup script and generated connect-shell runtime environment. This validates a real hosted OpenClaw onboarding/start/connect/inference user flow against the packaged start script.
  • messaging-providers (high): Required because WhatsApp messaging channel behavior and documentation changed. This job exercises real messaging channel add/rebuild/policy/runtime configuration, including WhatsApp QR-only channel parity and placeholder/secret boundaries.
  • issue-4462-scope-upgrade-approval (high): Required because the changed wrapper and runtime env are in the gateway token/device-auth boundary. This live regression validates gateway-token availability, private gateway alias handling, and the non-admin device approval/scope boundary from a real sandbox connect flow.

Optional E2E

  • whatsapp-qr-compact-e2e (medium): Useful adjacent confidence for the WhatsApp in-sandbox login path because the wrapper still forces compact QR rendering, although this PR primarily changes gateway-token/post-pair behavior rather than the QR renderer itself.
  • openshell-gateway-auth-contract (medium): Optional deeper auth-boundary evidence for OpenShell gateway authentication source behavior. The PR does not directly change mTLS/JWT generation, but it changes adjacent gateway token exposure rules.
  • test-e2e-gateway-isolation (medium): Optional image-level hardening backstop for the packaged start script and /tmp/nemoclaw-proxy-env.sh permissions/source hooks before live sandbox flows run.

New E2E recommendations

  • whatsapp-postpair-login-gateway-token-boundary (high): Existing live coverage checks WhatsApp channel add/rebuild/policy and compact QR rendering, but there is no live or hermetic E2E that runs the in-sandbox openclaw channels login --channel whatsapp wrapper against a controlled gateway/login failure and asserts a caller-selected OPENCLAW_GATEWAY_URL never receives OPENCLAW_GATEWAY_TOKEN.
    • Suggested test: Add a focused E2E/regression job that starts or simulates a connect shell with /tmp/nemoclaw-proxy-env.sh, invokes openclaw channels login --channel whatsapp with both the generated private gateway URL and a custom OPENCLAW_GATEWAY_URL, and verifies token forwarding/withholding plus user guidance without requiring a real WhatsApp phone scan.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: full-e2e,messaging-providers,issue-4462-scope-upgrade-approval

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: ubuntu-repo-cloud-openclaw
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-openclaw

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • ubuntu-repo-cloud-openclaw: The PR changes scripts/nemoclaw-start.sh in the OpenClaw sandbox startup/runtime shell environment and WhatsApp gateway-login wrapper path. The live-supported Ubuntu OpenClaw target is the smallest registry target that exercises sandbox startup, gateway wiring, connect/runtime environment, and baseline OpenClaw behavior.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field targets=ubuntu-repo-cloud-openclaw

Optional E2E targets

  • None.

Relevant changed files

  • scripts/nemoclaw-start.sh

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: Keep spoofed/trusted gateway-token boundary regression coverage.
Open items: 0 required · 2 warnings · 0 suggestions · 5 test follow-ups
Since last review: 2 prior items resolved · 0 still apply · 2 new items found

Action checklist

  • PRA-1 Resolve or justify: Keep spoofed/trusted gateway-token boundary regression coverage in test/nemoclaw-start-gateway-ws-host.test.ts:333
  • PRA-2 Resolve or justify: Cover successful WhatsApp login with caller errexit enabled in test/nemoclaw-start-gateway-ws-host.test.ts:333
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Cover successful WhatsApp login with caller errexit enabled
  • PRA-T5 Add or justify test follow-up: Acceptance clause

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify security test/nemoclaw-start-gateway-ws-host.test.ts:333 Add focused tests in the surviving gateway/runtime harness for spoofed mutable private alias plus explicit custom URL, and for the generated private fallback path, asserting custom/spoofed targets remain tokenless and only the intended generated fallback can inherit the ambient token.
PRA-2 Resolve/justify tests test/nemoclaw-start-gateway-ws-host.test.ts:333 Add a focused shell harness case alongside the current WhatsApp token test where the fake `openclaw channels login --channel whatsapp` exits 0 under caller `set -e`; after the wrapper returns, assert the command status is 0 and `case $- in *e*)` still reports `errexit` enabled.
Review findings by urgency: 0 required fixes, 2 items to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Keep spoofed/trusted gateway-token boundary regression coverage

  • Location: test/nemoclaw-start-gateway-ws-host.test.ts:333
  • Category: security
  • Problem: The current code withholds OPENCLAW_GATEWAY_TOKEN when OPENCLAW_GATEWAY_URL is explicitly overridden, but the PR deletes the broader fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 regression suite that also covered spoofing the caller-mutable NEMOCLAW_OPENCLAW_GATEWAY_URL alias and the trusted/generated gateway URL behavior. Without those negative/security cases, future edits to the runtime env or WhatsApp wrapper can accidentally reintroduce token forwarding or misclassify caller-controlled aliases without a focused failing test.
  • Impact: A later refactor could trust the mutable NEMOCLAW alias or forward the ambient gateway token to an attacker-controlled WebSocket endpoint without the security test suite catching the credential-boundary regression.
  • Recommended action: Add focused tests in the surviving gateway/runtime harness for spoofed mutable private alias plus explicit custom URL, and for the generated private fallback path, asserting custom/spoofed targets remain tokenless and only the intended generated fallback can inherit the ambient token.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` around the WhatsApp token test and compare with the deleted fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 cases in the PR diff; the shortest check is whether a test mutates both `OPENCLAW_GATEWAY_URL` and `NEMOCLAW_OPENCLAW_GATEWAY_URL` to an attacker URL and asserts `TOKEN=unset`.
  • Missing regression test: Add a shell harness test that sources the runtime env, sets both `OPENCLAW_GATEWAY_URL` and `NEMOCLAW_OPENCLAW_GATEWAY_URL` to `wss://attacker.example.test:443` with an ambient token, invokes `openclaw channels login --channel whatsapp`, and asserts the stub sees `TOKEN=unset`; add a companion generated-fallback test documenting the token behavior for the private URL.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` around the WhatsApp token test and compare with the deleted fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 cases in the PR diff; the shortest check is whether a test mutates both `OPENCLAW_GATEWAY_URL` and `NEMOCLAW_OPENCLAW_GATEWAY_URL` to an attacker URL and asserts `TOKEN=unset`.
  • Evidence: test/nemoclaw-start-gateway-ws-host.test.ts adds only `withholds the gateway token from caller-selected WhatsApp login gateways (fix(openclaw): restore local CLI pairing path #6291)`, which sets OPENCLAW_GATEWAY_URL to `wss://gateway.example.test:443` and asserts `TOKEN=unset`. The PR deletes `test/repro-6413-whatsapp-postpair-start.test.ts`, including cases named `rejects a caller that spoofs both mutable gateway URL aliases (fix(whatsapp): post-pair gateway restart fails without operator.admin #6413)` and `reconciles against the trusted URL when the caller URL matches it`. scripts/nemoclaw-start.sh still emits caller-mutable `export NEMOCLAW_OPENCLAW_GATEWAY_URL=...` and the WhatsApp wrapper chooses between caller `OPENCLAW_GATEWAY_URL` and that fallback.

PRA-2 Resolve/justify — Cover successful WhatsApp login with caller errexit enabled

  • Location: test/nemoclaw-start-gateway-ws-host.test.ts:333
  • Category: tests
  • Problem: The WhatsApp wrapper now deliberately disables `errexit` around `command openclaw`, captures the login status, conditionally restores `set -e`, and returns the login status. The surviving test covers the nonzero path under `set -euo pipefail`, but there is no focused regression proving the success path restores the caller's `errexit` state and returns 0 after the wrapper's internal `set +e` block.
  • Impact: A future shell edit could leave `errexit` disabled or mishandle the 0-status path after a successful WhatsApp login, changing caller shell semantics without the regression suite failing.
  • Recommended action: Add a focused shell harness case alongside the current WhatsApp token test where the fake `openclaw channels login --channel whatsapp` exits 0 under caller `set -e`; after the wrapper returns, assert the command status is 0 and `case $- in *e*)` still reports `errexit` enabled.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` for WhatsApp login tests and check whether any fake `openclaw` success case asserts the caller's `$-` still contains `e` after the wrapper returns.
  • Missing regression test: A test that sources the runtime env, enables `set -e`, stubs `openclaw` to exit 0, invokes `openclaw channels login --channel whatsapp`, then prints/asserts `STATUS=0` and `ERREXIT=on` after the call.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` for WhatsApp login tests and check whether any fake `openclaw` success case asserts the caller's `$-` still contains `e` after the wrapper returns.
  • Evidence: scripts/nemoclaw-start.sh captures `_nemoclaw_whatsapp_login_errexit`, runs `set +e`, invokes `command openclaw`, then restores `set -e` only when it was previously set before `return $_whatsapp_login_exit`. test/nemoclaw-start-gateway-ws-host.test.ts has `withholds the gateway token from caller-selected WhatsApp login gateways (fix(openclaw): restore local CLI pairing path #6291)` where the fake `openclaw` exits 23 and the harness runs under `set -euo pipefail`. The deleted `test/repro-6413-whatsapp-postpair-start.test.ts` included a successful `errexit` case, but no equivalent surviving test is listed in the static inventory.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Add or identify targeted runtime/integration validation for the changed behavior; do not report external E2E job pass/fail here.. Runtime/sandbox/infrastructure paths need behavioral runtime validation: docs/manage-sandboxes/messaging-channels.mdx, scripts/nemoclaw-start.sh. The PR changes sourced sandbox startup shell behavior and a gateway credential boundary. Existing runtime-ish shell harness coverage proves the explicit custom-gateway token is withheld and the nonzero `set -e` path prints guidance, but two concrete runtime regression gaps remain.
  • PRA-T2 Runtime validation — Add a shell harness test that sources the runtime env, sets both `OPENCLAW_GATEWAY_URL` and `NEMOCLAW_OPENCLAW_GATEWAY_URL` to `wss://attacker.example.test:443` with an ambient token, invokes `openclaw channels login --channel whatsapp`, and asserts the stub sees `TOKEN=unset`; add a companion generated-fallback test documenting the token behavior for the private URL.. Runtime/sandbox/infrastructure paths need behavioral runtime validation: docs/manage-sandboxes/messaging-channels.mdx, scripts/nemoclaw-start.sh. The PR changes sourced sandbox startup shell behavior and a gateway credential boundary. Existing runtime-ish shell harness coverage proves the explicit custom-gateway token is withheld and the nonzero `set -e` path prints guidance, but two concrete runtime regression gaps remain.
  • PRA-T3 Runtime validation — Add a test that sources the runtime env, enables `set -e`, stubs `openclaw` to exit 0, invokes `openclaw channels login --channel whatsapp`, then prints/asserts `STATUS=0` and `ERREXIT=on` after the call.. Runtime/sandbox/infrastructure paths need behavioral runtime validation: docs/manage-sandboxes/messaging-channels.mdx, scripts/nemoclaw-start.sh. The PR changes sourced sandbox startup shell behavior and a gateway credential boundary. Existing runtime-ish shell harness coverage proves the explicit custom-gateway token is withheld and the nonzero `set -e` path prints guidance, but two concrete runtime regression gaps remain.
  • PRA-T4 Cover successful WhatsApp login with caller errexit enabled — Add a focused shell harness case alongside the current WhatsApp token test where the fake `openclaw channels login --channel whatsapp` exits 0 under caller `set -e`; after the wrapper returns, assert the command status is 0 and `case $- in *e*)` still reports `errexit` enabled.
  • PRA-T5 Acceptance clause — Reopens fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 — add test evidence or identify existing coverage. The PR body states this relationship, but the review context returned `linkedIssues: []`, so no linked issue body or comments were available to map literally.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Keep spoofed/trusted gateway-token boundary regression coverage

  • Location: test/nemoclaw-start-gateway-ws-host.test.ts:333
  • Category: security
  • Problem: The current code withholds OPENCLAW_GATEWAY_TOKEN when OPENCLAW_GATEWAY_URL is explicitly overridden, but the PR deletes the broader fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 regression suite that also covered spoofing the caller-mutable NEMOCLAW_OPENCLAW_GATEWAY_URL alias and the trusted/generated gateway URL behavior. Without those negative/security cases, future edits to the runtime env or WhatsApp wrapper can accidentally reintroduce token forwarding or misclassify caller-controlled aliases without a focused failing test.
  • Impact: A later refactor could trust the mutable NEMOCLAW alias or forward the ambient gateway token to an attacker-controlled WebSocket endpoint without the security test suite catching the credential-boundary regression.
  • Recommended action: Add focused tests in the surviving gateway/runtime harness for spoofed mutable private alias plus explicit custom URL, and for the generated private fallback path, asserting custom/spoofed targets remain tokenless and only the intended generated fallback can inherit the ambient token.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` around the WhatsApp token test and compare with the deleted fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 cases in the PR diff; the shortest check is whether a test mutates both `OPENCLAW_GATEWAY_URL` and `NEMOCLAW_OPENCLAW_GATEWAY_URL` to an attacker URL and asserts `TOKEN=unset`.
  • Missing regression test: Add a shell harness test that sources the runtime env, sets both `OPENCLAW_GATEWAY_URL` and `NEMOCLAW_OPENCLAW_GATEWAY_URL` to `wss://attacker.example.test:443` with an ambient token, invokes `openclaw channels login --channel whatsapp`, and asserts the stub sees `TOKEN=unset`; add a companion generated-fallback test documenting the token behavior for the private URL.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` around the WhatsApp token test and compare with the deleted fix(whatsapp): post-pair gateway restart fails without operator.admin #6413 cases in the PR diff; the shortest check is whether a test mutates both `OPENCLAW_GATEWAY_URL` and `NEMOCLAW_OPENCLAW_GATEWAY_URL` to an attacker URL and asserts `TOKEN=unset`.
  • Evidence: test/nemoclaw-start-gateway-ws-host.test.ts adds only `withholds the gateway token from caller-selected WhatsApp login gateways (fix(openclaw): restore local CLI pairing path #6291)`, which sets OPENCLAW_GATEWAY_URL to `wss://gateway.example.test:443` and asserts `TOKEN=unset`. The PR deletes `test/repro-6413-whatsapp-postpair-start.test.ts`, including cases named `rejects a caller that spoofs both mutable gateway URL aliases (fix(whatsapp): post-pair gateway restart fails without operator.admin #6413)` and `reconciles against the trusted URL when the caller URL matches it`. scripts/nemoclaw-start.sh still emits caller-mutable `export NEMOCLAW_OPENCLAW_GATEWAY_URL=...` and the WhatsApp wrapper chooses between caller `OPENCLAW_GATEWAY_URL` and that fallback.

PRA-2 Resolve/justify — Cover successful WhatsApp login with caller errexit enabled

  • Location: test/nemoclaw-start-gateway-ws-host.test.ts:333
  • Category: tests
  • Problem: The WhatsApp wrapper now deliberately disables `errexit` around `command openclaw`, captures the login status, conditionally restores `set -e`, and returns the login status. The surviving test covers the nonzero path under `set -euo pipefail`, but there is no focused regression proving the success path restores the caller's `errexit` state and returns 0 after the wrapper's internal `set +e` block.
  • Impact: A future shell edit could leave `errexit` disabled or mishandle the 0-status path after a successful WhatsApp login, changing caller shell semantics without the regression suite failing.
  • Recommended action: Add a focused shell harness case alongside the current WhatsApp token test where the fake `openclaw channels login --channel whatsapp` exits 0 under caller `set -e`; after the wrapper returns, assert the command status is 0 and `case $- in *e*)` still reports `errexit` enabled.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` for WhatsApp login tests and check whether any fake `openclaw` success case asserts the caller's `$-` still contains `e` after the wrapper returns.
  • Missing regression test: A test that sources the runtime env, enables `set -e`, stubs `openclaw` to exit 0, invokes `openclaw channels login --channel whatsapp`, then prints/asserts `STATUS=0` and `ERREXIT=on` after the call.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `test/nemoclaw-start-gateway-ws-host.test.ts` for WhatsApp login tests and check whether any fake `openclaw` success case asserts the caller's `$-` still contains `e` after the wrapper returns.
  • Evidence: scripts/nemoclaw-start.sh captures `_nemoclaw_whatsapp_login_errexit`, runs `set +e`, invokes `command openclaw`, then restores `set -e` only when it was previously set before `return $_whatsapp_login_exit`. test/nemoclaw-start-gateway-ws-host.test.ts has `withholds the gateway token from caller-selected WhatsApp login gateways (fix(openclaw): restore local CLI pairing path #6291)` where the fake `openclaw` exits 23 and the harness runs under `set -euo pipefail`. The deleted `test/repro-6413-whatsapp-postpair-start.test.ts` included a successful `errexit` case, but no equivalent surviving test is listed in the static inventory.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

sandl99 added 2 commits July 9, 2026 19:05
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@src/lib/actions/sandbox/mcp-bridge-status-resolution.test.ts`:
- Around line 16-17: Keep the harness timeout ordering fixed by ensuring
HARNESS_PROCESS_TIMEOUT_MS remains below the Vitest timeout used in
HARNESS_TEST_OPTIONS. In mcp-bridge-status-resolution.test.ts, adjust the setup
around execTimeout() and testTimeoutOptions() so both derive from one shared
budget or add an explicit guard that prevents NEMOCLAW_EXEC_TIMEOUT from
exceeding NEMOCLAW_TEST_TIMEOUT. Use the HARNESS_PROCESS_TIMEOUT_MS and
HARNESS_TEST_OPTIONS constants as the anchor points for the fix.
🪄 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: Enterprise

Run ID: 7f321b35-b02b-47a3-9f08-6d1a0148dd40

📥 Commits

Reviewing files that changed from the base of the PR and between 280d901 and c1a6436.

📒 Files selected for processing (1)
  • src/lib/actions/sandbox/mcp-bridge-status-resolution.test.ts

Comment thread src/lib/actions/sandbox/mcp-bridge-status-resolution.test.ts Outdated
sandl99 added 2 commits July 9, 2026 19:54
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@test/nemoclaw-start-gateway-ws-host.test.ts`:
- Around line 327-385: The test in the WhatsApp gateway login case is not
actually verifying token withholding because OPENCLAW_GATEWAY_TOKEN is never
seeded, so the unset value can pass trivially. Update the test setup in the
`it("withholds the gateway token from caller-selected WhatsApp login gateways
(`#6291`)")` block to export a known token before invoking `openclaw channels
login --channel whatsapp`, then assert that the spawned `openclaw` process in
the fake bin sees `TOKEN=unset` and does not receive the seeded token. Keep the
existing checks around `writeRuntimeShellEnv`, `spawnSync`, and the call log so
the test still validates the gateway URL and insecure flag behavior.
🪄 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: Enterprise

Run ID: 8b200b08-4176-4ca7-94ef-c011827c5f91

📥 Commits

Reviewing files that changed from the base of the PR and between c1a6436 and 110bfcf.

📒 Files selected for processing (3)
  • scripts/nemoclaw-start.sh
  • src/lib/actions/sandbox/mcp-bridge-status-resolution.test.ts
  • test/nemoclaw-start-gateway-ws-host.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/actions/sandbox/mcp-bridge-status-resolution.test.ts
  • scripts/nemoclaw-start.sh

Comment on lines +327 to +385
it("withholds the gateway token from caller-selected WhatsApp login gateways (#6291)", () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-whatsapp-custom-gw-"));
try {
const runtimeEnv = writeRuntimeShellEnv(tmpDir);
const fakeBin = path.join(tmpDir, "bin");
const callLog = path.join(tmpDir, "openclaw-call.log");
fs.mkdirSync(fakeBin);
fs.writeFileSync(
path.join(fakeBin, "openclaw"),
`#!/usr/bin/env bash
{
printf 'ARGS=%s\n' "$*"
printf 'URL=%s\n' "\${OPENCLAW_GATEWAY_URL-unset}"
printf 'INSECURE=%s\n' "\${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS-unset}"
printf 'TOKEN=%s\n' "\${OPENCLAW_GATEWAY_TOKEN-unset}"
} > ${JSON.stringify(callLog)}
exit 23
`,
{ mode: 0o755 },
);

const result = spawnSync(
"bash",
[
"--noprofile",
"--norc",
"-c",
[
"set -euo pipefail",
`. ${JSON.stringify(runtimeEnv)}`,
"OPENCLAW_GATEWAY_URL=wss://gateway.example.test:443",
"OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=explicit-marker",
"openclaw channels login --channel whatsapp",
].join("\n"),
],
{
encoding: "utf-8",
timeout: 5000,
env: {
...process.env,
PATH: `${fakeBin}:${process.env.PATH ?? ""}`,
NODE_OPTIONS: "",
},
},
);

expect(result.status, result.stderr || result.stdout).toBe(23);
expect(result.stderr).toContain("Pairing exited with code 23 before it completed");
const call = fs.readFileSync(callLog, "utf-8");
expect(call).toContain("ARGS=channels login --channel whatsapp");
expect(call).toContain("URL=wss://gateway.example.test:443");
expect(call).toContain("INSECURE=explicit-marker");
expect(call).toContain("TOKEN=unset");
expect(call).not.toContain("test-gateway-token");
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## test/nemoclaw-start-gateway-ws-host.test.ts (relevant range)\n'
sed -n '327,385p' test/nemoclaw-start-gateway-ws-host.test.ts

printf '\n## search for OPENCLAW_GATEWAY_TOKEN usage in tests and scripts\n'
rg -n "OPENCLAW_GATEWAY_TOKEN|withholds the gateway token|clears the gateway token" test scripts -S

printf '\n## scripts/nemoclaw-start.sh around gateway unset logic\n'
rg -n "unset OPENCLAW_GATEWAY_TOKEN|_nemoclaw_whatsapp_gateway_url_from_override|OPENCLAW_GATEWAY_URL" scripts/nemoclaw-start.sh -n -S
sed -n '3430,3505p' scripts/nemoclaw-start.sh

Repository: NVIDIA/NemoClaw

Length of output: 2014


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('test/nemoclaw-start-gateway-ws-host.test.ts')
text = p.read_text()
print('OPENCLAW_GATEWAY_TOKEN set in this test:', 'OPENCLAW_GATEWAY_TOKEN=' in text[text.find('withholds the gateway token'):text.find('finally')])
PY

Repository: NVIDIA/NemoClaw

Length of output: 2014


Seed a known gateway token before checking it gets withheld

This test never sets OPENCLAW_GATEWAY_TOKEN, so TOKEN=unset and not.toContain("test-gateway-token") can pass without exercising the clearing path. Export a token first, then assert it is removed when the caller selects a gateway URL.

Suggested setup
             "set -euo pipefail",
             `. ${JSON.stringify(runtimeEnv)}`,
+            "OPENCLAW_GATEWAY_TOKEN=test-gateway-token",
             "OPENCLAW_GATEWAY_URL=wss://gateway.example.test:443",
             "OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=explicit-marker",
             "openclaw channels login --channel whatsapp",
📝 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
it("withholds the gateway token from caller-selected WhatsApp login gateways (#6291)", () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-whatsapp-custom-gw-"));
try {
const runtimeEnv = writeRuntimeShellEnv(tmpDir);
const fakeBin = path.join(tmpDir, "bin");
const callLog = path.join(tmpDir, "openclaw-call.log");
fs.mkdirSync(fakeBin);
fs.writeFileSync(
path.join(fakeBin, "openclaw"),
`#!/usr/bin/env bash
{
printf 'ARGS=%s\n' "$*"
printf 'URL=%s\n' "\${OPENCLAW_GATEWAY_URL-unset}"
printf 'INSECURE=%s\n' "\${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS-unset}"
printf 'TOKEN=%s\n' "\${OPENCLAW_GATEWAY_TOKEN-unset}"
} > ${JSON.stringify(callLog)}
exit 23
`,
{ mode: 0o755 },
);
const result = spawnSync(
"bash",
[
"--noprofile",
"--norc",
"-c",
[
"set -euo pipefail",
`. ${JSON.stringify(runtimeEnv)}`,
"OPENCLAW_GATEWAY_URL=wss://gateway.example.test:443",
"OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=explicit-marker",
"openclaw channels login --channel whatsapp",
].join("\n"),
],
{
encoding: "utf-8",
timeout: 5000,
env: {
...process.env,
PATH: `${fakeBin}:${process.env.PATH ?? ""}`,
NODE_OPTIONS: "",
},
},
);
expect(result.status, result.stderr || result.stdout).toBe(23);
expect(result.stderr).toContain("Pairing exited with code 23 before it completed");
const call = fs.readFileSync(callLog, "utf-8");
expect(call).toContain("ARGS=channels login --channel whatsapp");
expect(call).toContain("URL=wss://gateway.example.test:443");
expect(call).toContain("INSECURE=explicit-marker");
expect(call).toContain("TOKEN=unset");
expect(call).not.toContain("test-gateway-token");
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
});
"set -euo pipefail",
`. ${JSON.stringify(runtimeEnv)}`,
"OPENCLAW_GATEWAY_TOKEN=test-gateway-token",
"OPENCLAW_GATEWAY_URL=wss://gateway.example.test:443",
"OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=explicit-marker",
"openclaw channels login --channel whatsapp",
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 333-345: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.writeFileSync(
path.join(fakeBin, "openclaw"),
#!/usr/bin/env bash { printf 'ARGS=%s\n' "$*" printf 'URL=%s\n' "\${OPENCLAW_GATEWAY_URL-unset}" printf 'INSECURE=%s\n' "\${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS-unset}" printf 'TOKEN=%s\n' "\${OPENCLAW_GATEWAY_TOKEN-unset}" } > ${JSON.stringify(callLog)} exit 23 ,
{ mode: 0o755 },
)
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename-typescript)


[warning] 374-374: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(callLog, "utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename-typescript)

🤖 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 `@test/nemoclaw-start-gateway-ws-host.test.ts` around lines 327 - 385, The test
in the WhatsApp gateway login case is not actually verifying token withholding
because OPENCLAW_GATEWAY_TOKEN is never seeded, so the unset value can pass
trivially. Update the test setup in the `it("withholds the gateway token from
caller-selected WhatsApp login gateways (`#6291`)")` block to export a known token
before invoking `openclaw channels login --channel whatsapp`, then assert that
the spawned `openclaw` process in the fake bin sees `TOKEN=unset` and does not
receive the seeded token. Keep the existing checks around
`writeRuntimeShellEnv`, `spawnSync`, and the call log so the test still
validates the gateway URL and insecure flag behavior.

Source: Path instructions

@sandl99 sandl99 closed this Jul 9, 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 v0.0.79 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(whatsapp): post-pair gateway restart fails without operator.admin

1 participant