习慈羊xiciyang
联系
订阅
正在读取订阅状态…

把发布做成产线:四条包、七条 PR、零合并,和一条被漏看两小时的安全审查

晚上 11 点,我在翻 7 条没人理的 PR。4 条包里有 1 条被人指出了路径穿越:构造一个查询参数,就能读宿主机上任意可读文件。这条评论挂了 2 小时,监测器没发一封邮件。它只查 PR 状态,不查评论。

说到底,发布是一条五段流水线,这条线里的产出是判据。几道闸门决定监测哪几维,观测之外的部分会安静地变瞎。

一、主线框架:五段流水,前三段能写成命令

我把这件事拆成五段:判定这个包该不该发、修复能机械修的部分、打包公开、投递到收录列表、观测结果。前三段可以写成命令,第四段可以写成脚本,第五段决定这条产线会不会骗我。

下面按这五段写,把两次失败放进它们各自发生的段落。一次是脚本推错了仓库,一次是监测器看错了地方。

发布五段流水与两道闸门:判定段分 fail 与 warn,观测段分状态、评论、合并

二、判定:把「合格」写成能跑的判据

检查器最早是我给自己列的一张清单,一天之后变成了命令。判据十几条,分两档。

fail 意味着用户装不上、用不了、找不到:插件没有声明 dsh.bundle.patch,包能装但不会激活任何一层[1];仓库是私有的,收录列表抓不到[3];依赖里写着本地路径,别人 clone 下来装不起来。

warn 意味着能用但会被忽略:README 缺兼容性一节、关键词缺生态约定的那个词、打包时带上了构建日志。

这个分档不是洁癖。有一类返工很典型:README 改得很漂亮,插件却从来没被激活过。修的是 warn,坏的是 fail。

拿它扫自己全部三十多个包,几乎全被拦,病根高度集中:许可证、私有标记、绝对路径、缺兼容声明。发布能力缺的不是眼光,是出厂规格;看清这一点之后,剩下的全是机械活。

三、修复:四件事自动做,三件事必须留给人

修复器只做四件事:补许可证字段、写许可证正文、摘私有标记、补关键词。它明确不碰三样:兼容版本范围、绝对路径、仓库地址。

兼容范围要声明「在哪个版本上真跑过测试」,没跑过就写,等于伪造证据。绝对路径可能指向真实配置,机械替换会把功能改坏。仓库地址得先确认远端存在。

打包阶段同样克制:工具默认保留私有标记,除非显式要求摘掉。摘标记等于宣布发布意图,这件事不该由脚本批量完成。

四、投递:一条命令第一次跑就翻了车

产线最后收敛成一条命令:检查、跑测试、提交、建仓、公开、推送、打 tag、往两个列表开 PR、把新 PR 登记进监测列表。两个列表的收录要求都以公开仓库与源码级证据为前提[3][4]。四条包后来都走这条命令,一共开了七条 PR。

它第一次真跑就失败,报错说 head sha 为空。原因是脚本 clone 的是上游列表仓库,却把分支推到了 origin,也就是上游;分支根本没落到自己的 fork 上。

这个 bug 值得单独记:dry-run 永远发现不了它。dry-run 打印的是计划,计划里没有推送的真实结果。一条命令的价值,建立在它真的被执行过至少一次之上。

五、小结:闸门只证明了「能不能装」

七条 PR 全部 open、零合并。这说明产线证明了「能不能装」,没有证明「会不会被用」。后者要等别人点头,本地无法自动化。

漏看评论之后,我把监测器改成同时看三样:状态、评论、合并。只在变化时发信,新评论带作者和摘要,合并时往状态文件里追加日期和链接。

所以,发布产线的产物是判据,链接只是副产品。七条零合并的 PR 也证明了一件事:闸门只能证明「能装」,证明「有人愿意用」需要别人的动作。

更一般的结论在这里:自动化的代价是观测面之外全部变瞎。只查状态,就放弃评论这一维;只查合并,就放弃「有人在质疑」这一维。定时器很便宜,观测面的选择很贵。

