别让AI随便启动你的LSP:hmharness给语言服务器加SHA256门禁 GitHub:swsgbl/hmharness

0 阅读5分钟

先说工具全貌:hmharness 是一个开源的 HarmonyOS/OpenHarmony 开发智能体框架,把工程创建、检查、构建、签名、安装、启动、日志读取和结果验证接成本地工具链,让 AI 不只是生成代码,还要用本机环境证明结果;自进化行为受审批、预算、canary 和回滚约束。它不是 DevEco Studio 的替代品,而是开发智能体和鸿蒙工具链之间的验证层。本文只展开其中一环:LSP 来源信任与 SHA256 钉住。

仓库:github.com/swsgbl/hmha…

AI 编程工具要获得代码级上下文,通常绕不开 LSP。问题是,启动 LSP 不是“加载一个配置项”,而是执行一个本机二进制。它可能来自 PATH,也可能来自 DevEco 安装目录。对 agent 来说,“我能找到这个命令”和“这个命令现在可以被安全执行”是两件事,混在一起就是供应链风险。

hmharness 在公开提交 2faab3834b5424090846c0237341851f3ed38c90 中把这两步拆开了:先判断来源和用户信任,再对二进制做 SHA256 钉住;之后每次启动前重新计算哈希,变化就拒绝执行。

GitHub 仓库入口

1. PATH 找得到,不代表可以执行

最常见的情况是 hmharness 在 PATH 里发现了 rust-analyzer。PATH 的语义只是“这个命令能被找到”,它不说明:

  • 这个二进制是谁安装的;
  • 是否被升级或替换过;
  • agent 是否获得过用户授权去执行它。

因此 PATH 来源默认不信任。用户需要显式执行一次:

hmh lsp trust rust-analyzer

这次信任动作会把当前二进制路径和 SHA256 写入本地 trust store。之后不是永久放行,而是进入哈希校验路径。

来源信任分层

DevEco-local 来源的处理不同。hmharness 识别 DevEco 安装布局后,首次可以自动信任一次,因为这是用户已经安装的官方 IDE 布局;但它同样立即写入 SHA256。自动信任只发生在第一次,不等于以后文件变了也继续信任。

2. 启动前的决策流

packages/lsp/src/tools.ts 在真正 spawn LSP 前调用信任检查。核心顺序是:

发现 server:id / command / origin
-> 读取 HMH_HOME/cognitive/lsp-trust.json
-> 计算当前二进制 SHA256
-> 有记录且 actual == pinned,才进入启动
-> 无记录、来源不明或哈希变化,则拒绝执行

启动前信任决策流

这个设计的关键不是“记住一个白名单”,而是把发现、授权和完整性拆成三个独立判断。用户可以审计每一步为什么放行,也能撤销某个 server 的信任。

3. 哈希变化:默认拒执,不自动原谅

如果信任时写入的 pinned 和启动前算出的 actual 不同,hmharness 不会猜“这应该只是升级”。它默认输出:

binary CHANGED since trust
pinned  <old sha256>
actual  <new sha256>
refuse to spawn

哈希变化拒执

同时展示两个哈希,是为了把判断权交还给人:如果确认这是预期升级,可以重新执行 hmh lsp trust <id> 钉住新版本;如果不需要它,执行 hmh lsp untrust <id>;如果解释不了变化,就不要重新信任,先检查来源和安装过程。

4. Trust store 是本地明文 JSON

信任记录保存在:

HMH_HOME/cognitive/lsp-trust.json

每条记录包含 id、command、sha256、origin、trustedAt、autoTrusted。用户可以直接打开检查,也能看出某个 server 是自己显式信任的,还是 DevEco-local 官方布局自动信任的。

审计与边界

边界也要说清楚:这个机制证明“当前二进制和被信任时的哈希一致”,并阻断后续变化;它不证明二进制没有漏洞,不代替签名校验或包管理器校验,也不做云端信誉判断。trust store 本地保存,不上传遥测。

5. 公开测试怎么验证

公开测试 packages/lsp/src/__tests__/trust.test.ts 覆盖两条主路径:

  1. PATH server 初始拒绝,提示 hmh lsp trust;显式信任后钉住哈希;文件被替换后拒执并返回 pinned/actual;untrust 后回到未信任状态。
  2. DevEco-local server 首次自动信任并写哈希;后续同样做哈希校验;替换文件后同样拒绝执行。

源码口径可以复现:

git clone https://github.com/swsgbl/hmharness.git
cd hmharness
git checkout 2faab3834b5424090846c0237341851f3ed38c90
npm install
node --import tsx --test packages/lsp/src/__tests__/trust.test.ts

本地 targeted test 输出为 2 tests / 2 pass / 0 fail。但该功能提交在 GitHub Actions 的 verify 结论是 failure,所以本文不把它说成 CI 绿色提交。

6. 版本边界

截至本文发布:

  • 功能源码钉在 2faab3834b5424090846c0237341851f3ed38c90,该提交 verify=failure;
  • 当前公开 main cbc71e57d21cf059e0ba22d96e633080743d6809 的 verify 也是 failure;
  • npm latest 是 @hmharness/cli@0.23.20,其 gitHead 是 ea8348415744496ee9cf165ac8fbd310ed06e466;
  • GitHub Release 仍是 v0.18.12。

源码复现、npm latest 和 Release 是三个不同边界。安装试用时使用:

npm install -g @hmharness/cli@0.23.20

7. 结论

LSP 是 AI 编程工具接触代码语义的入口,也是执行本机二进制的入口。hmharness 这次做的不是复杂黑盒,而是一条可审计的供应链门禁:PATH 显式信任、DevEco-local 首次自动钉住、每次启动前哈希复核、变化即拒执。

对 agent 工具来说,这类默认拒绝的细节很麻烦,但比事后解释“为什么自动执行了一个被替换的二进制”更可靠。欢迎在 GitHub Discussions 反馈你的 LSP 来源、升级方式和哈希变化处理需求。

参考: