mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 14:22:02 +00:00
Resolves merge conflicts: - apps/server/src/routes/terminal/common.ts: Keep randomBytes import, use @automaker/utils for createLogger - apps/ui/eslint.config.mjs: Use main's explicit globals list with XMLHttpRequest and MediaQueryListEvent additions - apps/ui/src/components/views/terminal-view.tsx: Keep our terminal improvements (killAllSessions, beforeunload, better error handling) - apps/ui/src/config/terminal-themes.ts: Keep our search highlight colors for all themes - apps/ui/src/store/app-store.ts: Keep our terminal settings persistence improvements (merge function) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
187 lines
6.8 KiB
TypeScript
187 lines
6.8 KiB
TypeScript
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'));
|
|
});
|
|
});
|
|
});
|