name: Signing status(播报,不是门禁) # 第一句就是口径:**这是播报,不是门禁。它红了不代表不能合,它绿了也不代表签名就绪。** # 就绪度的结论只在 job summary 的三行字里(`packaging/check_signing_ready.py --line` 写的), # 不在 job 的颜色里。**本 workflow 不应被设为 required check**(GitHub 侧分支保护里不要勾它)。 # # 为什么要有它(M255):M254(CLAIMAUDIT)查出 `crates/core/src/update/trust.rs` 的 `PRODUCTION` # 表在 `PINNED-KEYS` 标记之间是空的,而空表一律 `KeyringEmpty` 拒装 ⇒ 今天任何正式二进制都验不过任何 # 清单(fail-closed,用户端表现为「更新永远失败」)。工具链早就齐了,缺的是**可见性**:这三行读数让 # 「今天差什么」在每次运行里都摆在台面上,而不是等发版时才发现。 # # 口径三条(由 `packaging/tests/signing_ready_selftest.py` 的接线判据机器校验,不是靠注释自律): # ① 就绪度那一步抓 `rc=$?` 之后**恒 `exit 0`** —— 未就绪用 `::warning::` 播报,不用 error 级注解 # (error 会让人以为构建挂了,与播报定位直接冲突)。真正的红留在 `release-publish.yml` 的签名步: # 那里今天必然红是**对的**,因为签不出来的产物本来就不能发。 # ② 文件名/名字都不带 guards、check 字样:它不是守卫,是一条状态播报。 # ③ 本文件**刻意不声明 `workflow_call:`**:没有这个触发器,别的 workflow 就没法 `uses:` 它 —— # 「不能被接进 dev 线变成必需检查」是一条机制,不是一句嘱咐。接线自检另外扫全部 workflow, # 任何 `uses: …/signing-status.yml` 出现即红(防的是有人先加 workflow_call 再接进来)。 # # 判据本体与 0/1/2 的语义:`packaging/check_signing_ready.py` 的文件头; # 人类要做的那几步:`packaging/docs/signing-runbook.md`。 on: push: branches: [main] pull_request: workflow_dispatch: permissions: contents: read jobs: # 尺子自测:它红 = **判据脚本坏了**(不是「签名没就绪」)。两者措辞在 summary 里分开写。 # 这一步照常会红,因为「尺子坏了」本来就该有人看见 —— 但它不阻断任何东西:本 workflow 独立、 # 非必需,也不在 `dev-guards.yml` 的 `uses:` 里。 selftest: name: 判据自测(三行/退出码/变异重放/接线) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 三行读数 + 0/1/2 语义 + 「退出码改绿必须被抓到」+ 接线不是门禁 run: python3 packaging/tests/signing_ready_selftest.py - name: 真跑三种情形(今天的状态 / 假 PinnedKey 副本 / 用法错) run: | set -uo pipefail work="$RUNNER_TEMP/signing-ready" mkdir -p "$work" # 结论只打印,不判定:这里要的是「三种情形各自的退出码与三行读数长什么样」, # 判据在上一跑的 selftest 里。所有 `|| true` 只为让这一步本身不变红。 run_and_show() { # run_and_show <说明> <命令...> note="$1"; shift echo "── $note" python3 packaging/check_signing_ready.py "$@" 2>&1 || true echo } run_and_show "今天的状态(真实 trust.rs:表空 ⇒ 未就绪)" # 副本夹一条假 PinnedKey(**不碰真实 trust.rs**):造出「就绪」的正路长什么样。 python3 - "$work" <<'PY' import sys from pathlib import Path trust = Path("crates/core/src/update/trust.rs").read_text(encoding="utf-8") begin = trust.index(">>> PINNED-KEYS >>>") + len(">>> PINNED-KEYS >>>") end = trust.index("<<< PINNED-KEYS <<<") fake = ' PinnedKey { key_id: "demo-not-a-real-key", public_key_hex: "' + "ab" * 32 + '" },\n' Path(sys.argv[1], "trust-with-fake-key.rs").write_text( trust[:begin] + "\n" + fake + trust[end:], encoding="utf-8" ) PY run_and_show "副本夹一条假 PinnedKey(②仍缺钥 ⇒ 仍未就绪,但 ① 会变就绪)" \ --trust "$work/trust-with-fake-key.rs" run_and_show "用法错(不存在的 trust.rs ⇒ 2)" --trust "$work/nope/trust.rs" || true # 播报:只把三行搬进 job summary,不看颜色。 status: name: 签名就绪度(播报) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # ② 要读「环境里有没有钥」,所以把 Secret 传进来(与 release-publish.yml 的做法一致)。 # 脚本只回显 key_id 与**公钥**,种子(seed_hex)一个字节都不打印 —— 用例 no_seed_leak 钉着这条。 - name: 三行就绪度(脚本给 0/1/2;本步恒 exit 0) env: ULL_MANIFEST_SIGNING_KEY: ${{ secrets.ULL_MANIFEST_SIGNING_KEY }} run: | set -uo pipefail set +e python3 packaging/check_signing_ready.py --line > "$RUNNER_TEMP/signing-ready.txt" 2>&1 rc=$? set -e cat "$RUNNER_TEMP/signing-ready.txt" case "$rc" in 0) echo "::notice::签名就绪:信任表非空,且环境里的钥与它同源。这是一条播报,不是门禁。" ;; 1) echo "::warning::签名未就绪:今天任何正式二进制都验不过任何清单(fail-closed)。该做什么见 packaging/docs/signing-runbook.md §2 的下单清单。" ;; *) echo "::warning::就绪度脚本用不了(rc=$rc,用法错):这是尺子的问题,不是签名状态 —— 看上面的 stderr。" ;; esac { echo echo "- 本 workflow 是**播报**,不是门禁:**不应被设为 required**,也不阻断任何其它 job。" echo "- 颜色 ≠ 结论:绿色只说明脚本跑完了;结论只看上面三行(尤其 ①「信任表」)。" echo "- fork / Dependabot 的 PR 运行拿不到仓库 Secret ⇒ ② 必然是「未就绪」;以 main 上的运行为准。" echo "- 真门禁在哪:\`release-publish.yml\` 的签名步(\`--check-pinned-keyring\` / \`--sign\` / \`--verify-pinned\`)。" } >> "$GITHUB_STEP_SUMMARY" exit 0