修复: 第五个落点 —— 判据写对了,却**没有任何人执行它**(check-file-modes.sh 空转)
pi `4fc16f66` 报的是 rc=2 那半个缝(M18)—— 我复核后**已经在 `e99a657` 修好了**,
而它的**父提交正是 pi 报信时读的 `6ee9902`**。又是同一形状的竞态。
但照 pi §四 那句「**每条分支的前提本身也要能被构造**」做审计时,
我发现**第五个落点,而且这一格的判据本身写得完全正确**:
`deploy/check-file-modes.sh` = 源文件权限政策的**唯一**判据。
它甚至专门修过自己那份 `[ -x ]` 恒真的 root 陷阱(`b7dc9e9`),改成直接读权限位 —— 修得对。
**但它从来没有被任何东西执行过。** 全仓 `grep -rn "check-file-modes"` 只有:
· `check-deploy-drift.mjs` 3 处**注释**(谈分工)
· `run-all.mjs:951` **注释**(讲 root 陷阱)
· `summary.py:77` **注释**,且**说法与实现不符**
· `summary.py:431` 一句 `print(...)` 的**文案**
⇒ 唯一一处非注释提及是一句 print 的文案。没有 install.sh / redeploy-* / hook / CI / cron 调它。
**而它当时正红着**:2 个文件是 600 + `jobs/` 缺属主 x 位。
★ 为什么这一类**只能靠判据守**(实测):
`git status` 看不见、`git diff` 看不见、`git ls-files -s` **只记 100644/100755**
(组/其他读位**不进版本库**)⇒ 把受跟踪文件 `chmod 600 ↔ 644` 两次 `git status` 都空。
套件也看不见(`jobs/` 缺 x 位时实测 `diag=none`、`ran=48`,全绿)⇒ **没有第二条通道**。
0600 在"跑的人恰好是属主"时不炸,换身份就是 EACCES,而那串报错**看起来像代码问题**。
修法:
· 接进 `deploy/install.sh`(check-shared-libs 之后),**走 `--check` 累积通道**
(照既有 npm_rc/CHECK_GATE_RC)。⚠️ 我第一版**直接调**,而门禁红时它 `exit 1`、
install.sh 是 `set -e` ⇒ 当场吞掉后面所有诊断:**实测**接线后 `构建 Gateway`
在日志里命中 **0 次**(接线前 2 次)—— 正是 install.sh:141-157 刚修过的同一个毛病,
我自己又造了一遍。改累积后回到 2 次,门禁报 `[FAIL] 权限政策没过(退出码 1)`。
· 修那两个文件:600 → 644 ⇒ 权限政策现在绿(rc=0)。
· 新增判据 `criteria-hygiene` 第 7 条:政策门禁必须被入口脚本在**可执行位置**调用。
★★ 变异验证时**我自己先假绿了一次**(单记):第一版用 `code()` 剥注释,而
`lib/read.mjs` 的 `stripComments()` 只认 `//` 与 `/* */` —— 那是 **JS** 的注释,
**`install.sh` 是 shell,注释是 `#`** ⇒ 对 shell 文件**原样返回** ⇒ 判据读到了
**我写在它上面那段解释里的** `` # `check-file-modes.sh` 红时 `exit 1` ``。
变异①(接线整段删掉)⇒ 第一版 **rc=0(假绿)**;自剥 shell `#` 后 **rc=1** ✓
变异②(只在 echo 里提一句)⇒ rc=1 ✓
变异③(gates 恒空 ∀x∈∅)⇒ rc=1(`只找到 0 个`)✓
(③ 第一次 python 锚点没匹配上、变异没施加,我重测并**先打印"变异已施加"**才算数。)
★ 射程如实标出:只管 `deploy/check-*.sh`(政策门禁族);**不管** `check-deploy-drift.mjs`
这类**按需手动工具**(自带 `--self-check`、文档写明"事后自查")——要求它进入口是**错的**。
它实测同样 0 处调用,但**本判据不覆盖它,也没修它**。判"有没有接线",不判"接得对不对"。
★ 通用纪律(CRITERIA.md §16.1.2):**判据自己也要能"被证明它真的在看代码"。**
若判据读的**语言**与 stripComments 实现的**语言**不一致(shell vs JS、Python vs JS),
那"剥注释"是**假的** ⇒ 判据消费散文,而**变异验证是唯一能戳破它的东西**。
全套 checks=516→**517** pass=512 fail=5 red=5 broken=0 verdict=red(5 条红都是别的会话的);
mutants=48 ran=48 skipped=0 diag=none baseline=7/7✓;5 个自检各 rc=0。
This commit is contained in:
@ -585,3 +585,116 @@ test('★ AGC 真身从未进过远端历史(泄露之后响的闹钟,不是
|
||||
+ ' 3) 查清是哪次 push 绕过了 `.githooks/pre-push`(`--no-verify`?没装的机器?)。\n'
|
||||
+ ` 命中:\n ${published.join('\n ')}`);
|
||||
});
|
||||
|
||||
/*
|
||||
* ★★ 政策门禁不许"写了但没人跑"(dsh 2026-09-19)。
|
||||
*
|
||||
* 形状(这是本仓第 5 次同一个形状,前 4 次见 `CRITERIA.md §16`):
|
||||
* `deploy/check-file-modes.sh` 是**源文件权限政策的唯一判据**,
|
||||
* 逻辑写得对(`b7dc9e9` 还专门修过它自己那份 `[ -x ]` 恒真的 root 陷阱),
|
||||
* **但全仓没有任何地方执行它** —— 唯一的非注释提及是 `mutants/summary.py`
|
||||
* 里一句 `print(...)` 的**文案**。而它当时**正红着**(2 个文件是 600、
|
||||
* `jobs/` 缺属主 x 位)。判据在,但走不到。
|
||||
*
|
||||
* 为什么这一类**只能靠判据守**、不能指望"顺手发现":
|
||||
* `git ls-files -s` 只记 **100644 / 100755**(只含可执行位),
|
||||
* **组/其他读位不进版本库** ⇒ 实测把受跟踪文件 `chmod 600 ↔ 644`,
|
||||
* `git status` 两次都空、`git diff` 也不动。没有任何"顺带"的通道。
|
||||
*
|
||||
* 判什么:**宣称是"政策/门禁"的 `deploy/check-*.sh`,必须至少被一个入口脚本
|
||||
* (`install.sh` / `redeploy-*.sh`)在**可执行位置**调用**。
|
||||
*
|
||||
* ★ 射程如实标出(别让它冒充比它更宽的东西):
|
||||
* · 只管 `deploy/check-*.sh`(**政策门禁那一族**),**不管** `check-deploy-drift.mjs`
|
||||
* 这类**按需手动工具** —— 后者自带 `--self-check`、文档里明确是"事后自查",
|
||||
* 要求它也进入口是**错的**(会把工具当门禁,然后逼人把它挂上去)。
|
||||
* · 判的是"**有没有**接线",**不判"接得对不对"**(挂在 `--check` 累积通道里
|
||||
* 而不是直接调,是另一条纪律,由 `install.sh` 自己的注释与 141-157 行守着)。
|
||||
* · 数的是**可执行位置**的出现,所以**注释里提到不算**(本仓纪律:
|
||||
* "注释说明禁令 ≠ 违反禁令")—— 用 `code()` 剥注释,与上一条同形。
|
||||
*/
|
||||
test('★ 政策门禁(deploy/check-*.sh)必须被入口脚本真正调用,不许"判据在但走不到"', () => {
|
||||
const DEPLOY = join(REPO_ROOT, 'deploy');
|
||||
const ENTRIES = ['install.sh', 'redeploy-gateway.sh', 'redeploy-plugin.sh'];
|
||||
|
||||
/*
|
||||
* ★★ 为什么**不能**直接用 `code()`(本判据第一版就是这么写的,**假绿了**):
|
||||
*
|
||||
* `lib/read.mjs` 的 `stripComments()` 只认 `//` 与 `/* *\/` —— 那是 **JS** 的注释。
|
||||
* `install.sh` 是 **shell**,它的注释是 `#`。于是 `code()` 对 shell 文件**原样返回**,
|
||||
* 包括我写在它上面那段解释里的一句
|
||||
* `# \`check-file-modes.sh\` 红时 \`exit 1\`,而本脚本是 \`set -e\``
|
||||
* ⇒ 变异验证(把接线整段删掉)**判据仍然绿** —— 它读到的是**我自己的解释文案**。
|
||||
* 实测:
|
||||
* 变异①(接线拆掉)⇒ 期望红,实际 **rc=0(绿)**
|
||||
* `code(install.sh).includes('check-file-modes.sh')` ⇒ **true**,命中的是 `#` 开头那行
|
||||
* 这正是本仓那条纪律的又一次现身("注释说明禁令 ≠ 违反禁令"),
|
||||
* 也是 `stripComments` 那段注释自己警告过的形状:"判据开始消费散文"。
|
||||
*
|
||||
* ⇒ 自己剥 shell 注释。**已知限制,方向如实标出**:
|
||||
* · 只处理"行首(可带空白)的 `#`"与"空白后的 ` #`";
|
||||
* `${VAR#pat}` 这种**没有空格**的写法因此**不会**被误当注释(正是想要的)。
|
||||
* · 引号内的 `#`(`echo "a # b"`)会被当成注释起点 ⇒ 该行后半被截掉。
|
||||
* 对本判据**方向是安全的**:截掉只会**漏掉**接线(假红),
|
||||
* 不会**凭空造出**接线(假绿)——而假红是会被人当场看见的那一侧。
|
||||
*/
|
||||
const stripShellComments = (src) => src.split('\n').map((line) => {
|
||||
const t = line.trimStart();
|
||||
if (t.startsWith('#')) return '';
|
||||
const m = line.match(/(^|\s)#/); // 行首或空白后的 #(避开 ${VAR#pat})
|
||||
return m ? line.slice(0, m.index) : line;
|
||||
}).join('\n');
|
||||
|
||||
/*
|
||||
* ★ 还要排掉"散文行":真接线长这样(命令位置)
|
||||
* "$REPO/deploy/check-shared-libs.sh"
|
||||
* bash "$REPO/deploy/check-sandbox.sh" ...
|
||||
* 而散文长这样
|
||||
* echo "药方:跑 deploy/check-file-modes.sh"
|
||||
* ⇒ 抹掉 `echo`/`printf` 开头的行。**不做字符串剥离** ——
|
||||
* 真接线里文件名**就在引号内**(`"$REPO/deploy/x.sh"`),
|
||||
* 剥字符串会把真接线一起剥掉(那是把判据弄瞎,不是弄准)。
|
||||
*/
|
||||
const entryCode = ENTRIES
|
||||
.map((e) => ({ e, src: stripShellComments(code(join(DEPLOY, e))) }))
|
||||
.filter(({ src }) => src.length > 0)
|
||||
.map(({ e, src }) => ({
|
||||
e,
|
||||
src: src.split('\n')
|
||||
.filter((l) => !/^\s*(echo|printf)\b/.test(l))
|
||||
.join('\n'),
|
||||
}));
|
||||
|
||||
/*
|
||||
* ★ 反空真护栏:本判据的结论是"每个门禁都有人调" ——
|
||||
* 如果 `deploy/check-*.sh` 一个都没列出来(路径写错、目录挪了),
|
||||
* `∀x∈∅` 会让它**看起来和真判据一样绿**。本仓纪律:"空真看起来和真判据一样绿"。
|
||||
*/
|
||||
const gates = readdirSync(DEPLOY)
|
||||
.filter((n) => /^check-.*\.sh$/.test(n))
|
||||
.sort();
|
||||
assert.ok(gates.length >= 3,
|
||||
`只找到 ${gates.length} 个 deploy/check-*.sh(期望 ≥3)—— 大概率是路径/目录变了,`
|
||||
+ '而不是"门禁真的变少了"。空真必须报红,不许静默通过。');
|
||||
|
||||
assert.ok(entryCode.length >= 2,
|
||||
`只读到 ${entryCode.length} 个入口脚本(期望 ≥2)—— 同上,反空真。`);
|
||||
|
||||
const unwired = [];
|
||||
for (const g of gates) {
|
||||
// 在**入口脚本的代码里**找这个文件名(含 `$REPO/deploy/` 前缀那种写法)
|
||||
const called = entryCode.some(({ src }) => src.includes(g));
|
||||
if (!called) unwired.push(g);
|
||||
}
|
||||
|
||||
assert.deepEqual(unwired, [],
|
||||
`这些政策门禁**写了却没有任何入口脚本调用**(判据在,但走不到):\n`
|
||||
+ ` ${unwired.join('\n ')}\n`
|
||||
+ ' 为什么这条要紧(实测形状):`deploy/check-file-modes.sh` 就这样空转了 ——\n'
|
||||
+ ' 它的权限政策判得**完全正确**,而它当时**正红着**(2 个文件 600 + `jobs/` 缺 x),\n'
|
||||
+ ' 全仓唯一的非注释提及是另一个文件里一句 `print(...)` 的文案。\n'
|
||||
+ ' ⇒ 药方:在 `deploy/install.sh` 里调用它。\n'
|
||||
+ ' ⚠️ 挂在 `--check` 下要**走累积通道**(照 `npm_rc`/`CHECK_GATE_RC` 的既有做法),\n'
|
||||
+ ' **不能直接调** —— 门禁红时它 `exit 1`,而 `install.sh` 是 `set -e`,\n'
|
||||
+ ' 会在那里中止、后面所有诊断一行都不打(`install.sh` 141-157 行刚修过同一个毛病)。');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user