From d177289a53bad13ede3f7ff7c42d795bdcd61982 Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Mon, 12 Oct 2026 14:19:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=85=A5=20M2=20=E4=B8=8E=20K3b=20?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E7=9A=84=E6=95=B4=E5=90=88=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=EF=BC=9A=E6=8A=A5=E5=91=8A=E8=87=AA=E6=9F=A5=E3=80=81=E8=A3=81?= =?UTF-8?q?=E5=88=A4=E6=91=98=E5=BD=95=E3=80=81=E6=94=B6=E9=81=AE=E7=BD=A9?= =?UTF-8?q?=E5=80=BC=E8=AE=A4=E3=80=8C=E7=A1=AE=E5=AE=9A=E5=8F=96=E8=87=AA?= =?UTF-8?q?=E9=81=AE=E7=BD=A9=E5=88=97=E3=80=8D=E6=97=B6=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E7=94=A8=20masking.=5Fderived=5Fmasks=20=E4=BA=A4=E5=9B=9E?= =?UTF-8?q?=E7=9A=84=20whole=20/=20collect=EF=BC=8C=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E5=9C=A8=E7=BB=93=E6=9E=9C=E5=90=8E=E9=9D=A2=E5=9E=AB=E4=B8=80?= =?UTF-8?q?=E5=88=97=E5=8E=BB=E6=8E=A2=E6=B5=8B=E6=95=B4=E4=BB=BD=E7=AE=97?= =?UTF-8?q?=E2=80=94=E2=80=94K3b=20=E6=8A=8A=E3=80=8C=E6=B2=A1=E6=9C=89=20?= =?UTF-8?q?*=20=E7=9A=84=E4=B8=80=E6=94=AF=E3=80=81=E5=88=97=E6=95=B0?= =?UTF-8?q?=E5=92=8C=E7=BB=93=E6=9E=9C=E5=AF=B9=E4=B8=8D=E4=B8=8A=E3=80=8D?= =?UTF-8?q?=E4=B9=9F=E5=88=A4=E6=95=B4=E4=BB=BD=E4=B9=8B=E5=90=8E=EF=BC=8C?= =?UTF-8?q?=E5=9E=AB=E8=BF=87=E7=9A=84=E6=AF=8F=E6=9D=A1=20SQL=20=E9=83=BD?= =?UTF-8?q?=E6=88=90=E4=BA=86=E6=95=B4=E4=BB=BD=E7=AE=97=EF=BC=8C=E6=B2=A1?= =?UTF-8?q?=E8=B5=B7=E5=88=AB=E5=90=8D=E7=9A=84=20UPPER(phone)=20=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E5=80=BC=E9=83=BD=E6=94=B6=E4=B8=8D=E5=88=B0=E3=80=81?= =?UTF-8?q?=E8=A3=81=E5=88=A4=E6=91=98=E5=BD=95=E9=87=8C=E7=85=A7=E7=BB=99?= =?UTF-8?q?=E5=8F=B7=E7=A0=81=E3=80=81=E5=BC=95=E7=94=A8=E5=AE=83=E7=9A=84?= =?UTF-8?q?=E6=8A=A5=E5=91=8A=E7=85=A7=E5=B8=B8=E5=87=BA=E5=85=B7=EF=BC=9B?= =?UTF-8?q?UNION=20=E5=90=8E=E4=B8=80=E6=94=AF=E6=98=AF=20*=20=E7=9A=84?= =?UTF-8?q?=E5=86=99=E6=B3=95=E4=B9=9F=E4=B8=80=E5=B9=B6=E8=AE=A4=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/evidence.py | 38 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/backend/app/api/evidence.py b/backend/app/api/evidence.py index 0c31b5e7..ba70c763 100644 --- a/backend/app/api/evidence.py +++ b/backend/app/api/evidence.py @@ -1662,12 +1662,13 @@ def _sure(snap: dict[str, Any], base: set[str], kind: str | None, """(能确定取自遮罩列的结果列, 只装着分档标签的列),都是小写(_MaskSets.sure):收遮罩值、交给裁判的摘录、报告自查 都从前一项起。 - 按数据源自己的方言认(masking._derived_hidden,交回要遮的列和 SQL 里指代遮罩列的名字):结果列名就是遮罩列、SQL 里 - 指代遮罩列的名字(c.phone AS tel 的 tel、UPPER(phone) AS p 的 p)、没起别名却按位置认得出取自遮罩列的 - (SELECT UPPER(phone) FROM customers)都算。认不准时那一套把整份的列都算上(派生来源里没起别名的表达式、PIVOT、SQL - 解析不了又写着遮罩列……):这样整份算进来的(_whole),只认名字对上的那几列——展示上多遮无妨,这里多算,自查就判 - 失败、写作者也改不掉(最大的一笔订单金额被说成取自手机号),区域名、金额也被收成遮罩值。以前凡是要遮的列盖住了全部 - 结果列、名字又对不上的都当整份算,按位置认得出的那一列也丢了,一个值都收不到(复核第 4 轮)。 + 按数据源自己的方言认(masking._derived_masks,工具边界遮的那一套):结果列名就是遮罩列、SQL 里指代遮罩列的名字 + (c.phone AS tel 的 tel、UPPER(phone) AS p 的 p)、没起别名却按位置认得出取自遮罩列的(SELECT UPPER(phone) FROM + customers)都算。认不准时那一套整份遮(whole:派生来源里没起别名的表达式、PIVOT、SQL 解析不了又写着遮罩列……), + 这时只认它的 collect——名字对上的、整份算之前已按位置认出的那几列。展示上多遮无妨,这里多算,自查就判失败、写作者 + 也改不掉(最大的一笔订单金额被说成取自手机号),区域名、金额也被收成遮罩值。整份算不算以那一套交回的 whole 为准: + 以前在结果后面垫一列再认一遍来探测,那一套把「没有 * 的一支、列数和结果对不上」也判整份之后,垫过的每条 SQL 都成了 + 整份算,按位置认得出的列一个都收不到(合入 K3b 之后的复核)。 只装着分档标签的列(CASE WHEN phone IS NULL THEN '未留' ELSE '已留' END)格子里是 SQL 写死的字,不算;只数个数的 (COUNT(*) FILTER (WHERE phone IS NULL)、SUM(phone IS NULL))先改写成那一套认得出的样子再认(_counted)。 出了意外只认列名对上的。""" @@ -1676,14 +1677,10 @@ def _sure(snap: dict[str, Any], base: set[str], kind: str | None, if not base or not columns: return direct, {} try: - from app.engine.masking import _derived_hidden, _snapshot_labels + from app.engine.masking import _derived_masks, _snapshot_labels - counted = _counted(snap, kind) - found, names = _derived_hidden(counted, set(base), kind, tables) - found &= columns - named = (names & columns) | direct - whole = columns <= found and not columns <= named and _whole(counted, base, kind, tables) - sure = named if whole else found | direct + found = _derived_masks(_counted(snap, kind), set(base), kind, tables) + sure = ((found.collect if found.whole else found.hidden) & columns) | direct labels = _snapshot_labels(snap, kind) return sure - {name for name in labels if name not in base}, labels except Exception: # noqa: BLE001 - 认不准:只认列名对上的 @@ -1691,21 +1688,6 @@ def _sure(snap: dict[str, Any], base: set[str], kind: str | None, return direct, {} -#: _whole 垫在结果列后面的一列:SQL 里的名字不会是它 -_PAD_COLUMN = "\x00pad" - - -def _whole(snap: dict[str, Any], base: set[str], kind: str | None, tables: dict[str, list[str]] | None) -> bool: - """要遮的列盖住了全部结果列时,是认不准、整份算进来的,还是每一列都真认得出取自遮罩列(_sure)。masking 那一套 - 认不准时交回全部的列,和每一列都按位置认出来的样子一样,所以结果后面垫一列再认一遍:认得出的列按 SQL 里的位置算, - 垫的那一列没有哪一项落得上;整份算的连它一起算进来。""" - from app.engine.masking import _derived_hidden - - padded = [*(str(c) for c in snap.get("columns") or []), _PAD_COLUMN] - found, _ = _derived_hidden({**snap, "columns": padded}, set(base), kind, tables) - return {c.lower() for c in padded} <= found - - def _counted(snap: dict[str, Any], kind: str | None) -> dict[str, Any]: """报告自查认确定取自遮罩列的列之前(_sure),把只决定算不算进来的写法改写成认遮罩列的那一套认得出的样子: