136 lines
4.6 KiB
Python
136 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import importlib.util
|
|
import py_compile
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
SDK_SRC = PROJECT_ROOT / "packages" / "jwebot-sdk" / "src"
|
|
KERNEL_SRC = PROJECT_ROOT / "packages" / "jwebot-kernel" / "src"
|
|
sys.path[:0] = [str(SDK_SRC), str(KERNEL_SRC)]
|
|
|
|
SPEC = importlib.util.spec_from_file_location(
|
|
"create_plugin",
|
|
PROJECT_ROOT / "tools" / "create-plugin.py",
|
|
)
|
|
MODULE = importlib.util.module_from_spec(SPEC)
|
|
assert SPEC.loader is not None
|
|
SPEC.loader.exec_module(MODULE)
|
|
|
|
|
|
class CreatePluginTests(unittest.TestCase):
|
|
def test_generator_creates_a_bounded_command_extension(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
destination = MODULE.create_plugin(
|
|
Path(directory),
|
|
"weather-command",
|
|
"/weather",
|
|
"Friend",
|
|
"查询天气",
|
|
)
|
|
self.assertTrue((destination / "plugin.toml").is_file())
|
|
manifest = (destination / "plugin.toml").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
self.assertIn('description = "查询天气"', manifest)
|
|
self.assertIn('help = ["/weather"]', manifest)
|
|
module = destination / "src" / "weather_command.py"
|
|
self.assertIn(
|
|
'context.commands.register("/weather", handle)',
|
|
module.read_text(encoding="utf-8"),
|
|
)
|
|
self.assertNotIn(
|
|
"subprocess",
|
|
module.read_text(encoding="utf-8"),
|
|
)
|
|
py_compile.compile(str(module), doraise=True)
|
|
py_compile.compile(
|
|
str(destination / "tests" / "test_plugin.py"),
|
|
doraise=True,
|
|
)
|
|
|
|
def test_generator_refuses_to_overwrite_existing_plugin(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
output = Path(directory)
|
|
MODULE.create_plugin(
|
|
output,
|
|
"weather-command",
|
|
"/weather",
|
|
"Friend",
|
|
"查询天气",
|
|
)
|
|
with self.assertRaises(FileExistsError):
|
|
MODULE.create_plugin(
|
|
output,
|
|
"weather-command",
|
|
"/weather",
|
|
"Friend",
|
|
"查询天气",
|
|
)
|
|
|
|
def test_generator_rejects_path_traversal_plugin_id(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
with self.assertRaisesRegex(ValueError, "invalid format"):
|
|
MODULE.create_plugin(
|
|
Path(directory),
|
|
"../outside",
|
|
"/weather",
|
|
"Friend",
|
|
"查询天气",
|
|
)
|
|
|
|
def test_generator_rejects_invalid_command(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
with self.assertRaisesRegex(ValueError, "invalid value"):
|
|
MODULE.create_plugin(
|
|
Path(directory),
|
|
"weather-command",
|
|
"weather",
|
|
"Friend",
|
|
"查询天气",
|
|
"/weather",
|
|
)
|
|
|
|
def test_generator_rejects_command_template_injection(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
with self.assertRaisesRegex(ValueError, "invalid value"):
|
|
MODULE.create_plugin(
|
|
Path(directory),
|
|
"weather-command",
|
|
'/"\\nentrypoint = "attacker:run',
|
|
"Friend",
|
|
"查询天气",
|
|
"/weather",
|
|
)
|
|
|
|
def test_generator_rejects_invalid_author(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
with self.assertRaisesRegex(ValueError, "author has an invalid format"):
|
|
MODULE.create_plugin(
|
|
Path(directory),
|
|
"weather-command",
|
|
"/weather",
|
|
"../Friend",
|
|
"查询天气",
|
|
)
|
|
|
|
def test_generator_rejects_invalid_help_description(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
with self.assertRaisesRegex(ValueError, "invalid display"):
|
|
MODULE.create_plugin(
|
|
Path(directory),
|
|
"weather-command",
|
|
"/weather",
|
|
"Friend",
|
|
"查询天气",
|
|
"plain text",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|