mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-17 10:03:08 +00:00
* Changes from fix/memory-and-context-mobile-friendly * fix: Improve file extension detection and add path traversal protection * refactor: Extract file extension utilities and add path traversal guards Code review improvements: - Extract isMarkdownFilename and isImageFilename to shared image-utils.ts - Remove duplicated code from context-view.tsx and memory-view.tsx - Add path traversal guard for context fixture utilities (matching memory) - Add 7 new tests for context fixture path traversal protection - Total 61 tests pass Addresses code review feedback from PR #813 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: Add e2e tests for profiles crud and board background persistence * Update apps/ui/playwright.config.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: Add robust test navigation handling and file filtering * fix: Format NODE_OPTIONS configuration on single line * test: Update profiles and board background persistence tests * test: Replace iPhone 13 Pro with Pixel 5 for mobile test consistency * Update apps/ui/src/components/views/context-view.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * chore: Remove test project directory * feat: Filter context files by type and improve mobile menu visibility --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
181 lines
5.4 KiB
TypeScript
181 lines
5.4 KiB
TypeScript
/**
|
|
* Tests for project fixture utilities
|
|
*
|
|
* Tests for path traversal guard and file operations in test fixtures
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test';
|
|
import {
|
|
createMemoryFileOnDisk,
|
|
memoryFileExistsOnDisk,
|
|
resetMemoryDirectory,
|
|
createContextFileOnDisk,
|
|
contextFileExistsOnDisk,
|
|
resetContextDirectory,
|
|
} from './fixtures';
|
|
|
|
test.describe('Memory Fixture Utilities', () => {
|
|
test.beforeEach(() => {
|
|
resetMemoryDirectory();
|
|
});
|
|
|
|
test.afterEach(() => {
|
|
resetMemoryDirectory();
|
|
});
|
|
|
|
test('should create and detect a valid memory file', () => {
|
|
const filename = 'test-file.md';
|
|
const content = '# Test Content';
|
|
|
|
createMemoryFileOnDisk(filename, content);
|
|
|
|
expect(memoryFileExistsOnDisk(filename)).toBe(true);
|
|
});
|
|
|
|
test('should return false for non-existent file', () => {
|
|
expect(memoryFileExistsOnDisk('non-existent.md')).toBe(false);
|
|
});
|
|
|
|
test('should reject path traversal attempt with ../', () => {
|
|
const maliciousFilename = '../../../etc/passwd';
|
|
|
|
expect(() => {
|
|
createMemoryFileOnDisk(maliciousFilename, 'malicious content');
|
|
}).toThrow('Invalid memory filename');
|
|
|
|
expect(() => {
|
|
memoryFileExistsOnDisk(maliciousFilename);
|
|
}).toThrow('Invalid memory filename');
|
|
});
|
|
|
|
test('should handle Windows-style path traversal attempt ..\\ (platform-dependent)', () => {
|
|
const maliciousFilename = '..\\..\\..\\windows\\system32\\config';
|
|
|
|
// On Unix/macOS, backslash is treated as a literal character in filenames,
|
|
// not as a path separator, so path.resolve doesn't traverse directories.
|
|
// This test documents that behavior - the guard works for Unix paths,
|
|
// but Windows-style backslashes are handled differently per platform.
|
|
// On macOS/Linux: backslash is a valid filename character
|
|
// On Windows: would need additional normalization to prevent traversal
|
|
expect(() => {
|
|
memoryFileExistsOnDisk(maliciousFilename);
|
|
}).not.toThrow();
|
|
|
|
// The file gets created with backslashes in the name (which is valid on Unix)
|
|
// but won't escape the directory
|
|
});
|
|
|
|
test('should reject absolute path attempt', () => {
|
|
const maliciousFilename = '/etc/passwd';
|
|
|
|
expect(() => {
|
|
createMemoryFileOnDisk(maliciousFilename, 'malicious content');
|
|
}).toThrow('Invalid memory filename');
|
|
|
|
expect(() => {
|
|
memoryFileExistsOnDisk(maliciousFilename);
|
|
}).toThrow('Invalid memory filename');
|
|
});
|
|
|
|
test('should accept nested paths within memory directory', () => {
|
|
// Note: This tests the boundary - if subdirectories are supported,
|
|
// this should pass; if not, it should throw
|
|
const nestedFilename = 'subfolder/nested-file.md';
|
|
|
|
// Currently, the implementation doesn't create subdirectories,
|
|
// so this would fail when trying to write. But the path itself
|
|
// is valid (doesn't escape the memory directory)
|
|
expect(() => {
|
|
memoryFileExistsOnDisk(nestedFilename);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
test('should handle filenames without extensions', () => {
|
|
const filename = 'README';
|
|
|
|
createMemoryFileOnDisk(filename, 'content without extension');
|
|
|
|
expect(memoryFileExistsOnDisk(filename)).toBe(true);
|
|
});
|
|
|
|
test('should handle filenames with multiple dots', () => {
|
|
const filename = 'my.file.name.md';
|
|
|
|
createMemoryFileOnDisk(filename, '# Multiple dots');
|
|
|
|
expect(memoryFileExistsOnDisk(filename)).toBe(true);
|
|
});
|
|
});
|
|
|
|
test.describe('Context Fixture Utilities', () => {
|
|
test.beforeEach(() => {
|
|
resetContextDirectory();
|
|
});
|
|
|
|
test.afterEach(() => {
|
|
resetContextDirectory();
|
|
});
|
|
|
|
test('should create and detect a valid context file', () => {
|
|
const filename = 'test-context.md';
|
|
const content = '# Test Context Content';
|
|
|
|
createContextFileOnDisk(filename, content);
|
|
|
|
expect(contextFileExistsOnDisk(filename)).toBe(true);
|
|
});
|
|
|
|
test('should return false for non-existent context file', () => {
|
|
expect(contextFileExistsOnDisk('non-existent.md')).toBe(false);
|
|
});
|
|
|
|
test('should reject path traversal attempt with ../ for context files', () => {
|
|
const maliciousFilename = '../../../etc/passwd';
|
|
|
|
expect(() => {
|
|
createContextFileOnDisk(maliciousFilename, 'malicious content');
|
|
}).toThrow('Invalid context filename');
|
|
|
|
expect(() => {
|
|
contextFileExistsOnDisk(maliciousFilename);
|
|
}).toThrow('Invalid context filename');
|
|
});
|
|
|
|
test('should reject absolute path attempt for context files', () => {
|
|
const maliciousFilename = '/etc/passwd';
|
|
|
|
expect(() => {
|
|
createContextFileOnDisk(maliciousFilename, 'malicious content');
|
|
}).toThrow('Invalid context filename');
|
|
|
|
expect(() => {
|
|
contextFileExistsOnDisk(maliciousFilename);
|
|
}).toThrow('Invalid context filename');
|
|
});
|
|
|
|
test('should accept nested paths within context directory', () => {
|
|
const nestedFilename = 'subfolder/nested-file.md';
|
|
|
|
// The path itself is valid (doesn't escape the context directory)
|
|
expect(() => {
|
|
contextFileExistsOnDisk(nestedFilename);
|
|
}).not.toThrow();
|
|
});
|
|
|
|
test('should handle filenames without extensions for context', () => {
|
|
const filename = 'README';
|
|
|
|
createContextFileOnDisk(filename, 'content without extension');
|
|
|
|
expect(contextFileExistsOnDisk(filename)).toBe(true);
|
|
});
|
|
|
|
test('should handle filenames with multiple dots for context', () => {
|
|
const filename = 'my.context.file.md';
|
|
|
|
createContextFileOnDisk(filename, '# Multiple dots');
|
|
|
|
expect(contextFileExistsOnDisk(filename)).toBe(true);
|
|
});
|
|
});
|