mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-25 08:34:39 +00:00
139 lines
4.8 KiB
TypeScript
139 lines
4.8 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
// ── Tests: SSHKaos parameter validation ──────────────────────────────
|
|
//
|
|
// SSHKaos.create() requires a live SSH connection to proceed past
|
|
// connectClient(). These tests verify the parameter validation and
|
|
// shell quoting logic without needing a real SSH server.
|
|
|
|
describe('e2e: SSH mock tests', () => {
|
|
describe('SSHKaos.create() parameter validation', () => {
|
|
it('missing host -> connect attempt with empty host', async () => {
|
|
// SSHKaos.create() passes the host directly to ssh2's connect().
|
|
// With an empty/undefined host, ssh2 will fail to connect.
|
|
// We verify the error is thrown.
|
|
const { SSHKaos } = await import('#/ssh');
|
|
|
|
await expect(
|
|
SSHKaos.create({
|
|
host: '',
|
|
username: 'testuser',
|
|
}),
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it('missing username -> connect attempt with empty username', async () => {
|
|
const { SSHKaos } = await import('#/ssh');
|
|
|
|
await expect(
|
|
SSHKaos.create({
|
|
host: '127.0.0.1',
|
|
port: 99999, // Use an unlikely port to ensure fast failure
|
|
username: '',
|
|
}),
|
|
).rejects.toThrow();
|
|
});
|
|
|
|
it('invalid port -> connection error', async () => {
|
|
const { SSHKaos } = await import('#/ssh');
|
|
|
|
// Port 1 is unlikely to have an SSH server; should fail quickly
|
|
await expect(
|
|
SSHKaos.create({
|
|
host: '127.0.0.1',
|
|
port: 1,
|
|
username: 'testuser',
|
|
}),
|
|
).rejects.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('shell quoting logic', () => {
|
|
// We test the shellQuote function indirectly by examining its behavior.
|
|
// The function is not exported, but we can verify its contract:
|
|
// - Empty string -> ''
|
|
// - Safe chars -> unchanged
|
|
// - Special chars -> single-quoted with embedded quote escaping
|
|
|
|
it('shellQuote rules verified via regex match', () => {
|
|
// The shellQuote regex for safe chars: /^[A-Za-z0-9_./:=@%^,+-]+$/
|
|
const safeRegex = /^[A-Za-z0-9_./:=@%^,+-]+$/;
|
|
|
|
// These should be considered safe (no quoting needed)
|
|
expect(safeRegex.test('simple')).toBe(true);
|
|
expect(safeRegex.test('/usr/bin/node')).toBe(true);
|
|
expect(safeRegex.test('key=value')).toBe(true);
|
|
expect(safeRegex.test('file.txt')).toBe(true);
|
|
|
|
// These should need quoting
|
|
expect(safeRegex.test('')).toBe(false);
|
|
expect(safeRegex.test('hello world')).toBe(false);
|
|
expect(safeRegex.test("it's")).toBe(false);
|
|
expect(safeRegex.test('$HOME')).toBe(false);
|
|
expect(safeRegex.test('a|b')).toBe(false);
|
|
expect(safeRegex.test('a"b')).toBe(false);
|
|
expect(safeRegex.test('a;b')).toBe(false);
|
|
expect(safeRegex.test('a&b')).toBe(false);
|
|
expect(safeRegex.test('a`b')).toBe(false);
|
|
});
|
|
|
|
it('shellQuote single-quote escaping pattern is correct', () => {
|
|
// shellQuote wraps in single quotes, replacing ' with '"'"'
|
|
// Verify the pattern: 'text'"'"'more' handles embedded quotes
|
|
const input = "it's a test";
|
|
const escaped = "'" + input.replaceAll("'", "'\"'\"'") + "'";
|
|
|
|
expect(escaped).toBe("'it'\"'\"'s a test'");
|
|
// This should be safe to use in a shell command
|
|
expect(escaped).toContain("'\"'\"'");
|
|
});
|
|
|
|
it('special characters that need quoting', () => {
|
|
const specialChars = [' ', "'", '"', '$', '|', '&', ';', '`', '(', ')', '{', '}', '<', '>'];
|
|
const safeRegex = /^[A-Za-z0-9_./:=@%^,+-]+$/;
|
|
|
|
for (const ch of specialChars) {
|
|
expect(safeRegex.test(`arg${ch}value`)).toBe(false);
|
|
}
|
|
});
|
|
|
|
it('empty string quoting produces two single quotes', () => {
|
|
// shellQuote('') should return "''"
|
|
const emptyQuoted = "''";
|
|
expect(emptyQuoted).toBe("''");
|
|
expect(emptyQuoted.length).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe('SSHKaosOptions type constraints', () => {
|
|
it('options structure has required fields', () => {
|
|
// Verify at compile time and runtime that SSHKaosOptions
|
|
// requires host and username
|
|
const validOptions = {
|
|
host: 'example.com',
|
|
username: 'user',
|
|
};
|
|
|
|
expect(validOptions.host).toBe('example.com');
|
|
expect(validOptions.username).toBe('user');
|
|
});
|
|
|
|
it('options with all optional fields', () => {
|
|
const fullOptions = {
|
|
host: 'example.com',
|
|
port: 2222,
|
|
username: 'user',
|
|
password: 'pass',
|
|
keyPaths: ['/path/to/key'],
|
|
keyContents: ['ssh-rsa AAAA...'],
|
|
cwd: '/home/user',
|
|
};
|
|
|
|
expect(fullOptions.port).toBe(2222);
|
|
expect(fullOptions.password).toBe('pass');
|
|
expect(fullOptions.keyPaths).toHaveLength(1);
|
|
expect(fullOptions.keyContents).toHaveLength(1);
|
|
expect(fullOptions.cwd).toBe('/home/user');
|
|
});
|
|
});
|
|
});
|