Skip to content

fix(onboard): treat an unreachable custom endpoint as a transport failure - #6867

Merged
cv merged 2 commits into
mainfrom
fix/onboard-unreachable-endpoint-recovery-6854
Jul 14, 2026
Merged

fix(onboard): treat an unreachable custom endpoint as a transport failure#6867
cv merged 2 commits into
mainfrom
fix/onboard-unreachable-endpoint-recovery-6854

Conversation

@yanyunl1991

@yanyunl1991 yanyunl1991 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

During nemoclaw onboard, choosing "Other OpenAI-compatible endpoint" and entering a DNS-unreachable base URL (https://example.invalid/v1) failed the SSRF preflight and silently looped back to provider selection — no probe guidance, no retry/back/exit prompt, no clean exit. This PR routes an unreachable endpoint through the existing transport-recovery path (DNS/VPN/URL hint + retry/back/exit + exit), matching the credential-failure path. The safety property is unchanged: no sandbox is created.

Closes #6854.

Reproduction

Exercised the real compiled recovery path on our DGX Spark aarch64 test host (matching the reporter's DGX Spark aarch64), driving validateCustomOpenAiLikeSelection against a host that does not resolve and capturing the recovery classification handed to the prompt.

Environment

  • Test machine: our DGX Spark aarch64 test host (GB10 GPU), Ubuntu 24.04
  • NemoClaw main (v0.0.82)

Observed on main (before fix)

recovery.kind = unknown     # -> promptValidationRecovery falls through to the
                            #    silent "Please choose a provider/model again"
                            #    branch and loops back to provider selection

Observed on fix/... (after fix)

recovery.kind = transport   # -> "Validation could not resolve the provider
                            #    hostname. Check DNS, VPN, or the endpoint URL."
                            #    + "Type 'retry', 'back', or 'exit'"

Analysis

preflightCustomEndpointOrFail (src/lib/onboard/inference-selection-validation.ts) builds a synthetic probe failure for an SSRF-preflight failure with curlStatus: 0 and httpStatus: 0. classifyValidationFailure has no status to key on, so it returns kind: "unknown" (retry: "selection"), and promptValidationRecovery takes its final else-branch — printing "Please choose a provider/model again" and returning to the menu with no guidance and no exit option. The credential path and every real transport failure (curl exit 6/7/28, HTTP 429/5xx) instead get getTransportRecoveryMessage + a retry/back/exit prompt. A DNS-unreachable endpoint is genuinely a transport failure, but the synthetic failure never carried that signal.

Fix

When the preflight reason is a host-resolution failure (cannot resolve endpoint host … / did not resolve to any address), mark the synthetic failure with curl's "could not resolve host" status (6). It then classifies as transport and routes through the existing transport recovery — which already emits the "Check DNS, VPN, or the endpoint URL" hint (curl 6 branch) and the retry/back/exit prompt with a clean exit. A private-IP SSRF block keeps status 0 (it resolved fine; the address is just refused), so that path is unchanged. No new recovery UI is added — the fix reuses the existing transport contract.

Changes

  • src/lib/onboard/inference-selection-validation.ts: classify an unresolved-host SSRF-preflight failure as a transport failure.
  • src/lib/onboard/inference-selection-validation.test.ts: regression test that an unreachable endpoint yields a transport recovery.

Type of Change

  • Code change (feature, bug fix, or refactor)

Verification

  • npm test passes (touched files)
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed

AI Disclosure

  • AI-assisted — tool: Claude Code

Signed-off-by: Yanyun Liao yanyunl@nvidia.com

Summary by CodeRabbit

  • Bug Fixes
    • Improved validation for custom OpenAI-compatible endpoints when DNS/host resolution fails.
    • Unreachable endpoints are now classified as transport failures, triggering the appropriate recovery flow instead of being treated as blocked/unsafe.
    • Continued to keep separate handling for endpoints that resolve to private or internal network addresses.
  • Tests
    • Added coverage to confirm DNS-style failures are detected as transport issues and follow the expected recovery path.

…lure

Choosing "Other OpenAI-compatible endpoint" and entering a DNS-unreachable
base URL failed the SSRF preflight and silently looped back to provider
selection: no probe guidance, no retry/back/exit prompt, and no clean exit.
The credential-failure and other transport-failure paths already offer that
recovery, but the preflight built a synthetic failure with curlStatus 0, so it
classified as "unknown" and fell through to the silent selection loop.

When the preflight fails because the host does not resolve (an unreachable or
non-existent endpoint), mark the synthetic failure with curl's "could not
resolve host" status (6). It then routes through the existing transport
recovery — a DNS/VPN/endpoint-URL hint plus a retry/back/exit prompt with a
clean exit — matching the credential path. A private-IP SSRF block keeps
status 0 (it resolved fine; the address is just refused), so its behavior is
unchanged.

Fixes #6854

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Yanyun Liao <yanyunl@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 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: 973ccc71-62fc-4b17-ae70-b5c2b2df8c94

📥 Commits

Reviewing files that changed from the base of the PR and between a92c710 and e775de7.

📒 Files selected for processing (1)
  • src/lib/onboard/inference-selection-validation.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/onboard/inference-selection-validation.test.ts

📝 Walkthrough

Walkthrough

Custom endpoint preflight failures now distinguish DNS-unresolved hosts from other blocked endpoints, routing unresolved hosts to transport recovery. A Vitest case verifies recovery classification and confirms endpoint probing is skipped.

Changes

Custom endpoint recovery

Layer / File(s) Summary
Transport failure classification and validation
src/lib/onboard/inference-selection-validation.ts, src/lib/onboard/inference-selection-validation.test.ts
Preflight failures normalize their reason and assign curl status 6 for unresolved hosts, while tests verify transport recovery is invoked without probing the endpoint.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: bug-fix, area: networking

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: unreachable custom endpoints are now treated as transport failures.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 fix/onboard-unreachable-endpoint-recovery-6854

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

@github-code-quality

github-code-quality Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

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

TypeScript / code-coverage/cli

The overall coverage in the fix/onboard-unreacha... branch remains at 79%, unchanged from the main branch.

Show a code coverage summary of the most impacted files.
File main 20130dd fix/onboard-unreacha... e775de7 +/-
src/lib/onboard...n-validation.ts 97% 97% 0%
src/lib/onboard...shboard-port.ts 89% 94% +5%
src/lib/policy/tiers.ts 80% 94% +14%
src/lib/core/pr...mpt-activity.ts 67% 92% +25%

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

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Informational

Advisor assessment: Informational / high confidence
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions
Status: No actionable findings remain in the canonical review ledger.

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · medium confidence · 2 blockers · 4 warnings · 1 suggestion
  • Model comparison: normalized findings differ; normalized E2E selections differ; Nemotron reported 2 more blockers, 4 more warnings, 1 more suggestion.

Nemotron output stays in workflow artifacts and does not change the assessment above.

Since last review: 0 prior items resolved · 0 still apply · 0 new items found

E2E guidance

Advisory only. E2E / PR Gate selects and runs jobs independently.

Recommended E2E: inference-routing, network-policy, onboard-repair, onboard-resume, cloud-onboard

1 optional E2E recommendation
  • onboard-negative-paths

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

…ypecheck

The #6854 regression test read `promptValidationRecovery.mock.calls[0][1]`,
which fails typecheck:cli (tsconfig.cli.json includes tests): the zero-arg
mock's call tuple has no index 1. Capture the recovery argument through a
typed closure instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Yanyun Liao <yanyunl@nvidia.com>
@wscurran wscurran added area: networking DNS, proxy, TLS, ports, host aliases, or connectivity area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow area: providers Inference provider integrations and provider behavior bug-fix PR fixes a bug or regression platform: dgx-spark Affects DGX Spark hardware or workflows labels Jul 14, 2026

@cjagwani cjagwani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maintainer review: approved. The change preserves the SSRF fail-closed boundary, classifies only unresolved-host preflight failures as transport recovery, keeps private/internal address rejection unchanged, and adds regression coverage proving no endpoint probe occurs. Required CI and the exact-head E2E gate are green; DCO and commit verification pass; no actionable automated-review findings remain.

@cv
cv merged commit 10542ae into main Jul 14, 2026
84 checks passed
@cv
cv deleted the fix/onboard-unreachable-endpoint-recovery-6854 branch July 14, 2026 17:49
jyaunches added a commit that referenced this pull request Jul 14, 2026
## Summary

Add v0.0.83 release notes to `docs/about/release-notes.mdx` for pre-tag
release prep.

## Source Summary

- #6773 -> `docs/about/release-notes.mdx`: Shared inference route
changes are explicit and fail-safe; status shows recorded route, live
route, and drift.
- #6875 -> `docs/about/release-notes.mdx`: DGX Station GB300 express
setup restored; vLLM storage preflight narrowed.
- #6770 -> `docs/about/release-notes.mdx`: Risky Spark vLLM server
warning during onboarding.
- #6856 -> `docs/about/release-notes.mdx`: Re-onboard reuse preserves
tier-default brave/tavily presets.
- #6867 -> `docs/about/release-notes.mdx`: Unreachable custom endpoint
routed through transport-recovery path.
- #6860 -> `docs/about/release-notes.mdx`: Rebuild preflight uses
model-aware token field for o-series/GPT-5.
- #6845 -> `docs/about/release-notes.mdx`: Corporate CA anchored for
image build TLS.
- #6833 -> `docs/about/release-notes.mdx`: SSH ControlMaster-delegated
forwards recognized in fallback.
- #6837 -> `docs/about/release-notes.mdx`: Hermes light skin writes via
stdin on macOS.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [x] 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 — justification:
- [x] Tests not applicable — justification: doc-only release notes
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed
- [ ] Non-success, skipped, or missing CI check accepted by maintainer

## Verification
- [x] PR description includes the DCO sign-off declaration and every
commit appears as Verified in GitHub
- [x] Normal pre-commit, commit-msg, and pre-push hooks passed
- [x] `npm run docs` passes with 0 errors

Signed-off-by: Jessica Yaunches <jyaunches@nvidia.com>

Signed-off-by: Jessica Yaunches <jyaunches@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: networking DNS, proxy, TLS, ports, host aliases, or connectivity area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow area: providers Inference provider integrations and provider behavior bug-fix PR fixes a bug or regression platform: dgx-spark Affects DGX Spark hardware or workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DGX Spark][Onboard] Unreachable custom OpenAI-compatible endpoint loops back to provider menu with no recovery guidance or exit option

4 participants