openpencil/tests/engine/mcp/path-scoping.test.ts
Danila Poyarkov 930cf39216 test: organize prefixed test files into folders
- Move top-level engine and e2e prefixed test files under domain folders
- Update fixture path helpers after moving render and pen tests
- Add lint coverage to prevent new top-level prefixed test files
- Refresh testing docs for the new fig and layout paths
2026-05-06 02:13:18 +03:00

49 lines
1.6 KiB
TypeScript

import { describe, test, expect } from 'bun:test'
import { resolve, sep } from 'node:path'
// Test the resolveSafePath logic directly (extracted for testability)
function resolveSafePath(filePath: string, root: string): string {
const resolved = resolve(filePath)
const normalizedSep = root.endsWith('/') || root.endsWith('\\') ? '' : sep
if (!resolved.startsWith(root + normalizedSep) && resolved !== root) {
throw new Error(`Path is outside the allowed root: ${root}`)
}
return resolved
}
describe('MCP path scoping', () => {
const root = resolve('/tmp/mcp-test-root')
test('allows path inside root', () => {
expect(resolveSafePath(`${root}/design.fig`, root)).toBe(`${root}/design.fig`)
})
test('allows nested path inside root', () => {
expect(resolveSafePath(`${root}/sub/dir/file.fig`, root)).toBe(`${root}/sub/dir/file.fig`)
})
test('allows root itself', () => {
expect(resolveSafePath(root, root)).toBe(root)
})
test('rejects path outside root', () => {
expect(() => resolveSafePath('/etc/passwd', root)).toThrow('outside the allowed root')
})
test('rejects path traversal', () => {
expect(() => resolveSafePath(`${root}/../../../etc/passwd`, root)).toThrow(
'outside the allowed root'
)
})
test('rejects sibling directory', () => {
expect(() => resolveSafePath(`${root}/../other-root/file.fig`, root)).toThrow(
'outside the allowed root'
)
})
test('rejects root prefix trick (root-evil)', () => {
expect(() => resolveSafePath(`${root}-evil/file.fig`, root)).toThrow('outside the allowed root')
})
})