Skip to content

Releases: EasyIndie/EasyBot

EasyBot v0.0.43

Choose a tag to compare

@github-actions github-actions released this 04 Oct 21:15

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

Choose a tag to compare

@github-actions github-actions released this 04 Oct 19:23

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 批量升级间接依赖;utoipa 5→6、
    utoipa-swagger-ui 9→10(OpenAPI 快照随之更新,属 schema 表达变化,无语义变更);
    serde_yaml(上游已归档弃用)改用维护 fork serde_norway 0.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
    (新 crate easybot-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 依赖、SDK ffi.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

Choose a tag to compare

@github-actions github-actions released this 01 Oct 08:50
f862866

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

Choose a tag to compare

@github-actions github-actions released this 04 Sep 16:23

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

Choose a tag to compare

@github-actions github-actions released this 04 Sep 14:56

Security

  • h2 0.4.15 → 0.4.16(RUSTSEC-2026-0258) — 修复 hyper 传递依赖 h2 的空 DATA 帧内存
    放大(连续空 DATA 帧可无界占用内存触发 OOM)。Cargo.lock 已锁定 0.4.16。

Changed

  • 依赖跨版本迁移(批量依赖升级中随主程序代码适配的两个破坏性升级):
    • ed25519-dalek 2 → 3(#97) — 密钥生成 CSPRNG 迁移到 getrandom 0.4 SysRng
      (rand_core::UnwrapErr),签名侧不再直接依赖 rand_core 0.6。
    • argon2 0.5 → 0.6(#110) — hash_password 改为单参(内部用 getrandom 生成随机盐),
      删除显式 SaltString::generate(&mut OsRng);校验路径不变(从 PHC 串读取参数,
      0.5 存量哈希仍可正常验证)。随本次迁移,rand_core 0.6 彻底移出依赖树。
  • 例行依赖与 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

Choose a tag to compare

@github-actions github-actions released this 14 Aug 16:30

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

Choose a tag to compare

@github-actions github-actions released this 14 Aug 12:17

Fixed

  • Windows-only clippy 门禁修复(2 项) — cross-check 升级为 clippy 后暴露的两个
    #[cfg(windows)] 专属 lint:
    • updater 回滚清理循环改 flatten()(clippy::manual_flatten)。
    • plugin-sign Command 枚举 SignArgs Box 化,规避 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

Choose a tag to compare

@github-actions github-actions released this 14 Aug 07:40

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.md Windows 升级表述
    与实现对齐;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

Choose a tag to compare

@github-actions github-actions released this 13 Aug 18:17

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.yaml name / 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

Choose a tag to compare

@github-actions github-actions released this 13 Aug 05:43

Added

  • 插件市场(P6) — 通过 GitHub Releases 分发第三方适配器插件,easybot plugin
    子命令 + REST API + 管理后台完整管理:

    • 安装流水线 — easybot plugin install [publisher/]name:按宿主 6-target
      triple 匹配产物 → ABI 预检(sdk_version)→ requires.easybot semver 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 testing feature 提供 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。
    • 示例 — 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 / API trust: 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 安装后加载找不到库;三者统一为下划线约定。