import { assert, describe, it } from "@effect/vitest";import * as NodeServices from "@effect/platform-node/NodeServices";import * as Duration from "effect/Duration";import * as Effect from "effect/Effect";import * as Fiber from "effect/Fiber";import * as Layer from "effect/Layer";import * as Result from "effect/Result";import * as Sink from "effect/Sink";import * as Stream from "effect/Stream";import * as TestClock from "effect/testing/TestClock";import { ChildProcessSpawner } from "effect/unstable/process"; import { baseSshArgs, getLastNonEmptyOutputLine, parseSshResolveOutput, resolveRemoteT3CliPackageSpec, runSshCommand,} from "./command.ts";import { SshCommandError } from "./errors.ts"; const encoder = new TextEncoder(); const makeFailedProcess = (input: { readonly stdout: string; readonly stderr?: string }) => { const stdoutStream = Stream.make(encoder.encode(input.stdout)); const stderrStream = input.stderr ? Stream.make(encoder.encode(input.stderr)) : Stream.empty; return ChildProcessSpawner.makeHandle({ pid: ChildProcessSpawner.ProcessId(123), stdout: stdoutStream, stderr: stderrStream, all: Stream.empty, exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(1)), isRunning: Effect.succeed(false), kill: () => Effect.void, stdin: Sink.drain, getInputFd: () => Sink.drain, getOutputFd: () => Stream.empty, unref: Effect.succeed(Effect.void), });}; const makeNeverFinishingProcess = () => { let finish: ((exitCode: ChildProcessSpawner.ExitCode) => void) | null = null; return ChildProcessSpawner.makeHandle({ pid: ChildProcessSpawner.ProcessId(123), stdout: Stream.empty, stderr: Stream.empty, all: Stream.empty, exitCode: Effect.callback<ChildProcessSpawner.ExitCode>((resume) => { finish = (exitCode) => resume(Effect.succeed(exitCode)); return Effect.sync(() => { finish = null; }); }), isRunning: Effect.succeed(true), kill: () => Effect.sync(() => { finish?.(ChildProcessSpawner.ExitCode(143)); }), stdin: Sink.drain, getInputFd: () => Sink.drain, getOutputFd: () => Stream.empty, unref: Effect.succeed(Effect.void), });}; describe("ssh command", () => { it.effect("parses resolved ssh config output into a target", () => Effect.sync(() => { assert.deepEqual( parseSshResolveOutput( "devbox", ["hostname devbox.example.com", "user julius", "port 2222", ""].join("\n"), ), { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, ); }), ); it.effect("builds interactive ssh args without forcing batch mode", () => Effect.sync(() => { assert.deepEqual( baseSshArgs( { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, { batchMode: "no" }, ), ["-o", "BatchMode=no", "-o", "ConnectTimeout=10", "-p", "2222"], ); }), ); it.effect("resolves the remote t3 package spec from the desktop release channel", () => Effect.sync(() => { assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.17", updateChannel: "latest", }), "t3@0.0.17", ); assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.17-nightly.20260415.44", updateChannel: "nightly", }), "t3@0.0.17-nightly.20260415.44", ); assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.0-dev", updateChannel: "nightly", isDevelopment: true, }), "t3@nightly", ); assert.equal( resolveRemoteT3CliPackageSpec({ appVersion: "0.0.0-dev", updateChannel: "latest", isDevelopment: true, }), "t3@nightly", ); }), ); it.effect("reads the last non-empty ssh output line", () => Effect.sync(() => { assert.equal( getLastNonEmptyOutputLine( ["Welcome to the host", "", '{"credential":"pairing-token"}', ""].join("\n"), ), '{"credential":"pairing-token"}', ); }), ); it.effect("includes stdout in non-zero command failures when stderr is empty", () => { const spawner = ChildProcessSpawner.make(() => Effect.succeed(makeFailedProcess({ stdout: "Pairing token creation failed\n" })), ); const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner); const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer); return Effect.gen(function* () { const result = yield* Effect.result( runSshCommand( { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, { remoteCommandArgs: ["sh", "-s"] }, ), ); assert.isTrue(Result.isFailure(result)); if (Result.isFailure(result)) { assert.instanceOf(result.failure, SshCommandError); assert.equal(result.failure.message, "Pairing token creation failed"); assert.equal(result.failure.stdout, "Pairing token creation failed\n"); assert.equal(result.failure.stderr, ""); } }).pipe(Effect.provide(processLayer)); }); it.effect("redacts credentials from stdout in non-zero command failures", () => { const spawner = ChildProcessSpawner.make(() => Effect.succeed(makeFailedProcess({ stdout: '{"credential":"pairing-secret"}\n' })), ); const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner); const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer); return Effect.gen(function* () { const result = yield* Effect.result( runSshCommand( { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, { remoteCommandArgs: ["sh", "-s"] }, ), ); assert.isTrue(Result.isFailure(result)); if (Result.isFailure(result)) { assert.instanceOf(result.failure, SshCommandError); assert.equal(result.failure.message, '{"credential":"[redacted]"}'); assert.equal(result.failure.stdout, '{"credential":"[redacted]"}\n'); } }).pipe(Effect.provide(processLayer)); }); it.effect("fails commands that never finish", () => { const spawner = ChildProcessSpawner.make(() => Effect.succeed(makeNeverFinishingProcess())); const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner); const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer, TestClock.layer()); return Effect.gen(function* () { const fiber = yield* Effect.forkChild( Effect.result( runSshCommand( { alias: "devbox", hostname: "devbox.example.com", username: "julius", port: 2222, }, { timeoutMs: 1 }, ), ), ); yield* Effect.yieldNow; yield* TestClock.adjust(Duration.millis(1)); const result = yield* Fiber.join(fiber); assert.isTrue(Result.isFailure(result)); if (Result.isFailure(result)) { assert.include(result.failure.message, "SSH command timed out after 1ms."); } }).pipe(Effect.provide(processLayer)); });});
import { assert, describe, it } from "@effect/vitest";
import * as NodeServices from "@effect/platform-node/NodeServices";
import * as Duration from "effect/Duration";
import * as Effect from "effect/Effect";
import * as Fiber from "effect/Fiber";
import * as Layer from "effect/Layer";
import * as Result from "effect/Result";
import * as Sink from "effect/Sink";
import * as Stream from "effect/Stream";
import * as TestClock from "effect/testing/TestClock";
import { ChildProcessSpawner } from "effect/unstable/process";
import {
baseSshArgs,
getLastNonEmptyOutputLine,
parseSshResolveOutput,
resolveRemoteT3CliPackageSpec,
runSshCommand,
} from "./command.ts";
import { SshCommandError } from "./errors.ts";
const encoder = new TextEncoder();
const makeFailedProcess = (input: { readonly stdout: string; readonly stderr?: string }) => {
const stdoutStream = Stream.make(encoder.encode(input.stdout));
const stderrStream = input.stderr ? Stream.make(encoder.encode(input.stderr)) : Stream.empty;
return ChildProcessSpawner.makeHandle({
pid: ChildProcessSpawner.ProcessId(123),
stdout: stdoutStream,
stderr: stderrStream,
all: Stream.empty,
exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(1)),
isRunning: Effect.succeed(false),
kill: () => Effect.void,
stdin: Sink.drain,
getInputFd: () => Sink.drain,
getOutputFd: () => Stream.empty,
unref: Effect.succeed(Effect.void),
});
};
const makeNeverFinishingProcess = () => {
let finish: ((exitCode: ChildProcessSpawner.ExitCode) => void) | null = null;
return ChildProcessSpawner.makeHandle({
pid: ChildProcessSpawner.ProcessId(123),
stdout: Stream.empty,
stderr: Stream.empty,
all: Stream.empty,
exitCode: Effect.callback<ChildProcessSpawner.ExitCode>((resume) => {
finish = (exitCode) => resume(Effect.succeed(exitCode));
return Effect.sync(() => {
finish = null;
});
}),
isRunning: Effect.succeed(true),
kill: () =>
Effect.sync(() => {
finish?.(ChildProcessSpawner.ExitCode(143));
}),
stdin: Sink.drain,
getInputFd: () => Sink.drain,
getOutputFd: () => Stream.empty,
unref: Effect.succeed(Effect.void),
});
};
describe("ssh command", () => {
it.effect("parses resolved ssh config output into a target", () =>
Effect.sync(() => {
assert.deepEqual(
parseSshResolveOutput(
"devbox",
["hostname devbox.example.com", "user julius", "port 2222", ""].join("\n"),
),
{
alias: "devbox",
hostname: "devbox.example.com",
username: "julius",
port: 2222,
},
);
}),
);
it.effect("builds interactive ssh args without forcing batch mode", () =>
Effect.sync(() => {
assert.deepEqual(
baseSshArgs(
{
alias: "devbox",
hostname: "devbox.example.com",
username: "julius",
port: 2222,
},
{ batchMode: "no" },
),
["-o", "BatchMode=no", "-o", "ConnectTimeout=10", "-p", "2222"],
);
}),
);
it.effect("resolves the remote t3 package spec from the desktop release channel", () =>
Effect.sync(() => {
assert.equal(
resolveRemoteT3CliPackageSpec({
appVersion: "0.0.17",
updateChannel: "latest",
}),
"t3@0.0.17",
);
assert.equal(
resolveRemoteT3CliPackageSpec({
appVersion: "0.0.17-nightly.20260415.44",
updateChannel: "nightly",
}),
"t3@0.0.17-nightly.20260415.44",
);
assert.equal(
resolveRemoteT3CliPackageSpec({
appVersion: "0.0.0-dev",
updateChannel: "nightly",
isDevelopment: true,
}),
"t3@nightly",
);
assert.equal(
resolveRemoteT3CliPackageSpec({
appVersion: "0.0.0-dev",
updateChannel: "latest",
isDevelopment: true,
}),
"t3@nightly",
);
}),
);
it.effect("reads the last non-empty ssh output line", () =>
Effect.sync(() => {
assert.equal(
getLastNonEmptyOutputLine(
["Welcome to the host", "", '{"credential":"pairing-token"}', ""].join("\n"),
),
'{"credential":"pairing-token"}',
);
}),
);
it.effect("includes stdout in non-zero command failures when stderr is empty", () => {
const spawner = ChildProcessSpawner.make(() =>
Effect.succeed(makeFailedProcess({ stdout: "Pairing token creation failed\n" })),
);
const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner);
const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer);
return Effect.gen(function* () {
const result = yield* Effect.result(
runSshCommand(
{
alias: "devbox",
hostname: "devbox.example.com",
username: "julius",
port: 2222,
},
{ remoteCommandArgs: ["sh", "-s"] },
),
);
assert.isTrue(Result.isFailure(result));
if (Result.isFailure(result)) {
assert.instanceOf(result.failure, SshCommandError);
assert.equal(result.failure.message, "Pairing token creation failed");
assert.equal(result.failure.stdout, "Pairing token creation failed\n");
assert.equal(result.failure.stderr, "");
}
}).pipe(Effect.provide(processLayer));
});
it.effect("redacts credentials from stdout in non-zero command failures", () => {
const spawner = ChildProcessSpawner.make(() =>
Effect.succeed(makeFailedProcess({ stdout: '{"credential":"pairing-secret"}\n' })),
);
const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner);
const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer);
return Effect.gen(function* () {
const result = yield* Effect.result(
runSshCommand(
{
alias: "devbox",
hostname: "devbox.example.com",
username: "julius",
port: 2222,
},
{ remoteCommandArgs: ["sh", "-s"] },
),
);
assert.isTrue(Result.isFailure(result));
if (Result.isFailure(result)) {
assert.instanceOf(result.failure, SshCommandError);
assert.equal(result.failure.message, '{"credential":"[redacted]"}');
assert.equal(result.failure.stdout, '{"credential":"[redacted]"}\n');
}
}).pipe(Effect.provide(processLayer));
});
it.effect("fails commands that never finish", () => {
const spawner = ChildProcessSpawner.make(() => Effect.succeed(makeNeverFinishingProcess()));
const spawnerLayer = Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner);
const processLayer = Layer.mergeAll(NodeServices.layer, spawnerLayer, TestClock.layer());
return Effect.gen(function* () {
const fiber = yield* Effect.forkChild(
Effect.result(
runSshCommand(
{
alias: "devbox",
hostname: "devbox.example.com",
username: "julius",
port: 2222,
},
{ timeoutMs: 1 },
),
),
);
yield* Effect.yieldNow;
yield* TestClock.adjust(Duration.millis(1));
const result = yield* Fiber.join(fiber);
assert.isTrue(Result.isFailure(result));
if (Result.isFailure(result)) {
assert.include(result.failure.message, "SSH command timed out after 1ms.");
}
}).pipe(Effect.provide(processLayer));
});
});