Skip to content

Commit ae75567

Browse files
author
echoVic
committed
feat(terminal): 添加bun-pty类型定义并修复pty调用
refactor(security): 重构路径检测逻辑并优化测试用例 style(test): 调整测试文件导入顺序
1 parent eda34a2 commit ae75567

File tree

3 files changed

+45
-9
lines changed

3 files changed

+45
-9
lines changed

packages/cli/src/server/routes/terminal.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ async function spawnPty(
4141
): Promise<IPtyProcess> {
4242
if (isBunRuntime()) {
4343
// Use bun-pty in Bun runtime
44-
// @ts-expect-error bun-pty is only available in Bun runtime
4544
const { spawn } = await import('bun-pty');
4645
const ptyProcess = spawn(command, args, {
4746
name: 'xterm-256color',
@@ -51,7 +50,7 @@ async function spawnPty(
5150
return {
5251
pid: ptyProcess.pid,
5352
write: (data: string) => ptyProcess.write(data),
54-
resize: (cols: number, rows: number) => ptyProcess.resize({ cols, rows }),
53+
resize: (cols: number, rows: number) => ptyProcess.resize(cols, rows),
5554
kill: () => ptyProcess.kill(),
5655
onData: (callback: (data: string) => void) => ptyProcess.onData(callback),
5756
onExit: (callback: (exitInfo: { exitCode: number }) => void) => ptyProcess.onExit(callback),
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
declare module 'bun-pty' {
2+
export function spawn(
3+
command: string,
4+
args: string[],
5+
options: {
6+
name?: string;
7+
cwd?: string;
8+
env?: Record<string, string>;
9+
cols?: number;
10+
rows?: number;
11+
}
12+
): {
13+
pid: number;
14+
write(data: string): void;
15+
resize(cols: number, rows: number): void;
16+
kill(signal?: string): void;
17+
onData(callback: (data: string) => void): void;
18+
onExit(callback: (exitInfo: { exitCode: number }) => void): void;
19+
};
20+
}

packages/cli/tests/security/path-traversal.test.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
21
import path from 'node:path';
3-
import { setupTestEnvironment } from '../support/helpers/setupTestEnvironment.js';
2+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
43
import type { TestEnvironment } from '../support/helpers/setupTestEnvironment.js';
4+
import { setupTestEnvironment } from '../support/helpers/setupTestEnvironment.js';
55

66
describe('路径遍历攻击防护', () => {
77
let env: TestEnvironment;
@@ -52,6 +52,26 @@ describe('路径遍历攻击防护', () => {
5252
});
5353

5454
describe('绝对路径限制', () => {
55+
const isWithinProject = (projectRoot: string, targetPath: string) => {
56+
if (
57+
!path.isAbsolute(targetPath) &&
58+
path.win32.isAbsolute(targetPath) &&
59+
process.platform !== 'win32'
60+
) {
61+
return false;
62+
}
63+
64+
const resolvedProject = path.resolve(projectRoot);
65+
const resolvedTarget = path.resolve(targetPath);
66+
const projectPrefix = resolvedProject.endsWith(path.sep)
67+
? resolvedProject
68+
: `${resolvedProject}${path.sep}`;
69+
70+
return (
71+
resolvedTarget === resolvedProject || resolvedTarget.startsWith(projectPrefix)
72+
);
73+
};
74+
5575
it('应该检测项目目录外的绝对路径', () => {
5676
const projectRoot = env.projectDir;
5777
const outsidePaths = [
@@ -62,9 +82,7 @@ describe('路径遍历攻击防护', () => {
6282
];
6383

6484
for (const outsidePath of outsidePaths) {
65-
const resolvedPath = path.resolve(outsidePath);
66-
const isWithinProject = resolvedPath.startsWith(projectRoot);
67-
expect(isWithinProject).toBe(false);
85+
expect(isWithinProject(projectRoot, outsidePath)).toBe(false);
6886
}
6987
});
7088

@@ -77,8 +95,7 @@ describe('路径遍历攻击防护', () => {
7795
];
7896

7997
for (const insidePath of insidePaths) {
80-
const isWithinProject = insidePath.startsWith(projectRoot);
81-
expect(isWithinProject).toBe(true);
98+
expect(isWithinProject(projectRoot, insidePath)).toBe(true);
8299
}
83100
});
84101
});

0 commit comments

Comments
 (0)