Skip to content

Commit 09071ca

Browse files
committed
🤖 fix: truncate ssh shard failure stderr
1 parent 5198aab commit 09071ca

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

src/node/runtime/transports/OpenSSHTransport.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,34 @@ describe("OpenSSHTransport.spawnRemoteProcess", () => {
8888
expect(markHealthy).not.toHaveBeenCalled();
8989
});
9090

91+
test("truncates connection-failure stderr before reporting shard health", async () => {
92+
const release = mock(() => undefined);
93+
let reportedError: string | undefined;
94+
const reportFailure = mock((error: string) => {
95+
reportedError = error;
96+
});
97+
const markHealthy = mock(() => undefined);
98+
acquireLeaseSpy.mockResolvedValue({
99+
controlPath: "/tmp/mux-ssh-test-shard",
100+
shardId: "shard-0",
101+
release,
102+
reportFailure,
103+
markHealthy,
104+
});
105+
const transport = new OpenSSHTransport({ host: "remote.example.com" });
106+
const spawnResult = await transport.spawnRemoteProcess("echo ok", {});
107+
const longStderr = `${"x".repeat(1100)}\n`;
108+
109+
spawnResult.onExit?.(255, longStderr);
110+
111+
if (reportedError == null) {
112+
throw new Error("Expected reportFailure to be called with a string error summary");
113+
}
114+
expect(reportedError.length).toBeLessThan(longStderr.trim().length);
115+
expect(reportedError.endsWith("…")).toBe(true);
116+
expect(markHealthy).not.toHaveBeenCalled();
117+
});
118+
91119
test("explicit headless (no service) includes host-key fallback options and BatchMode=yes", async () => {
92120
setSshPromptCapability(false);
93121
setOpenSSHHostKeyPolicyMode("headless-fallback");

src/node/runtime/transports/OpenSSHTransport.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ import type {
1414
PtySessionParams,
1515
} from "./SSHTransport";
1616

17+
const MAX_REPORTED_FAILURE_STDERR_CHARS = 1000;
18+
19+
function summarizeFailureStderr(stderr: string, exitCode: number): string {
20+
const trimmed = stderr.trim();
21+
if (trimmed.length === 0) {
22+
return `SSH exited with code ${exitCode}`;
23+
}
24+
if (trimmed.length <= MAX_REPORTED_FAILURE_STDERR_CHARS) {
25+
return trimmed;
26+
}
27+
return `${trimmed.slice(0, MAX_REPORTED_FAILURE_STDERR_CHARS)}…`;
28+
}
29+
1730
export class OpenSSHTransport implements SSHTransport {
1831
constructor(private readonly config: SSHConnectionConfig) {}
1932

@@ -94,7 +107,7 @@ export class OpenSSHTransport implements SSHTransport {
94107
process,
95108
onExit: (exitCode, stderr) => {
96109
if (this.isConnectionFailure(exitCode, stderr)) {
97-
lease.reportFailure(stderr.trim() || `SSH exited with code ${exitCode}`);
110+
lease.reportFailure(summarizeFailureStderr(stderr, exitCode));
98111
} else {
99112
lease.markHealthy();
100113
}

0 commit comments

Comments
 (0)