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>
127 lines
4.0 KiB
TypeScript
127 lines
4.0 KiB
TypeScript
/**
|
|
* Platform / protocol contract patrol — catches missing commands or broken defaults.
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
import { readFileSync } from 'node:fs'
|
|
import { resolve } from 'node:path'
|
|
import { mockDesktopApi } from '../setup'
|
|
import {
|
|
buildOpenTabPayload,
|
|
defaultPortForProtocol,
|
|
isSshSession,
|
|
sessionProtocol,
|
|
sessionToRdpConfig,
|
|
sessionToVncConfig,
|
|
tabTypeForProtocol,
|
|
} from '../../src/utils/sessionProtocol'
|
|
import { RDP_SESSION, VNC_SESSION, SSH_SESSION } from '../helpers/patrol'
|
|
import * as rdp from '../../src/platform/rdp'
|
|
import * as vnc from '../../src/platform/vnc'
|
|
import * as sftpPlatform from '../../src/platform/sftp'
|
|
|
|
const REQUIRED_SSH_KEYS = [
|
|
'sshConnect',
|
|
'sshDisconnect',
|
|
'sshCreateShell',
|
|
'sshShellWrite',
|
|
'sshShellResize',
|
|
'sshCloseShell',
|
|
'sshForwardLocal',
|
|
'sshForwardRemote',
|
|
'sshForwardDynamic',
|
|
'sshForwardStop',
|
|
] as const
|
|
|
|
const REQUIRED_SFTP_KEYS = [
|
|
'sftpConnect',
|
|
'sftpDisconnect',
|
|
'sftpListDirectory',
|
|
'sftpUpload',
|
|
'sftpUploadDir',
|
|
'sftpDownload',
|
|
'sftpDownloadDir',
|
|
'sftpMkdir',
|
|
'sftpRename',
|
|
'sftpDelete',
|
|
'sftpStat',
|
|
'sftpChmod',
|
|
] as const
|
|
|
|
describe('patrol / contracts', () => {
|
|
it('leaves HTML5 drag-and-drop available to the SFTP panes', () => {
|
|
const config = JSON.parse(
|
|
readFileSync(resolve(process.cwd(), 'src-tauri/tauri.conf.json'), 'utf8')
|
|
) as { app?: { windows?: Array<{ dragDropEnabled?: boolean }> } }
|
|
|
|
expect(config.app?.windows?.[0]?.dragDropEnabled).toBe(false)
|
|
})
|
|
|
|
it('exposes SSH + SFTP native commands on the desktop mock contract', () => {
|
|
for (const key of REQUIRED_SSH_KEYS) {
|
|
expect(typeof mockDesktopApi[key], key).toBe('function')
|
|
}
|
|
for (const key of REQUIRED_SFTP_KEYS) {
|
|
expect(typeof mockDesktopApi[key], key).toBe('function')
|
|
}
|
|
})
|
|
|
|
it('keeps protocol defaults for SSH / RDP / VNC', () => {
|
|
expect(defaultPortForProtocol('ssh')).toBe(22)
|
|
expect(defaultPortForProtocol('rdp')).toBe(3389)
|
|
expect(defaultPortForProtocol('vnc')).toBe(5900)
|
|
expect(tabTypeForProtocol('ssh')).toBe('terminal')
|
|
expect(tabTypeForProtocol('rdp')).toBe('rdp')
|
|
expect(tabTypeForProtocol('vnc')).toBe('vnc')
|
|
expect(isSshSession(SSH_SESSION)).toBe(true)
|
|
expect(isSshSession(RDP_SESSION)).toBe(false)
|
|
expect(sessionProtocol(VNC_SESSION)).toBe('vnc')
|
|
})
|
|
|
|
it('builds open-tab payloads with desktop configs for RDP/VNC', () => {
|
|
const rdpTab = buildOpenTabPayload(RDP_SESSION)
|
|
expect(rdpTab.type).toBe('rdp')
|
|
expect(rdpTab.rdpConfig).toEqual(
|
|
expect.objectContaining({
|
|
host: 'win.example.com',
|
|
port: 3389,
|
|
username: 'Administrator',
|
|
})
|
|
)
|
|
|
|
const vncTab = buildOpenTabPayload(VNC_SESSION)
|
|
expect(vncTab.type).toBe('vnc')
|
|
expect(vncTab.vncConfig).toEqual(
|
|
expect.objectContaining({
|
|
host: '192.168.1.50',
|
|
port: 5900,
|
|
})
|
|
)
|
|
|
|
const sshTab = buildOpenTabPayload(SSH_SESSION)
|
|
expect(sshTab.type).toBe('terminal')
|
|
expect(sshTab.rdpConfig).toBeUndefined()
|
|
expect(sshTab.vncConfig).toBeUndefined()
|
|
})
|
|
|
|
it('maps session credentials into RDP/VNC engine configs', () => {
|
|
expect(sessionToRdpConfig(RDP_SESSION).password).toBe('secret')
|
|
expect(sessionToVncConfig(VNC_SESSION).password).toBe('vnc-pass')
|
|
})
|
|
|
|
it('exports RDP / VNC / SFTP platform adapters', () => {
|
|
expect(typeof rdp.rdpConnect).toBe('function')
|
|
expect(typeof rdp.rdpDisconnect).toBe('function')
|
|
expect(typeof rdp.rdpResize).toBe('function')
|
|
expect(typeof vnc.vncConnect).toBe('function')
|
|
expect(typeof vnc.vncDisconnect).toBe('function')
|
|
expect(typeof sftpPlatform.uploadRemoteFile).toBe('function')
|
|
expect(typeof sftpPlatform.downloadRemoteFile).toBe('function')
|
|
})
|
|
|
|
it('refuses RDP/VNC connect outside Tauri runtime', async () => {
|
|
await expect(rdp.rdpConnect(sessionToRdpConfig(RDP_SESSION))).rejects.toThrow(/原生|native|Tauri|RDP/i)
|
|
await expect(vnc.vncConnect(sessionToVncConfig(VNC_SESSION))).rejects.toThrow(/原生|native|Tauri|VNC/i)
|
|
})
|
|
})
|