#!/usr/bin/env python3 # -*- coding: utf-8 -*- """交付脱敏 (发给非业主方时用): 把事实契约的**内部面**标题换成已有的脱敏公开标题, 重算逐条 sha 与契约 sha, 重出四个消费者, 再自校验. 契约本来就带 display.title_zh_public (BANNED 替换后的), 四个消费者也早已 BANNED 零命中; 只有 display.title_zh 这一处内部面留了原文。 用法: python scripts/deliver_desensitize.py --stage <暂存目录> (不动正本; 打包时用暂存目录里的这几个文件覆盖)""" from __future__ import annotations import argparse, importlib, json, shutil, sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1]; sys.path.insert(0, str(ROOT / "scripts")) def main(): ap = argparse.ArgumentParser(); ap.add_argument("--stage", required=True); a = ap.parse_args() stage = Path(a.stage).resolve(); (stage / "derived").mkdir(parents=True, exist_ok=True) m = importlib.import_module("guanlan_facts_contract") con = json.loads(m.CONTRACT.read_text(encoding="utf-8")) n = 0 for c in con["claims"]: d = c["display"] if d.get("banned_hits"): d["title_zh"] = d["title_zh_public"]; d["banned_hits"] = 0; n += 1 c["sha256"] = m.sha(m.canon({k: v for k, v in c.items() if k != "sha256"}).encode("utf-8")) con["banned_hits_total"] = 0; con["face"] = "delivery (标题已脱敏; 场名/台号保留 —— 那是本场自己的数据)" con["contract_sha256"] = m.sha(m.canon({k: v for k, v in con.items() if k not in ("contract_sha256", "built", "git_head")}).encode("utf-8")) cp = stage / m.CONTRACT.name; cp.write_text(json.dumps(con, ensure_ascii=False, indent=1), encoding="utf-8") # 用暂存路径重出消费者并自校验 (证明脱敏后整条链仍自洽) m.CONTRACT, m.DERIVED = cp, stage / "derived" m.render(con, m.DERIVED); bad = m.check() print(f"脱敏 {n} 条标题; 契约 sha {con['contract_sha256'][:16]}; 消费者重出 {len(list((stage / 'derived').glob('*')))} 个; 自校验 {'通过' if not bad else bad[:3]}") return 0 if not bad else 2 if __name__ == "__main__": sys.exit(main())