mirror of
https://github.com/haris-musa/excel-mcp-server.git
synced 2026-07-26 15:59:14 +08:00
Harden get_excel_path() for SSE and streamable-http transports: - Reject absolute paths supplied by remote clients - Resolve and validate relative paths stay within EXCEL_FILES_PATH - Reject filenames containing NUL bytes Add tests/test_sandbox_paths.py covering bypass vectors. Bump version to 0.1.8. Made-with: Cursor
59 lines
2.0 KiB
Python
59 lines
2.0 KiB
Python
import os
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
|
|
_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
_SRC = os.path.join(_REPO_ROOT, "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
import excel_mcp.server as server # noqa: E402
|
|
|
|
|
|
class TestGetExcelPathSandbox(unittest.TestCase):
|
|
def tearDown(self):
|
|
server.EXCEL_FILES_PATH = None
|
|
|
|
def test_stdio_accepts_absolute_only(self):
|
|
server.EXCEL_FILES_PATH = None
|
|
with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as f:
|
|
path = f.name
|
|
try:
|
|
self.assertEqual(server.get_excel_path(path), os.path.normpath(path))
|
|
with self.assertRaises(ValueError):
|
|
server.get_excel_path("relative_only.xlsx")
|
|
finally:
|
|
os.unlink(path)
|
|
|
|
def test_remote_rejects_absolute(self):
|
|
with tempfile.TemporaryDirectory() as d:
|
|
server.EXCEL_FILES_PATH = d
|
|
inner = os.path.join(d, "ok.xlsx")
|
|
with self.assertRaises(ValueError):
|
|
server.get_excel_path(inner)
|
|
|
|
def test_remote_allows_relative_inside_sandbox(self):
|
|
with tempfile.TemporaryDirectory() as d:
|
|
server.EXCEL_FILES_PATH = d
|
|
out = server.get_excel_path(os.path.join("subdir", "file.xlsx"))
|
|
self.assertTrue(server._resolved_path_is_within(d, out))
|
|
|
|
def test_remote_blocks_traversal(self):
|
|
with tempfile.TemporaryDirectory() as d:
|
|
server.EXCEL_FILES_PATH = d
|
|
with self.assertRaises(ValueError):
|
|
server.get_excel_path("../outside.xlsx")
|
|
with self.assertRaises(ValueError):
|
|
server.get_excel_path(os.path.join("a", "..", "..", "outside.xlsx"))
|
|
|
|
def test_remote_rejects_nul(self):
|
|
with tempfile.TemporaryDirectory() as d:
|
|
server.EXCEL_FILES_PATH = d
|
|
with self.assertRaises(ValueError):
|
|
server.get_excel_path("a\x00b.xlsx")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|