Files
MailUI4Agents/deploy/lib/env-defaults.sh
JianFeeeee 7eec311756 fix(deploy): C 扩到全文件(133/0 闭合)+ ① 加 realpath 判据 + ②b 明说"恒等" + 环境自足收成一处
pi 这一封四个实质点,逐个实测后处理:

**C. 口径扩到全部文件**(他给的是算术,不是口味,我认):
原先按后缀取(`.conf/.service/.timer/.bak*`),我说的"零违规就不扩"是把口味当论证。
他把成本量化了:差集极小 ⇒ 多读几次文件(几十 KB),而收益是那个 `0` 从
**"有范围的 0"**(只对我划的圈成立)变成**"闭合的 0"**(对整棵 /etc/systemd 成立)。
他还补了一句我没想到的:这条判据只报**内容里含仓库路径**的文件,
所以含仓库串的 `.dpkg-old`/`~`/无后缀文件**恰恰都是真信号**(过期的旧真相),
不是噪声 —— 我先前"二进制会变成噪声"的担心本来就不成立。
**验收实测:比了 133 个文件(全部,不筛后缀)、命中 0。**
另按他要求把"零违规"这个前提写进注释,并说明"红/WARN 拆分"为什么推迟
(零违规时拆分是重构不是修 bug;出现第一个非白名单命中时再决定分档)。

**反例 1(②b 对 pi 是跑不到的分支)**:确认。pi 的依赖是全局包软链
(`-> /usr/lib/node_modules/@earendil-works/pi-coding-agent`),`cp -a` 保留软链
⇒ 两侧 realpath 到**同一个 inode**(实测 `statSync(a).ino === statSync(b).ino`)
⇒ 版本集合按构造相等 ⇒ **②b 对 pi 永远不会红**。这正是本文件自己列过的第三种形态
(断言在、区分力不在),比"没写判据"更坏因为它看起来是绿的。
已改:两侧 realpath 相同时**明说"恒等、区分力为零"**并指出它真正覆盖谁(有 vendored 树的宿主),
不再报"版本集合一致"这种让人误以为验过的措辞。自检加了这一条。

**反例 2(① 的 realpath 盲区)**:确认,形状真实且三条判据全都看不见 ——
①只 grep 内容(仓库那份 unit 文本里没有仓库字面量)、②比内容(live 就是 repo 那个 inode,
必然"一致")、④只查固定名单。已加 realpath 判据:被检文件 realpath 落在仓库里 ⇒ 红,
与内容无关。自检加**正反两面**(内容干净但指向仓库 ⇒ 红;指向仓库外 ⇒ 不许红,
否则这条判据恒红)。实测:本机 `/etc/systemd/system` 下 0 条指向仓库的软链
(即这个 0 现在才是闭合的)。

**反例 3(环境假设第四次 ⇒ 建议收成一处)**:采纳。四次的形态一模一样
(HOME ⇒ 又一次 HOME ⇒ TMPDIR ⇒ GOMODCACHE/GOPATH),每次"再加一个预检"只挡已知那一个。
新增 `deploy/lib/env-defaults.sh`:一处给全 HOME/TMPDIR/GOMODCACHE(GOPATH)/PATH,
只设**未设**的变量,注释里写明四次历史与"否则第五次一定会来";
三个部署脚本开头 source 它;**删掉**我上一轮加的那个分散 go 预检。
实测:在 `HOME`/`TMPDIR`/`GOPATH`/`GOMODCACHE` **全空**的环境里
`bash deploy/install.sh --check` **exit 0**(go vet + go test 自己站起来),
兜住的变量会在 `AGENTMAIL_ENV_DEFAULTS` 里说明。

docs 补两条纪律:13「锚点必须一一对应 —— 连'文件名'都会骗你」(E 的探针教训)、
14「退出码也有量纲」(--self-check 的退出码不是自检的结论)。

验证:npm test exit 0;check-shared-libs exit 0;drift --self-check **35/0**;
prune 干跑 exit 0;install.sh --check 空环境 exit 0。
2026-09-14 20:42:54 +08:00

