test(presenter): 坏清单用例按错误分类区分「JSON 坏」与「签名被拒」
台账 §10 第 7 条 / M199 复审 P3-2:原来只断言「结果是 Failed」,而它喂的每一份清单都签对了 ——验签一旦 fail-open 或签名错误被误分类,这条用例照样绿。 现在两组各钉自己的分类: - 内容坏(5 个变体,签名都对):kind 必须是 invalid_manifest / invalid_version; - 字节好、只有签名对不上(放行就会报「有更新 0.9.0」):kind 必须是 signature_invalid 且不可重试。 变异证明(只改实现侧,跑完已还原): - A core::update::signature::verify_manifest fail-open → ② 分支红,实际 Available(0.9.0); - B core::update::manifest::from_json 把解析失败误分类成 SignatureInvalid → ① 分支红, 「not json:坏内容分类是 signature_invalid」。 两个变异各只打红对应分支,说明两类坏输入确实各走各的分类。 文件仍在 400 行红线内(394 行)。
This commit is contained in:
1 parent
06fcbb8a51
commit
133f14ba0b
1 file changed
+31
-10
@@ -6,7 +6,7 @@
|
||||
//! | 用例 | 守什么 |
|
||||
//! |---|---|
|
||||
//! | [`version_matrix_decides_who_gets_prompted`] | 版本更高才提示;同版本/更低一律不提示;`v0.2.3` 这类真实 tag 形态 |
|
||||
//! | [`a_broken_manifest_degrades_to_failure_not_up_to_date`] | 清单坏 JSON → 「检查失败」,**不是**「已是最新」 |
|
||||
//! | [`a_broken_manifest_degrades_to_failure_not_up_to_date`] | 坏 JSON → `invalid_*`、签名被拒 → `signature_*`;两种都是「检查失败」,**不是**「已是最新」 |
|
||||
//! | [`a_higher_version_without_our_platform_is_not_up_to_date`] | 有新版但没本平台产物 → 单独的变体 |
|
||||
//! | [`sha256_mismatch_refuses_the_apply_and_leaves_no_temp_file`] | 摘要不符拒绝应用、暂存文件不残留、目标没被换掉 |
|
||||
//! | [`a_successful_apply_leaves_the_new_file_and_a_backup`] | 换上去的是新字节、旧字节留在备份里、回报是「就位」 |
|
||||
@@ -191,11 +191,16 @@ fn version_matrix_decides_who_gets_prompted() {
|
||||
|
||||
// ------------------------------------------------------------- 清单契约降级
|
||||
|
||||
/// 坏 JSON / 缺字段 ⇒ **检查失败**,绝不是「已是最新」。
|
||||
/// 坏 JSON / 缺字段 / 签名被拒 ⇒ **检查失败**,绝不是「已是最新」;而且两种坏法**分类不同**。
|
||||
///
|
||||
/// 两个变体的文案与后果完全不同:说成「已是最新」会让用户以为网络通、版本新,实际一个字节都没取到。
|
||||
/// M199 复审 P3-2:旧版只断言「结果是 Failed」,而它喂的清单都**签对了**——验签一旦 fail-open,
|
||||
/// 坏签名清单会一路走到解析,坏 JSON 照样解析失败,断言全绿。现在内容坏必须落 `invalid_*`,
|
||||
/// 签名坏必须落 `signature_*` 且不可重试。
|
||||
/// 抓得住:验签被跳过/放行(② 会拿到 `Available 0.9.0`)、签名与解析互相误分类、失败被折叠成「已是最新」;
|
||||
/// 抓不住:签名算法细节(信封字段、`manifest_sha256` 冗余校验、钥表)——那在 core 的 `signature_cases.rs`。
|
||||
#[test]
|
||||
fn a_broken_manifest_degrades_to_failure_not_up_to_date() {
|
||||
// ① 签名是对的(`write_manifest` 成对落盘),内容坏:分类只能是「清单结构 / 版本号不合法」。
|
||||
for (label, manifest) in [
|
||||
("not json", "{ this is not json".to_string()),
|
||||
(
|
||||
@@ -221,16 +226,32 @@ fn a_broken_manifest_degrades_to_failure_not_up_to_date() {
|
||||
let tmp = TempDir::new("badmanifest");
|
||||
write_manifest(&tmp, &manifest);
|
||||
let outcome = outcome_of(job(&tmp).check(&version("0.2.2"), Channel::Stable));
|
||||
let Some(failure) = outcome.failure() else {
|
||||
panic!("{label}:坏清单必须降级成「检查失败」,实际 {outcome:?}");
|
||||
};
|
||||
let kind = failure.kind.as_str();
|
||||
assert!(
|
||||
matches!(outcome, UpdateOutcome::Failed(_)),
|
||||
"{label}:坏清单必须降级成「检查失败」,实际 {outcome:?}"
|
||||
);
|
||||
let failure = outcome.failure().expect("失败带原因");
|
||||
assert!(
|
||||
!failure.message.trim().is_empty(),
|
||||
"{label}:失败要有人话原因"
|
||||
matches!(kind, "invalid_manifest" | "invalid_version"),
|
||||
"{label}:坏内容分类是 {kind}"
|
||||
);
|
||||
assert!(!failure.message.trim().is_empty(), "{label}:失败没原因");
|
||||
}
|
||||
// ② 清单字节是好的(放行就会报「有更新 0.9.0」),只有签名对不上:必须落 `signature_invalid`。
|
||||
let tmp = TempDir::new("badsignature");
|
||||
tmp.write(
|
||||
"dist/stable.json",
|
||||
manifest_for("0.9.0", b"new", "").as_bytes(),
|
||||
);
|
||||
tmp.write(
|
||||
"dist/stable.json.sig",
|
||||
signature_envelope("another").as_bytes(),
|
||||
);
|
||||
let outcome = outcome_of(job(&tmp).check(&version("0.2.2"), Channel::Stable));
|
||||
let Some(failure) = outcome.failure() else {
|
||||
panic!("签名验不过必须拒装(放行就会报「有更新 0.9.0」),实际 {outcome:?}");
|
||||
};
|
||||
assert_eq!(failure.kind, "signature_invalid", "签名被拒的分类");
|
||||
assert!(!failure.retryable, "签名问题不可重试");
|
||||
}
|
||||
|
||||
/// 清单里**一条发布都没有**(`{"channel":"stable"}` / 空 `releases`)⇒ 已是最新,不是失败。
|
||||
|
||||
Reference in new issue
Block a user