(
identityFiles: string[],
agentOverride: string | undefined
)
| 458 | }; |
| 459 | |
| 460 | const attemptConnection = async ( |
| 461 | identityFiles: string[], |
| 462 | agentOverride: string | undefined |
| 463 | ): Promise<SSH2ConnectionEntry> => { |
| 464 | const resolvedConfigWithIdentities: ResolvedSSHConfig = { |
| 465 | ...resolvedConfig, |
| 466 | identityFiles, |
| 467 | }; |
| 468 | |
| 469 | const readableKeys = await resolvePrivateKeys(resolvedConfigWithIdentities.identityFiles); |
| 470 | if (abortSignal?.aborted) { |
| 471 | throw new Error(SSH2_OPERATION_ABORTED_ERROR); |
| 472 | } |
| 473 | const keysToTry: Array<Buffer | undefined> = |
| 474 | readableKeys.length > 0 ? readableKeys : [undefined]; |
| 475 | // Keep the sshPromptService wiring in place so known_hosts-backed |
| 476 | // verification can be restored without changing the public module API. |
| 477 | void sshPromptService; |
| 478 | |
| 479 | const connectWithKey = async ( |
| 480 | privateKey: Buffer | undefined, |
| 481 | reportAuthFailure: boolean |
| 482 | ): Promise<SSH2ConnectionEntry> => { |
| 483 | const proxy = resolvedConfigWithIdentities.proxyCommand |
| 484 | ? spawnProxyCommand(resolvedConfigWithIdentities.proxyCommand, proxyTokens) |
| 485 | : undefined; |
| 486 | |
| 487 | // Lazy-load ssh2 to avoid loading the native sshcrypto.node module at |
| 488 | // startup. Bun doesn't support the libuv functions the NAPI module calls, |
| 489 | // so eagerly importing ssh2 crashes the headless CLI in sandboxes. |
| 490 | const { Client: SSH2Client } = await import("ssh2"); |
| 491 | const client = new SSH2Client(); |
| 492 | const entry: SSH2ConnectionEntry = { |
| 493 | client, |
| 494 | resolvedConfig: resolvedConfigWithIdentities, |
| 495 | proxyProcess: proxy?.process, |
| 496 | lastActivityAt: Date.now(), |
| 497 | }; |
| 498 | |
| 499 | const cleanupProxy = () => { |
| 500 | if (proxy?.process?.exitCode === null) { |
| 501 | proxy.process.kill(); |
| 502 | } |
| 503 | }; |
| 504 | |
| 505 | const cleanupProxySocket = () => { |
| 506 | if (proxy?.sock && !proxy.sock.destroyed) { |
| 507 | proxy.sock.destroy(); |
| 508 | } |
| 509 | cleanupProxy(); |
| 510 | }; |
| 511 | |
| 512 | if (proxy) { |
| 513 | // ProxyCommand streams can emit EPIPE/ECONNRESET; handle to avoid crashes. |
| 514 | const attach = (emitter: NodeJS.EventEmitter, label: string) => { |
| 515 | attachStreamErrorHandler(emitter, label, { |
| 516 | logger: log, |
| 517 | onIgnorable: cleanupProxySocket, |
nothing calls this directly
no test coverage detected