六、闸门在三处失效:渠道、分数与评审

同一天还撞了三堵墙,它们分别说明闸门管不到哪里。

渠道:包在自己人这里满分,推到 npm 时撞上 2026 年的新政策。基于时间的一次性密码已经下线,发布要求硬件安全密钥或者带特殊权限的令牌,而那类令牌又要求账号本身已绑定设备凭证[2]。我没有硬件密钥,这条路当天断掉。检查器给不出提示,它检查包,不检查渠道。

分数:一个包拿到 96 分、状态 ready,里面还压着一条 warn——打包时带了一个构建日志。分数是排序工具,不适合当批准工具。

评审:维护者报告的那条路径穿越是真的。插件把调用方传进来的查询参数当文件路径读,构造一个参数就能读宿主机上任意可读文件。修复是把参数限定为记录自己登记过的变体,再做一次路径归一化确认落在存储目录内;Web 接口另外加一道连接信任检查。回归测试从 11 项涨到 17 项,专门留了一条穿越用例。

七、重来一次会先做的五件事,和一条没变的判断

  1. 先写检查器,再写第一个包。判据在前,产物在后。
  2. fail 和 warn 分开,只让 fail 拦住发布。混档等于没有闸门。
  3. 修复器默认 dry-run,且不碰需要判断的三样。宁可少修,不可修错。
  4. 一条命令必须真跑过一次才算存在。dry-run 通过不算。
  5. 监测第一天就把状态、评论、合并三条都接上。少接一条,就会在某天被两小时的延迟打脸。

那七个链接现在的期待值很低:零合并是常态,第一条合并才会告诉我词条写法和安装方式有没有被接受。在那之前,产线已经回本。它让我在一天里发现四个包的同一批出厂缺陷,回到开头那条被漏看的评论,答案也在这里:闸门只能证明能装,所以观测面必须单独设计,而观测面之外的部分,会安静地变瞎。

产品化里最不性感的一层大概就是这样:把东西做出来只是开始,把「合格」写成别人能复现的门,才算交付。

补记(2026-10-19)

写这篇时七条 PR 零合并。第二天凌晨,第一个收录到了:walkinglabs/awesome-deepseek-harness-plugins 合了 inference-serving 那条,词条现在就在列表里。

同一时间也来了另一条消息:inference-quantization 的分支和主干的 README 冲突,维护者要求 rebase 后重提。这台机器的 git 走代理时 TLS 握手失败,最后是用 GitHub API 从当前 main 重建分支、开了新 PR、关掉旧的——产线能替你发出去,但冲突处理仍然得有人判断。

所以这两件事最好一起看:一条被收录,一条被打回重做。这才是发布本来的样子。

文中提到的四个包

  • dsh-visual-memory:DSH 的无损视觉记忆,原图按内容寻址、可跨轮检索与精确读像素。
  • dsh-publish-guard:上面那套判定与修复的命令行实现,npx dsh-publish-guard <dir>。
  • inference-serving:把 checkpoint 部署成可访问端点,失败自动降级、全程哈希链审计。
  • inference-quantization:量化并在固定评测集上证明精度仍达标,不达标给明确结论。

参考文献

[1] DeepSeek Harness 官方文档,Packaging and installing a plugin(dsh.bundle.patch 与 engines.dsh 的强制校验)— https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/publish.md [2] npm 关于 granular access token 绕过 2FA 的收紧说明(2026-07 变更,直接发布自 2027-01 起移除)— https://github.blog/changelog/2026-07-08-npm-install-time-security-and-gat-bypass2fa-deprecation/ [3] walkinglabs/awesome-deepseek-harness-plugins 收录政策(源码级证据、静态安全初筛)— https://github.com/walkinglabs/awesome-deepseek-harness-plugins/blob/main/docs/INCLUSION_POLICY.md [4] 0xsline/awesome-deepseek-harness 贡献指南(仓库 + 一句据实描述,双语 README 同 PR)— https://github.com/0xsline/awesome-deepseek-harness/blob/main/contributing.md

评论

填个昵称就能发,不需要注册或登录