Skip to content

docs(verification): #1144 post-#1147 打包 shell 工具整链复跑(围栏 14/14 · 反向 14/14 · 负向控制 8/8) - #1150

Merged
jinjunnn merged 1 commit into
alphafrom
ac-1144b
Aug 26, 2026
Merged

jinjunnn merged 1 commit into
alphafrom
ac-1144b

Conversation

@jinjunnn

Copy link
Copy Markdown
Owner

Refs jinjunnn/alpha-code#1144

本轮关掉的是哪个缺口

关掉的是「AC1 的链条证据早于 #1147」这个缺口,不是「真模型」那一格。

上一轮 #1144 的取证跑在 c3c58308f。#1147(ac#1129)在那之后合进 alpha,而它换掉的
正是 AC1 链条上的执行咽喉那一格 —— session/tools.ts 里的
permission.ask({ permission: canonicalToolIdentity(…) }) 变成了
AlphaToolPolicyGate.gateToolExecution({ … })。于是「#1147 之后这条链是否仍到得了 bash
工具」在本轮之前是零证据。

packages/ext 在同一区间只动了一个测试文件,打包进 app 的 wrapper 逐字节未变
(extBundleSha256 与上一轮记录相同)⇒ 沙箱围栏本身的结论不受影响,本轮不重开它。

AC1 的「真模型回合」仍未闭合(缺模型凭据,owner 侧资源),本票不要按本 PR 关闭。
本轮也不跑 hardened 臂:AC2 的结论仍以上一轮为准,围栏与签名配方本区间都没动。

结论

