Skip to content

fix(dashboard): guide users to manual token auth when delivery channels fail#72802

Merged
BunsDev merged 7 commits intoopenclaw:mainfrom
praveen9354:fix/dashboard-tokenized-url-fallback-72081
May 4, 2026
Merged

fix(dashboard): guide users to manual token auth when delivery channels fail#72802
BunsDev merged 7 commits intoopenclaw:mainfrom
praveen9354:fix/dashboard-tokenized-url-fallback-72081

Conversation

@praveen9354
Copy link
Copy Markdown
Contributor

Summary

  • When openclaw dashboard cannot deliver the token-authenticated URL via either clipboard or browser auto-open, the user is now logged a CVE-safe self-recovery hint pointing to OPENCLAW_GATEWAY_TOKEN and gateway.auth.token.
  • No token value or #token= fragment marker is ever written to runtime logs — the existing CVE regression tests (dashboard.links.test.ts:101, :144) continue to enforce that contract on the success and SSH paths.
  • New regression test pins the contract: in the combined-failure scenario, the token must not appear in logs AND the user must be pointed at the env var so they can self-recover.

Fixes #72081.

Why

The reporter ran openclaw dashboard on WSL2 OpenEuler and saw only Dashboard URL: http://... (no token). Both delivery channels — clipboard and browser auto-open — fail in many WSL/headless/SSH environments. The previous fix (eaf6d3c146, commit fix(dashboard): keep bearer token out of runtime logs) correctly removed the token from logs to remediate a CVE, but it didn't account for the case where neither clipboard nor browser succeeds — leaving headless users stranded with no path to authenticate.

This change preserves the CVE fix exactly. It only adds a guidance hint when the delivery actually fails, telling the user where their token lives so they can manually append it as a URL fragment. The token itself never enters the log stream.

Why this scope

  • CVE-safe by design. The new hint never logs the token value or the #token= substring (which the existing CVE tests forbid). It logs only the well-known config/env names.
  • Owner-local. Touches only src/commands/dashboard.ts and its test — no shared SDK seam, no plugin runtime, no security helper changes.
  • Single condition gates everything. !copied && !opened && includeTokenInUrl covers both --no-open + clipboard fail and the default clipboard fail + browser fail paths.

Test plan

  • pnpm test src/commands/dashboard.links.test.ts src/commands/dashboard.test.ts — 14/14 passing (10 in dashboard.links.test.ts including new + 2 CVE regression tests, 4 in dashboard.test.ts)
  • pnpm check:changed — typecheck, lint, cycles, webhook/auth/pairing guards all clean
  • Manual repro on a real WSL2 instance — not run; recommend reviewer or follow-up tester verifies the new hint appears in a real WSL invocation when clipboard/browser both fail

AI-assisted

Built with Claude Code (Opus 4.7, 1M context). Lightly tested — unit and changed-lane gates pass; live behavior on a real WSL/headless system not directly verified. I understand what the code does: see "Why" above.

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle Bot added commands Command implementations size: XS labels Apr 27, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

Adds a CVE-safe recovery hint to dashboardCommand that fires when both clipboard copy and browser auto-open fail and the token URL was intended for delivery. The hint correctly avoids logging the token value or the populated fragment string, and a new regression test pins the contract.

Two P2 observations worth considering before merging:

  • The hint message tells users to "append as a URL fragment" but omits the fragment key name, which may leave headless users uncertain about the exact URL syntax needed.
  • The condition !copied && !opened && includeTokenInUrl also triggers when --no-open is used and clipboard fails, producing two simultaneous hints whose combined message could be slightly misleading.

Confidence Score: 4/5

Safe to merge; only P2 UX and coverage concerns, no runtime defects introduced.

The change is small and well-targeted. No P0 or P1 bugs were found. The two P2 observations (missing fragment key name in hint, and double-hint in --no-open + clipboard-fail path) are UX and coverage issues, not correctness defects. CVE safety contract is preserved by both the implementation and the updated test suite.

No files require special attention; src/commands/dashboard.ts lines 95–99 are the only new logic and both concerns relate to that block.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/commands/dashboard.ts
Line: 95-99

Comment:
**Hint fires in `--no-open` + clipboard-fail path too**

When a user explicitly passes `--no-open`, `opened` is always `false` (never assigned in the `noOpen` branch), so if clipboard also fails, this block fires alongside the existing `--no-open` hint ("Browser launch disabled (--no-open). Use the URL above."). The user sees two partially contradictory messages: one telling them to use the bare URL above, and one telling them to manually construct the fragment URL. The existing test at line 201 doesn't assert absence of the new hint, so this goes undetected.

