authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-05 09:16:06-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-05 09:16:06-07:00
log3fbc497b764ed904c4e50655da5b7a722d611fe5
treefdadaa639d21d84dcf8cc5d1b8a352e88dcf4c3c
parenta324cabc04019be14e8b66ec983fabf510ae2b2e
signature Signed by PGP key B5690EEEBB952194

refactor(ssh): keep package internals private (#10144)


4 files changed, 37 insertions(+), 39 deletions(-)

packages/ssh/src/auth.ts+26-28
......@@ -17,7 +17,7 @@ export interface SshPasswordRequest {
1717 readonly attempt: number;
1818}
1919
20export interface SshAskpassFile {
20interface SshAskpassFile {
2121 readonly path: string;
2222 readonly contents: string;
2323 readonly mode?: number;
......@@ -71,7 +71,7 @@ function joinSshAskpassPath(
7171 return platform === "win32" ? `${trimmed}\\${fileName}` : `${trimmed}/${fileName}`;
7272}
7373
74export const ASKPASS_POSIX_SCRIPT = `#!/bin/sh
74const ASKPASS_POSIX_SCRIPT = `#!/bin/sh
7575# Invoked by ssh via SSH_ASKPASS when T3 Code re-runs ssh with a cached password
7676# from the renderer's in-app prompt. We never expose a native dialog here - if
7777# T3_SSH_AUTH_SECRET is missing, that's a caller bug and we fail loudly.
......@@ -83,11 +83,11 @@ printf 'T3 Code ssh-askpass invoked without T3_SSH_AUTH_SECRET.\\n' >&2
8383exit 1
8484`;
8585
86export const ASKPASS_WINDOWS_LAUNCHER_SCRIPT = `@echo off\r
86const ASKPASS_WINDOWS_LAUNCHER_SCRIPT = `@echo off\r
8787powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0ssh-askpass.ps1" %*\r
8888`;
8989
90export const ASKPASS_WINDOWS_SCRIPT = `# Invoked by ssh via SSH_ASKPASS (through ssh-askpass.cmd) when T3 Code re-runs\r
90const ASKPASS_WINDOWS_SCRIPT = `# Invoked by ssh via SSH_ASKPASS (through ssh-askpass.cmd) when T3 Code re-runs\r
9191# ssh with a cached password from the renderer's in-app prompt. We never expose\r
9292# a native dialog here - if T3_SSH_AUTH_SECRET is missing, that's a caller bug\r
9393# and we fail loudly.\r
......@@ -99,7 +99,7 @@ if ($null -ne $env:T3_SSH_AUTH_SECRET) {\r
9999exit 1\r
100100`;
101101
102export const getDefaultSshAskpassDirectory = Effect.fn("ssh/auth.getDefaultSshAskpassDirectory")(
102const getDefaultSshAskpassDirectory = Effect.fn("ssh/auth.getDefaultSshAskpassDirectory")(
103103 function* () {
104104 const fs = yield* FileSystem.FileSystem;
105105 const path = yield* Path.Path;
......@@ -146,31 +146,29 @@ export const buildSshAskpassHelperDescriptor = Effect.fn(
146146 };
147147});
148148
149export const ensureSshAskpassHelpers = Effect.fn("ssh/auth.ensureSshAskpassHelpers")(
150 function* (input: {
151 readonly directory: string;
152 }): Effect.fn.Return<string, PlatformError.PlatformError, FileSystem.FileSystem | Path.Path> {
153 const fs = yield* FileSystem.FileSystem;
154 const path = yield* Path.Path;
155 const descriptor = yield* buildSshAskpassHelperDescriptor(input);
156 const platform = yield* HostProcessPlatform;
157
158 yield* fs.makeDirectory(path.dirname(descriptor.launcherPath), { recursive: true });
159
160 for (const file of descriptor.files) {
161 const existing = yield* fs.exists(file.path);
162 const current = existing ? yield* fs.readFileString(file.path) : null;
163 if (current !== file.contents) {
164 yield* fs.writeFileString(file.path, file.contents);
165 }
166 if (file.mode !== undefined && platform !== "win32") {
167 yield* fs.chmod(file.path, file.mode);
168 }
149const ensureSshAskpassHelpers = Effect.fn("ssh/auth.ensureSshAskpassHelpers")(function* (input: {
150 readonly directory: string;
151}): Effect.fn.Return<string, PlatformError.PlatformError, FileSystem.FileSystem | Path.Path> {
152 const fs = yield* FileSystem.FileSystem;
153 const path = yield* Path.Path;
154 const descriptor = yield* buildSshAskpassHelperDescriptor(input);
155 const platform = yield* HostProcessPlatform;
156
157 yield* fs.makeDirectory(path.dirname(descriptor.launcherPath), { recursive: true });
158
159 for (const file of descriptor.files) {
160 const existing = yield* fs.exists(file.path);
161 const current = existing ? yield* fs.readFileString(file.path) : null;
162 if (current !== file.contents) {
163 yield* fs.writeFileString(file.path, file.contents);
164 }
165 if (file.mode !== undefined && platform !== "win32") {
166 yield* fs.chmod(file.path, file.mode);
169167 }
168 }
170169
171 return descriptor.launcherPath;
172 },
173);
170 return descriptor.launcherPath;
171});
174172
175173export const buildSshChildEnvironment = Effect.fn("ssh/auth.buildSshChildEnvironment")(function* (
176174 input: SshChildEnvironmentOptions = {},
packages/ssh/src/command.ts+1-1
......@@ -80,7 +80,7 @@ export function remoteStateKey(target: DesktopSshEnvironmentTarget): string {
8080 .slice(0, 16);
8181}
8282
83export function buildSshHostSpec(target: DesktopSshEnvironmentTarget): string {
83function buildSshHostSpec(target: DesktopSshEnvironmentTarget): string {
8484 const destination = target.alias.trim() || target.hostname.trim();
8585 if (destination.length === 0) {
8686 throw new Error("SSH target is missing its alias/hostname.");
packages/ssh/src/config.ts+1-1
......@@ -89,7 +89,7 @@ const expandGlob = Effect.fnUntraced(function* (pattern: string) {
8989 return matchedPaths.toSorted((left, right) => left.localeCompare(right));
9090});
9191
92export const collectSshConfigAliasesFromFile = Effect.fnUntraced(function* (
92const collectSshConfigAliasesFromFile = Effect.fnUntraced(function* (
9393 filePath: string,
9494 visited = new Set<string>(),
9595 homeDir: string,
packages/ssh/src/tunnel.ts+9-9
......@@ -49,7 +49,7 @@ import {
4949 SshReadinessError,
5050} from "./errors.ts";
5151
52export const DEFAULT_REMOTE_PORT = 3773;
52const DEFAULT_REMOTE_PORT = 3773;
5353const REMOTE_PORT_SCAN_WINDOW = 200;
5454const SSH_READY_TIMEOUT_MS = 20_000;
5555const SSH_READY_PROBE_TIMEOUT_MS = 1_000;
......@@ -209,7 +209,7 @@ function buildRemoteNodeEngineCheckScript(): string {
209209(${remoteNodeEngineCheckMain.toString()})();`;
210210}
211211
212export function normalizeSshErrorMessage(stderr: string, fallbackMessage: string): string {
212function normalizeSshErrorMessage(stderr: string, fallbackMessage: string): string {
213213 const cleaned = stderr.trim();
214214 return cleaned.length > 0 ? cleaned : fallbackMessage;
215215}
......@@ -270,7 +270,7 @@ function tryPort(port) {
270270})().catch(() => process.exit(1));
271271`;
272272
273export const REMOTE_WAIT_READY_SCRIPT = `const http = require("node:http");
273const REMOTE_WAIT_READY_SCRIPT = `const http = require("node:http");
274274const port = Number.parseInt(process.argv[2] ?? "", 10);
275275const timeoutMs = Number.parseInt(process.argv[3] ?? "", 10);
276276const probeTimeoutMs = Number.parseInt(process.argv[4] ?? "", 10);
......@@ -318,7 +318,7 @@ function probe() {
318318})().catch(() => process.exit(1));
319319`;
320320
321export const REMOTE_NODE_ENV_SCRIPT = `prepend_path_if_dir() {
321const REMOTE_NODE_ENV_SCRIPT = `prepend_path_if_dir() {
322322 if [ -d "$1" ]; then
323323 case ":$PATH:" in
324324 *":$1:"*) ;;
......@@ -411,7 +411,7 @@ ensure_remote_node_path() {
411411}
412412`;
413413
414export const REMOTE_RUNNER_SCRIPT = `#!/bin/sh
414const REMOTE_RUNNER_SCRIPT = `#!/bin/sh
415415set -eu
416416@@T3_NODE_ENV_SCRIPT@@
417417ensure_remote_node_path || true
......@@ -456,7 +456,7 @@ printf 'Remote host is missing the t3 CLI and could not install @@T3_PACKAGE_SPE
456456exit 1
457457`;
458458
459export const REMOTE_LAUNCH_SCRIPT = `set -eu
459const REMOTE_LAUNCH_SCRIPT = `set -eu
460460@@T3_NODE_ENV_SCRIPT@@
461461STATE_KEY="$1"
462462STATE_DIR="$HOME/.t3/ssh-launch/$STATE_KEY"
......@@ -615,7 +615,7 @@ fi
615615printf '{"remotePort":%s,"serverKind":"%s"}\\n' "$REMOTE_PORT" "\${REMOTE_MANAGED:-managed}"
616616`;
617617
618export const REMOTE_PAIRING_SCRIPT = `set -eu
618const REMOTE_PAIRING_SCRIPT = `set -eu
619619STATE_DIR="$HOME/.t3/ssh-launch/@@T3_STATE_KEY@@"
620620DEFAULT_SERVER_HOME="$HOME/.t3"
621621RUNNER_FILE="$STATE_DIR/run-t3.sh"
......@@ -628,7 +628,7 @@ PAIRING_BASE_DIR="$DEFAULT_SERVER_HOME"
628628"$RUNNER_FILE" auth pairing create --base-dir "$PAIRING_BASE_DIR" --json
629629`;
630630
631export const REMOTE_STOP_SCRIPT = `set -eu
631const REMOTE_STOP_SCRIPT = `set -eu
632632STATE_DIR="$HOME/.t3/ssh-launch/@@T3_STATE_KEY@@"
633633PID_FILE="$STATE_DIR/pid"
634634PORT_FILE="$STATE_DIR/port"
......@@ -823,7 +823,7 @@ export const issueRemotePairingToken = Effect.fn("ssh/tunnel.issueRemotePairingT
823823 };
824824});
825825
826export const stopRemoteServer = Effect.fn("ssh/tunnel.stopRemoteServer")(function* (
826const stopRemoteServer = Effect.fn("ssh/tunnel.stopRemoteServer")(function* (
827827 target: DesktopSshEnvironmentTarget,
828828 input?: SshAuthOptions,
829829): Effect.fn.Return<