feat(workspaces): implement ssh tunneling and workspace connect command

This commit is contained in:
mkorwel
2026-03-19 08:50:42 -07:00
parent bd523c8d48
commit 22ff923100
7 changed files with 209 additions and 3 deletions
+1
View File
@@ -134,6 +134,7 @@ export * from './services/trackerTypes.js';
export * from './services/keychainService.js';
export * from './services/keychainTypes.js';
export * from './services/workspaceHubClient.js';
export * from './services/sshService.js';
export * from './skills/skillManager.js';
export * from './skills/skillLoader.js';
+64
View File
@@ -0,0 +1,64 @@
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { spawn } from 'node:child_process';
import { debugLogger } from '../utils/debugLogger.js';
export interface SSHOptions {
instanceName: string;
zone: string;
project: string;
command?: string;
forwardAgent?: boolean;
}
export class SSHService {
/**
* Connect to a GCE instance using gcloud compute ssh with IAP tunneling.
* This method spawns a child process and inherits stdio to allow interactive shell.
*/
async connect(options: SSHOptions): Promise<number> {
const { instanceName, zone, project, command, forwardAgent = true } = options;
const args = [
'compute',
'ssh',
instanceName,
`--zone=${zone}`,
`--project=${project}`,
'--tunnel-through-iap',
];
if (forwardAgent) {
args.push('--ssh-flag=-A');
}
if (command) {
args.push('--command', command);
}
debugLogger.log(`[SSHService] Executing: gcloud ${args.join(' ')}`);
return new Promise((resolve, reject) => {
const child = spawn('gcloud', args, {
stdio: 'inherit',
shell: true,
});
child.on('exit', (code) => {
if (code === 0) {
resolve(0);
} else {
reject(new Error(`gcloud ssh exited with code ${code}`));
}
});
child.on('error', (err) => {
reject(err);
});
});
}
}