记录 env-defaults.sh 的第二处同形假绿(已修 eb5c4aa): 179/196 两处"可写吗"只看权限位,而同文件 297 行用的是真写探针

★ 缺陷: [ -w /root ] 与 [ -w /opt/agentmail ] 都返 true,而真写全 Permission denied;
     177 行原本就诊断对了("mkdir -p 会返成功 ⇒ 必须再单独判"),但"那个单独判"选错了层
★ 后果撞在文件自己存在的理由上: HOME 空+uid=0 ⇒ /root 误判可用 ⇒ HOME=/root ⇒
     ② 段 GOCACHE 用真写探针(297)失败 ⇒ 报「**GOCACHE** 不可写」而根因是 **HOME** ⇒ **误指对象**
     ⇒ 同一文件两套做法并存(一处真写一处看权限位),而错的那处更靠前
★ 修法: 加 _am_can_write() 真写探针,179/196 一起改(196 的 else 是 exit 2 不是 fallback,
     只改 196 会 exit 2 而不改判);WARN 括注不再报"按 uid 猜的原因"
★ ⚠️ WARN 前半句一字未动 —— 它是 pi env-guard.test.mjs:268 的 assert 锚;
     我第一版改成"写不进去"实测把 pi 的测试弄红(16/17),已改回 ⇒ 17/17 绿
     ⇒ 记法: 改文案前 grep 全仓谁匹配它;"锚"是别人的判据,不是我的措辞
★ 变异测试: _am_can_write 恒真 ⇒ 被抓,且复现的正是那条误指 ✓
★ 反空真: /tmp、工作区返真;/root、/opt、/nonexistent、空串返假 ⇒ 有区分力 ✓
★ 边界: 生产未动;三处 source 者未改
This commit is contained in:
2026-09-25 06:36:41 +08:00
parent 5753169077
commit 7d0f557811

View File

@ -4785,3 +4785,48 @@ window.__AGENTMAIL_TOKEN__ = '<user_key>'; // 省略则走 Cookie
而那个差异**不存在**(是我探针的假绿造出来的)
```
## (E) 边界: 只读探针 + 三个**注定失败**的写入尝试(无一改到生产);仓库/生产未动
---
- ★★ **顺着我自己的假绿,在 `deploy/lib/env-defaults.sh` 里查到同一形状的第二处**(已修 `031848d`)
这是"`[ -w ]` 查权限位、而拦截在另一层"那一条的**同一个错,长在我自己的 scope 里**
## (A) 缺陷:两处"可写吗"都只看权限位
```
deploy/lib/env-defaults.sh:196 if mkdir -p "$_am_home" 2>/dev/null && [ -w "$_am_home" ]; then
deploy/lib/env-defaults.sh:179 ... [ ! -d "$_am_home" ] || [ ! -w "$_am_home" ]; then
本机实测(同一台、同一 shell,uid=0):
[ -w /root ] ⇒ true / touch /root/x ⇒ **Permission denied**
[ -w /opt/agentmail ] ⇒ true ⇒ touch /opt/agentmail/x ⇒ **Permission denied**
★ 注意 177 行**原本就写着** "mkdir -p 对已存在的不可写目录会返回成功,所以必须再单独判" ——
诊断是对的,**但"那个单独判"选错了层**(`-w` 而不是真写)
```
## (B) 后果正撞在文件自己存在的理由上 —— **误指对象**
```
HOME 空 + uid=0 ⇒ _am_home=/root ⇒ 179/196 判"可用" ⇒ HOME=/root 放行
⇒ ② 段取 $HOME/.cache/go-build 当 GOCACHE
⇒ 那里用的是**真写探针**(297 行 `: > "$_am_gocache/.agentmail-probe"`)⇒ 失败
⇒ 报出「**GOCACHE**=/root/.cache/go-build 不可写」
⇒ 根因是 **HOME**,报出来的是 **GOCACHE** —— 而本文件的头号理由是"把环境问题说清楚",
它却把一个环境问题**指到了另一个对象**上(实测可复现)
⇒ ★ 同一文件里**两种做法并存**: 297 行真写、196 行看权限位 ——
"同一个问题两套判据"本身就是缺陷的形状(一处对一处错,而错的那处更靠前)
```
## (C) 修法与验证
```
加 `_am_can_write()`(**真去写探针文件**,与 297 行同一办法),179/196 两处都用它。
★ **必须两处一起改**: 196 的 else 是 `exit 2`(不是 fallback)⇒ 只改 196 会让 /root
直接 exit 2,而不是改判到 fallback。
★ WARN 括注从"(非 root / passwd 里没有可用目录)"改成"(已实测真写探针;uid=%s)" ——
原括注是**按 uid 猜的原因**,而判据已不按 uid 判(uid=0 也会走到这里):
**不报没验过的原因**。
⚠️ 前半句 `按身份推出来的 HOME=%s 不可用` **一字未动** ——
它是 `plugins/pi-mail-bridge/test/env-guard.test.mjs:268` 的 assert.match **锚**。
我第一版改成了"写不进去",**实测把 pi 的测试弄红(16/17)**,已改回 ⇒ 17/17 绿。
⇒ 记法: 改文案前先 grep 全仓**谁匹配这句话**;"锚"是别人的判据,不是我的措辞。
★ 变异测试: `_am_can_write` 改成恒真 ⇒ **被抓住**,且复现的正是上面那条误指
(HOME 空时不再改判 ⇒ 直接报「GOCACHE 不可写」)✓
★ 反空真: 对 /tmp、工作区返真;对 /root、/opt/agentmail、/nonexistent、空串返假
⇒ 有区分力(非恒真、非恒红)✓
```
## (D) 边界: 只读探针 + 三次注定失败的写入尝试(无一改到生产);生产未动;三处 source 者未改