Skip to content

Commit de02eea

Browse files
Force Linux host platform for Windows users (#31)
1 parent a1f2ca1 commit de02eea

File tree

2 files changed

+45
-20
lines changed

2 files changed

+45
-20
lines changed

src/remoteConnector.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import { GitpodPublicApi } from './publicApi';
3838
import { SSHKey } from '@gitpod/public-api/lib/gitpod/experimental/v1/user_pb';
3939
import { getAgentSock, SSHError, testSSHConnection } from './sshTestConnection';
4040
import { gatherIdentityFiles } from './ssh/identityFiles';
41+
import { isWindows } from './common/platform';
42+
import SSHDestination from './ssh/sshDestination';
4143

4244
interface SSHConnectionParams {
4345
workspaceId: string;
@@ -443,7 +445,7 @@ export default class RemoteConnector extends Disposable {
443445
}
444446
}
445447

446-
private async getWorkspaceSSHDestination(session: vscode.AuthenticationSession, { workspaceId, gitpodHost, debugWorkspace }: SSHConnectionParams): Promise<{ destination: string; password?: string }> {
448+
private async getWorkspaceSSHDestination(session: vscode.AuthenticationSession, { workspaceId, gitpodHost, debugWorkspace }: SSHConnectionParams): Promise<{ destination: SSHDestination; password?: string }> {
447449
const serviceUrl = new URL(gitpodHost);
448450
const sshKeysSupported = session.scopes.includes(ScopeFeature.SSHPublicKeys);
449451

@@ -471,21 +473,20 @@ export default class RemoteConnector extends Disposable {
471473
throw new NoSSHGatewayError(gitpodHost);
472474
}
473475

474-
const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_key: string }[];
476+
const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_key: string }[];
475477
let user = workspaceId;
476478
// See https://github.com/gitpod-io/gitpod/pull/9786 for reasoning about `.ssh` suffix
477-
let hostName = workspaceUrl.host.replace(workspaceId, `${workspaceId}.ssh`)
479+
let hostname = workspaceUrl.host.replace(workspaceId, `${workspaceId}.ssh`);
478480
if (debugWorkspace) {
479481
user = 'debug-' + workspaceId;
480-
hostName = hostName.replace(workspaceId, user);
482+
hostname = hostname.replace(workspaceId, user);
481483
}
482-
const sshDestInfo = { user, hostName };
483484

484485
const sshConfiguration = await SSHConfiguration.loadFromFS();
485486

486487
const verifiedHostKey = await testSSHConnection({
487-
host: sshDestInfo.hostName,
488-
username: sshDestInfo.user,
488+
host: hostname,
489+
username: user,
489490
readyTimeout: 40000,
490491
password: ownerToken
491492
}, sshHostKeys, sshConfiguration, this.logger);
@@ -497,15 +498,15 @@ const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_ke
497498
throw result;
498499
}
499500
const parseKey = Array.isArray(result) ? result[0] : result;
500-
if (parseKey && await checkNewHostInHostkeys(sshDestInfo.hostName)) {
501-
await addHostToHostFile(sshDestInfo.hostName, verifiedHostKey!, parseKey.type);
502-
this.logger.info(`'${sshDestInfo.hostName}' host added to known_hosts file`);
501+
if (parseKey && await checkNewHostInHostkeys(hostname)) {
502+
await addHostToHostFile(hostname, verifiedHostKey!, parseKey.type);
503+
this.logger.info(`'${hostname}' host added to known_hosts file`);
503504
}
504505
} catch (e) {
505-
this.logger.error(`Couldn't write '${sshDestInfo.hostName}' host to known_hosts file:`, e);
506+
this.logger.error(`Couldn't write '${hostname}' host to known_hosts file:`, e);
506507
}
507508

508-
const hostConfiguration = sshConfiguration.getHostConfiguration(sshDestInfo.hostName);
509+
const hostConfiguration = sshConfiguration.getHostConfiguration(hostname);
509510
let identityKeys = await gatherIdentityFiles([], getAgentSock(hostConfiguration), false, this.logger);
510511

511512
if (registeredSSHKeys) {
@@ -526,19 +527,19 @@ const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_ke
526527
identityKeys = identityKeys.filter(k => !!registeredKeys.find(regKey => regKey.fingerprint === k.fingerprint));
527528
} else {
528529
if (identityKeys.length) {
529-
sshDestInfo.user = `${user}#${ownerToken}`;
530+
user = `${user}#${ownerToken}`;
530531
}
531532
const gitpodVersion = await getGitpodVersion(gitpodHost, this.logger);
532533
this.logger.warn(`Registered SSH public keys not supported in ${gitpodHost}, using version ${gitpodVersion.raw}`);
533534
}
534535

