feat(privacy): 关掉昵称脱敏 —— 脱敏有损,撞名就分不出博主
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s

需求:评论栏/作品栏要能分清是哪个博主。修好分组字段之后名字仍带星号,因为上游作为
教学版默认对昵称做中间脱敏(首尾各留 1 字,中间星号)。这个脱敏是**有损**的:

  「张三」和「张四」都变成「张*」
  「小明老师」和「小刚老师」都变成「小***师」

而本仓库的用途是监控一批公开创作者账号,分清谁是谁正是这一层要干的事。所以关掉它。

* config/base_config.py 新增 MASK_NICKNAME = False(和 INJECT_ALL_COOKIES 一样是个
  开关,不是删代码 —— 改回 True 就恢复上游行为)。
* tools/user_hash.py 的 mask_nickname 读这个开关,关闭时原样返回。读的是模块属性而
  不是导入值,测试才能 monkeypatch。脱敏实现本身一字未动。
* 顺带修一个数据陈旧问题:评论是去重后直接 continue 的,昵称只在首次入库时写一次,
  于是开关一改(或评论者改名)老评论永远停在旧值 —— 而重采是唯一能拿到新值的途径。
  现在已存在的评论会跟着刷新昵称(作品那边的 creator_name 早就是这么做的)。
* anonymous 的 creator_hash 保持不变:那是分组用的稳定键,不是显示名。

测试:
* 三个隐私套件 + weibo 的 autouse fixture 强制把开关打开 —— 它们验的是**脱敏机制
  本身**,机制仍然必须正确,所以显式打开来测,而不是让它们随部署配置漂。
* test_mask_and_hash_tools 改成两个方向都覆盖(开着脱敏 / 关着脱敏)。
* test_tieba_extractor.py 里 8 处字面量的脱敏期望值换成真实昵称 —— 提取器现在就是
  返回原文的,期望值理应跟着改(这一条是行为变更的直接后果,不是测试放宽)。
* 新增一条:已入库的评论昵称会随重采刷新(且不会因刷新而重复插入)。
This commit is contained in:
2026-10-10 15:48:15 +08:00
parent 67837b407e
commit cd85587f00
10 changed files with 129 additions and 14 deletions
+32
View File
@@ -698,3 +698,35 @@ class TestDouyinIngest:
await ingest_run(db, run2, task, tmp_path)
assert len(await _events(db, EVENT_METRIC_DELTA)) == 1
class TestNicknameRefresh:
"""已入库的评论,昵称要跟着重新采集的值走。
评论是去重后直接跳过的,若不刷新,脱敏开关一改(或评论者改了昵称),老数据就永远
停在旧值上 —— 而重采是唯一能拿到新值的途径。
"""
@pytest.mark.asyncio
async def test_an_existing_comment_gets_its_nickname_refreshed(self, db, tmp_path):
task = await _make_task(db)
_write_run_dir(tmp_path, [_note("n1")], comments=[_comment("c1", "n1", 500)])
run1 = await _make_run(db, task, started_at=1)
await ingest_run(db, run1, task, tmp_path)
assert (await db.scalar(select(MonitorComment))).nickname == "u***r"
_write_run_dir(
tmp_path,
[_note("n1")],
comments=[_comment("c1", "n1", 500, nickname="未脱敏的新昵称")],
)
run2 = await _make_run(db, task, started_at=2)
await ingest_run(db, run2, task, tmp_path)
comment = await db.scalar(select(MonitorComment))
assert comment.nickname == "未脱敏的新昵称"
# 去重的语义没变:同一条评论不该被插成两行。
assert (
len(list((await db.scalars(select(MonitorComment))).all())) == 1
)