import { describe, it, expect, beforeEach, vi } from 'vitest'; import { PermissionManager, getPermissionManager, resetPermissionManager, } from '../../../src/permission/manager.js'; import type { PermissionDecision, PermissionContext } from '../../../src/permission/types.js'; // Mock 检查器以避免文件系统操作 vi.mock('fs', () => ({ existsSync: vi.fn(() => false), readFileSync: vi.fn(), writeFileSync: vi.fn(), mkdirSync: vi.fn(), })); vi.mock('../../../src/permission/file-prompt.js', () => ({ promptFilePermission: vi.fn().mockResolvedValue({ allow: true, remember: false }), })); describe('PermissionManager - 权限管理器', () => { let manager: PermissionManager; const testProjectRoot = '/test/project'; beforeEach(() => { manager = new PermissionManager(testProjectRoot); vi.clearAllMocks(); }); describe('初始化', () => { it('创建时注册默认检查器', () => { // 应该包含 bash, file, web, git 检查器 expect(manager.getChecker('bash')).toBeDefined(); expect(manager.getChecker('file')).toBeDefined(); expect(manager.getChecker('web')).toBeDefined(); expect(manager.getChecker('git')).toBeDefined(); }); it('未注册的检查器返回 undefined', () => { expect(manager.getChecker('non-existent')).toBeUndefined(); }); }); describe('registerChecker', () => { it('注册自定义检查器', () => { const customChecker = { name: 'custom', check: vi.fn().mockResolvedValue({ allowed: true, action: 'allow' }), clearSessionPermissions: vi.fn(), }; manager.registerChecker(customChecker); expect(manager.getChecker('custom')).toBe(customChecker); }); it('覆盖已有检查器', () => { const newBashChecker = { name: 'bash', check: vi.fn().mockResolvedValue({ allowed: false, action: 'deny' }), clearSessionPermissions: vi.fn(), }; manager.registerChecker(newBashChecker); expect(manager.getChecker('bash')).toBe(newBashChecker); }); }); describe('setAskCallback', () => { it('设置回调传递给所有支持回调的检查器', () => { const callback = vi.fn().mockResolvedValue({ allow: true, remember: false, } as PermissionDecision); manager.setAskCallback(callback); // 验证回调被设置(通过间接方式) expect(callback).not.toHaveBeenCalled(); // 设置时不调用 }); }); describe('checkPermission', () => { it('使用指定检查器检查权限', async () => { const result = await manager.checkPermission('bash', { command: 'ls -la', workdir: testProjectRoot, }); expect(result.allowed).toBe(true); }); it('未注册的检查器返回 ask', async () => { const result = await manager.checkPermission('non-existent', { command: 'some command', workdir: testProjectRoot, }); expect(result.action).toBe('ask'); expect(result.needsConfirmation).toBe(true); expect(result.reason).toContain('未找到检查器'); }); }); describe('checkBashPermission - 便捷方法', () => { it('检查安全命令', async () => { const result = await manager.checkBashPermission({ command: 'git status', workdir: testProjectRoot, }); expect(result.allowed).toBe(true); }); it('检查危险命令', async () => { const result = await manager.checkBashPermission({ command: 'rm -rf /', workdir: testProjectRoot, }); expect(result.allowed).toBe(false); }); }); describe('checkFilePermission - 便捷方法', () => { it('检查读操作', async () => { const result = await manager.checkFilePermission({ operation: 'read', path: './src/index.ts', workdir: testProjectRoot, }); expect(result.allowed).toBe(true); }); it('检查写操作需要确认', async () => { const result = await manager.checkFilePermission({ operation: 'write', path: './src/new-file.ts', workdir: testProjectRoot, }); expect(result.action).toBe('ask'); }); }); describe('checkGitPermission - 便捷方法', () => { it('检查读操作', async () => { const result = await manager.checkGitPermission({ operation: 'status', }); expect(result.allowed).toBe(true); }); it('检查写操作需要确认', async () => { const result = await manager.checkGitPermission({ operation: 'push', }); expect(result.action).toBe('ask'); }); }); describe('checkWebPermission - 便捷方法', () => { it('检查网页访问', async () => { const result = await manager.checkWebPermission({ operation: 'fetch', url: 'https://example.com', }); // Web 检查器的默认行为 expect(result).toBeDefined(); }); }); describe('会话权限管理', () => { it('clearAllSessionPermissions 清除所有检查器的权限', () => { // 调用方法不应该抛出错误 expect(() => manager.clearAllSessionPermissions()).not.toThrow(); }); it('clearSessionPermissions 清除指定检查器的权限', () => { expect(() => manager.clearSessionPermissions('bash')).not.toThrow(); expect(() => manager.clearSessionPermissions('file')).not.toThrow(); expect(() => manager.clearSessionPermissions('git')).not.toThrow(); }); it('清除不存在的检查器权限不报错', () => { expect(() => manager.clearSessionPermissions('non-existent')).not.toThrow(); }); }); }); describe('全局实例管理', () => { beforeEach(() => { resetPermissionManager(); }); it('getPermissionManager 返回单例', () => { const manager1 = getPermissionManager('/test/project'); const manager2 = getPermissionManager(); expect(manager1).toBe(manager2); }); it('resetPermissionManager 重置单例', () => { const manager1 = getPermissionManager('/test/project'); resetPermissionManager(); const manager2 = getPermissionManager('/test/project'); expect(manager1).not.toBe(manager2); }); it('首次创建使用指定的 projectRoot', () => { const manager = getPermissionManager('/custom/root'); // 验证管理器已创建 expect(manager).toBeDefined(); }); });