If the intent is for the hint to fire in the `--no-open` scenario as well (the PR description says it does), it would be worth adding a test covering that scenario explicitly, and confirming the two messages together make sense.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/commands/dashboard.ts
Line: 95-99

Comment:
**Hint omits the URL fragment key name**

The message says "append your gateway token… as a URL fragment" but doesn't name the key (`token`). A headless user who hasn't seen the source will need to guess or consult docs to construct the correct fragment. The CVE constraint prohibits logging an actual secret value, but logging only the key name — with an explicit placeholder and no real value — carries no credential risk and would not trigger the existing CVE assertions.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(dashboard): guide users to manual to..." | Re-trigger Greptile

Comment thread src/commands/dashboard.ts Outdated
Comment thread src/commands/dashboard.ts Outdated
@praveen9354
Copy link
Copy Markdown
Contributor Author

Addressed both P2 observations in commit 1204cc61b9:

P2-1 — fragment key name: the hint now names the URL fragment key (`token`) explicitly so headless users know the URL syntax. The literal #token= substring is still avoided to keep the existing CVE regression tests at dashboard.links.test.ts:121 and :165 passing — the new wording uses backticks around the key name and a paraphrase of the fragment placement, which is unambiguous to humans without spelling out the forbidden substring.

P2-2 — double hint in --no-open + clipboard-fail: named the state (fallbackToManualAuth) and added a suppressNoOpenHint gate so the redundant "Browser launch disabled (--no-open). Use the URL above." is suppressed when the manual-auth hint speaks for that scenario. The SSH-path hint is preserved (its info — port forwarding — is complementary, not redundant).

Test coverage updated:

  • New assertion in the CVE-safe test pins that the hint contains the literal substring `token` (key name).
  • The pre-existing respects --no-open with plain URL hint when clipboard fails test was split into two: one for the token-configured case (now asserts suppression + manual-auth hint), and a preserved one for the no-token case (still expects "Use the URL above.").

All CVE regression tests still pass; 11/11 in dashboard.links.test.ts, 4/4 in dashboard.test.ts, full pnpm check:changed is green.

@praveen9354
Copy link
Copy Markdown
Contributor Author

Thanks for the QC review. Both non-blocking suggestions were independently raised by @greptile-apps and addressed in commit 1204cc61b9:

  • Fragment key name — the hint now includes key `token` so headless users know the URL syntax. The literal #token= substring is intentionally avoided to keep the existing CVE regression tests at dashboard.links.test.ts:121 and :165 passing.
  • --no-open message dedupsuppressNoOpenHint is now gated on options.noOpen === true && fallbackToManualAuth, so the redundant "Browser launch disabled (--no-open). Use the URL above." is suppressed when the manual-auth hint speaks for that scenario. The SSH-path hint is preserved (its info is complementary, not redundant).

pnpm test src/commands/dashboard.links.test.ts src/commands/dashboard.test.ts passes 15/15, including the existing CVE regression tests and a new no-token-preservation test.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 27, 2026

Both addresses look correct.

The key \token`literal in the hint message threads the needle well — it tells headless users the URL syntax without triggering the CVE regression on#token=`. The test at line 184 pins that contract explicitly.

The suppressNoOpenHint logic is also clean: it's scoped to options.noOpen === true && fallbackToManualAuth, so the SSH-path hint (which comes from formatControlUiSshHintMock and takes the same hint && branch) is unaffected — options.noOpen won't be true on that path.

The split of the old --no-open test into token-configured vs. no-token-configured cases is a nice touch too; the coverage is now unambiguous.

LGTM. No further concerns.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules and .greptile/config.

Re-review progress:

@praveen9354 praveen9354 force-pushed the fix/dashboard-tokenized-url-fallback-72081 branch from 1204cc6 to f6d0f71 Compare April 30, 2026 15:31
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 30, 2026

Codex review: needs maintainer review before merge.

Summary
The PR adds a dashboard CLI manual-auth fallback hint, regression tests, and a changelog entry for tokenized URL delivery failures.

Reproducibility: yes. Source inspection gives a high-confidence path: configure a literal gateway.auth.token or OPENCLAW_GATEWAY_TOKEN, make clipboard delivery fail, and make browser opening unavailable or pass --no-open; current main logs the bare dashboard URL without token-source or fragment-key recovery guidance.

Next step before merge
No repair PR is needed because this PR already contains the focused implementation; the remaining action is maintainer review plus exact-head validation.

Security
Cleared: Cleared: the diff only changes dashboard CLI logging, regression tests, and changelog text, with no dependency, workflow, install, release, or secret-value logging expansion.

Review details

Best possible solution:

