Spaces:
Paused
Paused
| import { describe, it, expect, beforeEach, vi } from 'vitest'; | |
| import path from 'path'; | |
| /** | |
| * Note: security.ts maintains module-level state (allowed paths Set). | |
| * We need to reset modules and reimport for each test to get fresh state. | |
| */ | |
| describe('security.ts', () => { | |
| beforeEach(() => { | |
| vi.resetModules(); | |
| }); | |
| describe('initAllowedPaths', () => { | |
| it('should load ALLOWED_ROOT_DIRECTORY if set', async () => { | |
| process.env.ALLOWED_ROOT_DIRECTORY = '/projects'; | |
| delete process.env.DATA_DIR; | |
| const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const allowed = getAllowedPaths(); | |
| expect(allowed).toContain(path.resolve('/projects')); | |
| }); | |
| it('should include DATA_DIR if set', async () => { | |
| delete process.env.ALLOWED_ROOT_DIRECTORY; | |
| process.env.DATA_DIR = '/data/dir'; | |
| const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const allowed = getAllowedPaths(); | |
| expect(allowed).toContain(path.resolve('/data/dir')); | |
| }); | |
| it('should include both ALLOWED_ROOT_DIRECTORY and DATA_DIR if both set', async () => { | |
| process.env.ALLOWED_ROOT_DIRECTORY = '/projects'; | |
| process.env.DATA_DIR = '/data'; | |
| const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const allowed = getAllowedPaths(); | |
| expect(allowed).toContain(path.resolve('/projects')); | |
| expect(allowed).toContain(path.resolve('/data')); | |
| expect(allowed).toHaveLength(2); | |
| }); | |
| it('should return empty array when no paths configured', async () => { | |
| delete process.env.ALLOWED_ROOT_DIRECTORY; | |
| delete process.env.DATA_DIR; | |
| const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const allowed = getAllowedPaths(); | |
| expect(allowed).toHaveLength(0); | |
| }); | |
| }); | |
| describe('isPathAllowed', () => { | |
| it('should allow paths within ALLOWED_ROOT_DIRECTORY', async () => { | |
| process.env.ALLOWED_ROOT_DIRECTORY = '/allowed/project'; | |
| process.env.DATA_DIR = ''; | |
| const { initAllowedPaths, isPathAllowed } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| // Paths within allowed directory should be allowed | |
| expect(isPathAllowed('/allowed/project/file.txt')).toBe(true); | |
| expect(isPathAllowed('/allowed/project/subdir/file.txt')).toBe(true); | |
| // Paths outside allowed directory should be denied | |
| expect(isPathAllowed('/not/allowed/file.txt')).toBe(false); | |
| expect(isPathAllowed('/tmp/file.txt')).toBe(false); | |
| expect(isPathAllowed('/etc/passwd')).toBe(false); | |
| }); | |
| it('should allow all paths when no restrictions are configured', async () => { | |
| delete process.env.DATA_DIR; | |
| delete process.env.ALLOWED_ROOT_DIRECTORY; | |
| const { initAllowedPaths, isPathAllowed } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| // All paths should be allowed when no restrictions are configured | |
| expect(isPathAllowed('/allowed/project/file.txt')).toBe(true); | |
| expect(isPathAllowed('/not/allowed/file.txt')).toBe(true); | |
| expect(isPathAllowed('/tmp/file.txt')).toBe(true); | |
| expect(isPathAllowed('/etc/passwd')).toBe(true); | |
| expect(isPathAllowed('/any/path')).toBe(true); | |
| }); | |
| it('should allow all paths when DATA_DIR is set but ALLOWED_ROOT_DIRECTORY is not', async () => { | |
| process.env.DATA_DIR = '/data'; | |
| delete process.env.ALLOWED_ROOT_DIRECTORY; | |
| const { initAllowedPaths, isPathAllowed } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| // DATA_DIR should be allowed | |
| expect(isPathAllowed('/data/settings.json')).toBe(true); | |
| // But all other paths should also be allowed when ALLOWED_ROOT_DIRECTORY is not set | |
| expect(isPathAllowed('/allowed/project/file.txt')).toBe(true); | |
| expect(isPathAllowed('/not/allowed/file.txt')).toBe(true); | |
| expect(isPathAllowed('/tmp/file.txt')).toBe(true); | |
| expect(isPathAllowed('/etc/passwd')).toBe(true); | |
| expect(isPathAllowed('/any/path')).toBe(true); | |
| }); | |
| }); | |
| describe('validatePath', () => { | |
| it('should return resolved path for allowed paths', async () => { | |
| process.env.ALLOWED_ROOT_DIRECTORY = '/allowed'; | |
| process.env.DATA_DIR = ''; | |
| const { initAllowedPaths, validatePath } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const result = validatePath('/allowed/file.txt'); | |
| expect(result).toBe(path.resolve('/allowed/file.txt')); | |
| }); | |
| it('should throw error for paths outside allowed directories', async () => { | |
| process.env.ALLOWED_ROOT_DIRECTORY = '/allowed'; | |
| process.env.DATA_DIR = ''; | |
| const { initAllowedPaths, validatePath } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| // Disallowed paths should throw PathNotAllowedError | |
| expect(() => validatePath('/disallowed/file.txt')).toThrow(); | |
| }); | |
| it('should not throw error for any path when no restrictions are configured', async () => { | |
| delete process.env.DATA_DIR; | |
| delete process.env.ALLOWED_ROOT_DIRECTORY; | |
| const { initAllowedPaths, validatePath } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| // All paths are allowed when no restrictions configured | |
| expect(() => validatePath('/disallowed/file.txt')).not.toThrow(); | |
| expect(validatePath('/disallowed/file.txt')).toBe(path.resolve('/disallowed/file.txt')); | |
| }); | |
| it('should resolve relative paths within allowed directory', async () => { | |
| const cwd = process.cwd(); | |
| process.env.ALLOWED_ROOT_DIRECTORY = cwd; | |
| process.env.DATA_DIR = ''; | |
| const { initAllowedPaths, validatePath } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const result = validatePath('./file.txt'); | |
| expect(result).toBe(path.resolve(cwd, './file.txt')); | |
| }); | |
| }); | |
| describe('getAllowedPaths', () => { | |
| it('should return array of allowed paths', async () => { | |
| process.env.ALLOWED_ROOT_DIRECTORY = '/projects'; | |
| process.env.DATA_DIR = '/data'; | |
| const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const result = getAllowedPaths(); | |
| expect(Array.isArray(result)).toBe(true); | |
| expect(result.length).toBe(2); | |
| expect(result).toContain(path.resolve('/projects')); | |
| expect(result).toContain(path.resolve('/data')); | |
| }); | |
| it('should return resolved paths', async () => { | |
| process.env.ALLOWED_ROOT_DIRECTORY = '/test'; | |
| process.env.DATA_DIR = ''; | |
| const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform'); | |
| initAllowedPaths(); | |
| const result = getAllowedPaths(); | |
| expect(result[0]).toBe(path.resolve('/test')); | |
| }); | |
| }); | |
| }); | |