Files
orca/src/main/ssh/ssh-connection-utils.test.ts
T
Neil fed1eca486 test: stop restating internal tuning constants, keep the ones that are contracts (#23950)
Removes ~74 assertions of the form `expect(SOME_CONSTANT).toBe(<literal>)` where
the literal is an internal tuning value — a timeout, retry count, debounce
interval, cache TTL, circuit-breaker window, Tailwind class string. Those cannot
fail for any reason a user would notice: they fail only when someone deliberately
changes the number, and then the test is simply updated. They are copies of the
declaration.

The same pattern is NOT junk when the exact value is observable outside this
process, so those were deliberately kept:
- terminal byte contracts: `\r`, `\x03` ETX, Kitty escapes, `\x1b[?1;2c`;
- wire and capability values: `agent.launch.v2`, protocol 3 / min-compatible 2,
  daemon per-feature boundary versions (a daemon survives app updates, so those
  pin what an old field daemon may be trusted with), relay header tokens;
- security invariants: the `127.0.0.1` bind default, an empty iframe `sandbox`;
- values external processes read: exit code 78 (EX_CONFIG) and exit code 3
  (systemd `RestartPreventExitStatus`), `ORCA_AGENT_SESSION_SPAWN_TOKEN`,
  `npx skills …` commands users paste, on-disk journal schema versions,
  the `orca_<hash>` filename prefix the fish sweeper matches;
- third-party names: expo-router's `unstable_settings` / `ErrorBoundary`,
  iOS Safari's 16px zoom threshold.

Where a case asserted a relation rather than a literal — `A < B`, a sum of parts,
a cap compared against a sibling budget — the relation stays and only the literal
went.

Test-only changes: no production file is touched and no test file is deleted.
2026-09-29 17:06:09 -07:00

775 lines
27 KiB
TypeScript

import { afterEach, describe, expect, it, vi, beforeEach } from 'vitest'
import { join } from 'node:path'
import { BaseAgent, utils, type ParsedKey } from 'ssh2'
vi.mock('os', () => ({
homedir: () => '/home/testuser'
}))
const mockExistsSync = vi.fn().mockReturnValue(false)
const mockReadFileSync = vi.fn()
const TEST_HOME = '/home/testuser'
function testHomePath(...parts: string[]): string {
return join(TEST_HOME, ...parts)
}
vi.mock('fs', () => ({
existsSync: (...args: unknown[]) => mockExistsSync(...args),
readFileSync: (...args: unknown[]) => mockReadFileSync(...args)
}))
import {
isTransientError,
isSystemSshFallbackError,
isGssapiSystemSshFallbackCandidate,
isAuthError,
isAgentFallbackError,
sleep,
shellEscape,
findDefaultKeyFile,
buildConnectConfig,
resolveAgentSocket
} from './ssh-connection-utils'
import { resolveEffectiveProxy } from './ssh-proxy-command'
import type { SshTarget } from '../../shared/ssh-types'
import type { SshResolvedConfig } from './ssh-config-parser'
// ── isTransientError ─────────────────────────────────────────────────
describe('isTransientError', () => {
it('returns true for ETIMEDOUT code', () => {
const err = new Error('timed out') as NodeJS.ErrnoException
err.code = 'ETIMEDOUT'
expect(isTransientError(err)).toBe(true)
})
it('returns true for ECONNREFUSED code', () => {
const err = new Error('refused') as NodeJS.ErrnoException
err.code = 'ECONNREFUSED'
expect(isTransientError(err)).toBe(true)
})
it('returns true for ECONNRESET code', () => {
const err = new Error('reset') as NodeJS.ErrnoException
err.code = 'ECONNRESET'
expect(isTransientError(err)).toBe(true)
})
it('returns true for EHOSTUNREACH code', () => {
const err = new Error('host unreachable') as NodeJS.ErrnoException
err.code = 'EHOSTUNREACH'
expect(isTransientError(err)).toBe(true)
})
it('returns true for ENETUNREACH code', () => {
const err = new Error('net unreachable') as NodeJS.ErrnoException
err.code = 'ENETUNREACH'
expect(isTransientError(err)).toBe(true)
})
it('returns true for EAI_AGAIN code', () => {
const err = new Error('dns') as NodeJS.ErrnoException
err.code = 'EAI_AGAIN'
expect(isTransientError(err)).toBe(true)
})
it('returns true for ETIMEDOUT in message (no code)', () => {
expect(isTransientError(new Error('connect ETIMEDOUT 1.2.3.4:22'))).toBe(true)
})
it('returns true for ECONNREFUSED in message', () => {
expect(isTransientError(new Error('connect ECONNREFUSED 1.2.3.4:22'))).toBe(true)
})
it('returns true for ECONNRESET in message', () => {
expect(isTransientError(new Error('read ECONNRESET'))).toBe(true)
})
it('returns true for the bounded SSH authentication watchdog', () => {
const timeout = Object.assign(new Error('Timed out while waiting for SSH authentication'), {
level: 'client-timeout'
})
expect(isTransientError(timeout)).toBe(true)
expect(isTransientError(new Error('Timed out while waiting for SSH authentication'))).toBe(true)
})
it('returns false for auth errors', () => {
expect(isTransientError(new Error('All configured authentication methods failed'))).toBe(false)
})
it('returns false for generic errors', () => {
expect(isTransientError(new Error('something went wrong'))).toBe(false)
})
})
// ── isSystemSshFallbackError ─────────────────────────────────────────
describe('isSystemSshFallbackError', () => {
it('returns true for local reachability errors that system ssh may bypass', () => {
const hostErr = new Error('host unreachable') as NodeJS.ErrnoException
hostErr.code = 'EHOSTUNREACH'
const netErr = new Error('net unreachable') as NodeJS.ErrnoException
netErr.code = 'ENETUNREACH'
expect(isSystemSshFallbackError(hostErr)).toBe(true)
expect(isSystemSshFallbackError(netErr)).toBe(true)
})
it('returns false for transient errors that should keep the normal retry path', () => {
const refused = new Error('refused') as NodeJS.ErrnoException
refused.code = 'ECONNREFUSED'
expect(isSystemSshFallbackError(refused)).toBe(false)
expect(isSystemSshFallbackError(new Error('connect ETIMEDOUT 1.2.3.4:22'))).toBe(false)
})
})
// ── isGssapiSystemSshFallbackCandidate ───────────────────────────────
describe('isGssapiSystemSshFallbackCandidate', () => {
const authErr = new Error('All configured authentication methods failed')
it('returns true for auth failures when resolved config enables GSSAPI', () => {
expect(isGssapiSystemSshFallbackCandidate(authErr, {}, { gssapiAuthentication: true })).toBe(
true
)
})
it('returns true for passphrase failures so Kerberos SSO runs before prompting', () => {
const passphraseErr = new Error('Encrypted private OpenSSH key detected, but no passphrase')
expect(
isGssapiSystemSshFallbackCandidate(passphraseErr, {}, { gssapiAuthentication: true })
).toBe(true)
})
it('returns false when the target already tried system ssh proactively', () => {
expect(
isGssapiSystemSshFallbackCandidate(
authErr,
{ gssapiAuthentication: true },
{ gssapiAuthentication: true }
)
).toBe(false)
})
it('returns false without GSSAPI in the resolved config', () => {
expect(isGssapiSystemSshFallbackCandidate(authErr, {}, { gssapiAuthentication: false })).toBe(
false
)
expect(isGssapiSystemSshFallbackCandidate(authErr, {}, null)).toBe(false)
})
it('returns false for network errors so retry semantics stay unchanged', () => {
const netErr = new Error('connect ETIMEDOUT 1.2.3.4:22')
expect(isGssapiSystemSshFallbackCandidate(netErr, {}, { gssapiAuthentication: true })).toBe(
false
)
})
})
// ── isAuthError ──────────────────────────────────────────────────────
describe('isAuthError', () => {
it('returns true for "All configured authentication methods failed"', () => {
expect(isAuthError(new Error('All configured authentication methods failed'))).toBe(true)
})
it('returns true for "Authentication failed"', () => {
expect(isAuthError(new Error('Authentication failed'))).toBe(true)
})
it('returns true for client-authentication level', () => {
const err = new Error('auth') as Error & { level: string }
err.level = 'client-authentication'
expect(isAuthError(err)).toBe(true)
})
it('returns true for server auth-attempt exhaustion', () => {
expect(isAuthError(new Error('Received disconnect: Too many authentication failures'))).toBe(
true
)
})
it.each([
'Permission denied (publickey).',
'Permission denied (publickey,password).',
'Permission denied, please try again.'
])('detects OpenSSH credential rejection: %s', (message) => {
expect(isAuthError(new Error(message))).toBe(true)
})
it('returns false for transient errors', () => {
expect(isAuthError(new Error('connect ETIMEDOUT'))).toBe(false)
})
it('does not classify a local filesystem permission failure as authentication', () => {
expect(isAuthError(new Error('Permission denied (os error 13)'))).toBe(false)
})
})
// ── isAgentFallbackError ────────────────────────────────────────────
describe('isAgentFallbackError', () => {
it('returns true for ssh2 agent-level failures', () => {
const err = new Error('Failed to connect to agent') as Error & { level: string }
err.level = 'agent'
expect(isAgentFallbackError(err)).toBe(true)
})
it('returns true when agent auth exhausts the server auth attempt limit', () => {
expect(
isAgentFallbackError(new Error('Received disconnect: Too many authentication failures'))
).toBe(true)
})
it('keeps unrelated transport errors out of agent fallback handling', () => {
expect(isAgentFallbackError(new Error('connect ECONNRESET'))).toBe(false)
})
})
// ── sleep ────────────────────────────────────────────────────────────
describe('sleep', () => {
it('resolves after the given delay', async () => {
const start = Date.now()
await sleep(50)
expect(Date.now() - start).toBeGreaterThanOrEqual(40)
})
})
// ── shellEscape ──────────────────────────────────────────────────────
describe('shellEscape', () => {
it('wraps string in single quotes', () => {
expect(shellEscape('hello')).toBe("'hello'")
})
it('escapes embedded single quotes', () => {
expect(shellEscape("it's")).toBe("'it'\\''s'")
})
it('handles empty string', () => {
expect(shellEscape('')).toBe("''")
})
it('handles special characters', () => {
expect(shellEscape('foo bar; rm -rf /')).toBe("'foo bar; rm -rf /'")
})
})
// ── findDefaultKeyFile ───────────────────────────────────────────────
describe('findDefaultKeyFile', () => {
beforeEach(() => {
mockExistsSync.mockReset()
mockExistsSync.mockReturnValue(false)
mockReadFileSync.mockReset()
})
it('returns undefined when no default keys exist', () => {
expect(findDefaultKeyFile()).toBeUndefined()
})
it('returns the first existing key file', () => {
mockExistsSync.mockImplementation((path: unknown) => {
return path === testHomePath('.ssh', 'id_ed25519')
})
mockReadFileSync.mockReturnValue(Buffer.from('key-contents'))
const result = findDefaultKeyFile()
expect(result).toBeDefined()
expect(result!.path).toBe('~/.ssh/id_ed25519')
expect(result!.contents).toEqual(Buffer.from('key-contents'))
})
it('probes regular and FIDO2 keys in stable default order', () => {
const checkedPaths: string[] = []
mockExistsSync.mockImplementation((path: unknown) => {
checkedPaths.push(String(path))
return false
})
findDefaultKeyFile()
expect(checkedPaths).toEqual([
testHomePath('.ssh', 'id_ed25519'),
testHomePath('.ssh', 'id_rsa'),
testHomePath('.ssh', 'id_ecdsa'),
testHomePath('.ssh', 'id_dsa'),
testHomePath('.ssh', 'id_xmss')
])
})
it('keeps a regular default ahead of a malformed FIDO2 default', () => {
mockExistsSync.mockImplementation((path: unknown) => {
return (
path === testHomePath('.ssh', 'id_rsa') || path === testHomePath('.ssh', 'id_ed25519_sk')
)
})
mockReadFileSync.mockImplementation((path: unknown) => {
if (String(path) === testHomePath('.ssh', 'id_ed25519_sk')) {
throw new Error('malformed FIDO2 key')
}
return Buffer.from('rsa-key')
})
expect(findDefaultKeyFile()).toEqual({
path: '~/.ssh/id_rsa',
contents: Buffer.from('rsa-key')
})
})
it('leaves FIDO2 defaults out of the ssh2 private-key fallback', () => {
mockExistsSync.mockImplementation((path: unknown) => {
return path === testHomePath('.ssh', 'id_ed25519_sk')
})
expect(findDefaultKeyFile()).toBeUndefined()
expect(mockReadFileSync).not.toHaveBeenCalled()
})
it('skips unreadable key files and tries next', () => {
mockExistsSync.mockImplementation((path: unknown) => {
return path === testHomePath('.ssh', 'id_ed25519') || path === testHomePath('.ssh', 'id_rsa')
})
mockReadFileSync.mockImplementation((path: unknown) => {
if (String(path) === testHomePath('.ssh', 'id_ed25519')) {
throw new Error('permission denied')
}
return Buffer.from('rsa-key')
})
const result = findDefaultKeyFile()
expect(result).toBeDefined()
expect(result!.path).toBe('~/.ssh/id_rsa')
})
})
// ── buildConnectConfig ──────────────────────────────────────────────
function makeTarget(overrides?: Partial<SshTarget>): SshTarget {
return {
id: 'test-1',
label: 'myhost',
host: 'example.com',
port: 22,
username: 'deploy',
...overrides
}
}
function makeResolved(overrides?: Partial<SshResolvedConfig>): SshResolvedConfig {
return {
hostname: '10.0.0.1',
port: 22,
identityFile: [],
forwardAgent: false,
identitiesOnly: false,
proxyUseFdpass: false,
controlMaster: 'no',
controlPersist: 'no',
userKnownHostsFiles: [],
globalKnownHostsFiles: [],
strictHostKeyChecking: 'ask',
hashKnownHosts: false,
updateHostKeys: 'no',
...overrides
}
}
describe('buildConnectConfig', () => {
const originalEnv = process.env.SSH_AUTH_SOCK
beforeEach(() => {
mockExistsSync.mockReset()
mockExistsSync.mockReturnValue(false)
mockReadFileSync.mockReset()
process.env.SSH_AUTH_SOCK = '/tmp/agent.sock'
})
afterEach(() => {
vi.restoreAllMocks()
if (originalEnv !== undefined) {
process.env.SSH_AUTH_SOCK = originalEnv
} else {
delete process.env.SSH_AUTH_SOCK
}
})
it('uses target host/port/username', () => {
const config = buildConnectConfig(makeTarget(), null)
expect(config.host).toBe('example.com')
expect(config.port).toBe(22)
expect(config.username).toBe('deploy')
})
it('falls back to resolved config when target fields are empty', () => {
const config = buildConnectConfig(
makeTarget({ host: '', port: 0, username: '' }),
makeResolved({ hostname: '10.0.0.1', port: 2222, user: 'admin' })
)
expect(config.host).toBe('10.0.0.1')
expect(config.port).toBe(2222)
expect(config.username).toBe('admin')
})
it('uses ssh -G HostName when a config-host target still points at its alias', () => {
const config = buildConnectConfig(
makeTarget({ label: 'workbox', configHost: 'workbox', host: 'workbox' }),
makeResolved({ hostname: 'workbox.internal' })
)
expect(config.host).toBe('workbox.internal')
})
it('uses ssh -G Port when a config-host target still has the default port', () => {
const config = buildConnectConfig(
makeTarget({ configHost: 'workbox', host: 'workbox', port: 22 }),
makeResolved({ port: 2202 })
)
expect(config.port).toBe(2202)
})
it('keeps explicit non-default target ports ahead of ssh -G Port', () => {
const config = buildConnectConfig(
makeTarget({ configHost: 'workbox', host: 'workbox', port: 2022 }),
makeResolved({ port: 2202 })
)
expect(config.port).toBe(2022)
})
it('uses fresh OpenSSH endpoint authority for imported config targets', () => {
const config = buildConnectConfig(
makeTarget({
source: 'ssh-config',
configHost: 'workbox',
host: 'stale.example.com',
port: 2022,
username: 'stale-user'
}),
makeResolved({
hostname: 'current.example.com',
port: 2202,
user: 'current-user'
})
)
expect(config.host).toBe('current.example.com')
expect(config.port).toBe(2202)
expect(config.username).toBe('current-user')
})
it('keeps imported endpoint fields as the fallback when ssh -G is unavailable', () => {
const config = buildConnectConfig(
makeTarget({
source: 'ssh-config',
configHost: 'workbox',
host: 'fallback.example.com',
port: 2022,
username: 'fallback-user'
}),
null
)
expect(config.host).toBe('fallback.example.com')
expect(config.port).toBe(2022)
expect(config.username).toBe('fallback-user')
})
it('sets readyTimeout to CONNECT_TIMEOUT_MS', () => {
const config = buildConnectConfig(makeTarget(), null)
expect(config.readyTimeout).toBe(30_000)
})
it('sets keepaliveInterval to 15s', () => {
const config = buildConnectConfig(makeTarget(), null)
expect(config.keepaliveInterval).toBe(15_000)
})
it('enables keyboard-interactive auth so MFA challenges can be answered', () => {
const config = buildConnectConfig(makeTarget(), null)
expect(config.tryKeyboard).toBe(true)
})
it('uses agent auth when no explicit key and SSH_AUTH_SOCK is set', () => {
const config = buildConnectConfig(makeTarget(), null)
expect(config.agent).toBe('/tmp/agent.sock')
})
it('enables agent forwarding when OpenSSH config requests it and an agent is available', () => {
const config = buildConnectConfig(makeTarget(), makeResolved({ forwardAgent: true }))
expect(config.agent).toBe('/tmp/agent.sock')
expect(config.agentForward).toBe(true)
})
it('does not enable agent forwarding without a usable agent', () => {
const platformSpy = vi.spyOn(process, 'platform', 'get').mockReturnValue('linux')
delete process.env.SSH_AUTH_SOCK
try {
const config = buildConnectConfig(makeTarget(), makeResolved({ forwardAgent: true }))
expect(config.agent).toBeUndefined()
expect(config.agentForward).toBeUndefined()
} finally {
platformSpy.mockRestore()
}
})
it('uses configured IdentityAgent before SSH_AUTH_SOCK', () => {
const config = buildConnectConfig(
makeTarget(),
makeResolved({ identityAgent: '/tmp/one-password.sock' })
)
expect(config.agent).toBe('/tmp/one-password.sock')
})
it('prefers ssh -G resolved IdentityAgent for config-host targets', () => {
const config = buildConnectConfig(
makeTarget({ configHost: 'work', identityAgent: '%d/.1password/agent.sock' }),
makeResolved({ identityAgent: testHomePath('.1password', 'agent.sock') })
)
expect(config.agent).toBe(testHomePath('.1password', 'agent.sock'))
})
it('allows IdentityAgent none to disable agent auth', () => {
const config = buildConnectConfig(makeTarget(), makeResolved({ identityAgent: 'none' }))
expect(config.agent).toBeUndefined()
})
it('resolves IdentityAgent SSH_AUTH_SOCK from the environment', () => {
expect(resolveAgentSocket(makeTarget(), makeResolved({ identityAgent: 'SSH_AUTH_SOCK' }))).toBe(
'/tmp/agent.sock'
)
expect(
resolveAgentSocket(makeTarget(), makeResolved({ identityAgent: '$SSH_AUTH_SOCK' }))
).toBe('/tmp/agent.sock')
})
it('uses the Windows OpenSSH agent pipe when no environment socket is available on Windows', () => {
const platformSpy = vi.spyOn(process, 'platform', 'get').mockReturnValue('win32')
delete process.env.SSH_AUTH_SOCK
try {
expect(resolveAgentSocket(makeTarget(), null)).toBe('\\\\.\\pipe\\openssh-ssh-agent')
} finally {
platformSpy.mockRestore()
}
})
it('wraps agent auth with IdentityFile filtering when IdentitiesOnly is enabled', () => {
mockReadFileSync.mockImplementation((path: unknown) => {
if (String(path) === '/home/user/.ssh/work_key.pub') {
return 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILI4wa2zRZoB26D015dsafYmu3jDCI7rh26bFXZrUiAp test-key'
}
throw new Error('unexpected read')
})
const config = buildConnectConfig(
makeTarget(),
makeResolved({ identityFile: ['/home/user/.ssh/work_key'], identitiesOnly: true })
)
expect(config.agent).toMatchObject({ kind: 'identity-filtered-agent' })
expect(config.agent).toBeInstanceOf(BaseAgent)
expect(config.privateKey).toBeUndefined()
expect(mockReadFileSync).toHaveBeenCalledWith('/home/user/.ssh/work_key.pub')
})
it('does not offer broad agent auth when IdentitiesOnly keys cannot be parsed', () => {
mockReadFileSync.mockReturnValue(Buffer.from('not-a-key'))
const config = buildConnectConfig(
makeTarget(),
makeResolved({ identityFile: ['/home/user/.ssh/work_key'], identitiesOnly: true })
)
expect(config.agent).toBeUndefined()
expect(config.privateKey).toEqual(Buffer.from('not-a-key'))
})
it('includes unencrypted target.identityFile auth when an agent is available', () => {
vi.spyOn(utils, 'parseKey').mockReturnValue({
isPrivateKey: () => true
} as ParsedKey)
mockReadFileSync.mockReturnValue(Buffer.from('key'))
const config = buildConnectConfig(makeTarget({ identityFile: '/home/user/.ssh/custom' }), null)
expect(config.agent).toBe('/tmp/agent.sock')
expect(config.privateKey).toEqual(Buffer.from('key'))
expect(mockReadFileSync).toHaveBeenCalledWith('/home/user/.ssh/custom')
})
it('defers encrypted target.identityFile auth when an agent is available', () => {
vi.spyOn(utils, 'parseKey').mockReturnValue(
new Error('Encrypted private OpenSSH key detected, but no passphrase given')
)
mockReadFileSync.mockReturnValue(Buffer.from('encrypted-key'))
const config = buildConnectConfig(makeTarget({ identityFile: '/home/user/.ssh/custom' }), null)
expect(config.agent).toBe('/tmp/agent.sock')
expect(config.privateKey).toBeUndefined()
expect(mockReadFileSync).toHaveBeenCalledWith('/home/user/.ssh/custom')
})
it('uses keyFile auth when target.identityFile is set and no agent is available', () => {
const platformSpy = vi.spyOn(process, 'platform', 'get').mockReturnValue('linux')
delete process.env.SSH_AUTH_SOCK
mockReadFileSync.mockReturnValue(Buffer.from('key'))
try {
const config = buildConnectConfig(
makeTarget({ identityFile: '/home/user/.ssh/custom' }),
null
)
expect(config.privateKey).toEqual(Buffer.from('key'))
expect(config.agent).toBeUndefined()
} finally {
platformSpy.mockRestore()
}
})
it('uses fresh OpenSSH IdentityFile authority for imported config targets', () => {
mockReadFileSync.mockImplementation((path: unknown) => Buffer.from(String(path)))
const config = buildConnectConfig(
makeTarget({
source: 'ssh-config',
configHost: 'workbox',
identityFile: '/home/user/.ssh/stale'
}),
makeResolved({ identityFile: ['/home/user/.ssh/current'] }),
{ includeAgent: false, includePrivateKey: true }
)
expect(config.privateKey).toEqual(Buffer.from('/home/user/.ssh/current'))
expect(mockReadFileSync).toHaveBeenCalledWith('/home/user/.ssh/current')
})
it('expands Windows-style target.identityFile before reading private key', () => {
mockReadFileSync.mockReturnValue(Buffer.from('key'))
const config = buildConnectConfig(makeTarget({ identityFile: '~\\.ssh\\custom' }), null, {
includeAgent: false,
includePrivateKey: true
})
expect(config.privateKey).toEqual(Buffer.from('key'))
expect(mockReadFileSync).toHaveBeenCalledWith(testHomePath('.ssh', 'custom'))
})
it('includes unencrypted resolved identityFile auth when an agent is available', () => {
vi.spyOn(utils, 'parseKey').mockReturnValue({
isPrivateKey: () => true
} as ParsedKey)
mockReadFileSync.mockReturnValue(Buffer.from('custom-key'))
const config = buildConnectConfig(
makeTarget(),
makeResolved({ identityFile: ['/home/user/.ssh/work_key'] })
)
expect(config.agent).toBe('/tmp/agent.sock')
expect(config.privateKey).toEqual(Buffer.from('custom-key'))
})
it('uses agent auth without probing when resolved identityFile is a default path (expanded)', () => {
const config = buildConnectConfig(
makeTarget(),
makeResolved({ identityFile: [testHomePath('.ssh', 'id_ed25519')] })
)
expect(config.agent).toBe('/tmp/agent.sock')
expect(config.privateKey).toBeUndefined()
expect(mockReadFileSync).not.toHaveBeenCalled()
})
it('does not probe default key files before agent auth', () => {
mockExistsSync.mockImplementation(
(p: unknown) => String(p) === testHomePath('.ssh', 'id_ed25519')
)
const config = buildConnectConfig(makeTarget(), null)
expect(config.agent).toBe('/tmp/agent.sock')
expect(config.privateKey).toBeUndefined()
expect(mockExistsSync).not.toHaveBeenCalled()
})
it('provides fallback key when no agent is available', () => {
const platformSpy = vi.spyOn(process, 'platform', 'get').mockReturnValue('linux')
delete process.env.SSH_AUTH_SOCK
mockExistsSync.mockImplementation(
(p: unknown) => String(p) === testHomePath('.ssh', 'id_ed25519')
)
mockReadFileSync.mockReturnValue(Buffer.from('fallback'))
try {
const config = buildConnectConfig(makeTarget(), null)
expect(config.agent).toBeUndefined()
expect(config.privateKey).toEqual(Buffer.from('fallback'))
} finally {
platformSpy.mockRestore()
}
})
it('can force private key inclusion for the post-agent fallback path', () => {
mockReadFileSync.mockReturnValue(Buffer.from('key'))
const config = buildConnectConfig(
makeTarget({ identityFile: '/home/user/.ssh/custom' }),
null,
{ includeAgent: false, includePrivateKey: true }
)
expect(config.agent).toBeUndefined()
expect(config.privateKey).toEqual(Buffer.from('key'))
})
})
// ── resolveEffectiveProxy ───────────────────────────────────────────
describe('resolveEffectiveProxy', () => {
it('returns target.proxyCommand first', () => {
const target = { ...makeTarget(), proxyCommand: 'cloudflared access ssh --hostname %h' }
const resolved = makeResolved({ proxyCommand: 'other' })
expect(resolveEffectiveProxy(target, resolved)).toEqual({
kind: 'proxy-command',
command: 'cloudflared access ssh --hostname %h'
})
})
it('uses fresh OpenSSH proxy authority for imported config targets', () => {
const target = {
...makeTarget(),
source: 'ssh-config' as const,
configHost: 'workbox',
proxyCommand: 'ssh -W %h:%p stale-bastion'
}
expect(resolveEffectiveProxy(target, makeResolved())).toBeUndefined()
expect(
resolveEffectiveProxy(target, makeResolved({ proxyCommand: 'ssh -W %h:%p current-bastion' }))
).toEqual({
kind: 'proxy-command',
command: 'ssh -W %h:%p current-bastion'
})
})
it('falls back to resolved proxyCommand', () => {
expect(
resolveEffectiveProxy(makeTarget(), makeResolved({ proxyCommand: 'ssh -W %h:%p gw' }))
).toEqual({
kind: 'proxy-command',
command: 'ssh -W %h:%p gw'
})
})
it('returns structured jump-host config for target.jumpHost', () => {
const target = { ...makeTarget(), jumpHost: 'bastion.example.com' }
expect(resolveEffectiveProxy(target, null)).toEqual({
kind: 'jump-host',
jumpHost: 'bastion.example.com'
})
})
it('returns structured jump-host config for resolved proxyJump', () => {
expect(resolveEffectiveProxy(makeTarget(), makeResolved({ proxyJump: 'jump.host' }))).toEqual({
kind: 'jump-host',
jumpHost: 'jump.host'
})
})
it('returns undefined when no proxy is configured', () => {
expect(resolveEffectiveProxy(makeTarget(), null)).toBeUndefined()
})
})