Land this focused dashboard-command fix after maintainer review and exact-head validation, preserving token redaction while giving headless and WSL users a manual auth path.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection gives a high-confidence path: configure a literal gateway.auth.token or OPENCLAW_GATEWAY_TOKEN, make clipboard delivery fail, and make browser opening unavailable or pass --no-open; current main logs the bare dashboard URL without token-source or fragment-key recovery guidance.

Is this the best way to solve the issue?

Yes. The proposed fix stays in src/commands/dashboard.ts, fires only when tokenized delivery failed, deduplicates the --no-open fallback, and preserves the existing log-redaction contract with regression tests.

Acceptance criteria:

  • pnpm test src/commands/dashboard.links.test.ts src/commands/dashboard.test.ts
  • pnpm check:changed

What I checked:

  • Current main delivery gap: Current main builds a tokenized dashboardUrl for clipboard/browser delivery but logs only the clean Dashboard URL, then logs only the existing SSH or --no-open hint when copy/open fails; it does not tell users where to retrieve the token or which fragment key to use. (src/commands/dashboard.ts:43, 9eed48fde5a9)
  • Existing tests protect redaction but not recovery guidance: The current tests assert that token values and '#token=' stay out of logs and cover the existing clipboard/no-open behavior, but they do not assert a manual-auth hint when both delivery paths fail. (src/commands/dashboard.links.test.ts:101, 9eed48fde5a9)
  • Docs support the token source and fragment syntax: Dashboard docs name gateway.auth.token and OPENCLAW_GATEWAY_TOKEN as shared-secret token sources, and Control UI docs document passing token via the URL fragment because fragments avoid request-log and Referer leakage. Public docs: docs/web/dashboard.md. (docs/web/dashboard.md:50, 9eed48fde5a9)
  • PR adds gated fallback logic: The PR adds fallbackToManualAuth for !copied && !opened && includeTokenInUrl, suppresses the redundant --no-open bare-URL hint in that state, and logs a hint naming OPENCLAW_GATEWAY_TOKEN, gateway.auth.token, and key token without a secret value or '#token=' marker. (src/commands/dashboard.ts:89, ca33caeeaf14)
  • PR adds regression coverage: The PR adds combined clipboard/browser failure coverage and splits the --no-open clipboard-failure path into token-configured and no-token cases, asserting the secret and '#token=' remain absent while recovery guidance is present. (src/commands/dashboard.links.test.ts:166, ca33caeeaf14)
  • Review-thread concerns addressed: Greptile's P2 comments about the missing fragment key and duplicate --no-open hint were addressed by commit f6d0f71, and Greptile's follow-up said both addresses looked correct. (f6d0f71f8131)

Likely related people:

  • steipete: Peter Steinberger introduced the dashboard command, restored tokenized Control UI links, and later centralized gateway auth env credential readers used by this path. (role: introduced behavior and recurring maintainer; confidence: high; commits: bb7397c63661, c5194d814817, a91731a83119; files: src/commands/dashboard.ts, src/commands/dashboard.links.test.ts, docs/web/dashboard.md)
  • Ziy1-Tan: The current bearer-token redaction behavior and CVE regression tests for dashboard logs date to the dashboard hardening change credited to Ziy/Ziy1-Tan. (role: token-log hardening introducer; confidence: high; commits: eaf6d3c1464a; files: src/commands/dashboard.ts, src/commands/dashboard.links.test.ts, CHANGELOG.md)
  • Josh Avant: Josh Avant added SecretRef support for gateway.auth.token, which is part of the token inclusion/exclusion contract this dashboard path depends on. (role: adjacent auth-resolution owner; confidence: medium; commits: 72cf9253fcb5; files: src/gateway/auth-token-resolution.ts, src/commands/dashboard.ts)

Remaining risk / open question:

  • Manual WSL/headless behavior was not live-verified in this read-only review; exact-head CI and the targeted dashboard tests should still gate merge.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 9eed48fde5a9.

praveen9354 and others added 3 commits May 1, 2026 18:23
The previous run failed on src/cli/gateway-cli/run.option-collisions.test.ts
("does not write startup failure bundles for expected gateway lock conflicts")
with a known mock-timing race; this PR touches only src/commands/dashboard*.
Empty commit to retrigger CI.
@BunsDev BunsDev self-assigned this May 4, 2026
@openclaw-barnacle openclaw-barnacle Bot added the docs Improvements or additions to documentation label May 4, 2026
@BunsDev BunsDev merged commit 0677a4f into openclaw:main May 4, 2026
93 of 94 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands Command implementations docs Improvements or additions to documentation size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: dashboard command run without giving a tocken

2 participants