docs(core): M240 复审 P2-1/P2-2/P2-3 —— 口径收窄、大写判据钉住、找回丢掉的负例
P2-1:「抹除能力没有下降」是绝对承诺,已改成准确口径——收窄的就是三类形状 (`=` 边界、填充不计段长、全小写点分串),每条都在 shape 模块文档里写明,并用 `known_narrowings_old_masked_new_keeps` 把「旧行为抹、新行为留」钉住。三条的旧行为 是用 M240 之前的真实代码(`git show 74be510:…` + rustc 探针)实测的,不是推断。 P2-2:「必须含大写」原先没有任何测试钉住(复审实测:删掉它 13 条仍全绿)。 查明原因:DNS 形状的全小写点分串早就被"首段是主机名"那条豁免救下,大写判据 只对**非 DNS 形状**的全小写点分串承担区分作用(标签带 `_`、标签超 63 字符、 `/` 前只有一段主机名)。选择保留(复审的 (b)),并补 `the_uppercase_requirement_is_load_bearing`(`sophisticated_backpacks.upgrades.reference` 等两条)——删掉判据 → 该测试与 `lowercase_dotted_names_are_spared` 红、其余 15 条绿。 同时改正事实错误:不是"第三段必为大写",而是头的 base64url **第三个字符**恒为 `ey` + `I/J/K/L`(`7B 22 xx` 的第三组 6 位 = `b1` 低 4 位 ++ `b2` 高 2 位 → 索引 8..11)。 P2-3:找回重构时丢掉的老负例 `dotted_token_rule_does_not_eat_normal_text` (4 条用例 + 直接断言 `!has_dotted_token(...)`,含 `eyJhbGciOiJIUzI1NiJ9.short.abc`); 语料测试的 doc 注明它**只守一个方向**,不得当"正例仍被抹"的背书。 判据与阈值一个字没动(40 / 3×8 / 64),扫描器代码零改动,纯文档 + 测试。
This commit is contained in:
1 parent
43f77d8865
commit
66929786c0
3 files changed
+123
-11
No files matched your search
@@ -112,6 +112,20 @@ fn brand_and_property_strings_survive() {
|
||||
}
|
||||
}
|
||||
|
||||
/// 老规则的负例(M240 重构时被丢掉过,复审 P2-3 要求找回):分段太短 / 总长不够 / 段数不够。
|
||||
#[test]
|
||||
fn dotted_token_rule_does_not_eat_normal_text() {
|
||||
for text in [
|
||||
"Service.Unavailable.today",
|
||||
"1.2.0",
|
||||
"xbl.xsts.entitlements.profile",
|
||||
"eyJhbGciOiJIUzI1NiJ9.short.abc",
|
||||
] {
|
||||
assert!(!has_dotted_token(text), "{text}");
|
||||
assert_eq!(scrub(text), text, "{text}");
|
||||
}
|
||||
}
|
||||
|
||||
/// 整条 HMCL 形状的 argv(`--dry-run` 的面):一处都不许动。
|
||||
#[test]
|
||||
fn hmcl_shaped_argv_survives_verbatim() {
|
||||
@@ -156,6 +170,9 @@ fn long_paths_and_class_paths_survive() {
|
||||
}
|
||||
|
||||
/// 语料组:M239 的回归语料,形状规则**一行都不许改**。
|
||||
///
|
||||
/// **只守一个方向**:它证明"该保留的保留了",**不能**拿来背书"正例仍被抹"——正例那一方向
|
||||
/// 由 `jwts_are_masked_in_every_log_shape` / `opaque_secrets_are_masked_in_every_log_shape` 显式断言。
|
||||
#[test]
|
||||
fn sample_corpus_is_untouched() {
|
||||
let files = corpus_files();
|
||||
@@ -225,6 +242,65 @@ fn url_host_is_exempt_but_the_path_half_is_still_judged() {
|
||||
assert_eq!(scrub(url), url);
|
||||
}
|
||||
|
||||
/// 「旧行为抹、新行为留」的三类形状(复审 P2-1:口径写准,别留"抹除能力没有下降"的绝对承诺)。
|
||||
///
|
||||
/// 三条都用 **M240 之前的真实代码**(`git show 74be510:crates/core/src/launch/redact.rs` 直接
|
||||
/// 用 rustc 编成探针)实测过:旧行为输出 `<redacted:token>`,现在逐字原样。前两条是本次要修的
|
||||
/// 误杀本身,第三条是全小写点分串的代价(理由见 `shape` 模块文档的「旧行为抹、新行为留」)。
|
||||
#[test]
|
||||
fn known_narrowings_old_masked_new_keeps() {
|
||||
// ① `=` 边界:键把值带过线(旧行为把 `键=值` 粘成一段凑够段数)
|
||||
let brand = "-Dminecraft.launcher.brand=UnluckyLauncher";
|
||||
assert_eq!(scrub(brand), brand, "旧行为:<redacted:token>");
|
||||
// ② 填充不算段长:末段实际 6 字符(旧行为把 `c2lnbm==` 算成 8 ≥ 8 → 抹)
|
||||
let padded = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.c2lnbm==";
|
||||
assert_eq!(scrub(padded), padded, "旧行为:<redacted:token>");
|
||||
// ② 的另一侧:末段 8 字符仍照抹(占位符在前、填充留在外面)
|
||||
assert_eq!(
|
||||
scrub("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.c2lnbmFy=="),
|
||||
format!("{TOKEN_PLACEHOLDER}==")
|
||||
);
|
||||
// ③ 全小写点分串:DNS 形的靠主机名豁免、非 DNS 形的靠"必须含大写"(旧行为都会抹)
|
||||
let lowercase = "sophisticatedbackpacks.upgrades.reference";
|
||||
assert_eq!(scrub(lowercase), lowercase, "旧行为:<redacted:token>");
|
||||
}
|
||||
|
||||
/// "必须含大写"这条判据**自己**在扛的用例(复审 P2-2 的 (b))。
|
||||
///
|
||||
/// 先划清它的实际覆盖面(复审的怀疑是对的):**DNS 形状**的全小写点分串(`a.b.c` 全小写)
|
||||
/// 已经被 [`is_dns_host`] 那条主机名豁免救下了,跟大写判据无关。大写判据唯一扛住的是
|
||||
/// **不是 DNS 形状**的全小写点分串——例如标签里带 `_`(Java 标识符常见写法)、标签超 63 字符、
|
||||
/// 或 `/` 之前只有一段主机名。下面就是这一类。
|
||||
///
|
||||
/// 删掉 `jwt_shaped` 里那条大写判据,**这条测试与 `lowercase_dotted_names_are_spared` 会红,
|
||||
/// 其余 15 条仍绿**(M240 复审实测:删判据 → 15 passed / 2 failed)。
|
||||
#[test]
|
||||
fn the_uppercase_requirement_is_load_bearing() {
|
||||
for text in [
|
||||
"sophisticated_backpacks.upgrades.reference", // 41 字符,段长 23/8/9,标签带 `_`
|
||||
"spongepowered_mixins.injections.callback", // 40 字符,段长 20/10/8,标签带 `_`
|
||||
] {
|
||||
assert_eq!(
|
||||
scrub(text),
|
||||
text,
|
||||
"全小写、非 DNS 形状的点分串被抹(大写判据失效?):{text}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 全小写点分串整体都不该被抹(两类出口各管一半,测试分开写以免把功劳记错):
|
||||
/// DNS 形的靠主机名豁免,非 DNS 形的靠"必须含大写"。
|
||||
#[test]
|
||||
fn lowercase_dotted_names_are_spared() {
|
||||
for text in [
|
||||
"sophisticatedbackpacks.upgrades.reference", // DNS 形状 → 主机名豁免
|
||||
"libraries.minecraftservices.entitlements", // DNS 形状 → 主机名豁免
|
||||
"sophisticated_backpacks.upgrades.reference", // 非 DNS → 大写判据
|
||||
] {
|
||||
assert_eq!(scrub(text), text, "全小写点分串被抹:{text}");
|
||||
}
|
||||
}
|
||||
|
||||
/// 两个入口必须一致:`scrub` 用 `has_*` 当闸门,闸门关着就永远不会调 `mask_*`。
|
||||
#[test]
|
||||
fn the_has_gate_agrees_with_the_maskers() {
|
||||
|
||||
Reference in new issue
Block a user