feat: harden local shell, SFTP, and desktop session reliability
Finder-launched terminals now inherit a login PATH so tools like ollama resolve, destructive SFTP/editor actions require confirmation, and terminal search plus window dragging work again. SSH forwards and RDP sessions keep listeners and survive reconnect without FastPath crashes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
188f3556ed
commit
08696896f9
223 files changed
+13493
-3423
No files matched your search
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* SSH session / terminal open patrol
|
||||
*/
|
||||
|
||||
import { render, screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import SessionDialog from '../../src/components/sessions/SessionDialog'
|
||||
import QuickConnectDialog, { parseSshTarget } from '../../src/components/sessions/QuickConnectDialog'
|
||||
import { useSessionStore } from '../../src/stores/sessionStore'
|
||||
import { useTabStore } from '../../src/stores/tabStore'
|
||||
import { mockDesktopApi } from '../setup'
|
||||
import { resetPatrolStores, SSH_SESSION } from '../helpers/patrol'
|
||||
import { buildOpenTabPayload } from '../../src/utils/sessionProtocol'
|
||||
|
||||
describe('patrol / ssh', () => {
|
||||
beforeEach(() => {
|
||||
resetPatrolStores()
|
||||
})
|
||||
|
||||
it('parses ssh targets used by quick connect', () => {
|
||||
expect(parseSshTarget('admin@10.0.0.8:2222')).toEqual({
|
||||
host: '10.0.0.8',
|
||||
port: 2222,
|
||||
username: 'admin',
|
||||
})
|
||||
expect(parseSshTarget('opsbase.cn')).toEqual({
|
||||
host: 'opsbase.cn',
|
||||
port: 22,
|
||||
username: 'root',
|
||||
})
|
||||
})
|
||||
|
||||
it('creates an SSH session with default port 22 and password auth', async () => {
|
||||
const user = userEvent.setup()
|
||||
render(<SessionDialog isOpen onClose={vi.fn()} editSession={null} />)
|
||||
|
||||
expect(screen.getByLabelText('端口')).toHaveValue(22)
|
||||
await user.clear(screen.getByLabelText('主机'))
|
||||
await user.type(screen.getByLabelText('主机'), 'root@opsbase.cn')
|
||||
await user.type(screen.getByLabelText('密码'), 'patrol-secret')
|
||||
await user.click(screen.getByRole('button', { name: '创建并保存' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockDesktopApi.sessionCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
host: 'opsbase.cn',
|
||||
port: 22,
|
||||
username: 'root',
|
||||
authType: 'password',
|
||||
password: 'patrol-secret',
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('opens a terminal tab from a saved SSH session payload', () => {
|
||||
const payload = buildOpenTabPayload(SSH_SESSION)
|
||||
useTabStore.getState().addTab(payload)
|
||||
const tab = useTabStore.getState().tabs.find((item) => item.sessionId === SSH_SESSION.id)
|
||||
expect(tab).toEqual(
|
||||
expect.objectContaining({
|
||||
type: 'terminal',
|
||||
sessionId: SSH_SESSION.id,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('quick-connect opens a terminal tab for user@host:port', async () => {
|
||||
const user = userEvent.setup()
|
||||
render(<QuickConnectDialog isOpen onClose={vi.fn()} />)
|
||||
|
||||
const input = screen.getByRole('textbox')
|
||||
await user.clear(input)
|
||||
await user.type(input, 'admin@10.0.0.8:2222')
|
||||
await user.type(screen.getByPlaceholderText('••••••••'), 'x')
|
||||
await user.click(screen.getByRole('button', { name: /连接/ }))
|
||||
|
||||
await waitFor(() => {
|
||||
const tabs = useTabStore.getState().tabs
|
||||
expect(tabs.some((tab) => tab.type === 'terminal')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps SSH sessions in the session store', () => {
|
||||
useSessionStore.setState({ sessions: [SSH_SESSION] })
|
||||
expect(useSessionStore.getState().sessions).toHaveLength(1)
|
||||
expect(useSessionStore.getState().sessions[0].protocol ?? 'ssh').toBe('ssh')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user