Skip to content

SSH: fall back to default identity files when agent lacks the key#312231

Merged
roblourens merged 2 commits intomainfrom
roblou/ssh-auth-fallback
Apr 23, 2026
Merged

SSH: fall back to default identity files when agent lacks the key#312231
roblourens merged 2 commits intomainfrom
roblou/ssh-auth-fallback

Conversation

@roblourens
Copy link
Copy Markdown
Member

Switch SSH auth in SSHRemoteAgentHostMainService to ssh2's authHandler callback, walking an ordered queue of attempts:

  1. Explicit privateKeyPath (if set)
  2. SSH agent (if SSH_AUTH_SOCK is set)
  3. Each existing default identity file (~/.ssh/id_ed25519, id_rsa, id_ecdsa, id_dsa, id_xmss), deduped against the explicit key

This mirrors OpenSSH client behavior: a host that accepts ~/.ssh/id_rsa still connects when the agent is running but doesn't have the key loaded — without needing an explicit `IdentityFile` entry in `~/.ssh/config`.

Other changes

  • Imported proper `ConnectConfig` typings from `ssh2` instead of `Record<string, unknown>`. Added `'ssh2'` to the eslint node-modules allow list.
  • Simplified `reconnect()` — always Agent mode; only forwards `privateKeyPath` for non-default `IdentityFile` entries.
  • New protected test seams: `_buildAuthAttempts`, `_isAgentAvailable`, `_readKeyFileIfExists`.
  • Replaced old per-method tests with snapshot-style `_buildAuthAttempts` cases (8) and a `makeAuthHandler` suite (2). All 42 tests pass.

Manual smoke (TODO before merging)

  • `ssh-add -D` (empty agent), connect via "Add Remote Agent Host via SSH..." → log shows `agent` then `publickey ~/.ssh/id_rsa`, succeeds.
  • Agent has the right key → succeeds on `agent`.
  • No `SSH_AUTH_SOCK` → falls through to default keys.
  • Explicit `privateKeyPath` → tried first.
  • Restart / reconnect path still works.

(Written by Copilot)

Switch SSH auth to ssh2's authHandler callback, walking an ordered queue
of attempts: explicit privateKeyPath -> agent (if SSH_AUTH_SOCK) -> each
existing default identity file. Mirrors OpenSSH client behavior so a
host that accepts ~/.ssh/id_rsa still connects when the agent doesn't
have it loaded, without needing an explicit IdentityFile in ssh config.

Also import proper ConnectConfig typings from ssh2 instead of using
Record<string, unknown>.

(Written by Copilot)
Copilot AI review requested due to automatic review settings April 23, 2026 21:35
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the SSH remote agent host connection logic to more closely match OpenSSH key fallback behavior by using ssh2’s authHandler with an ordered list of authentication attempts, and adjusts tests/linting accordingly.

Changes:

  • Switch _connectSSH to build an ordered auth-attempt queue and use a new makeAuthHandler to drive ssh2 authentication.
  • Refactor reconnect logic to always use Agent auth mode while optionally surfacing a non-default IdentityFile as an explicit key attempt.
  • Replace prior auth-config tests with _buildAuthAttempts and makeAuthHandler unit tests; allow ssh2 in ESLint config.
Show a summary per file
File Description
src/vs/platform/agentHost/node/sshRemoteAgentHostService.ts Introduces auth-attempt queue + authHandler, reconnect simplification, and new test seams for agent/key-file access.
src/vs/platform/agentHost/test/node/sshRemoteAgentHostService.test.ts Reworks tests to validate _buildAuthAttempts ordering and makeAuthHandler iteration/filters.
eslint.config.js Allows importing ssh2 by adding it to the node-modules allow list.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 3

Comment thread src/vs/platform/agentHost/node/sshRemoteAgentHostService.ts Outdated
Comment thread src/vs/platform/agentHost/node/sshRemoteAgentHostService.ts
Comment thread src/vs/platform/agentHost/node/sshRemoteAgentHostService.ts Outdated
… KeyFile fail-fast

- _connectSSH: when agentForward is enabled, also set connectConfig.agent
  to SSH_AUTH_SOCK so ssh2 actually has a socket to forward to. Warn when
  forwarding is requested without an agent available.
- makeAuthHandler: map 'agent' to 'publickey' for the methodsLeft filter,
  since SSH servers advertise 'publickey' (agent is just a publickey-flavored
  method at the protocol level). Tightened types to ssh2's
  AuthenticationType / AnyAuthMethod so this is enforced by the compiler.
- _buildAuthAttempts (KeyFile mode): fail fast with a localized error if
  privateKeyPath is missing or unreadable, instead of silently falling
  through to a generic auth failure.
- Added 3 unit tests covering the new behaviors.

(Written by Copilot)
@roblourens roblourens marked this pull request as ready for review April 23, 2026 22:04
@roblourens roblourens enabled auto-merge (squash) April 23, 2026 22:04
@roblourens roblourens merged commit f81f651 into main Apr 23, 2026
26 checks passed
@roblourens roblourens deleted the roblou/ssh-auth-fallback branch April 23, 2026 22:34
@vs-code-engineering vs-code-engineering Bot added this to the 1.118.0 milestone Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants