mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 06:47:29 +00:00
fix(ci): ID:15 排除表守卫改为「注入合成行真跑」,杜绝形似而无效的假绿
原判据(efe0cf1)剥注释后查 token:`${reason// /}` + `exit 1` 都在、提示文案都在,
但把 if 条件改成 `&& false` 后条件恒假、步骤实跑 EXIT=0,判据仍然绿 —— 假绿。
改为从 race job 里抽出「计算 -race 排除表并打印」步骤的 run 体,在临时 bash 里真跑三次:
1. 原样 → 必须 EXIT=0(正向基线)
2. 注入 reason 空的合成行 → 必须 EXIT=1
3. 注入 ticket 空的合成行 → 必须 EXIT=1
两条守卫各用只违反自己的输入单独打,不用一条顶另一条的包。
用合成行而非真实 webui 排除项 ⇒ 该排除项修好后被删掉也不会误报。
验证矩阵(verify_v4.py,5 变异 + 1 误报 + 基线):
✓ reason 守卫失效(token 全在 + && false) EXIT=1
✓ ticket 守卫失效(token 全在 + && false) EXIT=1
✓ 删 cmd/gui 剔除 EXIT=1
✓ 启动图判据步去掉 -count=1 EXIT=1
✓ race 退回写死两包 EXIT=1
✓ 删 webui 排除行(误报检查) EXIT=0
✓ 还原后基线 EXIT=0
go build ./... = 0 error,go vet ./... = 0 error
This commit is contained in:
71
.github/scripts/check-ci-gates.py
vendored
71
.github/scripts/check-ci-gates.py
vendored
@ -96,18 +96,67 @@ for _n, r in evid:
|
|||||||
check("DATA RACE" in r,
|
check("DATA RACE" in r,
|
||||||
"取证步骤应显式检查 DATA RACE 报告数(否则取证没意义)")
|
"取证步骤应显式检查 DATA RACE 报告数(否则取证没意义)")
|
||||||
|
|
||||||
# ── 3. skip 排除表:每项必须写原因,无原因必须步骤自己失败 ──
|
# ── 3. skip 排除表:真跑一次坏输入,要求它必须失败 ──
|
||||||
#
|
#
|
||||||
# ★ 这里曾经写成 `any("没有写原因" in r ...)` —— 只检查**提示文案还在**。
|
# ★ 这里换过三版,每一版的失效方式都值得记:
|
||||||
# 实测:把 `if [ -z "${reason// /}" ]; then` 改成 `if false; then`
|
# v1 `any("没有写原因" in r ...)` —— 只查提示文案;把 if 条件改 false 仍绿
|
||||||
# (文案全保留、校验实际失效),该断言仍然绿,而该步骤实跑 EXIT=0
|
# v2 剥注释后查 `${reason// /}` + `exit 1` —— 两个 token 都在仍可能不成立;
|
||||||
# —— 也就是说「无原因必须失败」这条保证彻底破掉,判据却看不见。
|
# 实测 `if [ -z "${reason// /}" ] && false; then` 依然绿
|
||||||
# 这正是本脚本自己在 docstring 里批判的「被文案顶包」,不能自己再犯。
|
# v3 真跑、但拿真实 webui 那一行做坏输入 —— 该排除项修好被删掉时**误报红**
|
||||||
# ⇒ 改为剥注释后断言**可执行的判空逻辑**:必须同时出现判空变量与 exit 1。
|
# v4(本条)用**合成行**注入 TABLE 再真跑:
|
||||||
race_code = "\n".join(code_lines(r) for _n, r in race)
|
# · 不依赖任何真实排除项 ⇒ 排除项增删不会引起误报
|
||||||
check('${reason// /}' in race_code and "exit 1" in race_code,
|
# · 真跑 ⇒ `&& false` 这类「形似而无效」的改动会被抓出来
|
||||||
"race job 排除表缺少真校验:剥注释后必须能看到 ${reason// /} 判空 + exit 1,"
|
#
|
||||||
"只有提示文案不算(把 if 条件改 false 就能骗过纯文案断言)")
|
# 两条守卫必须**各自**用只违反它的输入来验,否则一条会顶另一条的包
|
||||||
|
# (第一版我把 reason 与 ticket 同时清空,ticket 守卫兜住了,reason 守卫死没死看不出来)。
|
||||||
|
import subprocess as _sp
|
||||||
|
import tempfile as _tf
|
||||||
|
|
||||||
|
_tbl = None
|
||||||
|
for _n, _r in race:
|
||||||
|
if "计算 -race 排除表并打印" in (_n or ""):
|
||||||
|
_tbl = _r
|
||||||
|
if _tbl is None:
|
||||||
|
fails.append("race job 找不到「计算 -race 排除表并打印」步骤 —— 无法自测排除表守卫")
|
||||||
|
elif "${{" in _tbl:
|
||||||
|
fails.append("排除表步骤含 GitHub 表达式,本脚本无法本地执行它(需改用别的验证方式)")
|
||||||
|
else:
|
||||||
|
import re as _re
|
||||||
|
_m = _re.search(r"read -r -d '' TABLE <<'EOF'[^\n]*\n(.*?)\nEOF\n", _tbl, _re.S)
|
||||||
|
if _m is None:
|
||||||
|
fails.append("排除表步骤里找不到 TABLE heredoc —— 无法注入合成坏行")
|
||||||
|
else:
|
||||||
|
def _run_body(body):
|
||||||
|
fd, tmp_sh = _tf.mkstemp(suffix=".sh")
|
||||||
|
with __import__("os").fdopen(fd, "w", encoding="utf-8") as f:
|
||||||
|
f.write(body)
|
||||||
|
out = _tf.mktemp()
|
||||||
|
env = dict(__import__("os").environ)
|
||||||
|
env["GITHUB_OUTPUT"] = out
|
||||||
|
try:
|
||||||
|
return _sp.run(["bash", tmp_sh], capture_output=True, text=True, env=env)
|
||||||
|
finally:
|
||||||
|
__import__("os").unlink(tmp_sh)
|
||||||
|
if __import__("os").path.exists(out):
|
||||||
|
__import__("os").unlink(out)
|
||||||
|
|
||||||
|
def _inject(line):
|
||||||
|
inner = _m.group(1)
|
||||||
|
new_inner = (line + "\n" + inner) if inner.strip() else line
|
||||||
|
return _tbl[:_m.start(1)] + new_inner + _tbl[_m.end(1):]
|
||||||
|
|
||||||
|
# 正向:原样必须通过
|
||||||
|
if _run_body(_tbl).returncode != 0:
|
||||||
|
fails.append("排除表步骤用当前 ci.yml 实跑不通过(正向基线坏)")
|
||||||
|
|
||||||
|
_probe = "test|internal/probe/synthetic|TestSyntheticProbe"
|
||||||
|
# 只打 reason:reason 空、ticket 有效
|
||||||
|
if _run_body(_inject(_probe + "||PROBE-TICKET")).returncode == 0:
|
||||||
|
fails.append("合成行「reason 空 / ticket 有效」竟通过 ⇒ reason 守卫已失效"
|
||||||
|
"(形似而无效的改动,例如 if 条件加 && false)")
|
||||||
|
# 只打 ticket:reason 有效、ticket 空
|
||||||
|
if _run_body(_inject(_probe + "|合成探针原因|")).returncode == 0:
|
||||||
|
fails.append("合成行「reason 有效 / ticket 空」竟通过 ⇒ ticket 守卫已失效")
|
||||||
|
|
||||||
# ── 4. go job:整机启动图判据必须单列一步跑 kernelboot/modules ──
|
# ── 4. go job:整机启动图判据必须单列一步跑 kernelboot/modules ──
|
||||||
gojob = step_runs("go")
|
gojob = step_runs("go")
|
||||||
|
|||||||
Reference in New Issue
Block a user