Download packages/kaos/test/ssh-create.test.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 11.7 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/kaos/test/ssh-create.test.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/kaos/test/ssh-create.test.ts
-
curl -L -o ssh-create.test.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/kaos/test/ssh-create.test.ts
11.7 kB
| import { EventEmitter } from 'node:events'; | |
| import type { AnyAuthMethod, ConnectConfig, SFTPWrapper, Stats as SFTPStats } from 'ssh2'; | |
| import { afterEach, describe, expect, it, vi } from 'vitest'; | |
| import type { SSHKaos as SSHKaosType } from '#/ssh'; | |
| interface CreateHarnessState { | |
| attemptedKeys: string[]; | |
| connectConfigs: ConnectConfig[]; | |
| endCalls: number; | |
| readFileCalls: string[]; | |
| } | |
| interface CreateHarnessOptions { | |
| onConnect?: (client: EventEmitter, config: ConnectConfig, state: CreateHarnessState) => void; | |
| readFileValues?: Record<string, string>; | |
| sftp?: SFTPWrapper; | |
| sftpError?: Error; | |
| } | |
| function makeStats(isDirectory: boolean): SFTPStats { | |
| return { | |
| mode: isDirectory ? 0o040755 : 0o100644, | |
| uid: 1000, | |
| gid: 1000, | |
| size: 0, | |
| atime: 0, | |
| mtime: 0, | |
| isDirectory: () => isDirectory, | |
| isFile: () => !isDirectory, | |
| isBlockDevice: () => false, | |
| isCharacterDevice: () => false, | |
| isSymbolicLink: () => false, | |
| isFIFO: () => false, | |
| isSocket: () => false, | |
| }; | |
| } | |
| function createSuccessfulSftp(): SFTPWrapper { | |
| return { | |
| realpath(path: string, callback: (err: Error | undefined, absPath: string) => void): void { | |
| if (path === '.') { | |
| callback(undefined, '/home/tester'); | |
| return; | |
| } | |
| callback(undefined, path); | |
| }, | |
| stat(path: string, callback: (err: Error | undefined, stats: SFTPStats) => void): void { | |
| callback(undefined, makeStats(path !== '/home/tester/file.txt')); | |
| }, | |
| end(): void { | |
| // no-op | |
| }, | |
| } as SFTPWrapper; | |
| } | |
| async function loadSSHModule(options: CreateHarnessOptions = {}): Promise<{ | |
| SSHKaos: typeof SSHKaosType; | |
| state: CreateHarnessState; | |
| }> { | |
| vi.resetModules(); | |
| const state: CreateHarnessState = { | |
| attemptedKeys: [], | |
| connectConfigs: [], | |
| endCalls: 0, | |
| readFileCalls: [], | |
| }; | |
| class MockClient extends EventEmitter { | |
| connect(config: ConnectConfig): void { | |
| state.connectConfigs.push(config); | |
| if (options.onConnect) { | |
| options.onConnect(this, config, state); | |
| return; | |
| } | |
| queueMicrotask(() => { | |
| this.emit('ready'); | |
| }); | |
| } | |
| end(): void { | |
| state.endCalls += 1; | |
| queueMicrotask(() => { | |
| this.emit('close'); | |
| }); | |
| } | |
| sftp(callback: (err?: Error, sftp?: SFTPWrapper) => void): void { | |
| if (options.sftpError) { | |
| callback(options.sftpError); | |
| return; | |
| } | |
| callback(undefined, options.sftp ?? createSuccessfulSftp()); | |
| } | |
| } | |
| vi.doMock('ssh2', () => ({ | |
| Client: MockClient, | |
| utils: { | |
| sftp: { | |
| STATUS_CODE: { | |
| NO_SUCH_FILE: 2, | |
| PERMISSION_DENIED: 3, | |
| FAILURE: 4, | |
| NO_CONNECTION: 6, | |
| CONNECTION_LOST: 7, | |
| OP_UNSUPPORTED: 8, | |
| }, | |
| }, | |
| }, | |
| })); | |
| vi.doMock('node:fs/promises', () => ({ | |
| readFile: vi.fn(async (path: string) => { | |
| state.readFileCalls.push(path); | |
| const value = options.readFileValues?.[path]; | |
| if (value === undefined) { | |
| throw new Error(`Unexpected readFile(${path})`); | |
| } | |
| return value; | |
| }), | |
| })); | |
| const { SSHKaos } = await import('#/ssh'); | |
| return { SSHKaos, state }; | |
| } | |
| afterEach(() => { | |
| vi.doUnmock('ssh2'); | |
| vi.restoreAllMocks(); | |
| vi.resetModules(); | |
| }); | |
| describe('SSHKaos.create()', () => { | |
| it('initializes cwd equal to gethome() when no cwd option is passed', async () => { | |
| // Pins the Python test_ssh_kaos.py::test_pathclass_home_and_cwd invariant: | |
| // on a fresh SSH connection without an explicit cwd, `getcwd()` must equal | |
| // `gethome()`. The smoke-level SSH suite can't cover this because its | |
| // beforeEach chdirs into a per-test remote dir; this mock harness lets us | |
| // check the invariant without a live SSH server. | |
| const { SSHKaos } = await loadSSHModule(); | |
| const ssh = await SSHKaos.create({ | |
| host: 'example.com', | |
| username: 'tester', | |
| }); | |
| expect(ssh.pathClass()).toBe('posix'); | |
| expect(ssh.gethome()).toBe('/home/tester'); | |
| expect(ssh.getcwd()).toBe('/home/tester'); | |
| expect(ssh.getcwd()).toBe(ssh.gethome()); | |
| }); | |
| it('rejects a cwd that resolves to a regular file', async () => { | |
| const sftp = { | |
| realpath(path: string, callback: (err: Error | undefined, absPath: string) => void): void { | |
| if (path === '.') { | |
| callback(undefined, '/home/tester'); | |
| return; | |
| } | |
| callback(undefined, '/home/tester/file.txt'); | |
| }, | |
| stat(_path: string, callback: (err: Error | undefined, stats: SFTPStats) => void): void { | |
| callback(undefined, makeStats(false)); | |
| }, | |
| end(): void { | |
| // no-op | |
| }, | |
| } as SFTPWrapper; | |
| const { SSHKaos, state } = await loadSSHModule({ sftp }); | |
| const error = await SSHKaos.create({ | |
| host: 'example.com', | |
| username: 'tester', | |
| cwd: 'file.txt', | |
| }).catch((error: unknown) => error); | |
| expect(error).toBeInstanceOf(Error); | |
| expect((error as Error).name).toBe('KaosValueError'); | |
| expect((error as Error).message).toMatch(/not a directory/); | |
| expect(state.endCalls).toBe(1); | |
| }); | |
| it('tries multiple private keys via authHandler until one succeeds', async () => { | |
| const { SSHKaos, state } = await loadSSHModule({ | |
| readFileValues: { | |
| '/keys/second': 'second-key', | |
| }, | |
| onConnect(client, config, harnessState) { | |
| const authHandler = config.authHandler; | |
| if (typeof authHandler !== 'function') { | |
| client.emit('error', new Error('missing authHandler')); | |
| return; | |
| } | |
| const requestNextKey = (): void => { | |
| authHandler([], false, (auth: string | AnyAuthMethod | false) => { | |
| expect(auth).not.toBe(false); | |
| expect(typeof auth).toBe('object'); | |
| if (auth === false || typeof auth !== 'object') { | |
| client.emit('error', new Error('authHandler returned no auth method')); | |
| return; | |
| } | |
| if (auth.type !== 'publickey') { | |
| client.emit('error', new Error(`unexpected auth type: ${auth.type}`)); | |
| return; | |
| } | |
| const key = | |
| typeof auth.key === 'string' | |
| ? auth.key | |
| : Buffer.isBuffer(auth.key) | |
| ? auth.key.toString('utf-8') | |
| : JSON.stringify(auth.key); | |
| harnessState.attemptedKeys.push(key); | |
| if (key === 'first-key') { | |
| requestNextKey(); | |
| return; | |
| } | |
| queueMicrotask(() => { | |
| client.emit('ready'); | |
| }); | |
| }); | |
| }; | |
| requestNextKey(); | |
| }, | |
| }); | |
| const ssh = await SSHKaos.create({ | |
| host: 'example.com', | |
| username: 'tester', | |
| keyContents: ['first-key'], | |
| keyPaths: ['/keys/second'], | |
| }); | |
| expect(ssh.getcwd()).toBe('/home/tester'); | |
| expect(state.readFileCalls).toEqual(['/keys/second']); | |
| expect(state.attemptedKeys).toEqual(['first-key', 'second-key']); | |
| expect(state.connectConfigs[0]?.authHandler).toBeTypeOf('function'); | |
| expect(state.connectConfigs[0]?.privateKey).toBeUndefined(); | |
| }); | |
| it('ends the client when opening SFTP fails after connect succeeds', async () => { | |
| const { SSHKaos, state } = await loadSSHModule({ | |
| sftpError: new Error('sftp open failed'), | |
| }); | |
| await expect( | |
| SSHKaos.create({ | |
| host: 'example.com', | |
| username: 'tester', | |
| }), | |
| ).rejects.toThrow(/sftp open failed/); | |
| expect(state.endCalls).toBe(1); | |
| }); | |
| it('merges extraOptions into the ssh2 ConnectConfig', async () => { | |
| const { SSHKaos, state } = await loadSSHModule(); | |
| await SSHKaos.create({ | |
| host: 'example.com', | |
| username: 'tester', | |
| extraOptions: { | |
| keepaliveInterval: 10_000, | |
| readyTimeout: 5_000, | |
| // Cast to the ssh2 Algorithms shape — deliberately narrow for the test | |
| // harness so we can assert pass-through without pulling the full ssh2 | |
| // type graph. | |
| algorithms: { cipher: ['aes256-ctr'] } as never, | |
| }, | |
| }); | |
| const cfg = state.connectConfigs[0]; | |
| expect(cfg).toBeDefined(); | |
| expect(cfg?.keepaliveInterval).toBe(10_000); | |
| expect(cfg?.readyTimeout).toBe(5_000); | |
| expect(cfg?.algorithms).toEqual({ cipher: ['aes256-ctr'] }); | |
| // Managed fields must still come from top-level options. | |
| expect(cfg?.host).toBe('example.com'); | |
| expect(cfg?.username).toBe('tester'); | |
| }); | |
| it('managed fields override extraOptions when both are specified', async () => { | |
| const { SSHKaos, state } = await loadSSHModule(); | |
| await SSHKaos.create({ | |
| host: 'managed.example.com', | |
| username: 'managed', | |
| extraOptions: { | |
| // Malicious / accidental attempts to override managed fields must | |
| // NOT win — the top-level values take precedence. | |
| host: 'attacker.example.com', | |
| username: 'attacker', | |
| port: 1234, | |
| } as never, | |
| }); | |
| const cfg = state.connectConfigs[0]; | |
| expect(cfg?.host).toBe('managed.example.com'); | |
| expect(cfg?.username).toBe('managed'); | |
| expect(cfg?.port).toBe(22); // default, not the 1234 from extraOptions | |
| }); | |
| it('forwards a password-only connection without building an authHandler', async () => { | |
| // Password auth without any private keys must wire ssh2 ConnectConfig.password | |
| // directly rather than constructing an authHandler (the handler is only | |
| // needed when we're rotating through multiple private keys). | |
| const { SSHKaos, state } = await loadSSHModule(); | |
| const ssh = await SSHKaos.create({ | |
| host: 'example.com', | |
| username: 'tester', | |
| password: 'hunter2', | |
| }); | |
| const cfg = state.connectConfigs[0]; | |
| expect(cfg?.password).toBe('hunter2'); | |
| expect(cfg?.authHandler).toBeUndefined(); | |
| expect(ssh.getcwd()).toBe('/home/tester'); | |
| }); | |
| it('queues password after private keys when both are provided', async () => { | |
| // When the user supplies both keyContents and a password, buildAuthHandler | |
| // should try every private key first, then fall back to password auth. | |
| // We observe this by walking the handler to exhaustion and recording | |
| // which auth entries it yields. | |
| const yielded: string[] = []; | |
| const { SSHKaos } = await loadSSHModule({ | |
| onConnect(client, config) { | |
| const handler = config.authHandler; | |
| if (typeof handler !== 'function') { | |
| client.emit('error', new Error('missing authHandler')); | |
| return; | |
| } | |
| // Drain the handler — it yields one auth method per call until it | |
| // runs out, at which point it must emit `false` to signal "no more | |
| // auth methods" (but we stop as soon as we see the password entry). | |
| const pump = (): void => { | |
| handler([], false, (auth: string | AnyAuthMethod | false) => { | |
| if (auth === false) { | |
| client.emit('error', new Error('unexpected end of auth queue')); | |
| return; | |
| } | |
| if (typeof auth !== 'object') { | |
| client.emit('error', new Error(`unexpected auth: ${auth}`)); | |
| return; | |
| } | |
| yielded.push(auth.type); | |
| if (auth.type === 'password') { | |
| queueMicrotask(() => { | |
| client.emit('ready'); | |
| }); | |
| return; | |
| } | |
| pump(); | |
| }); | |
| }; | |
| pump(); | |
| }, | |
| }); | |
| await SSHKaos.create({ | |
| host: 'example.com', | |
| username: 'tester', | |
| keyContents: ['only-key'], | |
| password: 'hunter2', | |
| }); | |
| expect(yielded).toEqual(['publickey', 'password']); | |
| }); | |
| }); | |