Skip to content

Commit 435415e

Browse files
committed
Add text PII detection and redaction
1 parent 010f0d2 commit 435415e

15 files changed

Lines changed: 381 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-20) — Text PII Detection & Redaction](#whats-new-2026-06-20--text-pii-detection--redaction)
1617
- [What's new (2026-06-20) — Self-Healing Locator Write-Back](#whats-new-2026-06-20--self-healing-locator-write-back)
1718
- [What's new (2026-06-20) — DMN-Style Decision Tables](#whats-new-2026-06-20--dmn-style-decision-tables)
1819
- [What's new (2026-06-20) — Saga / Compensating Rollback](#whats-new-2026-06-20--saga--compensating-rollback)
@@ -107,6 +108,12 @@
107108

108109
---
109110

111+
## What's new (2026-06-20) — Text PII Detection & Redaction
112+
113+
Mask PII in text before it leaks. Full reference: [`docs/source/Eng/doc/new_features/v55_features_doc.rst`](docs/source/Eng/doc/new_features/v55_features_doc.rst).
114+
115+
- **`detect_pii` / `redact_pii_text`** (`AC_detect_pii` / `AC_redact_pii`, `ac_*`): image redaction existed but text (OCR, clipboard, LLM I/O, logs) had no string-level PII handling. This detects emails / phones / SSNs / credit cards / IPv4 / IBANs over plain text and redacts with `label` / `mask` / `partial` / `hash`. Overlapping spans dedupe (a card isn't also a phone); patterns are backtracking-safe. Pure-stdlib `re`+`hashlib`.
116+
110117
## What's new (2026-06-20) — Self-Healing Locator Write-Back
111118

112119
Persist corrected locators so heals aren't forgotten. Full reference: [`docs/source/Eng/doc/new_features/v54_features_doc.rst`](docs/source/Eng/doc/new_features/v54_features_doc.rst).

‎README/README_zh-CN.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-20) — 文本 PII 检测与遮蔽](#本次更新-2026-06-20--文本-pii-检测与遮蔽)
1516
- [本次更新 (2026-06-20) — 自我修复定位器回写](#本次更新-2026-06-20--自我修复定位器回写)
1617
- [本次更新 (2026-06-20) — DMN 式决策表](#本次更新-2026-06-20--dmn-式决策表)
1718
- [本次更新 (2026-06-20) — Saga / 补偿回滚](#本次更新-2026-06-20--saga--补偿回滚)
@@ -106,6 +107,12 @@
106107

107108
---
108109

110+
## 本次更新 (2026-06-20) — 文本 PII 检测与遮蔽
111+
112+
在文本泄漏前遮蔽 PII。完整参考:[`docs/source/Zh/doc/new_features/v55_features_doc.rst`](../docs/source/Zh/doc/new_features/v55_features_doc.rst)。
113+
114+
- **`detect_pii` / `redact_pii_text`**(`AC_detect_pii` / `AC_redact_pii`、`ac_*`):图像遮蔽已存在,但文本(OCR、剪贴板、LLM I/O、日志)无字符串级 PII 处理。本功能在纯文本上检测邮件/电话/SSN/信用卡/IPv4/IBAN 并以 `label`/`mask`/`partial`/`hash` 遮蔽。重叠区段会去重(卡号不会同时是电话);模式无回溯风险。纯标准库 `re`+`hashlib`。
115+
109116
## 本次更新 (2026-06-20) — 自我修复定位器回写
110117

111118
保存修正定位器,使修复不被遗忘。完整参考:[`docs/source/Zh/doc/new_features/v54_features_doc.rst`](../docs/source/Zh/doc/new_features/v54_features_doc.rst)。

‎README/README_zh-TW.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-20) — 文字 PII 偵測與遮蔽](#本次更新-2026-06-20--文字-pii-偵測與遮蔽)
1516
- [本次更新 (2026-06-20) — 自我修復定位器回寫](#本次更新-2026-06-20--自我修復定位器回寫)
1617
- [本次更新 (2026-06-20) — DMN 式決策表](#本次更新-2026-06-20--dmn-式決策表)
1718
- [本次更新 (2026-06-20) — Saga / 補償回溯](#本次更新-2026-06-20--saga--補償回溯)
@@ -106,6 +107,12 @@
106107

107108
---
108109

110+
## 本次更新 (2026-06-20) — 文字 PII 偵測與遮蔽
111+
112+
在文字洩漏前遮蔽 PII。完整參考:[`docs/source/Zh/doc/new_features/v55_features_doc.rst`](../docs/source/Zh/doc/new_features/v55_features_doc.rst)。
113+
114+
- **`detect_pii` / `redact_pii_text`**(`AC_detect_pii` / `AC_redact_pii`、`ac_*`):影像遮蔽已存在,但文字(OCR、剪貼簿、LLM I/O、日誌)無字串層級 PII 處理。本功能在純文字上偵測電子郵件/電話/SSN/信用卡/IPv4/IBAN 並以 `label`/`mask`/`partial`/`hash` 遮蔽。重疊區段會去重(卡號不會同時是電話);樣式無回溯風險。純標準函式庫 `re`+`hashlib`。
115+
109116
## 本次更新 (2026-06-20) — 自我修復定位器回寫
110117

111118
保存修正定位器,使修復不被遺忘。完整參考:[`docs/source/Zh/doc/new_features/v54_features_doc.rst`](../docs/source/Zh/doc/new_features/v54_features_doc.rst)。
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Text PII Detection & Redaction
2+
==============================
3+
4+
The image-redaction module blurs PII in screenshots, but text scraped from a UI,
5+
OCR, the clipboard, an LLM prompt/response, or a log line had no string-level
6+
equivalent — so PII could leak into action records, audit logs, or a model call.
7+
``detect_pii`` / ``redact_pii_text`` find and mask emails, phone numbers, SSNs,
8+
credit-card numbers, IPv4 addresses, and IBANs over plain text.
9+
10+
Patterns are deliberately simple (no nested quantifiers → no catastrophic
11+
backtracking). Pure standard library (``re`` + ``hashlib``); imports no
12+
``PySide6``.
13+
14+
Headless API
15+
------------
16+
17+
.. code-block:: python
18+
19+
from je_auto_control import detect_pii, redact_pii_text
20+
21+
detect_pii("mail a@b.com, ip 10.0.0.1")
22+
# -> [PIIFinding(kind='email', value='a@b.com', start=5, end=12), ...]
23+
24+
redact_pii_text("contact a@b.com") # -> "contact [email]"
25+
redact_pii_text("a@b.com", mode="mask") # -> "*******"
26+
redact_pii_text("4111111111111111", mode="partial") # -> "************1111"
27+
redact_pii_text("a@b.com", mode="hash") # -> "[email:fb98d44a]"
28+
29+
detect_pii(text, kinds=["email", "phone"]) # restrict detectors
30+
31+
``detect_pii`` returns non-overlapping findings sorted by position (the earlier,
32+
then longer, match wins — so a credit-card number is not also flagged as a
33+
phone). ``redact_pii_text`` modes: ``label`` (``[email]``), ``mask`` (``****``),
34+
``partial`` (keep last 4), ``hash`` (``[email:<digest>]``).
35+
36+
Executor commands
37+
-----------------
38+
39+
================================ ===================================================
40+
Command Effect
41+
================================ ===================================================
42+
``AC_detect_pii`` ``{findings}`` — PII spans in text.
43+
``AC_redact_pii`` ``{text}`` — text with PII masked.
44+
================================ ===================================================
45+
46+
``kinds`` accepts a list or JSON-string list. The same operations are exposed as
47+
MCP tools (``ac_detect_pii`` / ``ac_redact_pii``) and as Script Builder commands
48+
under **Data**.

‎docs/source/Eng/eng_index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Comprehensive guides for all AutoControl features.
7777
doc/new_features/v52_features_doc
7878
doc/new_features/v53_features_doc
7979
doc/new_features/v54_features_doc
80+
doc/new_features/v55_features_doc
8081
doc/ocr_backends/ocr_backends_doc
8182
doc/observability/observability_doc
8283
doc/operations_layer/operations_layer_doc
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
文字 PII 偵測與遮蔽
2+
==================
3+
4+
影像遮蔽模組會在螢幕截圖中模糊 PII,但從 UI、OCR、剪貼簿、LLM 提示/回應或日誌行擷取的
5+
*文字*卻沒有字串層級的對應 —— 因此 PII 可能洩漏進動作紀錄、稽核日誌或一次模型呼叫。
6+
``detect_pii`` / ``redact_pii_text`` 可在純文字上找出並遮蔽電子郵件、電話號碼、SSN、信
7+
用卡號、IPv4 位址與 IBAN。
8+
9+
樣式刻意保持簡單(無巢狀量詞 → 無災難性回溯)。純標準函式庫(``re`` + ``hashlib``);不匯
10+
入 ``PySide6``。
11+
12+
無頭 API
13+
--------
14+
15+
.. code-block:: python
16+
17+
from je_auto_control import detect_pii, redact_pii_text
18+
19+
detect_pii("mail a@b.com, ip 10.0.0.1")
20+
# -> [PIIFinding(kind='email', value='a@b.com', start=5, end=12), ...]
21+
22+
redact_pii_text("contact a@b.com") # -> "contact [email]"
23+
redact_pii_text("a@b.com", mode="mask") # -> "*******"
24+
redact_pii_text("4111111111111111", mode="partial") # -> "************1111"
25+
redact_pii_text("a@b.com", mode="hash") # -> "[email:fb98d44a]"
26+
27+
detect_pii(text, kinds=["email", "phone"]) # 限定偵測器
28+
29+
``detect_pii`` 回傳依位置排序、互不重疊的結果(較前、再較長的匹配勝出 —— 因此信用卡號不
30+
會同時被標記為電話)。``redact_pii_text`` 模式:``label``(``[email]``)、``mask``
31+
(``****``)、``partial``(保留末 4 碼)、``hash``(``[email:<digest>]``)。
32+
33+
執行器指令
34+
----------
35+
36+
================================ ===================================================
37+
指令 效果
38+
================================ ===================================================
39+
``AC_detect_pii`` ``{findings}`` —— 文字中的 PII 區段。
40+
``AC_redact_pii`` ``{text}`` —— 已遮蔽 PII 的文字。
41+
================================ ===================================================
42+
43+
``kinds`` 接受清單或 JSON 字串清單。相同操作亦提供為 MCP 工具(``ac_detect_pii`` /
44+
``ac_redact_pii``),以及 Script Builder 中 **Data** 分類下的指令。

‎docs/source/Zh/zh_index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ AutoControl 所有功能的完整使用指南。
7777
doc/new_features/v52_features_doc
7878
doc/new_features/v53_features_doc
7979
doc/new_features/v54_features_doc
80+
doc/new_features/v55_features_doc
8081
doc/ocr_backends/ocr_backends_doc
8182
doc/observability/observability_doc
8283
doc/operations_layer/operations_layer_doc

‎je_auto_control/__init__.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@
290290
from je_auto_control.utils.locator_repair import (
291291
RepairStore, RepairSuggestion, repair_from_heal,
292292
)
293+
# Text PII detection / redaction (free-text emails, phones, SSNs, cards, …)
294+
from je_auto_control.utils.pii_text import (
295+
PIIFinding, detect_pii, redact_pii_text,
296+
)
293297
# Background popup/interrupt watchdog (unattended automation)
294298
from je_auto_control.utils.watchdog import (
295299
PopupWatchdog, WatchdogRule, default_popup_watchdog,
@@ -756,6 +760,7 @@ def start_autocontrol_gui(*args, **kwargs):
756760
"Saga", "SagaResult", "run_saga",
757761
"DecisionTable", "Rule", "evaluate_table",
758762
"RepairStore", "RepairSuggestion", "repair_from_heal",
763+
"PIIFinding", "detect_pii", "redact_pii_text",
759764
# MCP server
760765
"AuditLogger", "HttpMCPServer", "MCPContent", "MCPPrompt",
761766
"MCPPromptArgument", "MCPResource", "MCPServer", "MCPTool",

‎je_auto_control/gui/script_builder/command_schema.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,28 @@ def _add_misc_specs(specs: List[CommandSpec]) -> None:
12021202
),
12031203
description="Approve a pending locator-repair suggestion.",
12041204
))
1205+
specs.append(CommandSpec(
1206+
"AC_detect_pii", "Data", "PII: Detect",
1207+
fields=(
1208+
FieldSpec("text", FieldType.STRING),
1209+
FieldSpec("kinds", FieldType.STRING, optional=True,
1210+
placeholder='["email", "phone"]'),
1211+
),
1212+
description="Detect PII spans (email/phone/ssn/card/ip/iban) in text.",
1213+
))
1214+
specs.append(CommandSpec(
1215+
"AC_redact_pii", "Data", "PII: Redact",
1216+
fields=(
1217+
FieldSpec("text", FieldType.STRING),
1218+
FieldSpec("kinds", FieldType.STRING, optional=True,
1219+
placeholder='["email"]'),
1220+
FieldSpec("mode", FieldType.ENUM, optional=True, default="label",
1221+
choices=("label", "mask", "partial", "hash")),
1222+
FieldSpec("mask_char", FieldType.STRING, optional=True,
1223+
default="*"),
1224+
),
1225+
description="Redact PII in text (label/mask/partial/hash).",
1226+
))
12051227
specs.append(CommandSpec(
12061228
"AC_generate_sop", "Report", "Generate SOP Document",
12071229
fields=(

‎je_auto_control/utils/executor/action_executor.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,6 +3373,23 @@ def _repair_approve(suggestion_id: str,
33733373
return {"approved": RepairStore(db).approve(suggestion_id)}
33743374

33753375

3376+
def _detect_pii(text: str, kinds: Any = None) -> Dict[str, Any]:
3377+
"""Adapter: detect PII spans in text."""
3378+
from je_auto_control.utils.pii_text import detect_pii
3379+
findings = detect_pii(text, kinds=_coerce_list(kinds) if kinds else None)
3380+
return {"findings": [{"kind": f.kind, "value": f.value,
3381+
"start": f.start, "end": f.end} for f in findings]}
3382+
3383+
3384+
def _redact_pii(text: str, kinds: Any = None, mode: str = "label",
3385+
mask_char: str = "*") -> Dict[str, Any]:
3386+
"""Adapter: redact PII in text (label/mask/partial/hash)."""
3387+
from je_auto_control.utils.pii_text import redact_pii_text
3388+
return {"text": redact_pii_text(
3389+
text, kinds=_coerce_list(kinds) if kinds else None, mode=mode,
3390+
mask_char=mask_char)}
3391+
3392+
33763393
class Executor:
33773394
"""
33783395
Executor
@@ -3661,6 +3678,8 @@ def __init__(self):
36613678
"AC_repair_resolved": _repair_resolved,
36623679
"AC_repair_pending": _repair_pending,
36633680
"AC_repair_approve": _repair_approve,
3681+
"AC_detect_pii": _detect_pii,
3682+
"AC_redact_pii": _redact_pii,
36643683
"AC_a11y_record_start": _a11y_record_start,
36653684
"AC_a11y_record_stop": _a11y_record_stop,
36663685
"AC_a11y_record_events": _a11y_record_events,

0 commit comments

Comments
 (0)