Skip to content

fix: 补齐六处"文档承诺了但代码里没有"的缺口 - #1

Open
arena-ai-coding-agent[bot] wants to merge 2 commits into
mainfrom
arena/01a0347f-agentpod
Open

fix: 补齐六处"文档承诺了但代码里没有"的缺口#1
arena-ai-coding-agent[bot] wants to merge 2 commits into
mainfrom
arena/01a0347f-agentpod

Conversation

@arena-ai-coding-agent

Copy link
Copy Markdown

这个 PR 做什么

修掉六处**"文档或配置已经承诺了,而实现是空的"**的缺口,外加过程中发现的三个同类问题。

它们的共同点是失效时一声不响:在本地什么都不报错,Markdown 照常把断链渲染成蓝色,
配置照常被解析 —— 只有照着文档去用的人才会撞上,而那个人通常是第一次来的读者。

缺口清单的完整版(含 P1/P2/P3 的建议与优先级)在 docs/FEATURE-REVIEW.md


六条

1. LICENSE 不存在

两份 README 的结尾都写着 [MIT](LICENSE)package.json 也没有 license 字段。
一个对外开源、README 里还写了 Contributing 流程的项目,仓库里没有许可证文本,
法律上等于"保留所有权利":任何人都不能合法使用它。这不是排版问题。

→ 补 LICENSE(MIT)+ package.jsonlicense 字段。

2. docs/MIGRATION.md 不存在,却被引用三次

其中一处是 ARCHITECTURE.md 的"见 MIGRATION.md 的进度表" ——
把"这个项目还没做什么"这个问题整个外包给了一个不存在的文件。

→ 诚实清单内联进 ARCHITECTURE.md,改成表格(缺什么 / 现状 / 影响),
不再指望一个外部文件。

3. web_search 是一条完整的死配置

config.js 解析 WEB_SEARCH_HOST / WEB_SEARCH_TENANT_CODE
run-service.js 一路传进工具上下文,然后没有任何东西读它 ——
全仓库没有名为 web_search 的工具。.env.example 还专门写了一节。

部署方照着 .env.example 配好搜索网关、重启,什么都不会发生,也没有一行日志说不对。
比"没这个功能"更难查。

→ 整条删除,并在 src/tools/index.js 写明为什么不留
以及将来要补时的正确顺序:先写工具再加配置,用现成的能力闸门
requires: ['webSearch'],后端没配就不注册,模型压根不知道有这回事)。

4. 架构文档的"诚实清单"已经不诚实了

它说当前骨架没有断线续接 —— 但那个功能做完了
src/agent/run-registry.js 缓冲事件、runService.attach()
HTTP 面 /v1/runs/:runId/events/healthzrunResume 能力位、
以及 test/run-resume.test.js 专门测的序号/重放/丢帧/归属校验。

顺带:/v1/runs/v1/runs/:runId/events 两条接口在两份 README 里都没有 ——
做完了的功能对外不可见。

→ 纠正清单;两份 README 补上接口表和「断线接回」一节,
写清三个设计决定:为什么是 GET 而不是重发 POST(一次抖动 = 又跑一轮又烧一份 token)、
为什么归属校验必须在写下任何字节之前(200 写出去就收不回来了)、
为什么丢帧要发 resync 而不是装作接上了(缺了几句又看不出缺过的回答更糟)。

5. CI 从未跑过 MySQL 存储契约

README 明确写着 "CI should do that, since it is what catches the double drifting",
而 workflow 里没有 mysql service

生产只有 MySQL 一种后端,测试却全跑在内存替身上。替身最大的风险不是"它错了",
而是**"它自己对了,但跟真的不一样"test/storage-drivers.test.js 早就把每条断言
跑两遍来挡这个,但真库那一遍在没有 AP_TEST_MYSQL_URL
整块跳过** ——
也就是说,唯一能发现替身漂移的那道闸,一次都没关过

⚠️ 这一条的改动没能进这个 PR。 推送被 GitHub 拒绝:
refusing to allow a GitHub App to create or update workflow .github/workflows/ci.yml without workflows permission

改动放在 docs/patches/ci-mysql-service.patch
需要有权限的人手工应用一次:

git apply docs/patches/ci-mysql-service.patch

补丁已验证:git apply --check 干净、产物与本地验过的版本逐字节一致、YAML 可解析。
内容是给 test job 挂 mysql:8.0(版本与 compose 对齐)+ 健康检查 + 设
AP_TEST_MYSQL_URL + 一步显式确认 mysql2 装上了(它是 optionalDependency,
免得"真库那一遍其实又被静默跳过"再次悄悄发生)。

两份 README 已经改成"CI 就是这么跑的" —— 补丁一天不应用,
那句话就一天是新的一处不准确描述,和它当初修掉的毛病同一个性质。
docs/patches/README.md 里也写了这一点。

6. 依赖安全告警一直红着,没有结论

→ 逐条判可达性,结论写进 docs/SECURITY-NOTES.md
(含复核方法和"什么时候必须回来重看")。

实际是 4 条 advisory(2 high + 2 low),全部来自 @mariozechner/pi-coding-agent

告警 结论 依据
GHSA-jfgx-wxx8-mp94 (high) 扩展安装路径可提权 不可达 本服务从不安装 pi 扩展
GHSA-jmr9-qjv8-65gv (high) extract-zip 软链接穿越 不可达 只被 pi 内置 find/grep 下载 fd/rg 时用到,而内置工具全关
GHSA-r95r-rj6r-c39x (low) auth.json 竞态 不可达 凭据只走 AuthStorage.inMemory(),从不落盘
GHSA-7v5m-pr3q-6453 (low) HTML 导出 XSS 不可达 不用 pi 的 HTML 会话导出

⚠️ npm audit fix --force 不仅是破坏性降级(pi → 0.49.3),而且修不了 ——
影响范围 <=0.73.1,而 0.73.1 就是当前最新版,上游尚无修复版本。
正确动作是盯上游,不是动版本号。

写这份文件而不是让它继续红着的理由:一个 npm audit 长期红着的项目,最后一定没人看它 ——
于是真出现一条该管的告警时,它和这几条一起被划过去。要么修掉,要么写清楚为什么不修,没有第三种状态。


过程中发现的三个同类问题(一并修了)

第 1 条那个断链是人眼看出来的。既然要修,就顺手写了一条测试去扫全仓库所有
markdown 的相对链接
—— 结果它当场又抓出两条我没看见的

  • managed-skills/README.md../skill-libs/README.md(不存在)
    → 补上,写清 skill-libs/managed-skills/ 的分工:
    一个进 worker 镜像、一个进 agent 镜像,
    搞混的表现是"模型说有这个技能、进去却找不到脚本",而且不报错。
  • sandbox-manager/README.mddocs/PROTOCOL.md(不存在,被引用 3 次
    → 那份协议文档没有随仓库开源。三处引用改指真实存在的
    sandbox-worker/PROTOCOL.md 与代码;并删掉一整块描述不存在目录的目录树
    workers/modules/docs/ —— 照着找的人会以为自己 clone 少了东西),
    换成实际的 src/ 结构。

第三条是修第 6 条时撞见的,比断链严重

  • docs/ISOLATION-CONTRACT.md 不存在,却被 4 处引用 ——
    包括 scripts/check-isolation-rules.js 在检查失败时打印的
    "详见 docs/ISOLATION-CONTRACT.md"(人看到报错时的第一指引),
    以及 run-turn.js 开头的"改这个文件前先读"。
    它是这个项目全部安全前提的落点
    → 按代码实况补齐:九条规则逐条写明 要求 / 为什么 / 在哪 / 谁守着
    并诚实标注边界之外的东西(内核逃逸、额度不是安全边界、agent 侧出站白名单是空的)。

由此补上的一个真缺口

