Skip to content

Commit 6cdbfd1

Browse files
authored
🤖 fix: suppress SSH warnings that pollute command output (#981)
Move `LogLevel=ERROR` outside the `identityFile` conditional so it applies to all SSH connections. This prevents SSH ControlMaster warnings like `mux_client_request_session` and `ControlSocket already exists` from appearing in git command output (e.g., as fake untracked files in the Review tab). Also refactors `exec()` to use `buildSSHArgs()` helper, eliminating ~30 lines of duplicated SSH arg building code. _Generated with `mux`_
1 parent 4731ce1 commit 6cdbfd1

File tree

1 file changed

+11
-41
lines changed

1 file changed

+11
-41
lines changed

src/node/runtime/SSHRuntime.ts

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -174,39 +174,10 @@ export class SSHRuntime implements Runtime {
174174
fullCommand = `timeout -s KILL ${remoteTimeout} ${fullCommand}`;
175175
}
176176

177-
// Build SSH args
177+
// Build SSH args from shared base config
178178
// -T: Disable pseudo-terminal allocation (default)
179179
// -t: Force pseudo-terminal allocation (for interactive shells)
180-
const sshArgs: string[] = [options.forcePTY ? "-t" : "-T"];
181-
182-
// Add port if specified
183-
if (this.config.port) {
184-
sshArgs.push("-p", this.config.port.toString());
185-
}
186-
187-
// Add identity file if specified
188-
if (this.config.identityFile) {
189-
sshArgs.push("-i", this.config.identityFile);
190-
// Disable strict host key checking for test environments
191-
sshArgs.push("-o", "StrictHostKeyChecking=no");
192-
sshArgs.push("-o", "UserKnownHostsFile=/dev/null");
193-
sshArgs.push("-o", "LogLevel=ERROR"); // Suppress SSH warnings
194-
}
195-
196-
// Enable SSH connection multiplexing for better performance and to avoid
197-
// exhausting connection limits when running many concurrent operations
198-
// ControlMaster=auto: Create master connection if none exists, otherwise reuse
199-
// ControlPath: Unix socket path for multiplexing
200-
// ControlPersist=60: Keep master connection alive for 60s after last session
201-
//
202-
// Socket reuse is safe even with timeouts because:
203-
// - Each SSH command gets its own channel within the multiplexed connection
204-
// - SIGKILL on the client immediately closes that channel
205-
// - Remote sshd terminates the command when the channel closes
206-
// - Multiplexing only shares the TCP connection, not command lifetime
207-
sshArgs.push("-o", "ControlMaster=auto");
208-
sshArgs.push("-o", `ControlPath=${this.controlPath}`);
209-
sshArgs.push("-o", "ControlPersist=60");
180+
const sshArgs: string[] = [options.forcePTY ? "-t" : "-T", ...this.buildSSHArgs()];
210181

211182
// Set comprehensive timeout options to ensure SSH respects the timeout
212183
// ConnectTimeout: Maximum time to wait for connection establishment (DNS, TCP handshake, SSH auth)
@@ -675,10 +646,10 @@ export class SSHRuntime implements Runtime {
675646
}
676647

677648
/**
678-
* Build common SSH arguments based on runtime config
679-
* @param includeHost - Whether to include the host in the args (for direct ssh commands)
649+
* Build base SSH args shared by all SSH operations.
650+
* Includes: port, identity file, LogLevel, ControlMaster options.
680651
*/
681-
private buildSSHArgs(includeHost = false): string[] {
652+
private buildSSHArgs(): string[] {
682653
const args: string[] = [];
683654

684655
// Add port if specified
@@ -692,19 +663,18 @@ export class SSHRuntime implements Runtime {
692663
// Disable strict host key checking for test environments
693664
args.push("-o", "StrictHostKeyChecking=no");
694665
args.push("-o", "UserKnownHostsFile=/dev/null");
695-
args.push("-o", "LogLevel=ERROR");
696666
}
697667

668+
// Suppress SSH warnings (e.g., ControlMaster messages) that would pollute command output
669+
// These go to stderr and get merged with stdout in bash tool results
670+
args.push("-o", "LogLevel=ERROR");
671+
698672
// Add ControlMaster options for connection multiplexing
699-
// This ensures git bundle transfers also reuse the master connection
673+
// This ensures all SSH operations reuse the master connection
700674
args.push("-o", "ControlMaster=auto");
701675
args.push("-o", `ControlPath=${this.controlPath}`);
702676
args.push("-o", "ControlPersist=60");
703677

704-
if (includeHost) {
705-
args.push(this.config.host);
706-
}
707-
708678
return args;
709679
}
710680

@@ -767,7 +737,7 @@ export class SSHRuntime implements Runtime {
767737
return;
768738
}
769739

770-
const sshArgs = this.buildSSHArgs(true);
740+
const sshArgs = [...this.buildSSHArgs(), this.config.host];
771741
const command = `cd ${shescape.quote(projectPath)} && git bundle create - --all | ssh ${sshArgs.join(" ")} "cat > ${bundleTempPath}"`;
772742

773743
log.debug(`Creating bundle: ${command}`);

0 commit comments

Comments
 (0)