Files
ai-terminal-assistant/tests/unit/agent/permission-merger.test.ts
T
kurihada 729fb2d42a feat: 添加完整的单元测试套件
- 新增 vitest 测试框架配置
- 添加 54 个测试文件,共 951 个测试用例
- 覆盖核心模块:
  - Agent: executor, registry, config-loader, permission-merger
  - Context: manager, compaction, prune, token-counter
  - Permission: manager, bash/file/git/web checkers, wildcard
  - Session: manager, storage
  - Tools: filesystem (12个), git (10个), web, shell, todo, task
  - LSP: client, server, language
  - Utils: config, diff
  - UI: terminal
2025-12-11 14:45:24 +08:00

235 lines
7.8 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
mergePermissions,
matchRule,
checkBashPermission,
checkFilePathPermission,
SYSTEM_DEFAULT_PERMISSION,
} from '../../../src/agent/permission-merger.js';
import type { AgentPermission, AgentBashPermission } from '../../../src/agent/types.js';
describe('matchRule - 命令规则匹配', () => {
describe('通配符 * 匹配', () => {
it('git diff* 匹配 git diff --staged', () => {
expect(matchRule('git diff --staged', 'git diff*')).toBe(true);
});
it('git diff* 不匹配 git status', () => {
expect(matchRule('git status', 'git diff*')).toBe(false);
});
it('rm -rf* 匹配危险命令', () => {
expect(matchRule('rm -rf /', 'rm -rf*')).toBe(true);
expect(matchRule('rm -rf /home/user', 'rm -rf*')).toBe(true);
});
it('rm -rf* 不匹配普通 rm', () => {
expect(matchRule('rm file.txt', 'rm -rf*')).toBe(false);
});
});
describe('精确匹配', () => {
it('pwd 精确匹配', () => {
expect(matchRule('pwd', 'pwd')).toBe(true);
});
it('pwd 不匹配带参数', () => {
expect(matchRule('pwd /home', 'pwd')).toBe(false);
});
});
describe('大小写不敏感', () => {
it('忽略大小写', () => {
expect(matchRule('GIT DIFF', 'git diff*')).toBe(true);
});
});
});
describe('checkBashPermission - Bash 权限检查', () => {
it('禁用时返回 deny', () => {
const permission: AgentBashPermission = { enabled: false };
expect(checkBashPermission('ls', permission)).toBe('deny');
});
it('匹配 allow 规则', () => {
const permission: AgentBashPermission = {
enabled: true,
rules: [{ pattern: 'ls *', action: 'allow' }],
default: 'deny',
};
expect(checkBashPermission('ls -la', permission)).toBe('allow');
});
it('匹配 deny 规则', () => {
const permission: AgentBashPermission = {
enabled: true,
rules: [{ pattern: 'rm -rf*', action: 'deny' }],
default: 'allow',
};
expect(checkBashPermission('rm -rf /', permission)).toBe('deny');
});
it('无匹配时返回默认值', () => {
const permission: AgentBashPermission = {
enabled: true,
rules: [],
default: 'ask',
};
expect(checkBashPermission('npm install', permission)).toBe('ask');
});
it('规则优先级:先匹配的规则优先', () => {
const permission: AgentBashPermission = {
enabled: true,
rules: [
{ pattern: 'git push --force*', action: 'deny' },
{ pattern: 'git push*', action: 'ask' },
],
default: 'allow',
};
expect(checkBashPermission('git push --force origin', permission)).toBe('deny');
expect(checkBashPermission('git push origin', permission)).toBe('ask');
});
});
describe('checkFilePathPermission - 文件路径权限检查', () => {
it('无敏感路径规则返回 null', () => {
expect(checkFilePathPermission('/home/user/file.txt', undefined)).toBeNull();
expect(checkFilePathPermission('/home/user/file.txt', [])).toBeNull();
});
it('匹配敏感路径规则', () => {
const rules = [
{ pattern: '*.env', action: 'deny' as const },
{ pattern: '/etc/*', action: 'ask' as const },
];
expect(checkFilePathPermission('.env', rules)).toBe('deny');
expect(checkFilePathPermission('/etc/passwd', rules)).toBe('ask');
});
it('不匹配时返回 null', () => {
const rules = [{ pattern: '*.env', action: 'deny' as const }];
expect(checkFilePathPermission('config.json', rules)).toBeNull();
});
});
describe('mergePermissions - 权限合并', () => {
describe('优先级:Agent > Global > System', () => {
it('Agent 配置覆盖 Global 和 System', () => {
const system: AgentPermission = { file: { read: 'allow', write: 'ask' } };
const global: AgentPermission = { file: { write: 'allow' } };
const agent: AgentPermission = { file: { write: 'deny' } };
const merged = mergePermissions(system, global, agent);
expect(merged.file?.write).toBe('deny');
});
it('Global 配置覆盖 System', () => {
const system: AgentPermission = { file: { write: 'ask' } };
const global: AgentPermission = { file: { write: 'allow' } };
const merged = mergePermissions(system, global, undefined);
expect(merged.file?.write).toBe('allow');
});
it('无覆盖时使用 System 默认值', () => {
const merged = mergePermissions(SYSTEM_DEFAULT_PERMISSION, undefined, undefined);
expect(merged.file?.read).toBe('allow');
expect(merged.file?.write).toBe('ask');
});
});
describe('Bash 权限合并', () => {
it('Agent 禁用 bash 覆盖全局', () => {
const system: AgentPermission = { bash: { enabled: true } };
const global: AgentPermission = { bash: { enabled: true } };
const agent: AgentPermission = { bash: { enabled: false } };
const merged = mergePermissions(system, global, agent);
expect(merged.bash?.enabled).toBe(false);
});
it('Global 禁用 bash 且 Agent 未覆盖', () => {
const system: AgentPermission = { bash: { enabled: true } };
const global: AgentPermission = { bash: { enabled: false } };
const merged = mergePermissions(system, global, undefined);
expect(merged.bash?.enabled).toBe(false);
});
it('规则按优先级合并:Agent > Global > System', () => {
const system: AgentPermission = {
bash: { rules: [{ pattern: 'ls *', action: 'allow' }] },
};
const global: AgentPermission = {
bash: { rules: [{ pattern: 'cat *', action: 'allow' }] },
};
const agent: AgentPermission = {
bash: { rules: [{ pattern: 'rm *', action: 'deny' }] },
};
const merged = mergePermissions(system, global, agent);
// Agent 规则在前
expect(merged.bash?.rules?.[0].pattern).toBe('rm *');
expect(merged.bash?.rules?.[1].pattern).toBe('cat *');
expect(merged.bash?.rules?.[2].pattern).toBe('ls *');
});
});
describe('Git 权限合并', () => {
it('合并所有级别的 Git 权限', () => {
const system: AgentPermission = { git: { read: 'allow', write: 'ask', dangerous: 'deny' } };
const agent: AgentPermission = { git: { write: 'deny' } };
const merged = mergePermissions(system, undefined, agent);
expect(merged.git?.read).toBe('allow'); // 来自 system
expect(merged.git?.write).toBe('deny'); // 来自 agent
expect(merged.git?.dangerous).toBe('deny'); // 来自 system
});
});
describe('Web 权限合并', () => {
it('合并 Web 权限', () => {
const system: AgentPermission = { web: 'ask' };
const agent: AgentPermission = { web: 'deny' };
const merged = mergePermissions(system, undefined, agent);
expect(merged.web).toBe('deny');
});
});
});
describe('SYSTEM_DEFAULT_PERMISSION - 系统默认权限', () => {
it('文件读取默认允许', () => {
expect(SYSTEM_DEFAULT_PERMISSION.file?.read).toBe('allow');
});
it('文件写入默认询问', () => {
expect(SYSTEM_DEFAULT_PERMISSION.file?.write).toBe('ask');
});
it('Bash 默认启用', () => {
expect(SYSTEM_DEFAULT_PERMISSION.bash?.enabled).toBe(true);
});
it('包含安全命令白名单', () => {
const rules = SYSTEM_DEFAULT_PERMISSION.bash?.rules ?? [];
const lsRule = rules.find((r) => r.pattern === 'ls *');
expect(lsRule?.action).toBe('allow');
});
it('包含危险命令黑名单', () => {
const rules = SYSTEM_DEFAULT_PERMISSION.bash?.rules ?? [];
const rmRule = rules.find((r) => r.pattern === 'rm -rf *');
expect(rmRule?.action).toBe('deny');
});
it('Git 读取默认允许', () => {
expect(SYSTEM_DEFAULT_PERMISSION.git?.read).toBe('allow');
});
it('Git 危险操作默认拒绝', () => {
expect(SYSTEM_DEFAULT_PERMISSION.git?.dangerous).toBe('deny');
});
});