67 lines
3.2 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
#
# 部署脚本的**环境自足**声明:一处给全,不再每条命令旁各写一个预检。
#
# # 为什么要有这个文件
#
# 2026-09-14 这条链上一共修了**四次**同一形状的错,每次形态一模一样:
# **部署路径上假设了一个环境变量存在**。四次都是"再加一个预检",
# 而预检只挡**已知的那一个** —— 挡住 `HOME` 之后 `GOMODCACHE` 才露出来
# (两者其实是同一个根因的两面:`HOME` 决定 go 默认缓存位置)。
# pi 的原话:**"否则第五次一定会来。"**
#
# 四次记录(每次都是实测,不是推测):
# 1. `HOME` 未设 ⇒ `go` 拒绝工作(`homeagent` 的 build.sh,当次修了一处)
# 2. `HOME` 未设 ⇒ 同一族再现(`install.sh`,当次又修一处)
# 3. `TMPDIR` 未设/不可写 ⇒ 构建与测试把临时文件写到意外位置
# (`redeploy-plugin.sh:160` 曾写成 `TMPDIR=${TMPDIR:-/tmp} npx tsc …`,即就地兜了一次)
# 4. `GOMODCACHE`/`GOPATH` 都未设(`HOME` 也没设)⇒
# `go: module cache not found: neither GOMODCACHE nor GOPATH is set`
#
# # 纪律
#
# · 需要环境的脚本**开头** `source` 本文件,别在命令行里内联兜底;
# · 本文件只设**未设**的变量(`:-` 语义),绝不覆盖调用者已经给的值;
# · 失败要**说清是环境问题**并按仓库约定用退出码 2(环境),不要让它冒充代码缺陷。
#
# 注意:本文件被 `source`,**不能带 `set -e`**(那会改调用者的语义)。
# 调用者自己已经有 `set -uo pipefail`(`install.sh` 另有 `-e`),这里不重复声明。
# shellcheck shell=bash
# ① HOME:`go`/`npm`/`npx` 都会用它推默认缓存与配置位置。
# 以 root 跑部署时它通常就是 /root;显式给出以免"沙箱/最小环境下 HOME 为空"。
if [ -z "${HOME:-}" ]; then
HOME=/root
export HOME
AGENTMAIL_ENV_DEFAULTS="${AGENTMAIL_ENV_DEFAULTS:-} HOME=$HOME"
fi
# ② TMPDIR:构建暂存与测试都往这里写。缺省 /tmp 可能与真实挂载不符,
# 但"空的 TMPDIR"比"指错一个已存在的目录"更糟 —— 后者会让判据看错地方。
if [ -z "${TMPDIR:-}" ]; then
TMPDIR=/tmp
export TMPDIR
AGENTMAIL_ENV_DEFAULTS="${AGENTMAIL_ENV_DEFAULTS:-} TMPDIR=$TMPDIR"
fi
# ③ GOMODCACHE / GOPATH:go 的模块缓存。**只在 go 存在时**推导,
# 且只在两者都空的时候推导(有 GOPATH 时 go 自己会算 GOMODCACHE)。
if command -v go >/dev/null 2>&1; then
if [ -z "${GOMODCACHE:-}" ] && [ -z "${GOPATH:-}" ]; then
GOPATH="$HOME/go"
export GOPATH
AGENTMAIL_ENV_DEFAULTS="${AGENTMAIL_ENV_DEFAULTS:-} GOPATH=$GOPATH"
fi
fi
# ④ PATH:只保证常见系统目录在(最小环境里 PATH 可能为空)。
case ":${PATH:-}:" in
*:/usr/bin:*) : ;;
*) PATH="${PATH:+$PATH:}/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; export PATH
AGENTMAIL_ENV_DEFAULTS="${AGENTMAIL_ENV_DEFAULTS:-} PATH=+系统目录" ;;
esac
# 给调用者一句可打印的话:本次**兜了哪几个**变量(空则说明环境本来就齐)。
export AGENTMAIL_ENV_DEFAULTS="${AGENTMAIL_ENV_DEFAULTS:-}"