Skip to content

feat(ssh): pre-check the Remote SSH extension before starting the tunnel - #2168

Closed
anton-107 wants to merge 1 commit into
mainfrom
feat/ssh-remote-extension-precheck
Closed

feat(ssh): pre-check the Remote SSH extension before starting the tunnel#2168
anton-107 wants to merge 1 commit into
mainfrom
feat/ssh-remote-extension-precheck

Conversation

@anton-107

Copy link
Copy Markdown
Contributor

Changes

databricks ssh connect needs the host editor's Remote SSH extension to open the
remote window, and checks for it by shelling out to <command> --list-extensions
from inside the terminal. Check the running editor's own extension registry
instead, before the terminal exists, and offer a button that installs through the
editor's marketplace client.

  • HostUtils.getHostSshExtension() resolves the extension id, display name and
    minimum version per host, mirroring the CLI's IDE descriptors the way
    getHostCliCommand already mirrors its --ide handling.
  • HostUtils.getSshExtensionStatus() returns ok / missing / outdated from
    extensions.getExtension, treating an unparseable version as too old exactly as
    the CLI does.
  • SshCommands.offerToInstallSshExtension() prompts, then runs
    workbench.extensions.installExtension.

Unlike the host-CLI PATH warning beside it, this awaits the user's choice rather
than firing and forgetting: installing takes a moment, and the point is to let the
attempt the user just started succeed rather than fail and depend on a retry. It
still never gates the tunnel — a dismissed or failed install falls through to the
CLI's own check, which reports the real error.

Why

The CLI-side extension check is the largest single source of failed IDE-mode
tunnels in telemetry, and its failures are sticky: of the users whose first
attempt hit it, only about an eighth ever established a tunnel, despite averaging
2.7 attempts. It is heavily Windows-skewed, and it is also why Cursor users fail
less often than VS Code users — Cursor ships a Remote SSH equivalent, while VS
Code needs a marketplace install.

Reading the editor's registry cannot fail the way spawning a process can, so this
removes the list-failure path rather than working around it. The extension already
passes --auto-approve, so today these users are never prompted at all: the CLI
goes straight to an auto-install that fails inside a terminal they did not ask
for. This is the same shape as the existing host-CLI PATH pre-check, applied to
the bigger cause.

Companion CLI change, which splits the single telemetry category behind this into
four so the remaining failures are attributable: databricks/cli#6497.

Tests

Not yet compiled or tested — please treat as unverified. The npm registry does
not resolve from the environment this was written in, so yarn install fails and
there is no node_modules to typecheck or run Mocha against. This needs a
yarn test run on a machine with registry access before it should be trusted or
merged. That is the main reason this is a draft.

What was verified without a toolchain:

  • All four touched files parse under Node's type stripper.
  • Added lines sit within Prettier's 80 columns, and follow the repo's 4-space,
    double-quote, bracketSpacing: false settings.
  • Import order matches the convention (external packages before local relative
    imports).
  • Narrowing is done on status.kind directly rather than through an aliased
    boolean, so nothing depends on inference I could not check.

Tests written but not executed — 11 cases across two files:

  • hostUtils.test.ts: per-host extension id, missing / at-minimum / above-minimum
    / below-minimum / unparseable version, and that the Cursor floor applies in
    Cursor.
  • SshCommands.test.ts: silent when usable, offers Install when missing, offers
    Update naming the installed version, installs nothing when dismissed, and does
    not throw when the install itself fails.

One thing worth a reviewer's attention: hostUtils.ts now imports semver, which
is not a declared dependency — only @types/semver is in devDependencies.
src/whatsNewPopup.ts already relies on the same hoisted package in shipped code,
so I followed that precedent, but adding it to dependencies may be the right
call and I could not relock without registry access.

This pull request and its description were written by Isaac.


This PR was created with GitHub MCP.

`databricks ssh connect` needs the host editor's Remote SSH extension to open
the remote window, and checks for it by shelling out to
`<command> --list-extensions` from inside the terminal. That check is the
largest single source of failed IDE-mode tunnels, and its failures are sticky:
most users who hit it never get a working tunnel, even across several attempts.