535536
return {
536-
destination: Buffer.from(JSON.stringify(sshDestInfo), 'utf8').toString('hex'),
537+
destination: new SSHDestination(hostname, user),
537538
password: identityKeys.length === 0 ? ownerToken : undefined
538539
};
539540
}
540541

541-
private async getWorkspaceLocalAppSSHDestination(params: SSHConnectionParams): Promise<{ localAppSSHDest: string; localAppSSHConfigPath: string }> {
542+
private async getWorkspaceLocalAppSSHDestination(params: SSHConnectionParams): Promise<{ destination: SSHDestination; localAppSSHConfigPath: string }> {
542543
return vscode.window.withProgress({
543544
location: vscode.ProgressLocation.Notification,
544545
cancellable: true,
@@ -558,7 +559,7 @@ const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_ke
558559
}, token);
559560

560561
return {
561-
localAppSSHDest: connection.getHost(),
562+
destination: new SSHDestination(connection.getHost()),
562563
localAppSSHConfigPath: connection.getConfigFile()
563564
};
564565
} catch (e) {
@@ -721,7 +722,7 @@ const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_ke
721722
? (await this.experiments.get<boolean>('gitpod.remote.useLocalApp', session.account.id, { gitpodHost: params.gitpodHost }))!
722723
: (await this.experiments.get<boolean>('gitpod.remote.useLocalApp', session.account.id, { gitpodHost: params.gitpodHost }, 'gitpod_remote_useLocalApp_sh'))!;
723724
const userOverride = String(isUserOverrideSetting('gitpod.remote.useLocalApp'));
724-
let sshDestination: string | undefined;
725+
let sshDestination: SSHDestination | undefined;
725726
if (!forceUseLocalApp) {
726727
const openSSHVersion = await getOpenSSHVersion();
727728
const gatewayFlow = { kind: 'gateway', openSSHVersion, userOverride, ...sshFlow };
@@ -782,7 +783,7 @@ const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_ke
782783
this.telemetry.sendUserFlowStatus('connecting', localAppFlow);
783784

784785
const localAppDestData = await this.getWorkspaceLocalAppSSHDestination(params);
785-
sshDestination = localAppDestData.localAppSSHDest;
786+
sshDestination = localAppDestData.destination;
786787
localAppSSHConfigPath = localAppDestData.localAppSSHConfigPath;
787788

788789
this.telemetry.sendUserFlowStatus('connected', localAppFlow);
@@ -811,12 +812,21 @@ const sshHostKeys = (await sshHostKeyResponse.json()) as { type: string; host_ke
811812

812813
await this.updateRemoteSSHConfig(usingSSHGateway, localAppSSHConfigPath);
813814

814-
await this.context.globalState.update(`${RemoteConnector.SSH_DEST_KEY}${sshDestination!}`, { ...params, isFirstConnection: true });
815+
await this.context.globalState.update(`${RemoteConnector.SSH_DEST_KEY}${sshDestination!.toRemoteSSHString()}`, { ...params, isFirstConnection: true });
815816

816817
const forceNewWindow = this.context.extensionMode === vscode.ExtensionMode.Production;
818+
819+
// Force Linux as host platform (https://github.com/gitpod-io/gitpod/issues/16058)
820+
if (isWindows) {
821+
const existingSSHHostPlatforms = vscode.workspace.getConfiguration('remote.SSH').get<{ [host: string]: string }>('remotePlatform', {});
822+
if (!existingSSHHostPlatforms[sshDestination!.hostname]) {
823+
await vscode.workspace.getConfiguration('remote.SSH').update('remotePlatform', { ...existingSSHHostPlatforms, [sshDestination!.hostname]: 'linux' }, vscode.ConfigurationTarget.Global);
824+
}
825+
}
826+
817827
vscode.commands.executeCommand(
818828
'vscode.openFolder',
819-
vscode.Uri.parse(`vscode-remote://ssh-remote+${sshDestination}${uri.path || '/'}`),
829+
vscode.Uri.parse(`vscode-remote://ssh-remote+${sshDestination!.toRemoteSSHString()}${uri.path || '/'}`),
820830
{ forceNewWindow }
821831
);
822832
}

src/ssh/sshDestination.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,19 @@ export default class SSHDestination {
4141
}
4242
return result;
4343
}
44+
45+
toRemoteSSHString() {
46+
if (!this.user && !this.port) {
47+
return this.hostname;
48+
}
49+
50+
const obj: any = { hostName: this.hostname };
51+
if (this.user) {
52+
obj.user = this.user;
53+
}
54+
if (this.port) {
55+
obj.port = this.port;
56+
}
57+
return Buffer.from(JSON.stringify(obj), 'utf8').toString('hex');
58+
}
4459
}

0 commit comments

Comments
 (0)