写第 9 条时发现:noTools: 'builtin'(pi 内置工具的总闸,也是上面两条 high
"不可达"的前提)此前只由代码注释守着 —— 旁边写着"不要改",
而它在 diff 里只有一个单词,改掉之后功能照常工作、没有任何征兆,
只是命令不再跑在 sandbox 里了。现有的 R2 规则拦的是
createBashTool( / createCodingTools(覆盖不到这种写法

→ 新增静态规则 R2-AgentSession 必须保持 noTools: builtin
单独验证过它确实能抓到故意写坏的值(临时把一处改成 'all',规则报红,改回后零命中)。

规则第一版写成 :\s*(?!['"]builtin['"]),因为 \s*回溯到"一个空格都不吃"
的位置让否定环视成立,把两处写对的地方全判红了。已改成 :(?!\s*['"]builtin['"])
并在注释里记下这个坑 —— 7 个用例正反都验过。


验证

npm run check    ✅ 1347 项全过(基线 1325,+22)
                 ✅ lint 干净
                 ✅ 隔离检查 9 条规则零命中
npm run build --prefix web   ✅ 通过
  • 新规则做了双向验证:正确写法不误报 + 故意写坏必被抓到(改动已还原,git diff 确认逐字节一致)。
  • CI 补丁做了三重验证git apply --check 干净、产物与验过的版本逐字节一致、YAML 可解析。
  • 所有改动文件确认为干净 UTF-8(零替换字符)。

审阅建议

按这个顺序看最快:

  1. docs/FEATURE-REVIEW.md —— 完整盘点,P0 那节标了每条的结论
  2. docs/ISOLATION-CONTRACT.md —— 新增,是否与你心里的契约一致(这份最需要你确认
  3. docs/SECURITY-NOTES.md —— 四条可达性判断是否认可
  4. 代码改动很小:src/ 三个文件共 -7 行 +9 行(删死配置 + 一段注释),
    scripts/check-isolation-rules.js 加一条规则

需要你决定的两件事

  1. LICENSE 的版权署名目前写的是 2026 AgentPod contributors —— 要换成具体个人或公司请直接改。
  2. CI 补丁需要手工应用(见第 5 条),否则 README 里那句"CI 就是这么跑的"是不准确的。

Arena Agent and others added 2 commits August 24, 2026 16:16
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
这一批的共同点:文档或配置已经承诺了某件事,而实现是空的。
它们的失效方式都很安静——在本地什么都不报错,只有照着文档去用的人才会撞上。

1. LICENSE 不存在
   两份 README 结尾都写着 [MIT](LICENSE),package.json 也没有 license 字段。
   一个写了 Contributing 流程的开源项目,仓库里没有许可证文本,
   法律上等于"保留所有权利"。补 LICENSE + license 字段。

2. docs/MIGRATION.md 不存在,却被引用三次
   其中一处是 ARCHITECTURE.md 的"见 MIGRATION.md 的进度表"——
   把"这个项目还没做什么"整个外包给了一个不存在的文件。
   改成把诚实清单内联进 ARCHITECTURE.md(表格:缺什么/现状/影响)。

3. web_search 是一条完整的死配置
   config.js 解析 WEB_SEARCH_HOST/TENANT_CODE、run-service 一路传进工具上下文,
   然后没有任何东西读它;.env.example 还专门写了一节。部署方配好搜索网关重启,
   什么都不会发生,也没有一行日志说不对。整条删除,并在 src/tools/index.js
   写明为什么不留、以及将来要补时的正确顺序(先写工具再加配置)。

4. 架构文档的"诚实清单"已经不诚实
   它说没有"断线续接",但那个功能做完了(run-registry 缓冲 +
   /v1/runs/:runId/events + /healthz 的 runResume 宣告 + 专门的测试)。
   同时两份 README 都缺 /v1/runs 与 /v1/runs/:runId/events 两条接口——
   做完了的功能对外不可见。补上接口表与"断线接回"一节。

5. CI 从未跑过 MySQL 存储契约
   README 写着"CI should do that, since it is what catches the double drifting",
   而 workflow 里没有 mysql service。唯一能发现内存替身与真库漂移的闸,
   一次都没关过。
   ⚠️ 改动放在 docs/patches/ci-mysql-service.patch,需要有权限的人手工应用——
   GitHub App 没有 workflows 权限,带着 .github/workflows/ 的改动推分支会被
   服务端拒绝。补丁已验证:apply 干净、产物与本地验过的版本逐字节一致、YAML 可解析。

6. 依赖安全告警一直红着,没有结论
   实为 4 条 advisory(2 high + 2 low),全部来自 pi。逐条判可达性后结论是
   四条都不可达,依据写进 docs/SECURITY-NOTES.md(含复核方法与回看条件)。
   注:npm audit fix --force 会把 pi 降到 0.49.3,且修不了——
   影响范围 <=0.73.1 而 0.73.1 就是最新版,上游尚无修复版本。

顺带修掉过程中发现的三个同类问题:

- 新增 test/docs-links.test.js(扫全仓库 markdown 的相对链接),当场又抓出两条:
  managed-skills → ../skill-libs/README.md 不存在(补上,写清与 managed-skills
  的分工:一个进 worker 镜像一个进 agent 镜像);sandbox-manager → docs/PROTOCOL.md
  不存在且被引用 3 次(那份文档未随仓库开源,改指真实存在的
  sandbox-worker/PROTOCOL.md 与代码,并删掉一整块描述不存在目录的目录树)。

- docs/ISOLATION-CONTRACT.md 不存在,却被 4 处引用,其中一处是隔离检查失败时
  打印给人的第一指引。这比断链严重——它是整个项目安全前提的落点。
  按代码实况补齐:九条规则逐条写明 要求/为什么/在哪/谁守着,
  并标注边界之外的东西(内核逃逸、额度不是安全边界、agent 侧出站白名单为空)。

- 补静态规则 R2-AgentSession 必须保持 noTools: builtin。
  在此之前这个总闸只由代码注释守着,而它在 diff 里只有一个单词,改掉之后
  功能照常、命令却不再跑在沙盒里。它同时是上面两条 high 告警"不可达"的前提。
  (规则第一版的否定环视因 \s* 回溯把两处写对的地方全判红了,已在注释里记下。)

验证:npm run check 全绿(1347 项,较之前 +22),web 构建通过,
隔离检查 9 条规则零命中,并单独验证了新规则确实能抓到故意写坏的 noTools。

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants