From 6b7c12d9da91acff4f650e49fb807fd31cd87e3f Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 14 Sep 2026 19:46:07 +0800 Subject: [PATCH] =?UTF-8?q?fix(pi-bridge):=20"=E5=BC=80=E5=85=B3=E8=A2=AB?= =?UTF-8?q?=E8=AE=A4"=E9=82=A3=E6=9D=A1=E5=88=A4=E6=8D=AE=E8=87=AA?= =?UTF-8?q?=E5=B7=B1=E4=B9=9F=E6=9C=89=E5=81=87=E7=BB=BF=20=E2=80=94?= =?UTF-8?q?=E2=80=94=20=E6=88=91=E6=8C=89=E7=9C=9F=E5=AE=9E=E6=B5=8B?= =?UTF-8?q?=E9=87=8F=E5=88=86=E5=8F=89=EF=BC=8C=E4=BA=8E=E6=98=AF=E6=B0=B8?= =?UTF-8?q?=E8=BF=9C=E8=B5=B0=E7=9F=AD=E8=B7=AF=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pi 评审第二轮指出:上一版"开关真的被认"只在"真实测量不足"那个分支里断言, 机器一恢复健康(/tmp 被清空)这条就退化成"只验 --measure"的弱检查, 而它守的恰恰是"开关别静默失效"。 认下之后我做变异(把开关整个忽略掉、永远用真实测量)验证,**发现比这更糟**: 那条新写的判据**在变异下照样绿**。 原因是我写成了 `realAvail < MIN_FREE_BYTES ? (不足分支,只看退出码) : (充足分支)`, 而本机真实可用**就是 0** ⇒ 永远走不足分支;开关被整个忽略时,回退测量同样给 exit 2 ⇒ 断言通过。**"断言在,区分力不在"** —— 与 pi 点的是同一类病, 只是它藏在一个**跑不到的分支**里(嵌套三元短路),比"分支退化"更难看出来。 修法:不跟真实测量比,**让两个探针自己互为反面**,并断言**输出里的判定词** (不只看退出码 —— 退出码可能与真实状态巧合相同): 探针 A:注入 1 字节 ⇒ exit 2 + 必须打印「< 需要」 探针 B:注入 128 MiB(>阈值)⇒ exit 0 + 必须打印「≥ 需要」 开关被忽略 ⇒ 两次都按真实测量给同一个答案 ⇒ 至少一条红。这个论证不依赖真实测量 是多少。变异自检实测:注入"忽略开关"的变异后,第 23、24、25 三条一起红。 顺带修一处**HEAD 里就带着的坏行**:第 162 行的 `test(..., () => {` 后面被塞进了 `// 覆盖…` 注释(上一次编辑吃掉了那个换行),整行不合法。这次一并拆回两行。 过程中我两次改坏文件(一次把手写 `replace` 的锚点算错、把"非法参数"那条整条删掉), 两次都靠 `git checkout HEAD -- ` 拉回重做 —— 这正是上一轮写进 `lib/env-error.mjs` 的那条纪律(变异/改写只对已提交文件做、还原只走 git)当场生效。 验证:`npm test` **475/475**;env-guard 单跑 30 条全过(含 24 号在两个探针下的双断言)。 --- .../pi-mail-bridge/test/env-guard.test.mjs | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/plugins/pi-mail-bridge/test/env-guard.test.mjs b/plugins/pi-mail-bridge/test/env-guard.test.mjs index 2396328..6999ff9 100644 --- a/plugins/pi-mail-bridge/test/env-guard.test.mjs +++ b/plugins/pi-mail-bridge/test/env-guard.test.mjs @@ -115,37 +115,28 @@ test('端到端:退出码 2 与文案(两个方向都验,不依赖机器 assert.match(good.stdout, /env-preflight/); }); -test('★开关真的被认:按真实测量分叉,两个分支各有分辨力', () => { - // pi 评审指出上一版的漏洞:原来只在"真实测量不足"那个分支里断言, - // 机器一恢复健康(/tmp 被清空)这条就退化成"只验 --measure"的弱检查 —— - // 而它守的恰恰是"开关别静默失效"。 +test('★开关真的被认:两个探针必须给出**相反**的判定与相反的关键词', () => { + // pi 评审的漏洞一:上一版只在"真实测量不足"那个分支里断言 ⇒ 机器一恢复健康 + // (/tmp 被清空)这条就退化成弱检查,而它守的恰恰是"开关别静默失效"。 // - // 两个方向是**对偶**的,各守一个机器状态,所以按实测分叉、在两个分支里 - // 断言**相反**的方向 ⇒ 任何机器状态下都有分辨力,不会退化成弱检查: + // 漏洞二(我做变异时撞上的,比漏洞一更隐蔽):按"真实测量"分叉的写法本身留了一个 + // 短路分支 —— 本机真实可用就是 0 ⇒ 永远走不足分支,而那个分支只看退出码; + // 于是把开关**整个忽略掉**(永远用真实测量),断言**照样绿**。 + // "断言在,区分力不在" —— 与 pi 点的是同一类病,只是它藏在"跑不到的分支"里。 // - // 真实不足 ⇒ 注入大数必须放行 (若开关被忽略,回退测量 ⇒ 2 ≠ 0 ⇒ 红) - // 真实充足 ⇒ 注入 0 必须 exit 2(若开关被忽略,回退测量 ⇒ 0 ≠ 2 ⇒ 红) - // - // 判据红的方式不一样,但**红**这件事在两种机器状态下都成立。 - const measured = runPreflight(['--measure=/tmp']); - assert.equal(measured.status, 0, '--measure 只量一次并 exit 0'); - const m = /"availBytes":\s*(\d+|null)/.exec(measured.stdout); - assert.ok(m, `--measure 必须回一个数或 null,实际:${measured.stdout.trim()}`); + // 修法:**不跟真实测量比,让两个探针自己互为反面**,并断言**输出里的判定词** + // (不只看退出码 —— 退出码可能与真实状态巧合相同): + // 探针 A:注入 1 字节 ⇒ exit 2 + 必须打印「< 需要」 + // 探针 B:注入 128 MiB(>阈值)⇒ exit 0 + 必须打印「≥ 需要」 + // 若开关被忽略,两次都按**真实**测量给同一个答案 ⇒ 至少一条红。 + // 这个论证不依赖真实测量是多少。 + const tiny = runPreflight(['--inject-avail=1']); + assert.equal(tiny.status, 2, '注入 1 字节必须 exit 2'); + assert.match(tiny.stderr + tiny.stdout, /<\s*需要/, '必须打印「不足」的判定'); - if (m[1] === 'null') { - // 量不到就**不能**分叉(既不知道机器是哪种状态)。明说并让判据红, - // 而不是悄悄跳过 —— 跳过会把"失去分辨力"伪装成"验过了"。 - assert.fail('本机 /tmp 量不出可用空间,这条判据无法分叉 —— 别让它静默退化'); - } - const realAvail = Number(m[1]); - - if (realAvail < MIN_FREE_BYTES) { - const injected = runPreflight(['--inject-avail=999999999']); - assert.equal(injected.status, 0, '真实不足 + 注入充足 ⇒ 必须按注入的走(开关被认)'); - } else { - const injected = runPreflight(['--inject-avail=0']); - assert.equal(injected.status, 2, '真实充足 + 注入 0 ⇒ 必须按注入的走(开关被认)'); - } + const plenty = runPreflight(['--inject-avail=134217728']); + assert.equal(plenty.status, 0, '注入 128 MiB(> 32 MiB 阈值)必须放行'); + assert.match(plenty.stdout, /≥\s*需要/, '必须打印「充足」的判定(不是靠退出码近似)'); }); test('★非法参数必须炸(exit 2),不能静默放行', () => { @@ -159,7 +150,8 @@ test('★非法参数必须炸(exit 2),不能静默放行', () => { assert.equal(runPreflight(['--inject-avail=null']).status, 0, 'null 是合法值(没测到 ⇒ 放行)'); }); -test('测量层:读不到的目录 → null(这条判据不依赖机器状态,永远跑得了)', () => { // 覆盖"读不到 ⇒ null ⇒ 放行"那一支。端到端那条一旦被跳过,就只剩这条管它。 +test('测量层:读不到的目录 → null(这条判据不依赖机器状态,永远跑得了)', () => { + // 覆盖"读不到 ⇒ null ⇒ 放行"那一支。端到端那条一旦被跳过,就只剩这条管它。 assert.equal(measureAvailBytes('/definitely/not/here'), null); assert.equal(measureAvailBytes(''), null, '空串不是合法目录'); assert.equal(measureAvailBytes(undefined), null, '不传也要能兜住');