Path: blob/main/src/vs/platform/agentHost/common/sshRemoteAgentHost.ts
13394 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Event } from '../../../base/common/event.js';6import { IDisposable } from '../../../base/common/lifecycle.js';7import { URI } from '../../../base/common/uri.js';8import { createDecorator } from '../../instantiation/common/instantiation.js';910export const ISSHRemoteAgentHostService = createDecorator<ISSHRemoteAgentHostService>('sshRemoteAgentHostService');1112/**13* IPC channel name for the main-process SSH service.14*/15export const SSH_REMOTE_AGENT_HOST_CHANNEL = 'sshRemoteAgentHost';1617export const enum SSHAuthMethod {18/** Use the local SSH agent for key-based auth. */19Agent = 'agent',20/** Authenticate with an explicit private key file. */21KeyFile = 'keyFile',22/** Authenticate with a password. */23Password = 'password',24}2526export interface ISSHAgentHostConfig {27/** Remote hostname or IP. */28readonly host: string;29/** SSH port (default 22). */30readonly port?: number;31/** Username on the remote machine. */32readonly username: string;33/** Authentication method. */34readonly authMethod: SSHAuthMethod;35/** Path to the private key file (when {@link authMethod} is KeyFile). */36readonly privateKeyPath?: string;37/** Password string (when {@link authMethod} is Password). */38readonly password?: string;39/** Display name for this connection. */40readonly name: string;41/** SSH config host alias (e.g. "robfast2") for reconnection on restart. */42readonly sshConfigHost?: string;43/** Dev override: custom command to start the remote agent host instead of the default CLI. */44readonly remoteAgentHostCommand?: string;45/** When true, enables OpenSSH agent forwarding ([email protected]) for this connection. Requires {@link authMethod} to be Agent. */46readonly agentForward?: boolean;47}4849/**50* A sanitized view of the SSH config that omits secret material51* (password, private key path). Exposed on active connections so52* consumers can inspect connection metadata without accessing credentials.53*/54export type ISSHAgentHostConfigSanitized = Omit<ISSHAgentHostConfig, 'password' | 'privateKeyPath'>;5556export interface ISSHAgentHostConnection extends IDisposable {57/** The SSH config used to establish this connection (secrets stripped). */58readonly config: ISSHAgentHostConfigSanitized;59/** The connection address (e.g. `ssh:myhost` or `user@host:22`) registered with IRemoteAgentHostService. */60readonly localAddress: string;61/** The display name. */62readonly name: string;63/** Fires when this SSH connection is closed or lost. */64readonly onDidClose: Event<void>;65}6667/**68* Manages SSH connections that bootstrap a remote agent host process.69*70* Each connection SSHs into a remote machine, ensures the VS Code CLI71* is installed, starts `code agent-host`, and creates a WebSocket relay72* over the SSH channel. Messages are forwarded between the renderer and73* the remote agent host via IPC through the shared process.74*/75export interface ISSHRemoteAgentHostService {76readonly _serviceBrand: undefined;7778/** Fires when the set of active SSH connections changes. */79readonly onDidChangeConnections: Event<void>;8081/** Progress messages during connect. */82readonly onDidReportConnectProgress: Event<ISSHConnectProgress>;8384/** Currently active SSH-bootstrapped connections. */85readonly connections: readonly ISSHAgentHostConnection[];8687/**88* Bootstrap a remote agent host over SSH.89*90* 1. Opens an SSH connection to the remote host91* 2. Downloads and installs the VS Code CLI if needed92* 3. Starts `code agent-host`93* 4. Creates a WebSocket relay over the SSH channel94* 5. Registers the connection with {@link IRemoteAgentHostService}95*96* Resolves with the connection handle once the agent host is reachable.97*/98connect(config: ISSHAgentHostConfig): Promise<ISSHAgentHostConnection>;99100/**101* Disconnect an SSH-bootstrapped connection by host address.102* Tears down the SSH tunnel, stops the remote agent host, and103* removes the entry from {@link IRemoteAgentHostService}.104*/105disconnect(host: string): Promise<void>;106107/** List SSH config host aliases (excluding wildcards). */108listSSHConfigHosts(): Promise<string[]>;109110/**111* Ensure `~/.ssh/config` exists (creating it with the right permissions if112* missing) and return its URI. The parent `~/.ssh` directory is created113* with mode 0700 and the config file with mode 0600 on POSIX systems.114*/115ensureUserSSHConfig(): Promise<URI>;116117/**118* List the known SSH configuration file URIs in priority order — typically the119* per-user `~/.ssh/config` (always returned, even if it does not yet exist) and120* the system-wide `/etc/ssh/ssh_config` (only when present on disk).121*/122listSSHConfigFiles(): Promise<URI[]>;123124/** Resolve full SSH config for a host via `ssh -G`. */125resolveSSHConfig(host: string): Promise<ISSHResolvedConfig>;126127/**128* Re-establish an SSH tunnel on startup for a previously connected host.129* Returns the new local forwarded address and registers it.130*/131reconnect(sshConfigHost: string, name: string): Promise<ISSHAgentHostConnection>;132}133/**134* Serializable result from a successful SSH connect operation.135* Returned over IPC from the main process.136*/137export interface ISSHConnectResult {138/** Unique identifier for this connection's relay channel. */139readonly connectionId: string;140/** Display-friendly address (e.g. "ssh:robfast2"). */141readonly address: string;142readonly name: string;143readonly connectionToken: string | undefined;144readonly config: ISSHAgentHostConfigSanitized;145/** SSH config host alias for reconnection on restart. */146readonly sshConfigHost?: string;147}148149/**150* Resolved SSH configuration for a host, obtained from `ssh -G`.151*/152export interface ISSHResolvedConfig {153readonly hostname: string;154readonly user: string | undefined;155readonly port: number;156readonly identityFile: string[];157readonly forwardAgent: boolean;158}159160export interface ISSHConnectProgress {161readonly connectionKey: string;162readonly message: string;163}164165/**166* A message relayed from a remote agent host through the SSH tunnel.167* The shared process acts as a WebSocket proxy, forwarding JSON messages168* bidirectionally between the SSH channel and the renderer via IPC.169*/170export interface ISSHRelayMessage {171readonly connectionId: string;172readonly data: string;173}174175/**176* Main-process service that performs the actual SSH work.177* The renderer calls this over IPC and handles registration178* with {@link IRemoteAgentHostService} locally.179*/180export const ISSHRemoteAgentHostMainService = createDecorator<ISSHRemoteAgentHostMainService>('sshRemoteAgentHostMainService');181182export interface ISSHRemoteAgentHostMainService {183readonly _serviceBrand: undefined;184185/** Fires when the set of active SSH connections changes. */186readonly onDidChangeConnections: Event<void>;187188/** Fires when a connection is closed from the shared process side. */189readonly onDidCloseConnection: Event<string /* connectionId */>;190191/** Progress messages during connect (e.g. "Installing CLI..."). */192readonly onDidReportConnectProgress: Event<ISSHConnectProgress>;193194/** Fires when a message is received from a remote agent host via the SSH relay. */195readonly onDidRelayMessage: Event<ISSHRelayMessage>;196197/** Fires when a relay connection to a remote agent host closes. */198readonly onDidRelayClose: Event<string /* connectionId */>;199200/**201* Bootstrap a remote agent host over SSH. Returns serializable202* connection info for the renderer to register.203*/204connect(config: ISSHAgentHostConfig): Promise<ISSHConnectResult>;205206/**207* Send a message to a remote agent host through the SSH relay.208*/209relaySend(connectionId: string, message: string): Promise<void>;210211/**212* Disconnect an SSH-bootstrapped connection by host address.213*/214disconnect(host: string): Promise<void>;215216/** List SSH config host aliases (excluding wildcards). */217listSSHConfigHosts(): Promise<string[]>;218219/**220* Ensure `~/.ssh/config` exists (creating it with the right permissions if221* missing) and return its URI.222*/223ensureUserSSHConfig(): Promise<URI>;224225/** List the known SSH configuration file URIs (user config always included). */226listSSHConfigFiles(): Promise<URI[]>;227228/** Resolve full SSH config for a host via `ssh -G`. */229resolveSSHConfig(host: string): Promise<ISSHResolvedConfig>;230231/**232* Re-establish an SSH tunnel for a previously connected host.233* Resolves the SSH config alias, connects, and returns fresh234* connection info with a new local forwarded port.235*/236reconnect(sshConfigHost: string, name: string, remoteAgentHostCommand?: string, agentForward?: boolean): Promise<ISSHConnectResult>;237}238239240