setupDirectSsh function
Future<void>
setupDirectSsh(
- LumeVM vm
)
Implementation
Future<void> setupDirectSsh(lume.LumeVM vm) async {
final keyFile = File(_sshKeyPath);
if (!keyFile.existsSync()) {
await Process.run('ssh-keygen', [
'-t',
'ed25519',
'-f',
_sshKeyPath,
'-N',
'',
'-q',
]);
_log.info('Generated SSH key at $_sshKeyPath');
}
final pubKey = File('$_sshKeyPath.pub').readAsStringSync().trim();
final ip = vm.ipAddress;
if (ip == null) {
throw StateError('VM IP is null; cannot install SSH key.');
}
// Drive the system `ssh` binary's password auth via SSH_ASKPASS (no TTY
// required). Using /usr/bin/ssh keeps this exempt from macOS Local Network
// privacy when the worker runs as a LaunchAgent.
final askpass = File(_askPassPath);
askpass.writeAsStringSync("#!/bin/sh\nprintf '%s' '$sshPassword'\n");
await Process.run('chmod', ['+x', _askPassPath]);
const installCmd =
'mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys';
Future<int> runPasswordSsh(String command) async {
final process = await Process.start(
'/usr/bin/ssh',
[
..._sshBaseOpts,
'-o',
'PubkeyAuthentication=no',
'-o',
'PreferredAuthentications=password,keyboard-interactive',
'-o',
'NumberOfPasswordPrompts=1',
'$sshUser@$ip',
command,
],
environment: {
'SSH_ASKPASS': _askPassPath,
'SSH_ASKPASS_REQUIRE': 'force',
'DISPLAY': ':0',
},
);
await process.stdin.close();
await process.stdout.drain<void>();
await process.stderr.drain<void>();
return process.exitCode;
}
// The append uses base64 of the public key to avoid any quoting issues over
// the password-auth ssh channel.
final pubKeyB64 = base64Encode(utf8.encode('$pubKey\n'));
final appendCmd =
'printf %s \'$pubKeyB64\' | base64 -D >> ~/.ssh/authorized_keys';
var exitCode = -1;
for (var attempt = 1; attempt <= 5; attempt++) {
exitCode = await runPasswordSsh('$installCmd && $appendCmd');
if (exitCode == 0) break;
_log.warning(
'SSH key install attempt $attempt failed (exit $exitCode); retrying...',
);
await Future<void>.delayed(const Duration(seconds: 5));
}
try {
askpass.deleteSync();
} catch (_) {}
if (exitCode != 0) {
throw Exception('Failed to install SSH key on VM. Exit code: $exitCode');
}
_log.info('SSH key installed on VM');
}