From cb2157a49adc39f71b22dd9c06a234a334a7c541 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Sat, 26 Sep 2026 00:42:29 +0800 Subject: [PATCH] =?UTF-8?q?=E2=98=85=E2=98=85=20=E6=94=B6=20pi=20=E4=B8=A4?= =?UTF-8?q?=E5=A4=84**=E5=AE=9E=E6=B5=8B=E6=89=93=E5=87=BA=E7=9A=84?= =?UTF-8?q?=E6=88=91=E8=87=AA=E5=B7=B1=E7=9A=84=E7=BC=BA=E9=99=B7**:=20?= =?UTF-8?q?=E2=91=A0=20=E6=8E=A2=E9=92=88=E6=A0=87=E8=AE=B0=E4=B8=8E?= =?UTF-8?q?=E5=88=A4=E6=8D=AE=E8=87=AA=E8=BA=AB=E6=BA=90=E7=A0=81**?= =?UTF-8?q?=E7=A2=B0=E6=92=9E**=20=E2=87=92=20=E5=81=87=E7=BA=A2=EF=BC=88?= =?UTF-8?q?=E6=94=B9=E7=94=A8**=E8=BF=90=E8=A1=8C=E6=97=B6=20nonce**?= =?UTF-8?q?=EF=BC=89=E2=91=A1=20=E8=B0=83=E7=94=A8=E8=80=85=E8=B0=93?= =?UTF-8?q?=E8=AF=8D**=E8=BF=87=E5=AE=BD**=EF=BC=88=E5=AD=90=E4=B8=B2?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=20=E2=89=A0=20=E6=8C=87=E5=90=91=E6=9C=AC?= =?UTF-8?q?=E5=BA=93=EF=BC=89=E2=87=92=20=E5=81=87=E7=BA=A2=EF=BC=88?= =?UTF-8?q?=E8=B0=93=E8=AF=8D=E6=94=B6=E7=B4=A7=20+=20=E5=B0=BE=E9=94=9A?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ★★ (A) pi `551d7d85`: 固定标记 `__AM_P_TAIL__` 与**判据文件自身内容**碰撞 ⇒ 假红 根因: 该字面量**就在本判据源码里**(:374 探针串、:379 grep 那行), 所以当**本判据自己被当数据读**(域偏宽/自指)时,`grep -F … | head -1` 匹配到的是**源码里那行**,而不是文件末尾之后的真尾探针 我复现(自指场景): head=1、tail=375、内容行数=536、应为 538 ⇒ 差 163 (pi 报 162 @ 它的 HEAD,逐位吻合同一机制) ⇒ 修法: **运行时 nonce**(`_am_nonce="AM${RANDOM}${RANDOM}${$}Z"`)—— 该记号**不可能**预先出现在任何静态文件里 ⇒ 碰撞**不可表示** ★ 比"再加几个下划线""改成 tail -1"更根本: 前两者只是让碰撞**更难**,nonce 让它**不可能** ★ 实测: 自指场景不再报"探针失败",改为正确报出**真违规**(:293/:401 那两处探针字面量本身) ★ (B) pi `ae164e2e`: 谓词 `.*env-defaults\.sh` 只要求**子串出现** ⇒ `. /tmp/not-our-lib/env-defaults.sh.other` ⇒ rc=**1** 并报其裸赋值,而它**没 source 本库** ⇒ **假红** ⇒ 修法(pi 的诊断对: **域的宽度该用谓词精度管,不该用阈值管** —— 空集/下界守卫都只兜"域偏小"这一方向,加上界阈值只是把**精确性**问题换成**调参**问题): 谓词改成"source 的**参数末尾**必须是 `…/lib/env-defaults.sh`": `[^[:alnum:]_.-]lib/env-defaults\.sh["']?[[:space:]]*$` ★ 前半排除 `not-our-lib/…`(`-lib` 前是 `-`);**尾锚**排除 `env-defaults.sh.other`(更长的名字) ★ 实测: 本仓 3 个真实调用者全认出;pi 的假红例与 5 个别式反例全拒 ⚠️ 射程: 行内文本判法,不解析变量取值 ⇒ `. "$SOMEDIR/lib/env-defaults.sh"` 而 $SOMEDIR 指向别处时仍算调用者(**偏宽**、方向安全: 多查一个文件而非漏查) ★★ (C) 反向对照里**补上 pi 的假红样本**(`/tmp/not-our-lib/env-defaults.sh.other`)—— 它正是 (B) 那条回归的守卫;实测把谓词回退成过宽版 ⇒ 反向对照**打红**(rc=1) ★ 回归: 基线 rc=0;pi① rc=1 / pi② rc=0 / pi 假红例 rc=0 / 真调用者 rc=1; 12 向变异矩阵全 rc=1;criteria-hygiene 10/10;--git-hooks 负对照(PATH 无 git / pre-push 不可执行) rc=1 未破 --- deploy/check-require-declaration.sh | 51 ++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/deploy/check-require-declaration.sh b/deploy/check-require-declaration.sh index 934c879..8555bc5 100755 --- a/deploy/check-require-declaration.sh +++ b/deploy/check-require-declaration.sh @@ -150,12 +150,30 @@ _strip_comments_lex() { _is_caller_text() { local t t="$(printf '%s\n' "$1" | _strip_comments_lex /dev/stdin)" - case "$t" in - *env-defaults.sh*) - grep -qE '^[[:space:]]*(\.|source)[[:space:]].*env-defaults\.sh' <<< "$t" - ;; - *) return 1 ;; - esac + # ★★★ 谓词从"**行内出现子串**"收紧为"**指向本库**"(pi `ae164e2e` 实测打出的**假红**,我复现): + # 旧谓词 `.*env-defaults\.sh` 只要求**子串出现** ⇒ + # `. /tmp/not-our-lib/env-defaults.sh.other` ⇒ rc=**1** 并报该文件裸赋值 + # 而该文件**没有 source 本库** ⇒ **假红**(域偏宽)。 + # ★ pi 的诊断对: **域的宽度该用谓词精度管,不该用阈值管** —— + # 空集守卫 / 下界守卫**都只兜"域偏小/空"**这个方向,加"上界阈值"只会把 + # 一个**精确性**问题换成一个**调参**问题(阈值调多少都是猜)。 + # ⇒ 收紧后的谓词: source 的**参数末尾**必须是 `…/lib/env-defaults.sh`(可带引号/空白), + # 即"**这一行指向的就是本库那个文件**",而不是"这一行里出现过这个字符串"。 + # ① `[^[:alnum:]_.-]lib/env-defaults\.sh` ⇒ 前面必须是**路径分隔符或词边界**, + # 排除 `not-our-lib/env-defaults.sh`(`-lib` 前面是 `-`)这类同后缀异文件 + # ② `["']?[[:space:]]*$` ⇒ **尾锚** ⇒ 排除 `env-defaults.sh.other` 这类**更长**的名字 + # ★ 实测(本仓 3 个真实调用者 + 6 个反例): + # `. "$REPO/deploy/lib/env-defaults.sh"` ⇒ 调用者 ✓ + # `. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/…"` ⇒ 调用者 ✓(两处真实形态) + # `. "${REPO#/home}/deploy/lib/env-defaults.sh"` ⇒ 调用者 ✓ + # `. "$A #B/deploy/lib/env-defaults.sh"` ⇒ 调用者 ✓ + # `. /tmp/not-our-lib/env-defaults.sh.other` ⇒ 不算 ✓(pi 的假红例) + # `. /tmp/not-our-lib/env-defaults.sh` ⇒ 不算 ✓ + # `. /tmp/x/lib/env-defaults.sh.other` ⇒ 不算 ✓ + # ⚠️ 射程: 这是**行内文本**的判法,不解析变量实际取值 —— + # 若有人写 `. "$SOMEDIR/lib/env-defaults.sh"` 而 `$SOMEDIR` 指向别处, + # 本判据仍算它"调用者"(**偏宽**、方向安全,会多查一个文件而不是漏查)。 + grep -qE '^[[:space:]]*(\.|source)[[:space:]].*[^[:alnum:]_.-]lib/env-defaults\.sh["'"'"']?[[:space:]]*$' <<< "$t" } # ① 找"调用者":非注释行里以 `. ` 或 `source ` 起头、且提到 env-defaults.sh 的文件。 @@ -301,6 +319,8 @@ AGENTMAIL_REQUIRE="git go"' || true)" _pc_bad="" _is_caller_text '. /dev/null;# 提到 env-defaults.sh' && _pc_bad="分号后的注释(该截没截)" _is_caller_text '# . env-defaults.sh' && _pc_bad="${_pc_bad}整行注释" + # ★ pi `ae164e2e` 打出的**假红**(谓词过宽: 子串出现 ≠ 指向本库)—— 这条必须在反向对照里: + _is_caller_text '. /tmp/not-our-lib/env-defaults.sh.other' && _pc_bad="${_pc_bad}同名后缀的**别的**文件" if [ -n "$_pc_bad" ]; then printf ' [FAIL] 判据自检失败(调用者判定,反向):**非调用者样本**被判成了调用者(%s)——\n' "$_pc_bad" >&2 printf ' ⇒ 域会**偏大**,与该库无关的文件被拖进来报红(假红)。按红计。\n' >&2 @@ -369,14 +389,23 @@ agentmail_require git go' || true)" # `sed 135d` ⇒ `t=801` ≠ 802 ⇒ 抓到;`head/tail -N` ⇒ 缺探针 ⇒ 抓到; # `tac` ⇒ `h=802 t=1`(顺序反)⇒ 抓到;`grep -v '^$'` / `sort -u` ⇒ `t` 偏离 ⇒ 抓到。 # ★ 三个条件合起来 = "**这个过滤器是逐行原位的**"(保行数、保顺序、保两端)。 - _probe_in="AGENTMAIL_REQUIRE=\"__AM_P_HEAD__\" + # ★★★ 但**固定标记**本身有个洞(pi `551d7d85` 实测打出的**假红**,我复现): + # 标记 `__AM_P_TAIL__` 是**字面量**,而它**出现在本判据自己的源码里**(:374/:379 两处)。 + # 于是当**本判据文件自己被当成数据读**(域偏宽 / 自指)时,`grep -F … | head -1` + # 匹配到的是**源码里那行**,不是文件末尾之后的真尾探针 ⇒ 行号算术失败 ⇒ **假红**。 + # ★ 这不是"域偏宽"的问题被误报 —— 是**探针的记号与数据不可分辨**。 + # ⇒ 修法: 用**运行时 nonce**(`$RANDOM` + pid)代替固定字面量 ⇒ + # 该记号**不可能**预先出现在任何静态文件里 ⇒ 碰撞**不可表示**(比"再多加几个下划线"根本)。 + # ⚠️ 射程: 这消掉"记号与数据碰撞"这一类;**不**改变"域偏宽"本身是否该红(那是谓词的事,见 `_is_caller_text`)。 + _am_nonce="AM${RANDOM}${RANDOM}${$}Z" + _probe_in="AGENTMAIL_REQUIRE=\"${_am_nonce}HEAD\" $(cat "$f") -AGENTMAIL_REQUIRE=\"__AM_P_TAIL__\"" +AGENTMAIL_REQUIRE=\"${_am_nonce}TAIL\"" # 内容行数与探针**同一条读取路径**(都经 `printf '%s\n'` 补回被命令替换吃掉的尾换行) _probe_n="$(printf '%s\n' "$(cat "$f")" | awk 'END{print NR}')" _probe_out="$(_scan_stripped "$(strip_text "$_probe_in")" || true)" - _ph="$(grep -F '__AM_P_HEAD__' <<< "$_probe_out" | head -1 | cut -d: -f1)" - _pt="$(grep -F '__AM_P_TAIL__' <<< "$_probe_out" | head -1 | cut -d: -f1)" + _ph="$(grep -F "${_am_nonce}HEAD" <<< "$_probe_out" | head -1 | cut -d: -f1)" + _pt="$(grep -F "${_am_nonce}TAIL" <<< "$_probe_out" | head -1 | cut -d: -f1)" _pexp=$(( ${_ph:-0} + _probe_n + 1 )) if [ -z "$_ph" ] || [ -z "$_pt" ] || [ "$_ph" -ge "$_pt" ] || [ "$_pt" -ne "$_pexp" ]; then printf ' [FAIL] %s 逐文件探针失败:读入这一环**不是逐行原位**的 —— 它在丢弃或重排内容。\n' "$f" >&2 @@ -389,7 +418,7 @@ AGENTMAIL_REQUIRE=\"__AM_P_TAIL__\"" printf ' ⇒ 按红计(绝不能因为两条通道都不说话就当成"没问题")。\n' >&2 exit 1 fi - unset _probe_in _probe_out _probe_n _ph _pt _pexp + unset _probe_in _probe_out _probe_n _ph _pt _pexp _am_nonce # ★★★ 逐行局部不变量(2026-09-25 **pi 提的非循环补法**,我实测后采纳): # 上一节的首尾探针只锁"**行数 / 顺序 / 两端**"(**形状**),锁不住"**某一行内容被抹**"。 # pi 的补法: 对**每一行**要求