Files
xinmi/mcp-server/test_file_path_security.py
T
yawan f7fc992f57
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
2026-09-22 16:19:06 +08:00

77 lines
2.8 KiB
Python

#!/usr/bin/env python3
import os
import tempfile
import unittest
from upload_paths import clear_active_transport, resolve_upload_file_path, set_active_transport
class ResolveUploadFilePathTest(unittest.TestCase):
def setUp(self):
self._old_transport = os.environ.get("MCP_TRANSPORT")
self._old_roots = os.environ.get("MCP_ALLOWED_UPLOAD_DIRS")
os.environ.pop("MCP_TRANSPORT", None)
def tearDown(self):
clear_active_transport()
if self._old_transport is None:
os.environ.pop("MCP_TRANSPORT", None)
else:
os.environ["MCP_TRANSPORT"] = self._old_transport
if self._old_roots is None:
os.environ.pop("MCP_ALLOWED_UPLOAD_DIRS", None)
else:
os.environ["MCP_ALLOWED_UPLOAD_DIRS"] = self._old_roots
def test_network_transport_blocks_path_outside_cwd(self):
os.environ["MCP_TRANSPORT"] = "http"
with tempfile.TemporaryDirectory() as tmp:
os.chdir(tmp)
allowed = os.path.join(tmp, "note.txt")
with open(allowed, "w", encoding="utf-8") as handle:
handle.write("ok")
resolved = resolve_upload_file_path("note.txt")
self.assertEqual(resolved, os.path.realpath(allowed))
with self.assertRaises(ValueError):
resolve_upload_file_path("/etc/passwd")
def test_active_transport_without_env_blocks_path_outside_cwd(self):
"""CLI --transport http sets active transport without MCP_TRANSPORT env."""
set_active_transport("http")
with tempfile.TemporaryDirectory() as tmp:
os.chdir(tmp)
allowed = os.path.join(tmp, "note.txt")
with open(allowed, "w", encoding="utf-8") as handle:
handle.write("ok")
resolved = resolve_upload_file_path("note.txt")
self.assertEqual(resolved, os.path.realpath(allowed))
with self.assertRaises(ValueError):
resolve_upload_file_path("/etc/passwd")
def test_explicit_allowed_roots(self):
with tempfile.TemporaryDirectory() as tmp:
os.environ["MCP_ALLOWED_UPLOAD_DIRS"] = tmp
allowed = os.path.join(tmp, "doc.md")
with open(allowed, "w", encoding="utf-8") as handle:
handle.write("hello")
resolved = resolve_upload_file_path(os.path.join(tmp, "doc.md"))
self.assertEqual(resolved, os.path.realpath(allowed))
outside = tempfile.NamedTemporaryFile(delete=False)
try:
outside.write(b"secret")
outside.close()
with self.assertRaises(ValueError):
resolve_upload_file_path(outside.name)
finally:
os.unlink(outside.name)
if __name__ == "__main__":
unittest.main()