Check the running editor's own extension registry instead, before the terminal
exists, and offer a button that installs through the editor's marketplace
client. Reading the registry cannot fail the way spawning a process can, so this
removes the list-failure path rather than working around it.

Unlike the host-CLI PATH warning next to it, this awaits the user's choice:
installing takes a moment, and the point is to let the attempt they just started
succeed rather than fail and depend on a retry. It still never gates the tunnel
-- a dismissed or failed install falls through to the CLI's own check, which
reports the real error.

Adds HostUtils.getHostSshExtension/getSshExtensionStatus, mirroring the CLI's IDE
descriptors the way getHostCliCommand already mirrors its --ide handling.

Co-authored-by: Isaac <no-reply@databricks.com>
@anton-107
anton-107 deployed to test-trigger-is September 2, 2026 19:13 — with GitHub Actions Active
@anton-107
anton-107 deployed to test-trigger-is September 2, 2026 19:13 — with GitHub Actions Active
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

If integration tests don't run automatically, an authorized user can run them manually by following the instructions below:

Trigger:
go/deco-tests-run/vscode

Inputs:

  • PR number: 2168
  • Commit SHA: 446109795539b3bb9cb6a0b260c60a3ec6d49a39

Checks will be approved automatically on success.

@anton-107
anton-107 deployed to test-trigger-is September 2, 2026 19:14 — with GitHub Actions Active
@rugpanov

rugpanov commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🤖 Integration tests ❌ 1 of 41 test jobs failed for 44610979 (40 passed).
View run

@anton-107

Copy link
Copy Markdown
Contributor Author

Closing for now — not abandoned, and the branch stays. Reopening is the way to resume.

State when closed, so it does not need rediscovering:

The 11 tests do pass. The "never compiled or tested" caveat is cleared. The npm blocker was only the default registry; the corp proxy (https://npm-proxy.cloud.databricks.com/, already in ~/.npmrc) works, and YARN_NPM_REGISTRY_SERVER=<proxy> yarn install --immutable succeeds. All 11 pass. Full suite 1053 passing / 10 failing, with all 10 in files this PR does not touch (they need the bundled CLI binary from package:cli:fetch). tsc --noEmit output is byte-identical on this branch and its base, so the PR adds no type errors.

Two environment notes if repeating that: build packages/databricks-vscode-types first or tsc fails TS6305, and pin prettier to exactly 3.1.1 — 3.9.6 flags a third file CI does not.

The CI failure is Prettier, not the tests. Two stray trailing newlines plus one ternary that fits on one line, in the two new test files. Because Prettier fails at step 8, Building packages and Unit Tests were skipped — so CI has never actually exercised this code. The MOCHA_GREP message in the same log is a warning (0 errors, 1 warning) and pre-exists on main; it is not what fails the job.

Open before this should merge:

  • yarn prettier --write the two test files.
  • The awaited install has no timeout. offerToInstallSshExtension is awaited at SshCommands.ts:185 before resolveTunnelContext, and the executeCommand at line 520 has no timeout. The catch covers a failed install; a hung one has nothing to fall through to and blocks tunnel start. Not hypothetical for Cursor — the CLI's own descriptor (experimental/ssh/internal/vscode/run.go:65-69) documents Cursor's marketplace hanging auto-installs indefinitely (DECO-27339). Different code path, same marketplace, and a hang is exactly what catch cannot cover.
  • Merge main (branch is behind).
  • Optionally declare semver in dependencies. It resolves today via hoisting plus esbuild --bundle, and src/whatsNewPopup.ts already ships the same way, so this is fragility rather than a break.

Verified correct: extension ids and version floors match the CLI exactly (ms-vscode-remote.remote-ssh at 0.120.0, anysphere.remote-ssh at 1.0.32); unparseable version treated as outdated like the CLI; a failed or dismissed install does not gate the tunnel.

Worth re-checking the premise before resuming: this pre-check targets IDE_SSH_EXTENSION_MISSING, and databricks/cli#6497 splits that category into four. Once that ships and the breakdown is re-run, the dominant outcome may be INSTALL_FAILED rather than the list-failure path this removes — which would re-scope the fix. That measure-before-fixing step is DECO-28102's suggested order.

@anton-107 anton-107 closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants