目标
消灭 gate 的 "skipped = success" fail-open 面:gate 作为唯一 required check,必须是显式断言每个上游 job result == 'success' 的 aggregator,skipped / neutral 一律视为红。
背景(源自 #81 §3.1)
GitHub 官方行为:skipped 的 job 上报 Success,即使是 required check 也不阻止合并。当前 .github/workflows/gate.yml 的 aggregator 已有 if: always() 和 needs 断言,但断言条件是 result != "success" and result != "skipped" 才算失败——即 skipped 被当绿。任何路径过滤、if: 条件、上游被 skip 的传导,都会让 gate "绿但没跑"。无人值守下 gate 是唯一判据,这个缝必须焊死。
同时明确一条规范:paths: / paths-ignore: 过滤禁止放在 workflow 级(会导致 check 完全不产生 → 永久 pending),只能放 job 级并由 aggregator 显式判定。
涉及文件
.github/workflows/gate.yml(aggregator 断言段)——本仓
CI-Workflows/.github/workflows/check.yml / ci.yml(下游仓同款 aggregator,若存在相同模式一并修)
standards/(workflow 级路径过滤禁令)
执行步骤
gate.yml 的 "hygiene green?" 步骤改为严格断言:needs 中任何 job 的 result 不等于 "success" 即失败(skipped、cancelled、failure、startup_failure 全部算红)。
- 检查 CI-Workflows 内所有被复用的 workflow 与各业务仓的 caller workflow,凡有 aggregator 模式的同步改为严格断言。
- 在 standards 写明:required check 链路上的 workflow 禁用 workflow 级
paths: 过滤;job 级过滤必须配 aggregator 显式判定(且被跳过的 job 不得是安全相关 job——安全 job 永远不许 skip)。
- 复核现有所有 workflow,确认无 workflow 级
paths:/paths-ignore:。
验收标准
- gate aggregator 断言为严格相等
== "success",不接受 skipped。
- 上游 job 被 skip 的 PR,gate 变红。
- 全部上游真跑且绿时,gate 正常变绿(无回归)。
- 组织内无 required 链路上的 workflow 级路径过滤。
测试方法(预先指定)
T1 skip 注入测试(核心,负向)
- 在测试仓
Use-up-Plan 构造一个 PR:临时给 gate 的上游 job(如 hygiene 的调用 job)加一个恒为 false 的 job 级 if:(if: false),使该 job 被 skip。
- 断言:aggregator job 执行且 conclusion 为
failure(gh api repos/.../commits/<sha>/check-runs --jq '.check_runs[] | select(.name=="gate") | .conclusion' 返回 failure),PR 无法合并。
- 关闭该 PR,删除分支。
T2 全绿回归(正向)
- 在同一测试仓开一个正常 PR(所有上游真跑且通过)。
- 断言:gate conclusion 为
success,PR 可合并。
T3 断言逻辑单元验证
- 在 PR 的 aggregator step 里(或本地复现其 jq 片段)喂入构造的 NEEDS JSON:
{"hygiene":{"result":"skipped"}} → 必须 exit 1
{"hygiene":{"result":"success"}} → 必须 exit 0
{"hygiene":{"result":"cancelled"}} → 必须 exit 1
三个用例全部符合才通过。
T4 静态扫描
grep -rn "^ paths" .github/workflows/ && grep -rn "paths-ignore" .github/workflows/ 对组织内各仓执行,断言 required 链路上无 workflow 级路径过滤(结果为空或仅存于非 required 的 workflow 并逐个登记豁免理由)。
依赖
无(可与 P1-1/P1-2 并行;合入顺序建议在 P1-2 之前,避免死锁拆除后假绿 PR 涌入)
目标
消灭 gate 的 "skipped = success" fail-open 面:gate 作为唯一 required check,必须是显式断言每个上游 job
result == 'success'的 aggregator,skipped / neutral 一律视为红。背景(源自 #81 §3.1)
GitHub 官方行为:skipped 的 job 上报 Success,即使是 required check 也不阻止合并。当前
.github/workflows/gate.yml的 aggregator 已有if: always()和 needs 断言,但断言条件是result != "success" and result != "skipped"才算失败——即 skipped 被当绿。任何路径过滤、if:条件、上游被 skip 的传导,都会让 gate "绿但没跑"。无人值守下 gate 是唯一判据,这个缝必须焊死。同时明确一条规范:
paths:/paths-ignore:过滤禁止放在 workflow 级(会导致 check 完全不产生 → 永久 pending),只能放 job 级并由 aggregator 显式判定。涉及文件
.github/workflows/gate.yml(aggregator 断言段)——本仓CI-Workflows/.github/workflows/check.yml/ci.yml(下游仓同款 aggregator,若存在相同模式一并修)standards/(workflow 级路径过滤禁令)执行步骤
gate.yml的 "hygiene green?" 步骤改为严格断言:needs中任何 job 的result不等于"success"即失败(skipped、cancelled、failure、startup_failure 全部算红)。paths:过滤;job 级过滤必须配 aggregator 显式判定(且被跳过的 job 不得是安全相关 job——安全 job 永远不许 skip)。paths:/paths-ignore:。验收标准
== "success",不接受 skipped。测试方法(预先指定)
T1 skip 注入测试(核心,负向)
Use-up-Plan构造一个 PR:临时给 gate 的上游 job(如 hygiene 的调用 job)加一个恒为 false 的 job 级if:(if: false),使该 job 被 skip。failure(gh api repos/.../commits/<sha>/check-runs --jq '.check_runs[] | select(.name=="gate") | .conclusion'返回failure),PR 无法合并。T2 全绿回归(正向)
success,PR 可合并。T3 断言逻辑单元验证
{"hygiene":{"result":"skipped"}}→ 必须 exit 1{"hygiene":{"result":"success"}}→ 必须 exit 0{"hygiene":{"result":"cancelled"}}→ 必须 exit 1三个用例全部符合才通过。
T4 静态扫描
grep -rn "^ paths" .github/workflows/ && grep -rn "paths-ignore" .github/workflows/对组织内各仓执行,断言 required 链路上无 workflow 级路径过滤(结果为空或仅存于非 required 的 workflow 并逐个登记豁免理由)。依赖
无(可与 P1-1/P1-2 并行;合入顺序建议在 P1-2 之前,避免死锁拆除后假绿 PR 涌入)