fix(m200-r1): 文档降到实测能撑的程度 + 守门收紧 core 声明内容(复审 P2-1 / P3-1)

复审 reviewer-presenterfix-r1 的 fix-then-merge 两条,逐条落地。

P2-1(a)「两档」措辞被本次提交自己作废 ⇒ 三处全改成三档:
* `crates/core/src/update/trust.rs` 模块文档(读者最先看到的那句,上次漏了)
* `crates/core/src/update/tests/support_sign.rs` 模块文档 + `TEST_SIGNING_SEED` 的文档

P2-1(b)「三者都进不了发布产物」被复证实测证伪(`cfg!()` 是运行时假分支,不是 `#[cfg]`
编译期剔除;无 feature 的 dev 与 --release 两档 core rlib 里公钥十六进制与 `test-only-key` 都在)
⇒ 降级到事实能撑的断言:「不会被 `keyring()` 并进信任表,正式构建永远不认这把测试钥」,
并明写「字节仍编在产物里」「字节级不在产物里未证、也未声称」「换 `#[cfg]` 是另一条结构性改动」。
没有换成 `#[cfg]`(那是复审建议另开的 mission)。

P3-1 守门对 core「自己的声明」只认形状 ⇒ 收紧为只许空数组:
`DECLARATION` 从 `^\s*update-test-key\s*=\s*\[` 改成 `^\s*update-test-key\s*=\s*\[\s*\]\s*$`,
并加一条自检向量(core 声明里偷偷带子 feature ⇒ 必须红)。`--self-test` 从 6 条变 7 条
(5 红 / 2 绿)+ 基线,`packaging/README.md` 的计数同步。

⚠ 一个自己踩出来的坑,已被既有守门抓住:收紧时我先在 `check_test_key_off.py` 里把那条更宽的
测试通道 feature 写成**字面量**(自检向量 + 文档表格),`check_test_source_off.py` 立刻红
(`packaging/**` 按字面扫,这次提交前它一直是绿的)。改法照该文件自己的声明办——用
`OTHER_FEATURE = "-".join(("update", "test", "source"))` 拼出来,源码里字面量为 0,
自检向量仍然构造出完整字符串并必须判红。

验证(均在最终树上):`cargo test --workspace --all-targets` 0、`cargo fmt --all --check` 0、
`check_test_key_off.py --self-test` 0(7 向量)/ 正式扫描 0、`check_test_source_off.py` 0、
`check_workflows_yaml.py` 0。
This commit is contained in:
AskaEth committed 2026-11-09 07:56:33 +08:00
1 parent 528f5706a0
commit 540b82e197
4 files changed
+36 -14

No files matched your search

+4 -4
View File
@@ -5,15 +5,15 @@
//!
//! 签名走 `ed25519-dalek` 的 `SigningKey`(与仓里验签用的 `verify_strict` 同一棵树),而**不是**
//! 自写实现——M190 r1 复审把自写曲线算术整体删掉了,这里也不留第二条算法。测试钥的种子是公开的
//! (见下),它只对 `cfg(test)` 与 `update-test-source` 构建有意义。
//! (见下),它只对 `cfg(test)` / `update-test-source` / `update-test-key` 三档构建有意义。
use super::support::TempDir;
/// 测试签名钥的 32 字节种子。
///
/// **它是公开的,故意不保密**:它只对 `cfg(test)` 与 `update-test-source` 构建有意义
/// (`trust::TEST_ONLY` 才认这把钥),正式构建的信任表里没有它,所以拿它签不出任何正式版本
/// 能装的清单。正式私钥只能来自仓库 Secret(见 `packaging/docs/signing.md`)。
/// **它是公开的,故意不保密**:它只对 `cfg(test)` / `update-test-source` / `update-test-key` 三档
/// 构建有意义(`trust::TEST_ONLY` 才认这把钥),正式构建的信任表里没有它,所以拿它签不出任何正式
/// 版本能装的清单。正式私钥只能来自仓库 Secret(见 `packaging/docs/signing.md`)。
pub(crate) const TEST_SIGNING_SEED: &[u8; 32] = b"ull-m190-test-key-seed-000000001";
/// 测试钥的 `key_id`(与 `trust::TEST_ONLY` 里那条一致)。
+14 -6
View File
@@ -35,10 +35,12 @@
//! # ② 把打印出来的 `PinnedKey { … }` 一行贴到下面 PINNED-KEYS 标记之间
//! ```
//!
//! 测试/验收构建另有一把**只在** `cfg(test)` 与 `update-test-source` feature 里存在的测试钥:
//! 它的私钥种子就写在测试夹具里、公开可见,因此它可以签出「本仓库自己认得」的清单,但对任何正式
//! 构建毫无意义(正式表里没有它)。这条也由 `packaging/check_test_source_off.py` 的同一道闸守着
//! ——正式发布流水线与打包脚本都不许打开 `update-test-source`。
//! 测试/验收构建另有一把**只在** `cfg(test)` / `update-test-source` / `update-test-key` 三档里存在的
//! 测试钥(三档的口径见下面 `keyring()`):它的私钥种子就写在测试夹具里、公开可见,因此它可以签出
//! 「本仓库自己认得」的清单,但对任何正式构建毫无意义(正式表里没有它,`keyring()` 也不会把它并进
//! 信任表)。后两档(那两个 feature)各由 `packaging/check_test_source_off.py` /
//! `check_test_key_off.py` 守着 ——正式发布流水线与打包脚本都不许打开它们。
//! (`cfg(test)` 那档不需要守门:发布构建里根本没有 `test` cfg。)
use std::sync::OnceLock;
@@ -80,8 +82,14 @@ pub(crate) const TEST_ONLY: &[PinnedKey] = &[PinnedKey {
/// | `update-test-source` | CLI 的端到端验收(`--features update-test-source`) | 那是**另一个 target**,`cfg(test)` 不生效 |
/// | `update-test-key` | `crates/presenter` 的 `[dev-dependencies]` | presenter 的更新链路用例编译 core 时既无 `cfg(test)`,也不该打开 `update-test-source`(那条会同时给出「本地目录当更新源」这条路)。这一档**只**加一把公开的测试公钥,不开任何数据源开关 |
///
/// 三者都进不了发布产物:`PRODUCTION` 之外没有任何路径能把 `TEST_ONLY` 带进 `--release` 构建
/// (官方构建三个 feature 都不开,且 `check_test_source_off.py` / `check_test_key_off.py` 守着)。
/// 三者都**不会被 `keyring()` 并进信任表**:正式构建永远不认这把测试钥(官方构建三个 feature 都不开,
/// 且 `check_test_source_off.py` / `check_test_key_off.py` 守着)。
///
/// ⚠ **别把这句话读成「产物里没有这段字节」**:这里的门是 `cfg!()`,它只让分支**不可达**,不是
/// `#[cfg]` 的编译期剔除 —— `TEST_ONLY` 的**字节**照编在产物里(实测:无 feature 的 dev 与
/// `--release` 两档 core rlib 里,公钥十六进制与 `test-only-key` 都还在)。「字节级不在产物里」
/// 这一点**未证**、也未在此声称;它与「装不上公开种子签出来的清单」无关(信任表里没有它,验签仍
/// fail-closed)。要换成 `#[cfg]` 让字节真的消失,是另一条结构性改动。
pub(crate) fn keyring() -> &'static [PinnedKey] {
static ALL: OnceLock<Vec<PinnedKey>> = OnceLock::new();
ALL.get_or_init(|| {