被测 sha 8a438007b2ae8b8da76137c68053916ac306f66a(= 构建时的 origin/alpha,含 #1147/#1148);
四份结果 JSON 与负向控制自报的 gitSha 全部是这一个。

断言 结论
post-#1147,一次 agent 回合 → shell 工具 → wrapper → sandbox-exec 仍然通,越界写入不落盘 PASS 14/14(7 条 × 2 轮)
反向臂(围栏移除的打包副本)同一套语料落盘 PASS 14/14
正样本:同一条工具链上工作区内写入 PASS 两臂各 2 轮 4/4 落盘
基线 §2.5/§2.6 原驱动面(prompt !command)同轮复跑 PASS 围栏 14/14 不落盘 / 反向 14/14 落盘
这条链可以被闸关掉(负向控制) PASS 8/8
被测包里确实含 #1147 PASS(产物出处,五个标记)
AC1 字面的「真模型」 仍未闭合

四轮各 21 pass / 0 fail / 2 跳过,合计 84 pass / 0 fail。56 个 escape 格全部
processStarted=true(工具自己的 state.output 里看得见 AC1144-STARTED —— 空输出不算拦住);
28 次工具调用 tool=bash / completed / commandIntact=true / 按 callID 认领本回合那一格。

构建:上一轮在这里翻过车,本轮的证据

bun run build 的 prebuild 要取 https://models.dev/api.json,本机代理完不成它的 TLS ⇒
build 退出 1、electron-vite 一次没跑,而 package:mac 照跑、打包上一份 out/。本轮:

OPENCODE_CHANNEL=prod MODELS_DEV_API_JSON=<abs>/packages/opencode/test/tool/fixtures/models-api.json \
  bun run --cwd packages/ui-mac build > build.log 2>&1     → EXIT=0
grep -c "built in" build.log                               → 3      ← 真构建的指纹(失败那轮是 0)
                                                             ✓ built in 13.69s
package:mac                                                → EXIT=0

打包跑完 git status --porcelain = 0 行、git ls-files packages/ui-mac/resources/icons = 0
⇒ #1076 §8 第 2 条(打包弄脏 43 个图标)确实已随 ac#1115 消失,本轮自己核的。

负向控制:这条链是可以被关掉的

只加一个产品自带的配置键,一位变化:

臂 OPENCODE_PERMISSION 引擎下发的 tools 结果
allow(控制组) {"bash":"allow","external_directory":"allow"} 16 个,含 bash 工具 completed,工作区文件落盘,逃逸被围栏拦住
deny 同上 + "builtin::bash":"deny" 15 个,不含 bash 什么都没跑,什么都没落盘

它证明这套测量能测出「链被关掉」的状态 ⇒ 四轮里的「链是通的」是真实测量而不是空转。
README §4 同时写清了它不能证明的事:bash 从目录里消失在 c3c58308f 上同样会发生
(Permission.disabled 的 identity 分支早于 #1147),所以它区分不了新旧闸 ——
那个问题由产物出处回答,不由行为回答。

产物出处:包里真的是 #1147

挑在 c3c58308f 的 packages/{opencode,schema,core}/src 零命中、在 8a438007b 命中的字符串,
再看它在 app.asar 里在不在:alpha-app-builtin / plugin-file / plugin-hook /
gateToolExecution / permission-ruleset —— 五个全部命中。app.asar 有 2,689,313 个字面
NUL 字节,全程 grep -a,并附手段自证的正/负样本(AlphaToolPolicy 9 行;两个 XYZZY 假串 0 行)。

本地门

本 PR 只改 docs/(git diff --name-only origin/alpha...HEAD | grep -v '^docs/' = 0)。

门 怎么跑的 结果
north-star git diff --name-only origin/alpha...HEAD -- $UPSTREAM_PATHS 0 行
docs 链接闸 python3 scripts/check-doc-links.py docs/README.md docs/verification/…/README.md 43 links / 2 files,exit 0
链接闸的手段自证 同一份 README 末尾追加一条坏链后重跑 exit 1,精确指出那一条 ✅(第一次跑我把两个路径塞进一个 zsh 变量,它报「0 links / 1 file」而 exit 0 —— 正是 alpha-work/CLAUDE.md 记的那个假绿,已改成显式实参)
文档契约 check_docs_contract.py --profile alpha --strict alpha-code PASS(报的 2 个 error 全在 alpha-web/docs/privacy/,与本 PR 无关的存量)
typecheck / unit 不适用 —— 零个源文件改动 —

--no-verify 推的:pre-push 钩子 exec 的是 scripts/alpha-check.sh,它的 [8/9] 步会真建探针
worktree 并写全 worktree 共享的 core.hooksPath(还会每跑一次泄漏一棵装好的探针树,ac#928)。
本机此刻有别的 lane 在跑,派发书也明确要求本 lane 不跑它。上面那张表是替代它的实跑证据。

生产代码

一个字节都没改。 取证 runner 沿用上一轮那一份
(docs/verification/2026-08-26-req138-1144-packaged-shell-tool-chain/run.ts),只修了它 finally
里 spawnSync("git", …).stdout.trim() 在 cwd 消失时抛错、导致整轮结果 JSON 一个字都写不出来
的缺陷(改成 ?.trim() ?? "")。该值只进结果对象的 gitSha 字段,不参与任何 probe 的 ok。

文档影响

docs/verification/2026-08-26-req138-1144-postmerge-chain/(新)+ docs/README.md 索引一行。
不覆盖上一轮那份 —— c3c58308f 的证据仍然有效,只是不覆盖 #1147 之后的链条可达性。

🤖 Generated with Claude Code

https://claude.ai/code/session_01QHDS2BFKuzm9uNH1svU2oj

…/14 · 负向控制 8/8)

上一轮 #1144 的取证跑在 c3c5830;#1147(ac#1129)在那之后合进 alpha,换掉了
session/tools.ts 里执行咽喉那一格(permission.ask → AlphaToolPolicyGate.gateToolExecution),
于是「这条链是否仍到得了 bash 工具」变成零证据。本轮只补这一格。

被测 sha 8a43800(= 构建时的 origin/alpha,含 #1147/#1148),四份结果 JSON 自报一致。
构建走仓内离线快照(MODELS_DEV_API_JSON,退出码单独取、built in 行数核为 3),
避开上一轮那次「build 退出 1 而 package:mac 照跑上一份 out/」的假成功。

- 围栏臂 ×2 轮:shell 工具 14/14 不落盘、prompt !command 14/14 不落盘,正样本落盘;
- 反向臂 ×2 轮(只改打包副本里 wrapper 那一行,ext sha 9cc40e89… 与前两轮逐字相同):
  两个驱动面各 14/14 落盘;
- 四轮各 21 pass / 0 fail;56 个 escape 格全部 processStarted=true,
  28 次工具调用 tool=bash / completed / commandIntact / 按 callID 认领;
- 负向控制 8/8:只加一个配置键 builtin::bash=deny,引擎下发的工具从 16 个降到 15 个
  (少的正是 bash)、什么都没落盘;allow 臂在同一脚本同一产物上跑通 —— 证明「链是通的」
  是真实测量而非空转。README §4 同时写清它**不能**区分新旧闸,那由产物出处回答;
- 产物出处:五个在 c3c5830 零命中、在 8a43800 命中的标记全部出现在 app.asar 里
  (grep -a;该文件有 2,689,313 个字面 NUL),并附手段自证的正/负样本。

未闭合项不变:AC1 字面的「真模型回合」仍缺模型凭据;本轮不跑 hardened 臂(AC2 结论仍以
上一轮为准,围栏与签名配方本区间未动)。

未改任何生产代码。取证 runner 沿用上一轮那一份,只修了它的 finally 里
spawnSync("git",…).stdout.trim() 在 cwd 消失时抛错、导致整轮结果写不出来的缺陷
(改成 ?.trim() ?? "";该值只进结果对象的 gitSha 字段,不参与任何 probe 判定)。

Refs #1144

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QHDS2BFKuzm9uNH1svU2oj
@jinjunnn
jinjunnn merged commit 6d7b5b6 into alpha Aug 26, 2026
5 of 6 checks passed
@jinjunnn
jinjunnn deleted the ac-1144b branch August 26, 2026 18:08
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.

1 participant