mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 16:02:24 +00:00
fix: clean up system ssh probe listeners (#3824)
This commit is contained in:
@@ -565,6 +565,41 @@ describe('SshConnection', () => {
|
||||
'printf ORCA-SYSTEM-SSH-OK'
|
||||
)
|
||||
})
|
||||
|
||||
it('removes system SSH probe listeners after timeout', async () => {
|
||||
vi.useFakeTimers()
|
||||
const channel = new EventEmitter() as ReturnType<typeof createSystemCommandChannel>
|
||||
channel.stdin = { end: vi.fn(), write: vi.fn() }
|
||||
channel.stderr = new EventEmitter()
|
||||
channel.close = vi.fn()
|
||||
spawnSystemSshCommandMock.mockReturnValueOnce(channel)
|
||||
vi.mocked(resolveWithSshG).mockResolvedValueOnce({
|
||||
hostname: 'example.com',
|
||||
port: 22,
|
||||
identityFile: [],
|
||||
forwardAgent: false,
|
||||
identitiesOnly: false,
|
||||
proxyUseFdpass: true
|
||||
})
|
||||
const conn = new SshConnection(createTarget({ configHost: 'fdpass-host' }), createCallbacks())
|
||||
|
||||
try {
|
||||
const connect = expect(conn.connect()).rejects.toThrow('System SSH connection timed out')
|
||||
await vi.advanceTimersByTimeAsync(30_000)
|
||||
|
||||
await connect
|
||||
expect(channel.close).toHaveBeenCalled()
|
||||
expect(channel.listenerCount('data')).toBe(0)
|
||||
expect(channel.listenerCount('error')).toBe(1)
|
||||
expect(channel.listenerCount('close')).toBe(1)
|
||||
expect(channel.stderr.listenerCount('data')).toBe(0)
|
||||
expect(
|
||||
(conn as unknown as { systemCommandChannels: Set<unknown> }).systemCommandChannels.size
|
||||
).toBe(0)
|
||||
} finally {
|
||||
vi.useRealTimers()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('shouldUseSystemSshTransport', () => {
|
||||
|
||||
@@ -372,47 +372,60 @@ export class SshConnection {
|
||||
let stdout = ''
|
||||
let stderr = ''
|
||||
let settled = false
|
||||
const timeout = setTimeout(() => {
|
||||
const cleanup = (): void => {
|
||||
clearTimeout(timeout)
|
||||
channel.off('data', onStdoutData)
|
||||
channel.stderr.off('data', onStderrData)
|
||||
channel.off('error', onError)
|
||||
channel.off('close', onClose)
|
||||
this.systemCommandChannels.delete(channel)
|
||||
}
|
||||
const settle = (callback: () => void): void => {
|
||||
if (settled) {
|
||||
return
|
||||
}
|
||||
settled = true
|
||||
channel.close()
|
||||
reject(new Error('System SSH connection timed out'))
|
||||
cleanup()
|
||||
callback()
|
||||
}
|
||||
const onStdoutData = (data: Buffer): void => {
|
||||
stdout += data.toString('utf-8')
|
||||
}
|
||||
const onStderrData = (data: Buffer): void => {
|
||||
stderr += data.toString('utf-8')
|
||||
}
|
||||
const onError = (err: Error): void => {
|
||||
settle(() => reject(err))
|
||||
}
|
||||
const onClose = (code: number | null): void => {
|
||||
settle(() => {
|
||||
if (this.disposed || connectGeneration !== this.connectGeneration) {
|
||||
reject(new Error('SSH connection attempt was cancelled'))
|
||||
return
|
||||
}
|
||||
if (code !== 0 || !stdout.includes('ORCA-SYSTEM-SSH-OK')) {
|
||||
reject(
|
||||
new Error(
|
||||
`System SSH probe failed${code != null ? ` (exit ${code})` : ''}.${stderr ? ` stderr: ${stderr.trim()}` : ''}`
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
this.setState('connected')
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
const timeout = setTimeout(() => {
|
||||
settle(() => {
|
||||
channel.close()
|
||||
reject(new Error('System SSH connection timed out'))
|
||||
})
|
||||
}, CONNECT_TIMEOUT_MS)
|
||||
|
||||
channel.on('data', (data: Buffer) => {
|
||||
stdout += data.toString('utf-8')
|
||||
})
|
||||
channel.stderr.on('data', (data: Buffer) => {
|
||||
stderr += data.toString('utf-8')
|
||||
})
|
||||
channel.on('error', (err: Error) => {
|
||||
if (settled) {
|
||||
return
|
||||
}
|
||||
settled = true
|
||||
clearTimeout(timeout)
|
||||
reject(err)
|
||||
})
|
||||
channel.on('close', (code: number | null) => {
|
||||
if (settled) {
|
||||
return
|
||||
}
|
||||
settled = true
|
||||
clearTimeout(timeout)
|
||||
if (this.disposed || connectGeneration !== this.connectGeneration) {
|
||||
reject(new Error('SSH connection attempt was cancelled'))
|
||||
return
|
||||
}
|
||||
if (code !== 0 || !stdout.includes('ORCA-SYSTEM-SSH-OK')) {
|
||||
reject(
|
||||
new Error(
|
||||
`System SSH probe failed${code != null ? ` (exit ${code})` : ''}.${stderr ? ` stderr: ${stderr.trim()}` : ''}`
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
this.setState('connected')
|
||||
resolve()
|
||||
})
|
||||
channel.on('data', onStdoutData)
|
||||
channel.stderr.on('data', onStderrData)
|
||||
channel.on('error', onError)
|
||||
channel.on('close', onClose)
|
||||
})
|
||||
} catch (err) {
|
||||
this.useSystemSshTransport = false
|
||||
|
||||
Reference in New Issue
Block a user