fix(plugin): 修复坏插件模块声明击穿模块调度导致接口大面积报错

- projection 只接受映射类型的 get_module 声明,非法值跳过并记日志
- dispatcher 同步/异步路径防御非映射方法表,单个坏插件被隔离
- media 端点改用 application 层插件运行时门面,消除分层违规依赖
- 图片能力测试打桩 models.dev 目录边界,适配仓库内离线目录留空

Closes #6346
This commit is contained in:
jxxghp
2026-08-18 15:53:28 +08:00
parent dc23977b0c
commit 8d62f33155
8 changed files with 124 additions and 16 deletions
+16 -6
View File
@@ -99,10 +99,15 @@ class ModuleInvocationDispatcher:
"""同步执行插件方法,保留插件顺序、短路和列表合并语义。"""
for plugin, module_dict in self._plugin_catalog.get_plugin_modules().items():
plugin_id, plugin_name = plugin
func = module_dict.get(method)
if not func:
continue
try:
# 防御坏插件把方法表声明成非映射类型,避免击穿整个模块调度
if not isinstance(module_dict, Mapping):
raise TypeError(
f"插件 {plugin_id} 的模块声明必须是映射,实际是 {type(module_dict).__name__}"
)
func = module_dict.get(method)
if not func:
continue
logger.info("请求插件 %s 执行:%s ...", plugin_name, method)
if self.is_valid_empty(result):
result = func(*args, **kwargs)
@@ -140,10 +145,15 @@ class ModuleInvocationDispatcher:
"""异步执行插件方法,并把同步函数移入线程池。"""
for plugin, module_dict in self._plugin_catalog.get_plugin_modules().items():
plugin_id, plugin_name = plugin
func = module_dict.get(method)
if not func:
continue
try:
# 防御坏插件把方法表声明成非映射类型,避免击穿整个模块调度
if not isinstance(module_dict, Mapping):
raise TypeError(
f"插件 {plugin_id} 的模块声明必须是映射,实际是 {type(module_dict).__name__}"
)
func = module_dict.get(method)
if not func:
continue
logger.info("请求插件 %s 执行:%s ...", plugin_name, method)
if self.is_valid_empty(result):
result = await self._async_call(func, *args, **kwargs)
+10 -1
View File
@@ -87,7 +87,16 @@ class PluginProjection:
continue
try:
if plugin.get_state():
modules[(plugin_id, plugin.get_name())] = plugin.get_module() or []
declared = plugin.get_module()
# 基类默认实现返回 None;只接受映射,防止把 list 当成方法表传入调度器
if declared is None:
continue
if not isinstance(declared, Mapping):
self._logger.error(
f"插件 {plugin_id} 的 get_module() 返回值必须是字典,实际是 {type(declared).__name__}"
)
continue
modules[(plugin_id, plugin.get_name())] = declared
except Exception as error:
self._logger.error(f"获取插件 {plugin_id} 模块出错:{str(error)}")
return modules