openpencil/tests/engine/mcp-path-scoping.test.ts
Danila Poyarkov d692953d62 test: fix pre-existing failures and add coverage for new features
- Fix mcp-stdio.test.ts: defer heavy SDK imports to avoid describe()
  registration race when running full suite
- Fix mcp-server.test.ts: add server.close() to properly clean up
  sessions and pending requests between tests (eliminates 8 unhandled
  errors)
- Add mcp-path-scoping tests: path traversal, sibling dir, root prefix
  trick, valid paths
- Add editor-store-path tests: setPlannedFilePath with Unix/Windows
  paths
- Add MCP server tests: open_file/new_document registered when mcpRoot
  is set, absent when null

0 fail, 0 errors, 1108 pass
2026-04-22 17:20:09 +03:00

51 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'
)
})
})