fix(相位/安全): 部署门禁只判产物自证;静默 break 改成出声;内核读数带时间坐标
pi 2026-09-14 的裁定与两条更正,逐条落地。 1. **相位裁定(选 c)**:`packaging`/`build-stamp` 属于**构建相位**,不属于安装相位。 `run-all.mjs` 现在有相位:`AGENTMAIL_CRITERIA_PHASE=install`(部署门禁用)。 每条判据登记它读的哪一侧(`ARTIFACT`/`SOURCE`),install 相位里出现 SOURCE 侧判据 → 红; 被跳过的判据**点名打印**,不静默丢。汇总打 `RESULT phase=build|install`。 规则入册 `test/CRITERIA.md` §11(含三个真实实例:check-shared-libs 恒红、 packaging 一改前端就卡死、HOME 在门禁跑完之后才炸)。 安装相位**真正能判的那一半**:`deploy/install.sh` 读**产物自证**(不重算 dist)—— `releaseCandidate !== true` → 拒绝;产物 `gitRev` ≠ HEAD → "这个包比源码旧" → 拒绝; 放行要显式 `--allow-dirty` / `--allow-stale`;`--check` 干跑只报结论不拦。 实测干跑输出:`产物:gitRev=6702cc2 树=dirty releaseCandidate=false | 当前 HEAD=6702cc2` → 报"不是发布候选 + 正式安装会被拒绝 + 要放行请显式说清"。 2. **别解析运行器文本**(pi §5):`broken`/`red` 的判定改成按 TAP 的**名字**—— 文件级失败的测试名就是路径,断言失败的名字是判据名。变异双向验证: 未定义标识符 → 「跑不起来的判据」;把某条判据条件改成假 → 「红的判据」。 不再往关键字表里加补丁(那是往文本解析里加补丁,方向是错的)。 3. **静默 break 是安全相关**(pi §3):`session_update` 找不到活动会话时不再静默 break, 改成出声日志(走 journalctl 那条通道),写清两种成因(此刻没在跑 / **接管会话**重启后无法定位)、 方向(收紧被延迟)、以及兜底的**前提**("下次投递"要求这条会话还会收到新邮件)。 `lib/mail-session-id.js` 模块头同步改成安全相关措辞("人以为自己收紧了权限、实际没有"), 四桥逐字节同源,`check-shared-libs.sh` 退出码 0。 4. 内核读数补时间坐标(pi 13ea2fdf):`BUILD_INFO.txt` 里除原始 `dep`/`=>` 行外, 现在还有 `kernelBinMtime` 与**正在运行的进程启动时间** —— 二进制会在两次读数之间被换掉, 没有时间坐标的读数不成立。
This commit is contained in:
@ -20,11 +20,15 @@ ETC=/etc/agentmail
|
||||
# 而"最后一个能跑这一步的人"(有 root 的那个人)每次都在**改完一堆东西之后**才第一次跑它,
|
||||
# 于是第一次失败就发生在最贵的时候。干跑把"门自己跑得动吗"提前暴露出来。
|
||||
CHECK_ONLY=0
|
||||
ALLOW_DIRTY=0
|
||||
ALLOW_STALE=0
|
||||
for a in "$@"; do
|
||||
case "$a" in
|
||||
--check) CHECK_ONLY=1 ;;
|
||||
--allow-dirty) ALLOW_DIRTY=1 ;;
|
||||
--allow-stale) ALLOW_STALE=1 ;;
|
||||
-h|--help) sed -n '2,20p' "$0"; exit 0 ;;
|
||||
*) echo "未知参数:$a(支持 --check)" >&2; exit 2 ;;
|
||||
*) echo "未知参数:$a(支持 --check / --allow-dirty / --allow-stale)" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@ -49,7 +53,44 @@ if [[ $CHECK_ONLY -eq 1 ]]; then
|
||||
else
|
||||
( cd "$REPO/client/electron" && npm ci --no-audit --no-fund 2>/dev/null || npm install --no-audit --no-fund )
|
||||
fi
|
||||
( cd "$REPO/client/electron" && npm run typecheck && npm test && npm run build )
|
||||
# 相位(pi 2026-09-14 裁定):部署门禁问的是"**别人已经产出的产物**能不能装到这台机器上",
|
||||
# 不是"产物是不是从当前源码新鲜构建的"。后者属于构建相位(`packaging`/`build-stamp`),
|
||||
# 挂在这里会**恒红**(部署路径不重新打包)—— 门挂错了相位。所以这里显式声明相位。
|
||||
( cd "$REPO/client/electron" && npm run typecheck && AGENTMAIL_CRITERIA_PHASE=install npm test && npm run build )
|
||||
|
||||
# ── 安装相位真正能判的那一半:**读产物自证**(不是重算 dist)──
|
||||
# 同一个不变量("这份产物是谁")在两个相位要两种判据:构建相位重新计算,安装相位读它自己说的。
|
||||
if [[ -f "$REPO/client/electron/dist/BUILD_INFO.json" ]]; then
|
||||
echo "==> 产物自证(安装相位)"
|
||||
read -r A_REV A_DIRTY A_RC < <(node -e '
|
||||
const d = require("'"$REPO"'/client/electron/dist/BUILD_INFO.json");
|
||||
console.log([d.gitRev ?? "?", d.gitDirty ? "dirty" : "clean", d.releaseCandidate === undefined ? "?" : String(d.releaseCandidate)].join(" "));
|
||||
')
|
||||
HEAD_REV="$(git -C "$REPO" rev-parse --short HEAD)"
|
||||
echo " 产物:gitRev=$A_REV 树=$A_DIRTY releaseCandidate=$A_RC | 当前 HEAD=$HEAD_REV"
|
||||
refuse=0
|
||||
if [[ "$A_RC" == "false" ]]; then
|
||||
echo " ✗ 这个包**不是发布候选**(构建时工作树是脏的)—— 它可能含着别人未提交的半成品。" >&2
|
||||
refuse=1
|
||||
fi
|
||||
if [[ "$A_REV" != "$HEAD_REV" ]]; then
|
||||
echo " ✗ 这个包比源码旧:产物 gitRev=$A_REV ≠ HEAD=$HEAD_REV。" >&2
|
||||
refuse=1
|
||||
fi
|
||||
if [[ $refuse -eq 1 ]]; then
|
||||
[[ $A_RC == "false" && $ALLOW_DIRTY -eq 1 ]] || [[ $A_REV != "$HEAD_REV" && $ALLOW_STALE -eq 1 ]] || true
|
||||
if [[ $CHECK_ONLY -eq 1 ]]; then
|
||||
echo " (干跑:正式安装会被拒绝。要放行就显式说清:--allow-dirty / --allow-stale)" >&2
|
||||
elif { [[ "$A_RC" != "false" || $ALLOW_DIRTY -eq 1 ]] && [[ "$A_REV" == "$HEAD_REV" || $ALLOW_STALE -eq 1 ]]; }; then
|
||||
echo " (你显式放行了:--allow-dirty/--allow-stale —— 风险由你承担)" >&2
|
||||
else
|
||||
echo " 拒绝安装。放行要显式:sudo $0 --allow-dirty --allow-stale" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "==> 产物自证:dist/BUILD_INFO.json 不存在(还没构建过)—— 本相位只能报"不知道",不能报"没问题"" >&2
|
||||
fi
|
||||
|
||||
echo "==> 校验插件共用模块同源"
|
||||
# lib/ 下的纯函数模块在三个插件里逐字节相同(见 docs/PLUGIN-CONTRACT.md 第六节)。
|
||||
|
||||
Reference in New Issue
Block a user