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'); }); });