Repository navigation
Releases: EasyIndie/EasyBot
Release list
EasyBot v0.0.43
Fixed
-
进程外插件在真实宿主中无法启动(
plugin handshake failed: plugin process exited) —AdapterManager::start()在调用AdapterFactory之后会再调用一次
init(),而工厂内部也已经调用过init()。对内置适配器这只是重复解析配置(无害),
但对进程外插件意味着第二次init会 spawn 第二个子进程,第一个被
kill_on_drop杀掉;已退出进程的 reader 任务在 EOF 时会把「进程已退出」错误投递给
新握手的请求,导致插件永远无法启动。修复:IpcPluginAdapter::init改为幂等:子进程存活时只复用,不再重复 spawn;- 未决请求表改为按 spawn 换代(每次 spawn 换新的
pending表),已退出进程的
reader 只清理自己那一代,不会误伤新进程的请求; - 新增回归测试
ipc_adapter_init_is_idempotent。
该缺陷仅影响真实宿主启动路径(
AdapterFactory+AdapterManager双重 init),
单测与ProcessPluginTestHost直接调用init因而未暴露。
EasyBot v0.0.42
Added
-
QQ 公/私域机器人 intent 自动降级探测 — QQ 公/私域机器人的频道消息
intent(GUILD_MESSAGES/PUBLIC_GUILD_MESSAGES)互斥且官方无运行时探测端点。
适配器默认订阅群/C2C + 私域频道消息的保守集;当 Identify 以 close 4013/4014
(invalid / disallowed intents)被拒时,自动翻转频道 intent 位并重连重试一次
(Identify 成功收到READY后不再切换)。显式配置config.extra.intents时
保持既有语义,不自动切换。 -
Telegram 相册 / 多图出站(
send_media_group) — 新增
SendMediaGroupParams与PlatformAdapter::send_media_group(默认实现返回
CapabilityNotSupported),POST /api/v1/messages/send增加可选media_group
字段(优先级高于media)。Telegram 适配器将 2–10 条媒体经sendMediaGroup
一次发出:纯 URL 走 JSON body,含 base64 走 multipart +attach://;单条自动
退化为普通send_media,贴纸与超过 10 条明确拒绝。Discord / 飞书 / QQ / 微信
未实现该能力,经 trait 默认实现返回CapabilityNotSupported。 -
管理后台前端测试与类型工具链 — 在
crates/easybot-api/templates/新增 dev-only
工具链(package.json+ vitest + jsdom + eslint,不进运行时产物):tests/utils.test.js
29 项断言覆盖parsePrometheus/fmtDuration/statusBadgeClass/msgTypeLabel/
escapeHtml等纯函数;新增.github/workflows/frontend.yml(npm ci/test/lint,Action 固定 SHA,
通过仓库 pinning 门禁);新增js/types.d.ts手写类型契约(对照 OpenAPI)。 -
进程外插件 PoC(Linux 静态宿主插件路线验证) — 在
tests/integration内新增自包含的
进程外插件示例(ipc-mock-plugin插件进程 +IpcPluginAdapter宿主代理 + 端到端测试),
并验证 musl 静态(static-pie)宿主可拉起进程外插件完成完整生命周期(握手/连接/双向
事件/发送),全程不依赖 dlopen。结论与迁移建议见docs/other/plugin-out-of-process-poc.md。
Changed
- 核心大模块拆分(可维护性,对外 API 不变) —
auth/api_key.rs(3169 行)拆为
auth/api_key/{mod,keys,audit,billing,grants,tests}.rs;adapter/manager.rs、
storage/sqlite.rs、plugin/manager.rs的#[cfg(test)]测试模块抽出为
*/tests.rs子模块,adapter/manager.rs的重连分类与退避逻辑抽出为
adapter/manager/reconnect.rs。 - 依赖升级(兼容范围内) —
cargo update批量升级间接依赖;utoipa5→6、
utoipa-swagger-ui9→10(OpenAPI 快照随之更新,属 schema 表达变化,无语义变更);
serde_yaml(上游已归档弃用)改用维护 forkserde_norway0.9,以package别名
保持全部serde_yaml::调用不变。 - 微信适配器测试补齐 —
tests/send_mock.rs由 12 项扩充至 33 项,覆盖媒体类型映射
(image/video/audio/document/sticker/animation)、CDN 上传错误路径、getuploadurl业务
错误、缺失x-encrypted-param、非法 base64、能力声明与全部“不支持”操作。 - 覆盖率门禁 — 新增仓库根
codecov.yml:project(target: auto+threshold: 1%)
与 patch(target: 75%)阈值;coverage.yml移除continue-on-error并设
fail_ci_if_error: true。在分支保护中把codecov/project、codecov/patch设为
required 后即可阻止不达标的合并。 - 管理后台前端模块化(对外行为不变) —
templates/js/admin.js(2752 行单文件)
拆为 11 个文件(00-utils/10-core/21-overview…29-apikey-dialogs/30-tail,
全部 ≤683 行),由build.rs按文件名排序内联,拼接顺序保持原相对顺序;设计 token
收敛到单一templates/css/tokens.css(admin/home/docs 三页共用);Tab 支持 hash 深链
(#/logs等,支持刷新/收藏/前进后退)。 - 管理后台前端无障碍与文档搜索 — Tab 栏 emoji 改为内联 SVG 图标(
currentColor,
随主题/激活态变色)+ 完整 ARIA tabs 语义(aria-controls/aria-labelledby+
roving tabindex);文档页搜索由“仅过滤侧边栏标题”升级为标题+正文全文匹配
(隐藏不匹配章节,并显示“匹配 N / 总数”)。 - 个人微信适配器改为默认关闭(行为变更) — 微信无凭据要求(扫码登录),此前会被
无条件自动启用,导致每次启动都尝试连接微信 API 并后台重试;现改为 opt-in:
仅当配置显式adapters.wechat.enabled: true时才启动。其余四个适配器(凭据检测)与
插件适配器的自动启用逻辑不变。实现为注册表新增「无凭据时是否自动启用」策略位
(AdapterRegistry::register_with_policy),默认true保持向后兼容。
Breaking Changes
- 插件架构改为「进程外」——cdylib /
dlopen路径已移除 — 官方 Linux 发行版是
musl 全静态二进制(无INTERP/动态加载器),dlopen在任何情况下都不可能成功,
因此进程内插件在发行版上完全无法加载(与插件自身如何编译无关)。现改为:插件编译为
独立可执行文件,宿主将其作为子进程启动,双方通过 stdin/stdout 逐行 JSON
(新 crateeasybot-plugin-protocol)通信。- 迁移:
declare_plugin!→run_plugin!(放src/main.rs);产物 cdylib → bin;
plugin.yaml的library→command(library仍作为别名兼容)。
详见docs/other/plugin-cdylib-to-process-migration.md。 - 收益:崩溃隔离(插件退出 →
HealthStatus::Down→ 宿主重连/spawn)、静态宿主可用、
无 FFI 跨堆分配器问题(旧「FFI 分配器契约」随架构废止)。 - 注意:v1 仅提供崩溃隔离,不是安全沙箱(无 seccomp/降权);
生产隔离仍依赖容器化,见docs/18 plugin-security.md。 - 移除
libloading依赖、SDKffi.rs/declare_plugin!、PluginAdapterProxy与
测试用tests/plugins/mock-adapter(cdylib)。 - 加载器只保留一套:
PluginLoader(loader.rs)直接实现进程外扫描/验签/工厂,
删除了重复且不做签名校验的ProcessPluginLoader;旧式清单(仅library)现返回
PluginError::LegacyCdylibPlugin(错误信息含迁移指引),安装落位名与
PluginManifest::command_path()缺省推导统一为{name}(Windows{name}.exe)。 - 顺带修复
plugins/example-slack-plugin参考样例:它自 cdylib 时代起就无法编译
(API 漂移 + 未在 workspace 内),现已迁移为进程外插件、加入workspace.exclude
并验证可构建、可完成协议握手。
- 迁移:
Removed
- 移除未使用的
rand_core直接依赖 — easybot-core 的 CSPRNG 统一经
getrandom::rand_core(0.10 系)重导出使用,原先直接声明的rand_core 0.9未被引用;
移除后消除一处版本重复(剩余 0.9 来自 tungstenite 传递依赖,属上游)。
Fixed
- 修复
gateway.local.yaml为空(仅注释)时静默重置全部配置 —config::merge_configs
在local非 Mapping 时执行*base = local;只含注释的gateway.local.yaml解析为
Value::Null,于是整个基础配置被替换为 Null,再反序列化时所有字段回落 serde 默认值
(例如在gateway.yaml里把server.port改成 8081 会被静默重置回 8080,
server.adminPassword/storage.path等一并失效)。现 Null local 视为“无覆盖”直接返回,
并补充回归测试test_merge_configs_null_local_is_noop。 - 发布流程两处陷阱修复(不影响发布产物) —
scripts/release-preflight.sh的cargo run -p easybot-bin(不带特性)会把
target/debug/easybot重建成无插件版,导致随后cargo test --workspace的
cli::test_production_*/cli::test_plugin_cli_*误报失败;现让预检以
--features "default,plugin-system"构建并运行,使测试直接复用正确的插件版二进制。.github/workflows/release.yml的容器标签改由已校验的发布版本推导(type=raw),
不再依赖github.ref_type:此前用workflow_dispatch在分支 ref 上重跑发布时
docker/metadata-action的type=semver产生 0 个标签,docker作业以
tag is needed when pushing to registry失败。
- 管理后台前端修复 — 补定义
--bg-subtle、修正未定义的var(--primary)(调试面板
日志颜色);api()增加非 JSON/空响应防御并附带err.status;指标可视化中
method/path/platform 插值统一escapeHtml;PUT /config的 409 语义化(提示
“需审阅后重启”而非“保存失败”);会话删除/改名、Key 吊销/删除、插件卸载与目标授权
删除等 6 处原生confirm()/prompt()替换为可样式化的自研 modal(含焦点管理与 Enter/ESC)。
EasyBot v0.0.41
Fixed
-
管理后台日志环形缓冲不再无过滤采集依赖库内幕(并修复
RUST_LOG被忽略) —
LogCollector图层此前未挂过滤器,会接收并保存hyper/sqlx/tower_http/
axum等所有 target 的TRACE/DEBUG事件:环形缓冲(上限 5000 条)被依赖库噪音占满,
业务与插件日志被挤掉;同时未过滤的图层不对全局最大级别提供任何约束,tracing全局最大
级别被抬到TRACE,所有trace!/debug!宏(包括依赖内的)都被真实构造/记录,带来
不必要的 CPU 与内存开销。现让内存收集器与控制台fmt层共用同一过滤器(默认
easybot=<level>),并读取RUST_LOG(存在时接管过滤),兼现docs/16/docs/17中
RUST_LOG=<target>=<level>可按 target 细分日志的承诺——此前该环境变量被完全忽略。 -
修复空载下匿名内存持续增长直至 cgroup OOM(issue #139) — 事务性 outbox 发布器每 250ms 调用
unpublished_outbound_events(),其ORDER BY completed_at, id缺少覆盖索引,SQLite 每次排序都会
构建一个 TEMP B-tree;承载该临时结构的匿名内存不会被释放,导致空载下匿名内存单调增长
(实测空载 ~0.3MB/min,容器最终逼近内存上限并被 OOM kill)。GET /api/v1/messages/deliveries
与GET /api/v1/sessions/{key}/export的ORDER BY created_at DESC, id DESC同样退化为临时 B-tree。
新增 schema 迁移 v4:为outbound_deliveries建立
(event_published, completed_at, id)、(actor_id, created_at DESC, id DESC)、
(platform, chat_id, created_at DESC, id DESC)三个索引,使上述查询走索引排序、不再创建临时 B-tree。
升级前(schema < 4)的库会在启动时自动迁移;CREATE INDEX IF NOT EXISTS可重复执行。 -
修复 Windows Docker Desktop bind mount 上无法打开既有
gateway.db(Operation not permitted) —
storage::sqlite::create_pool在 Unix 下对已存在的数据库文件强制执行chmod 0600,
成功与否被当作打开数据库的硬性前提。Windows Docker Desktop 的 bind mount(9p/virtiofs)
会拒绝对迁移进来的既有文件执行chmod并返回EPERM(os error 1),导致create_pool
返回错误、bin/src/main.rs回退到内存库:消息/outbox 表不存在(no such table: messages)、
持久化的 API key 无法加载致 REST/WebSocket 认证全部 401。现将权限收紧改为纵深防御:
失败仅记录 warn 并继续,依赖底层文件系统 ACL 打开数据库;新建文件仍以0600创建。
容器自身创建的库(如auth.db)权限收紧正常,不受影响。 -
内存回退库不再静默降级:执行 schema 迁移 + 显式报告降级状态 —
当 SQLite 仍无法打开而回退到内存库时,bin/src/main.rs现在对内存库执行同一套
版本化迁移,避免消息/outbox 持久化持续报no such table: messages/
outbound_deliveries(此前单容器 2 天可刷出 162MB 日志)。回退日志从warn
升为单条error,附可操作指引(提示属主不匹配与chown 10001:10001)。
新增AppState.storage_ephemeral,/api/v1/ready在内存回退时把
message_storage标为ephemeral、整体status为degraded并返回 503,
/api/v1/health同步报告degraded,消除"数据未落盘但健康检查仍绿"的运维盲区。 -
根治下载/插件安装偶发"下载产物为空"缺陷(
updater::github::download_binary) —
根因是tokio::fs::File的write_all只保证字节拷入内部缓冲并派发后台阻塞写任务,
poll_write随即返回Ready——字节未必已写入 OS。download_binary未flush就
返回Ok,调用方(自动更新替换、插件安装)用独立 fd/path 读该文件做 sha256 校验时,
高负载下会读到尚未落盘的空文件(历史表现为下载测试偶发sha256 of empty,
e3b0c442…)。已在返回前补file.flush().await等待后台写任务完成,并把 0 字节
响应判为失败(此前无 Content-Length 的 0 字节完整响应会被静默当成成功)。
test_download_verifies_sha256中为此设的 8 次重试循环一并移除——回归即真缺陷,
应修根因而非加重试预算。
EasyBot v0.0.40
Security
- 发布容器镜像构建期升级系统包(修复 CVE-2026-14456) —
Dockerfile.release在FROM
之后新增RUN apk upgrade --no-cache。基础镜像 digest 固定于 Alpine 构建快照,而 Alpine
重建 3.22 base 的节奏晚于 openssl 补丁发布(修复版 3.5.8-r0 已在 v3.22/main),因此纯 digest
升级无法消除预装 openssl/libcrypto3 3.5.7-r0 的高危漏洞(CVE-2026-14456,无界内存 DoS)。
构建期升级保证每次产出的运行时镜像都携带仓库最新系统包。受影响的 v0.0.39 镜像由本版本
发布的镜像取代(latest/0.0/0.0.40;历史0.0.39精确 tag 属已淘汰快照)。
Changed
- 发布流水线把容器镜像校验纳入版本发布前置要求并提前暴露问题(CI) —
- 新增
container-preflight作业:在verify/build-binaries之前用同一 Trivy 门禁
(CRITICAL/HIGH、exit-code 1)本地构建并扫描发布镜像。坏基础镜像约 2 分钟即失败,
后续昂贵作业不再启动,节约 CI 运行成本。 create-release现在依赖docker作业:GitHub Release 仅在镜像构建、推送与扫描全部通过后
才发布(v0.0.39 教训:create-release原不等待 docker,镜像带 CVE 时 Release 仍会先行发布,
留下一个带漏洞镜像的已发布版本)。
- 新增
EasyBot v0.0.39
Security
- h2 0.4.15 → 0.4.16(RUSTSEC-2026-0258) — 修复 hyper 传递依赖 h2 的空 DATA 帧内存
放大(连续空 DATA 帧可无界占用内存触发 OOM)。Cargo.lock已锁定 0.4.16。
Changed
- 依赖跨版本迁移(批量依赖升级中随主程序代码适配的两个破坏性升级):
- 例行依赖与 CI 工具更新 — 运行时:thiserror / uuid / futures / async-trait / ureq /
http-body-util / larksuite-oapi-sdk-rs;CI Actions:install-action / sbom-action /
setup-buildx-action / fetch-metadata / rust-toolchain。 - 文档结构与内容梳理(#115) — 对齐实现事实:合并一次性商用薄文档到常驻文档、
删除过期过程文档(auto-update-tasks / test-plan / upgrade-strategy /
windows-upgrade-verify),README/CLAUDE/docs 与代码一致化;同步 release-preflight
必需文档清单与残留引用。 - 新增 OrzMC 完整客户端接入实战文档(#114) — 首个真实外部客户接入案例,覆盖
架构对接、心跳语义、会话清理、config.changed预置语义等完整实战路径。
EasyBot v0.0.38
Fixed
- Windows 回滚 data-safety:服务名可配置(issue #95 反馈 #5) — rollback 的
data-safety 保护此前硬编码检测服务名EasyBot(precheck::is_windows_service_running),
自定义 NSSM 服务名部署(如EasyBotTest)时检测不到运行中的服务 → 放行回滚,造成
"DB/config 已回滚但 exe 未变 + manifest 已删"的半状态。新增server.serviceName
(gateway.yaml,默认EasyBot),updater 预检与回滚均按该配置检测服务;自定义服务名
部署须将serviceName设为与 NSSM 注册名一致。--init模板已含注释示例。
EasyBot v0.0.37
Fixed
- Windows-only clippy 门禁修复(2 项) — cross-check 升级为 clippy 后暴露的两个
#[cfg(windows)]专属 lint:updater回滚清理循环改flatten()(clippy::manual_flatten)。plugin-signCommand枚举SignArgsBox 化,规避 Windows 布局下
clippy::large_enum_variant(CLI 一次性解析,零成本)。
Changed
- CI 门禁:cross-check 升级为 clippy —
platform-matrix.yml的Check target
由cargo check改为cargo clippy -- -D warnings(setup-rust 加 clippy component)。
此前 Windows target 的#[cfg(windows)]代码从没被 clippy 检查(Linux clippy 剔除
cfg 块、Windows 仅 rustc check),Windows-only lint 只在推送后暴露;现在
Windows/macOS 目标均纳入 clippy 门禁。 - 文档:
windows-upgrade-verify.md补充 v0.0.32→v0.0.36 验收结论并更新验收清单。
EasyBot v0.0.36
Fixed
- Windows 升级:分离辅助脚本两步替换(issue #95 U2) — 运行中的 exe 被 Windows
进程映射锁定,原地rename会得到 os error 5。update/rollback改为「暂存 → 分离
辅助脚本两步替换」:新 exe 下载校验后暂存为独立文件,先运行校验再提交;交换在
本进程退出后由分离.cmd批处理完成(CREATE_NO_WINDOW隐藏窗口、15 次有界重试、
marker 写OK/TIMEOUT)。Unix 保持原地rename语义不变。updater/replace.rs、
mod.rs、bin/main.rs相应调整;Windows 需先停服务再启动(文档已说明)。 update支持全局--dir(issue #95 U1) —--dir改为 clap 全局参数,
easybot update --dir <home>/check-update --dir <home>/rollback --dir <home>
均可解析并显示在各子命令--help。verify_binary校验新二进制时透传--dir,
修复自定义目录部署下校验落到默认目录的缺口。- 更新失败/回滚后清理残留(issue #95 U3) — 新增
cleanup_artifacts:
失败(下载/替换/校验)与显式rollback完成后删除陈旧.bak、.update_manifest.json
与{home}/.update/临时目录;下载失败不再残留临时文件。成功路径仍保留备份供
rollback。 - 迁移结果显式确认(issue #95 U4) —
run_migrations/run_migrations_pg返回
本次实际执行的Vec<AppliedMigration>;启动日志打印「✓ 数据库迁移完成:N 条」清单,
update提示明确「N 条迁移将在重启后由新版本执行」。
Changed
- Windows 服务检测(
precheck.rs)由 stub 实现为sc.exe query EasyBot探测。 - 文档:
windows-deployment.md第 9 节升级流程、第 10 节 Defender 误报处理、
FAQ 新增升级类条目;upgrade-strategy.md/01 user-guide.mdWindows 升级表述
与实现对齐;windows-deployment.md补充 NSSM 前置项(§1 三种安装方式 + §7
NSSM 命令对照表 + FAQ);新增windows-upgrade-verify.md真机验证清单。 - U2 分离辅助脚本两步替换已通过 Windows 真机 + NSSM 验收(2026-08-14:U1
--dir、分离交换、场景 C/E/F、A·B 前置路径);场景 A/B/D/G 完整端到端作为
发版后回归项。
EasyBot v0.0.35
Fixed
-
gateway.local.yaml覆盖合并不再注入结构体默认值 — 修复本地覆盖配置合并的
serde 默认值注入 bug:此前gateway.local.yaml经load_config反序列化为完整
GatewayConfig(缺失键被默认值补齐,如server.host默认127.0.0.1)再序列化
合并,默认值被当成"显式字段"覆盖基础配置(容器基础配置server.host=0.0.0.0
被覆盖为127.0.0.1,监听退回容器回环,经反向代理/隧道的公网入口 502)。现本地
覆盖改走load_config_value按原始 YAML Value 合并,只合并文件显式写出的键;
合并后仍校验 webhook 防 SSRF。覆盖文件不再需要显式重复server.host: "0.0.0.0"。 -
FFI 分配器契约(行为变更) — 移除宿主
#[global_allocator]mimalloc(bin/
的main.rs/Cargo.toml),宿主与进程内 dlopen 的插件共用默认系统分配器。
此前宿主 mimalloc + 插件系统 malloc 时,跨 FFI 的 String/Vec/Value 所有权转移会
交叉 free → SIGABRT;插件各自静态链接 mimalloc 则进程内两套堆 → 析构死锁。
现在插件保持默认分配器即可安全收发消息。详见docs/17 plugin-methodology.md
「FFI 分配器契约」。 -
插件 FFI 分配器契约(宿主侧,
PluginAdapterProxy) —PluginLoader::create_adapter()
改为返回PluginAdapterProxy:宿主只借读插件返回的Box<Box<dyn PlatformAdapter>>
胖指针(ptr::read+ManuallyDrop,不取得所有权),代理 Drop 时调用插件的
easybot_plugin_destroy——谁分配谁释放。此前宿主Box::from_raw后用自己的
分配器释放插件分配的内存:macOS 两侧共享系统 libc 无感;Linux 宿主是 musl-static,
与插件 malloc 各一份堆,跨堆释放即 UB(SIGABRT / 堆损坏)。符号不变、无需 ABI bump,
向后兼容;加载路径经mock-adapter真实 cdylib 端到端验证。
Added
- 插件命名规则 — 官方插件统一
easybot-xxx前缀,且同一个名字贯穿仓库名 /
[package].name/ cdylib 产物 /plugin.yamlname /platform_name()/ 市场安装名。
详见docs/16 plugin-guide.md「命名规则」。 - 主仓与入门样例解耦 — 官方入门样例独立为
EasyIndie/easybot-hello-adapter
(教学样例仓库,含插件开发指南,与主仓仅文档/链接互引);本仓库移除
plugins/example-hello-adapter/(workspace 成员已裁剪,Cargo.lock 同步清理)。
Changed
- 市场目录仓库重命名 —
EasyIndie/EasyBot-Plugins→EasyIndie/EasyBot-Registry。
默认注册源与DEFAULT_CATALOG_REPO同步更新;旧仓库名经 GitHub 301 重定向,
历史链接仍可用。安装/搜索/更新行为不变(easybot plugin install <pub>/<name>)。
EasyBot v0.0.34
Added
-
插件市场(P6) — 通过 GitHub Releases 分发第三方适配器插件,
easybot plugin
子命令 + REST API + 管理后台完整管理:- 安装流水线 —
easybot plugin install [publisher/]name:按宿主 6-target
triple 匹配产物 → ABI 预检(sdk_version)→requires.easybotsemver range
校验 → 信任确认 → 下载 → SHA256 比对 + ed25519 验签 → 原子落位(含合成
plugin.yaml+plugin.sig.json)。--file <dir>离线安装走同流水线跳过下载。 - 多注册表(Taps) —
plugins.registries列表合并多源 catalog,插件名支持
publisher/name限定,5min 缓存。官方目录默认源为
EasyIndie/EasyBot-Plugins(catalog.json)。 - 信任管理(VS Code 1.97 语义) — 信任按发布者粒度存
plugins/.trust;
--yes不自动信任,显式plugin trust <publisher> --public-key <k>才加入。 - 更新语义 —
plugin update显式触发、默认 pin 当前版本,--latest/--channel
才跨版本(防更新攻击)。 - 启停语义 —
disable立即 stop+unregister;enable下次启动生效(v1 不做热
dlopen);孤儿会话/消息由现有 TTL 保留策略兜底。 - CLI —
easybot plugin new/list/search/info/install/uninstall/enable/disable/ update/trust/inspect。 - REST API —
GET /plugins(含加载失败清单)、GET /plugins/catalog、
POST /plugins/install、DELETE /plugins/{name}、
POST /plugins/{name}/enable|disable(PluginsRead/PluginsManage权限)。 - 管理后台 — 🧩 Plugins tab:已装表(含失败行与原因)、市场目录(发布者徽标 +
搜索)、安装/卸载/启停、首次第三方信任确认。
- 安装流水线 —
-
生产模式插件签名门禁(行为变更) —
--production/EASYBOT_ENV=production
启动时扫描plugins/目录,未签名插件且未设plugins.allowUntrusted: true则拒绝
启动。此前手放的未签名插件在生产模式可加载;现在需走市场安装(带签名)或显式
allowUntrusted。dev 环境不受影响(lenient:有签名验、无签名 warn)。 -
开发者工作流(DX) —
- 脚手架 —
easybot plugin new <name>生成独立可构建的插件工程(SDK git tag
依赖,无需 clone 主仓),含src/lib.rs骨架、plugin.yaml、单元测试、
PluginTestHost 集成测试、plugin-publish.yml发布模板。 - 测试宿主 — SDK
testingfeature 提供PluginTestHost内存宿主,离线跑通
attach → init → connect → send → 事件流,配recv_event/inbound_text等构造器。 - 发布者 CI 模板 —
.github/workflows/plugin-publish.yml(自包含,仅公开 action- 40 位 SHA 固定):6-target 交叉编译 + gitleaks 扫描 +
easybot-plugin-sign
ed25519 签名 + 组装easybot-plugin.json+ Release。
- 40 位 SHA 固定):6-target 交叉编译 + gitleaks 扫描 +
- 示例 —
plugins/example-hello-adapter/入门 echo 适配器(workspace 成员,
CI 持续编译验证脚手架产出形状)。 - 文档 —
docs/02 plugin-dev.md重拆为docs/plugin-quickstart.md(15 分钟教程)、
docs/plugin-guide.md(完整参考)、docs/plugin-methodology.md(方法论);新建
docs/SECURITY.md(信任模型)与docs/docker-compose.plugin-dev.yml(Docker 联调)。
- 脚手架 —
-
easybot-plugin-sign独立工具 —gen-keypair/sign(ed25519),仅发布者
CI 使用,主程序不持私钥。sign --sig-json <path>额外写出离线分发用的
plugin.sig.json(install --file读取此格式验签),--name显式指定插件名
(kebab-case 插件必须——库名推导是下划线 crate 名)。
Changed
plugin.yaml支持enabled字段 —Option<bool>,缺省启用,向后兼容。PluginLoader支持PluginLoadPolicy— lenient(dev 默认)/ strict(prod),
新增DisabledPlugin/SignatureVerificationFailed错误变体,加载时对plugin.sig.json
重新验签。AdapterRegistry::unregister— 卸载/禁用插件时移除平台工厂。- 配置 —
GatewayConfig新增plugins:段(directory/autoLoad/
verifySignatures/allowUntrusted/trustedPublishers/registries),
easybot --init展开默认值。 - 配置字段接线 —
plugins.directory(插件目录,相对/绝对路径)、
plugins.autoLoad(启动自动加载)、plugins.verifySignatures(关闭签名校验)
现全部生效;目录由resolve_plugins_dir统一解析,生产门禁 / 加载 / CLI 一致。 - 生产模式加载策略 — 生产启动时
PluginManager使用 strict 加载策略(强制签名- 发布者信任,信任 = 配置
trustedPublishers∪ 用户.trust);plugins.allowUntrusted: true时退化为"有签名验、无签名放行"。dev 恒 lenient 不受影响。
- 发布者信任,信任 = 配置
Fixed
- 信任语义落地(对齐文档) —
plugin install --yes/ APItrust: true现与文档
一致,不再自动把发布者写入.trust(此前实现会写入)——一次性确认仅放行本次
安装;plugin update在发布者更换签名密钥(密钥轮换/泄露)时返回needs_trust,
需显式plugin trust重新信任。 - 安装下载加固(安全) —
artifact.url仅允许 https + GitHub 主机(防 SSRF /
host 混淆);artifact.library与plugin.yaml的library仅允许裸文件名
(防路径穿越,下载前拒绝);--file离线安装同步校验requires.easybot兼容范围。 - 生产启动扫描跳过禁用插件 —
enabled:false的插件不加载、无需验签,不再被
生产门禁误拒。 install --file缺省库名按宿主 triple 推导 — 此前传字面量"host"(既不含
windows也不含apple),macOS/Windows 上离线安装落位为.so扩展名错误、
加载期重验签失效;现按current_target_triple()推导。- 缺省库名按下划线 crate 名推导 — cargo cdylib 产物是下划线 crate 名
(kebab-case 包名 → 下划线,如libhello_adapter.dylib),推导(manifest.library_path
/default_library_name)与发布 CI 的library字段原先用连字符名,导致 kebab-case
插件手动安装 /--file安装后加载找不到库;三者统一为下划线约定。