Skip to content

fix(cli): show SSH port-forward hint for remote dashboard access (#5925)#5929

Open
atulya-singh wants to merge 2 commits into
NVIDIA:mainfrom
atulya-singh:fix/5925-ssh-port-forward-hint
Open

fix(cli): show SSH port-forward hint for remote dashboard access (#5925)#5929
atulya-singh wants to merge 2 commits into
NVIDIA:mainfrom
atulya-singh:fix/5925-ssh-port-forward-hint

Conversation

@atulya-singh

@atulya-singh atulya-singh commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Summary

When NemoClaw runs inside an SSH session, the dashboard URL binds to 127.0.0.1 on the remote host and is unreachable from the operator's workstation browser without a port forward. The post-onboard summary and dashboard-url output now print a copy-pastable ssh -L <port>:127.0.0.1:<port> <user>@<host> example, and the Quickstart and remote-GPU deploy docs cross-reference the same command.

Related Issue

Fixes #5925

Changes

  • Add pure helper src/lib/onboard/ssh-forward-hint.ts:
    • isSshSession() detects SSH_CONNECTION / SSH_CLIENT / SSH_TTY.
    • buildSshForwardHintLines() derives the host from the SSH_CONNECTION server-IP field and the user from USER/LOGNAME, returning a copy-pastable ssh -L block. Returns null outside an SSH session or when the dashboard already binds a routable address (WSL fallback, NEMOCLAW_DASHBOARD_BIND=0.0.0.0). Unsafe usernames fall back to <user>; an unknown host falls back to <host>.
  • src/lib/dashboard-url-command.ts: append the hint to non-quiet output (both token and session-auth paths); suppressed under --quiet so scripted consumers still get exactly one line.
  • src/lib/onboard/dashboard.ts: printDashboard shows the hint in the post-onboard "is ready" summary (covers OpenClaw and agent dashboards).
  • Docs: new "Open the Dashboard When You SSH'd into a Remote Host" subsection in docs/get-started/quickstart.mdx, and a copy-pastable ssh -L command in docs/deployment/deploy-to-remote-gpu.mdx (Remote Dashboard Access).
  • Tests: ssh-forward-hint.test.ts (8 cases) plus 3 new dashboard-url-command.test.ts cases (hint over SSH, absent without SSH, suppressed under --quiet).

The hint only ever references loopback forwarding; it does not suggest binding to 0.0.0.0, and it points to the already-printed dashboard URL rather than reprinting the tokenized URL, so it does not duplicate the secret token.

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)

Signed-off-by: Atulya Singh atulyarajsingh@gmail.com

Summary by CodeRabbit

  • New Features

    • Added SSH port-forwarding guidance for dashboard access when running inside an SSH session.
    • Dashboard onboarding now can display copy-pastable ssh -L instructions when needed.
  • Bug Fixes

    • Dashboard URL command output now includes the correct remote access hint when applicable, and omits it in quiet mode or when forwarding isn’t required.
    • Improved SSH-session detection so guidance appears reliably.
  • Documentation

    • Updated quickstart and remote GPU deployment guide with clearer local workstation access steps and ssh -L examples.
  • Tests

    • Added coverage for SSH hint generation and session detection behavior.

…DIA#5925)

Signed-off-by: Atulya Singh <atulyarajsingh@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Jun 28, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c1740f0f-ca50-4529-9f9c-2e00673333d3

📥 Commits

Reviewing files that changed from the base of the PR and between 9191002 and 9be161a.

📒 Files selected for processing (5)
  • docs/deployment/deploy-to-remote-gpu.mdx
  • src/lib/dashboard-url-command.test.ts
  • src/lib/onboard/dashboard.ts
  • src/lib/onboard/ssh-forward-hint.test.ts
  • src/lib/onboard/ssh-forward-hint.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/deployment/deploy-to-remote-gpu.mdx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/onboard/ssh-forward-hint.ts
  • src/lib/onboard/dashboard.ts
  • src/lib/onboard/ssh-forward-hint.test.ts

📝 Walkthrough

Walkthrough

Adds SSH-session detection and copy-pastable ssh -L hint generation for dashboard access, wires it into dashboard-url and onboarding output, and updates quickstart and deployment docs with matching remote-SSH instructions.

Changes

SSH Port-Forward Hint

Layer / File(s) Summary
ssh-forward-hint module and tests
src/lib/onboard/ssh-forward-hint.ts, src/lib/onboard/ssh-forward-hint.test.ts
New module exports isSshSession and buildSshForwardHintLines, parses SSH connection details, sanitizes the username, checks whether forwarding is needed from the access URL, and returns formatted hint lines or null. Tests cover SSH detection, formatting, placeholders, sanitization, custom formatting, and non-forwarding cases.
dashboard-url command integration
src/lib/dashboard-url-command.ts, src/lib/dashboard-url-command.test.ts
DashboardUrlCommandDeps gains optional env; a local helper calls buildSshForwardHintLines and prints the hint block when present. The helper is invoked in both the plain URL and token-based output paths. Tests cover SSH-session output, session-auth behavior, no-hint output without SSH env, and quiet-mode suppression.
onboard dashboard output
src/lib/onboard/dashboard.ts
OnboardDashboardDeps gains optional env, and printDashboard computes SSH hint lines from chain.port and chain.accessUrl before the existing “Manage later” output.
Quickstart and deployment docs
docs/get-started/quickstart.mdx, docs/deployment/deploy-to-remote-gpu.mdx
Quickstart adds a remote-SSH dashboard subsection with loopback binding explanation and an ssh -L example. The deployment guide adds matching remote dashboard port-forwarding instructions and references the CLI output flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

area: cli, area: onboarding, area: docs, bug-fix

Suggested reviewers

  • cjagwani
  • cv
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% 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 is specific and accurately describes the main CLI UX change for SSH port-forward hints.
Linked Issues check ✅ Passed The PR adds SSH port-forward hints to dashboard-url and onboarding output, plus matching docs, as requested.
Out of Scope Changes check ✅ Passed The code and docs changes stay focused on remote dashboard access and supporting tests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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: 3

🧹 Nitpick comments (1)
src/lib/dashboard-url-command.test.ts (1)

88-138: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a non-quiet assertion for the session/none branch.

These cases only exercise the tokenized URL path. runDashboardUrlCommand now prints the SSH hint in the plain-URL branch too, but the visible session coverage is still quiet-only, so a regression there would slip through.

🤖 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 `@src/lib/dashboard-url-command.test.ts` around lines 88 - 138, The test
coverage for runDashboardUrlCommand is missing a non-quiet assertion for the
plain-URL path when no tokenized session is used, so add a case that exercises
the session/none branch with quiet false and verifies the SSH hint is printed
there too. Update the dashboard URL command tests around runDashboardUrlCommand
and makeSinks to assert the Remote access SSH hint appears in the non-quiet
plain-URL output, while keeping the quiet-mode behavior unchanged.
🤖 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 `@docs/deployment/deploy-to-remote-gpu.mdx`:
- Line 154: Split the combined sentence in the deployment guide into two
separate source lines to follow the one-sentence-per-line MDX rule. Update the
surrounding prose in the deployment section so the first sentence about running
nemoclaw over SSH and the command output stands alone, and the second sentence
about opening the dashboard URL on your workstation is on its own line.

In `@src/lib/onboard/dashboard.ts`:
- Around line 496-499: Pass env explicitly into buildSshForwardHintLines from
this OnboardDashboard flow instead of letting it read process.env implicitly.
Thread env through OnboardDashboardDeps here the same way dashboard-url already
does, and update the call site in the dashboard summary rendering so the SSH
hint stays deterministic and testable. Also make sure any related SSH hint or
detection helpers use the passed env argument rather than ambient shell state.

In `@src/lib/onboard/ssh-forward-hint.ts`:
- Around line 27-37: The helper serverAddressFromSshConnection should not derive
the SSH destination from SSH_CONNECTION, since it only exposes the remote socket
address and loses the original host, port, aliases, and ProxyJump details.
Update the ssh-forward-hint flow to return a placeholder unless the caller can
pass the original destination string explicitly, and keep
serverAddressFromSshConnection limited to fallback behavior rather than
constructing the ssh -L example target.

---

Nitpick comments:
In `@src/lib/dashboard-url-command.test.ts`:
- Around line 88-138: The test coverage for runDashboardUrlCommand is missing a
non-quiet assertion for the plain-URL path when no tokenized session is used, so
add a case that exercises the session/none branch with quiet false and verifies
the SSH hint is printed there too. Update the dashboard URL command tests around
runDashboardUrlCommand and makeSinks to assert the Remote access SSH hint
appears in the non-quiet plain-URL output, while keeping the quiet-mode behavior
unchanged.
🪄 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: e1935265-b6a6-458e-8355-ff9cab336012

📥 Commits

Reviewing files that changed from the base of the PR and between 4db5d5d and 9191002.

📒 Files selected for processing (7)
  • docs/deployment/deploy-to-remote-gpu.mdx
  • docs/get-started/quickstart.mdx
  • src/lib/dashboard-url-command.test.ts
  • src/lib/dashboard-url-command.ts
  • src/lib/onboard/dashboard.ts
  • src/lib/onboard/ssh-forward-hint.test.ts
  • src/lib/onboard/ssh-forward-hint.ts

Comment thread docs/deployment/deploy-to-remote-gpu.mdx Outdated
Comment thread src/lib/onboard/dashboard.ts
Comment thread src/lib/onboard/ssh-forward-hint.ts Outdated
Comment on lines +27 to +37
* Resolve the server (this host) address from `SSH_CONNECTION`, whose format is
* `<client-ip> <client-port> <server-ip> <server-port>`. The third field is the
* address the operator SSH'd into, which is exactly what belongs in the
* `ssh -L` example. Returns null when unset or malformed so callers can fall
* back to a placeholder.
*/
function serverAddressFromSshConnection(value: string | undefined): string | null {
if (!value) return null;
const parts = value.trim().split(/\s+/).filter(Boolean);
const serverIp = parts[2];
return serverIp && serverIp.length > 0 ? serverIp : null;

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

Do not turn SSH_CONNECTION into the SSH destination.

SSH_CONNECTION only gives you the remote socket address. It does not preserve the original host token, -p port, ProxyJump, or any SSH config alias, so the generated ssh -L ... ${user}@${host} command is not reliably copy-pastable for the very sessions this feature targets. Use a placeholder unless the caller can provide the original destination string explicitly.

Also applies to: 89-97

🤖 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 `@src/lib/onboard/ssh-forward-hint.ts` around lines 27 - 37, The helper
serverAddressFromSshConnection should not derive the SSH destination from
SSH_CONNECTION, since it only exposes the remote socket address and loses the
original host, port, aliases, and ProxyJump details. Update the ssh-forward-hint
flow to return a placeholder unless the caller can pass the original destination
string explicitly, and keep serverAddressFromSshConnection limited to fallback
behavior rather than constructing the ssh -L example target.

Signed-off-by: Atulya Singh <atulyarajsingh@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant