@yottameta/yotta-compliance 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/NOTICE +12 -0
- package/README.md +265 -0
- package/README.zh-CN.md +242 -0
- package/SKILL.md +208 -0
- package/assets/banner.png +0 -0
- package/bin/install.js +163 -0
- package/install.sh +132 -0
- package/package.json +35 -12
- package/references/coverage.md +123 -0
- package/references/report-format.md +263 -0
- package/references/rule-authoring.md +241 -0
- package/rules/data-export.json +175 -0
- package/rules/pipl.json +406 -0
- package/scripts/yotta_compliance.py +1426 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# 覆盖范围与规则清单
|
|
2
|
+
|
|
3
|
+
元规把“覆盖级别”作为报告的第一等字段:`baseline_review` 表示可以输出该框架的独立 finding;
|
|
4
|
+
`mapping_only` 表示只把基础规则映射到该框架的主题,不输出该框架的独立合规结论。
|
|
5
|
+
|
|
6
|
+
## 1. 覆盖级别
|
|
7
|
+
|
|
8
|
+
| 级别 | 含义 | 报告行为 |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `baseline_review` | 对基础框架执行确定性规则审查 | 可输出 finding;覆盖摘要状态为 `reviewed` |
|
|
11
|
+
| `mapping_only` | 只做主题映射 | 只显示 `框架:mapping_only` 标签;不输出独立结论 |
|
|
12
|
+
|
|
13
|
+
`mapping_only` 不得被描述为“已审查该框架”,也不得用于对外声称“通过某框架认证”。
|
|
14
|
+
|
|
15
|
+
## 2. 当前基础框架
|
|
16
|
+
|
|
17
|
+
| 规则包 | 框架 | 规则数 | 规则包版本 |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| `pipl` | `PIPL`(个人信息保护法) | 11 | `2026.09.1` |
|
|
20
|
+
| `data-export` | `DATA-EXPORT`(数据出境) | 4 | `2026.09.1` |
|
|
21
|
+
|
|
22
|
+
## 3. PIPL 规则清单
|
|
23
|
+
|
|
24
|
+
来源:中国人大网《中华人民共和国个人信息保护法》官方全文
|
|
25
|
+
(https://www.npc.gov.cn/npc/c2/c30834/202108/t20210820_313088.html)。
|
|
26
|
+
|
|
27
|
+
| rule_id | 主题 | severity | 断言 | 来源条款 |
|
|
28
|
+
|---|---|---|---|---|
|
|
29
|
+
| `PIPL-NOTICE-001` | 未出现处理目的的告知表述 | medium | absent / document | 第十七条第一款第二项 |
|
|
30
|
+
| `PIPL-PURPOSE-002` | 未出现最小必要或影响最小约束 | medium | absent / document | 第六条 |
|
|
31
|
+
| `PIPL-BASIS-003` | 未出现处理个人信息的合法性依据 | medium | absent / document(置信 low) | 第十三条 |
|
|
32
|
+
| `PIPL-RETENTION-004` | 未出现个人信息保存期限说明 | medium | absent / document | 第十七条第一款第二项、第十九条 |
|
|
33
|
+
| `PIPL-RETENTION-005` | 保存期限达到或超过 3 年 | low | numeric_compare `gte 3` | 第十九条 |
|
|
34
|
+
| `PIPL-SENSITIVE-006` | 涉及敏感个人信息但未出现单独同意 | high | absent / document | 第二十八条、第二十九条 |
|
|
35
|
+
| `PIPL-MINOR-007` | 涉及不满十四周岁未成年人信息但未出现监护人同意 | high | absent / document | 第三十一条 |
|
|
36
|
+
| `PIPL-SHARE-008` | 对外提供个人信息但未出现单独同意 | high | absent / document | 第二十三条 |
|
|
37
|
+
| `PIPL-RIGHTS-009` | 未出现个人权利相关表述 | low | absent / document(置信 low) | 第十七条第一款第三项、第四十四条至第四十七条 |
|
|
38
|
+
| `PIPL-INCIDENT-010` | 未出现个人信息泄露补救与通知机制 | low | absent / document(置信 low) | 第五十一条第五项、第五十七条 |
|
|
39
|
+
| `PIPL-PIPIA-011` | 涉及影响评估情形但未出现个人信息保护影响评估 | medium | absent / document | 第五十五条 |
|
|
40
|
+
|
|
41
|
+
`PIPL-RETENTION-005` 只识别 `保存期限:N年` 形式,且只做阈值提示,不判断保存期限是否合法。
|
|
42
|
+
|
|
43
|
+
## 4. 数据出境规则清单
|
|
44
|
+
|
|
45
|
+
来源:《中华人民共和国个人信息保护法》第三十八条至第四十条;数据出境制度口径参照国家网信办
|
|
46
|
+
《促进和规范数据跨境流动规定》(2024-03-22,https://www.cac.gov.cn/2024-03/22/c_1712776611775634.htm)。
|
|
47
|
+
v0.1 未将人数阈值做成规则,相关阈值规则推迟到规则包 v2。
|
|
48
|
+
|
|
49
|
+
| rule_id | 主题 | severity | 断言 | 来源条款 |
|
|
50
|
+
|---|---|---|---|---|
|
|
51
|
+
| `EXPORT-SAFEGUARD-001` | 数据出境未出现安全评估、标准合同或保护认证 | high | absent / document | 第三十八条第一款 |
|
|
52
|
+
| `EXPORT-CONSENT-002` | 数据出境未出现单独同意 | high | absent / document | 第三十九条 |
|
|
53
|
+
| `EXPORT-NOTICE-003` | 数据出境未出现境外接收方告知 | medium | absent / document | 第三十九条 |
|
|
54
|
+
| `EXPORT-STORAGE-004` | 数据出境未出现境内存储说明 | low | absent / document(置信 low) | 第四十条 |
|
|
55
|
+
|
|
56
|
+
`EXPORT-STORAGE-004` 的适用性与“关键信息基础设施运营者”或“达到规定数量的处理者”身份有关,
|
|
57
|
+
规则只做概览性提示,必须人工核对适用性。
|
|
58
|
+
|
|
59
|
+
## 5. mapping_only 主题映射
|
|
60
|
+
|
|
61
|
+
### 5.1 pipl 包
|
|
62
|
+
|
|
63
|
+
| 框架 | 主题 | 映射规则数 |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| GDPR | breach_notification / children / data_subject_rights / dpia / lawful_basis / purpose_limitation / special_categories / storage_limitation | 10 |
|
|
66
|
+
| HIPAA | breach_notification / phi_context | 2 |
|
|
67
|
+
| SOC2 | incident_response / privacy_notice | 2 |
|
|
68
|
+
| PCI-DSS | account_data_context | 1 |
|
|
69
|
+
| ISO27001 | incident_management / retention_governance | 2 |
|
|
70
|
+
| 等保 | data_retention / emergency_response | 2 |
|
|
71
|
+
|
|
72
|
+
### 5.2 data-export 包
|
|
73
|
+
|
|
74
|
+
| 框架 | 主题 | 映射规则数 |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| GDPR | international_transfers | 3 |
|
|
77
|
+
| ISO27001 | data_residency / supplier_agreements | 2 |
|
|
78
|
+
| 等保 | data_residency / security_assessment | 2 |
|
|
79
|
+
|
|
80
|
+
映射只表示“该基础规则与这些框架主题相关”,不表示这些框架已经过审查。
|
|
81
|
+
|
|
82
|
+
## 6. 明确未覆盖
|
|
83
|
+
|
|
84
|
+
以下范围不在 v0.1 的 `baseline_review` 内:
|
|
85
|
+
|
|
86
|
+
1. **语义理解**:词形不同的同义表述可能漏检;absence 只判断检索词是否出现。
|
|
87
|
+
2. **文档级范围判断**:absence 的 `scope` 为 `document`,检索词出现在任何位置即视为已出现,
|
|
88
|
+
不判断其是否适用于当前处理活动。
|
|
89
|
+
3. **否定句建模**:「不会对外提供」「未经同意不得处理」等否定表述仍可能触发候选匹配。
|
|
90
|
+
4. **中文数字解析**:「三年」「十万」等中文数字不解析、不换算。
|
|
91
|
+
5. **数据出境人数阈值**:100 万人以上、10 万人以上、1 万人敏感个人信息等阈值需要单位感知的
|
|
92
|
+
数值原语,v0.1 不做跨单位换算,因而没有对应规则。
|
|
93
|
+
6. **其它框架的独立结论**:GDPR / HIPAA / SOC2 / PCI-DSS / ISO27001 / 等保 仅 `mapping_only`。
|
|
94
|
+
7. **非文本输入**:PDF / docx / 图片不直接解析,需先转成 UTF-8 文本或 Markdown。
|
|
95
|
+
8. **法律判断**:不判断合同效力、不预测诉讼结果、不替代律师或合规顾问。
|
|
96
|
+
|
|
97
|
+
## 7. 如何核对覆盖范围
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# 列出实际装载的规则
|
|
101
|
+
python3 scripts/yotta_compliance.py rules list
|
|
102
|
+
|
|
103
|
+
# 只看某个框架
|
|
104
|
+
python3 scripts/yotta_compliance.py rules list --framework pipl
|
|
105
|
+
|
|
106
|
+
# 查看单条规则的来源与测试用例
|
|
107
|
+
python3 scripts/yotta_compliance.py rules show PIPL-NOTICE-001
|
|
108
|
+
|
|
109
|
+
# 校验规则包结构
|
|
110
|
+
python3 scripts/yotta_compliance.py rules validate --pack rules/pipl.json
|
|
111
|
+
python3 scripts/yotta_compliance.py rules validate --pack rules/data-export.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Markdown 报告的「框架覆盖摘要」与 JSON 的 `framework_coverage` 反映实际装载结果;
|
|
115
|
+
两者是判断某框架是否进入本次审查的权威依据。
|
|
116
|
+
|
|
117
|
+
## 8. 更新规则包时的要求
|
|
118
|
+
|
|
119
|
+
- 升 `pack_version`,并同步更新本文件的规则清单与来源条款;
|
|
120
|
+
- 每条规则补齐正例、反例、边界例,并让 `test_ids` 与夹具逐项一致;
|
|
121
|
+
- 来源使用官方文本,写到条款号与 `https://` 链接;
|
|
122
|
+
- 重新运行规则包校验与全量契约测试;
|
|
123
|
+
- 规则包内容或行为发生变化时,随技能版本一起进入发布流程。
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# 报告契约
|
|
2
|
+
|
|
3
|
+
元规同时提供人类可读的 Markdown 报告与稳定的 JSON 契约。JSON 用于自动化、审计与二次处理,
|
|
4
|
+
字段语义不随文案样式调整而改变。
|
|
5
|
+
|
|
6
|
+
## 1. Markdown 报告
|
|
7
|
+
|
|
8
|
+
Markdown 报告固定包含七节,顺序不变:
|
|
9
|
+
|
|
10
|
+
| 节 | 内容 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| 1. 输入摘要 | 来源、大小、行数、SHA-256、规则包 id / 版本 / 覆盖级别 / 规则数 |
|
|
13
|
+
| 2. 框架覆盖摘要 | 规则包、框架、覆盖级别、状态、规则数;`mapping_only` 单独说明 |
|
|
14
|
+
| 3. 风险汇总 | 输出 finding 数、全部 finding 数、按严重度计数、已检查 / 命中规则数 |
|
|
15
|
+
| 4. 逐条发现 | finding id、规则 id、标题、严重度、置信度、框架映射、条款类型、证据、说明、建议、来源 |
|
|
16
|
+
| 5. 未覆盖范围 | `mapping_only` 框架、PDF / docx 说明、`--include-safe` 时的未命中规则 |
|
|
17
|
+
| 6. 人工复核清单 | 低置信 finding 与无法验证的数值 / 日期项 |
|
|
18
|
+
| 7. 免责声明 | 固定声明:本工具提供基于确定性规则的条款审查建议与证据链,不构成法律意见 |
|
|
19
|
+
|
|
20
|
+
每条 finding 的证据展示规则:
|
|
21
|
+
|
|
22
|
+
- `matched_span` 显示原文 quote、行、列与 `section_id`;
|
|
23
|
+
- `document_scope` / `section_scope` 显示范围与起止行列,不显示伪造 quote;
|
|
24
|
+
- 单条 finding 最多展示 5 条证据;超出时追加 `evidence_note`,完整数量保留在 `evidence_total`。
|
|
25
|
+
|
|
26
|
+
## 2. JSON 顶层字段
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"schema_version": "1.0",
|
|
31
|
+
"tool": "yotta-compliance",
|
|
32
|
+
"tool_version": "0.1.0",
|
|
33
|
+
"generated_at": "2026-09-24T12:00:00Z",
|
|
34
|
+
"input": {},
|
|
35
|
+
"rule_packs": [],
|
|
36
|
+
"framework_coverage": [],
|
|
37
|
+
"summary": {},
|
|
38
|
+
"findings": [],
|
|
39
|
+
"review_items": [],
|
|
40
|
+
"disclaimer": "本工具提供基于确定性规则的条款审查建议与证据链,不构成法律意见。"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| 字段 | 说明 |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `schema_version` | JSON 契约版本,当前为 `1.0` |
|
|
47
|
+
| `tool` | 固定为 `yotta-compliance` |
|
|
48
|
+
| `tool_version` | 引擎版本 |
|
|
49
|
+
| `generated_at` | UTC ISO-8601 时间戳;这是重复运行唯一允许变化的字段 |
|
|
50
|
+
| `input` | 输入摘要,不回显原文 |
|
|
51
|
+
| `rule_packs` | 实际装载的规则包元信息与 SHA-256 |
|
|
52
|
+
| `framework_coverage` | 基础框架与 `mapping_only` 框架的覆盖摘要 |
|
|
53
|
+
| `summary` | 计数与可选已检查规则列表 |
|
|
54
|
+
| `findings` | 达到 `--min-severity` 的 finding 列表 |
|
|
55
|
+
| `review_items` | 低置信与无法验证项 |
|
|
56
|
+
| `disclaimer` | 固定免责声明 |
|
|
57
|
+
|
|
58
|
+
## 3. input
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"kind": "file",
|
|
63
|
+
"path": "D:\\work\\contract.md",
|
|
64
|
+
"sha256": "…",
|
|
65
|
+
"bytes": 1234,
|
|
66
|
+
"lines": 56
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| 字段 | 说明 |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `kind` | `file` / `stdin` / `memory` |
|
|
73
|
+
| `path` | 文件输入时的绝对路径;stdin 时为 `null` |
|
|
74
|
+
| `sha256` | 输入 UTF-8 字节的 SHA-256 |
|
|
75
|
+
| `bytes` | UTF-8 字节数 |
|
|
76
|
+
| `lines` | 按 `\n` 计算的行数 |
|
|
77
|
+
|
|
78
|
+
报告不包含原文;如需复核,按 `path` 与 `sha256` 找回同一份输入。
|
|
79
|
+
|
|
80
|
+
## 4. rule_packs
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"pack_id": "pipl",
|
|
85
|
+
"framework": "PIPL",
|
|
86
|
+
"pack_version": "2026.09.1",
|
|
87
|
+
"coverage_level": "baseline_review",
|
|
88
|
+
"sha256": "…",
|
|
89
|
+
"rule_count": 11
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`sha256` 用于确认报告引用的规则包版本未被替换;正式审查记录建议同时保存 `pack_id`、
|
|
94
|
+
`pack_version` 与 `sha256`。
|
|
95
|
+
|
|
96
|
+
## 5. framework_coverage
|
|
97
|
+
|
|
98
|
+
每个基础框架或 `mapping_only` 框架各占一项:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"framework": "GDPR",
|
|
103
|
+
"coverage_level": "mapping_only",
|
|
104
|
+
"status": "mapping_only",
|
|
105
|
+
"pack_id": "pipl",
|
|
106
|
+
"pack_version": "2026.09.1",
|
|
107
|
+
"rule_count": 10,
|
|
108
|
+
"topics": ["lawful_basis", "purpose_limitation"],
|
|
109
|
+
"note": "仅主题映射,不等同于对该框架的合规审查。"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| 字段 | 说明 |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `framework` | 框架名 |
|
|
116
|
+
| `coverage_level` | `baseline_review` 或 `mapping_only` |
|
|
117
|
+
| `status` | `reviewed` 或 `mapping_only` |
|
|
118
|
+
| `pack_id` | 产生该行的规则包 |
|
|
119
|
+
| `pack_version` | 规则包版本 |
|
|
120
|
+
| `rule_count` | 基础包为规则数;`mapping_only` 为映射条目数 |
|
|
121
|
+
| `topics` | 仅 `mapping_only` 提供 |
|
|
122
|
+
| `note` | 仅 `mapping_only` 提供 |
|
|
123
|
+
|
|
124
|
+
`mapping_only` 行不得被解读为已完成该框架的审查。
|
|
125
|
+
|
|
126
|
+
## 6. summary
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"findings_total": 3,
|
|
131
|
+
"findings_total_all": 11,
|
|
132
|
+
"by_severity": {"info": 0, "low": 4, "medium": 4, "high": 3, "critical": 0},
|
|
133
|
+
"by_confidence": {"low": 4, "medium": 7, "high": 0},
|
|
134
|
+
"rules_checked": 15,
|
|
135
|
+
"rules_matched": 13,
|
|
136
|
+
"review_items": 4,
|
|
137
|
+
"checked_rules": []
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
| 字段 | 说明 |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `findings_total` | 达到 `--min-severity` 的 finding 数 |
|
|
144
|
+
| `findings_total_all` | 过滤前 finding 总数 |
|
|
145
|
+
| `by_severity` | 全部 finding 的严重度计数 |
|
|
146
|
+
| `by_confidence` | 全部 finding 的置信度计数 |
|
|
147
|
+
| `rules_checked` | 本次运行实际检查的规则数 |
|
|
148
|
+
| `rules_matched` | 候选命中的规则数,含 matched / matched_no_finding |
|
|
149
|
+
| `review_items` | 人工复核项数量 |
|
|
150
|
+
| `checked_rules` | 仅在 `--include-safe` 时提供 |
|
|
151
|
+
|
|
152
|
+
`checked_rules` 每项形如:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"rule_id": "PIPL-SENSITIVE-006",
|
|
157
|
+
"pack_id": "pipl",
|
|
158
|
+
"status": "no_match"
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`status` 取值:
|
|
163
|
+
|
|
164
|
+
| 值 | 含义 |
|
|
165
|
+
|---|---|
|
|
166
|
+
| `no_match` | 候选未命中,规则未继续求值 |
|
|
167
|
+
| `matched` | 求值后输出 finding |
|
|
168
|
+
| `matched_no_finding` | 候选命中,但断言未输出 finding 或进入人工复核 |
|
|
169
|
+
|
|
170
|
+
## 7. findings
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"finding_id": "F-0001",
|
|
175
|
+
"rule_id": "PIPL-NOTICE-001",
|
|
176
|
+
"title": "未出现处理目的的告知表述",
|
|
177
|
+
"severity": "medium",
|
|
178
|
+
"confidence": "medium",
|
|
179
|
+
"framework_mapping": ["PIPL", "GDPR:mapping_only"],
|
|
180
|
+
"clause_types": ["personal_information"],
|
|
181
|
+
"evidence": [
|
|
182
|
+
{
|
|
183
|
+
"kind": "matched_span",
|
|
184
|
+
"quote": "个人信息",
|
|
185
|
+
"start": 12,
|
|
186
|
+
"end": 16,
|
|
187
|
+
"line": 3,
|
|
188
|
+
"column": 5,
|
|
189
|
+
"section_id": "para-2"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"kind": "document_scope",
|
|
193
|
+
"start": 0,
|
|
194
|
+
"end": 120,
|
|
195
|
+
"line": 1,
|
|
196
|
+
"column": 1,
|
|
197
|
+
"end_line": 9,
|
|
198
|
+
"end_column": 12,
|
|
199
|
+
"section_id": null,
|
|
200
|
+
"scope_label": "全文范围"
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
"evidence_total": 5,
|
|
204
|
+
"evidence_note": "仅显示前 5 条证据,共 8 条。",
|
|
205
|
+
"rationale": "规则说明只描述可观察文本现象。",
|
|
206
|
+
"remediation": "面向用户的补充或核对建议。",
|
|
207
|
+
"source": {
|
|
208
|
+
"type": "official",
|
|
209
|
+
"citation": "《中华人民共和国个人信息保护法》第十七条第一款第二项",
|
|
210
|
+
"url": "https://www.npc.gov.cn/"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
| 字段 | 说明 |
|
|
216
|
+
|---|---|
|
|
217
|
+
| `finding_id` | 在本次报告中从 `F-0001` 起连续编号 |
|
|
218
|
+
| `rule_id` / `title` | 命中的规则 |
|
|
219
|
+
| `severity` | `info` / `low` / `medium` / `high` / `critical` |
|
|
220
|
+
| `confidence` | `low` / `medium` / `high` |
|
|
221
|
+
| `framework_mapping` | 基础框架 + 命中的 `框架:mapping_only` 标签 |
|
|
222
|
+
| `clause_types` | 规则声明的条款类型 |
|
|
223
|
+
| `evidence` | 原文证据数组;`quote` 必须等于原文切片 |
|
|
224
|
+
| `evidence_total` | 证据总数;超过 5 条时仅前 5 条进入 `evidence` |
|
|
225
|
+
| `evidence_note` | 证据被截断时出现 |
|
|
226
|
+
| `rationale` / `remediation` | 规则说明与建议动作 |
|
|
227
|
+
| `source` | 规则来源与链接 |
|
|
228
|
+
|
|
229
|
+
finding 按严重度降序、`rule_id`、证据起始位置排序,保证同一输入结果稳定。
|
|
230
|
+
|
|
231
|
+
## 8. review_items
|
|
232
|
+
|
|
233
|
+
低置信 finding 与无法验证的 compare 结果进入人工复核清单:
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{
|
|
237
|
+
"kind": "low_confidence",
|
|
238
|
+
"rule_id": "PIPL-BASIS-003",
|
|
239
|
+
"pack_id": null,
|
|
240
|
+
"finding_id": "F-0005",
|
|
241
|
+
"reason": "低置信结论,必须人工核验后才能采信。"
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
| `kind` | 触发条件 |
|
|
246
|
+
|---|---|
|
|
247
|
+
| `low_confidence` | finding 的 `confidence=low` |
|
|
248
|
+
| `unverifiable` | 数值 / 日期无法解析,或时长单位与规则声明不一致 |
|
|
249
|
+
|
|
250
|
+
`unverifiable` 不输出数值结论,也不伪造原文引用。
|
|
251
|
+
|
|
252
|
+
## 9. CLI 行为与退出码
|
|
253
|
+
|
|
254
|
+
- Markdown 是默认格式;`--format json` 输出 JSON;
|
|
255
|
+
- `--out` 缺省时只写 stdout;`--out` 写入成功时在 stderr 输出目标路径;
|
|
256
|
+
- `--gate` 达到阈值时返回 1;`--gate off` 不触发闸门;
|
|
257
|
+
- `--min-severity` 只过滤 `findings`,不改变全部 finding 的汇总计数;
|
|
258
|
+
- 输入错误返回 2;规则包错误返回 3;用法错误返回 4。
|
|
259
|
+
|
|
260
|
+
## 10. 确定性
|
|
261
|
+
|
|
262
|
+
同一输入、同一规则包、同一参数重复运行时,除 `generated_at` 外,JSON 结果必须完全一致。
|
|
263
|
+
审计场景建议使用 `--format json`,并保留输入 SHA-256、规则包 SHA-256 与报告文件。
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# 规则包编写规范
|
|
2
|
+
|
|
3
|
+
元规的规则包是**版本化 JSON 数据**:内核只读取字段、编译正则、匹配文本与复算证据,
|
|
4
|
+
不把规则正文当作代码执行。规则质量直接决定审查结论的可信度,因此每条正式规则都必须有
|
|
5
|
+
来源、正例、反例、边界例和可复算的期望结果。
|
|
6
|
+
|
|
7
|
+
## 1. 目录与版本
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
rules/
|
|
11
|
+
├── pipl.json
|
|
12
|
+
└── data-export.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- 每个规则包对应一个框架与一个 `pack_id`;
|
|
16
|
+
- 规则包内容发生变化时,必须升 `pack_version`;
|
|
17
|
+
- `rules/` 进入发布包;`scripts/fixtures/` 下的测试夹具不进入发布包;
|
|
18
|
+
- `rules validate` 是发布前硬闸门,校验失败时退出码为 3。
|
|
19
|
+
|
|
20
|
+
## 2. 规则包字段
|
|
21
|
+
|
|
22
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `schema_version` | string | 是 | 当前固定为 `"1.0"` |
|
|
25
|
+
| `pack_id` | string | 是 | 规则包 id,如 `pipl` / `data-export` |
|
|
26
|
+
| `framework` | string | 是 | 基础框架名,如 `PIPL` / `DATA-EXPORT` |
|
|
27
|
+
| `pack_version` | string | 是 | 规则包版本,如 `2026.09.1` |
|
|
28
|
+
| `jurisdiction` | string | 否 | 司法辖区,如 `CN` |
|
|
29
|
+
| `coverage_level` | string | 是 | `baseline_review` 或 `mapping_only` |
|
|
30
|
+
| `clause_type_lexicon` | object | 否 | 条款类型到关键词数组的映射 |
|
|
31
|
+
| `mapping_only` | array | 否 | 其它框架的主题映射 |
|
|
32
|
+
| `rules` | array | 是 | 非空规则列表 |
|
|
33
|
+
|
|
34
|
+
`clause_type_lexicon` 中声明过的类型才能被 `clause_type` 条件引用;引用未声明的类型判为包损坏。
|
|
35
|
+
|
|
36
|
+
`mapping_only` 数组元素形如:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"framework": "GDPR",
|
|
41
|
+
"topics": {
|
|
42
|
+
"lawful_basis": ["PIPL-BASIS-003"],
|
|
43
|
+
"storage_limitation": ["PIPL-RETENTION-004", "PIPL-RETENTION-005"]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`topics` 中引用的 `rule_id` 必须存在;`mapping_only` 只影响 finding 的框架标签,不改变基础框架的
|
|
49
|
+
审查结论,也不得用于对外声称“已审查该框架”。
|
|
50
|
+
|
|
51
|
+
## 3. 单条规则字段
|
|
52
|
+
|
|
53
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `rule_id` | string | 是 | 全局唯一;建议 `框架-主题-序号` |
|
|
56
|
+
| `title` | string | 是 | 面向用户的规则标题 |
|
|
57
|
+
| `clause_types` | array | 否 | 该规则涉及的条款类型 |
|
|
58
|
+
| `match` | object | 是 | 候选匹配条件 |
|
|
59
|
+
| `assert` | object | 是 | 断言与搜索条件 |
|
|
60
|
+
| `severity` | string | 是 | `info` / `low` / `medium` / `high` / `critical` |
|
|
61
|
+
| `confidence_policy` | object | 否 | `exact_match` 与 `absence` 的置信度 |
|
|
62
|
+
| `evidence` | array | 是 | 至少一项:`matched_span` / `document_scope` / `section_scope` |
|
|
63
|
+
| `rationale` | string | 是 | 只描述可观察文本现象,不臆测真实业务 |
|
|
64
|
+
| `source` | object | 是 | `type` / `citation` / `url` |
|
|
65
|
+
| `remediation` | string | 是 | 面向用户的补充或核对建议 |
|
|
66
|
+
| `test_ids` | array | 是 | 非空;正式规则须与正例 / 反例 / 边界例逐一相等 |
|
|
67
|
+
|
|
68
|
+
示例:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"rule_id": "PIPL-NOTICE-001",
|
|
73
|
+
"title": "未出现处理目的的告知表述",
|
|
74
|
+
"clause_types": ["personal_information"],
|
|
75
|
+
"match": {
|
|
76
|
+
"operator": "any",
|
|
77
|
+
"conditions": [
|
|
78
|
+
{"kind": "clause_type", "value": "personal_information"}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
"assert": {
|
|
82
|
+
"operator": "absent",
|
|
83
|
+
"target": "processing_purpose_notice",
|
|
84
|
+
"scope": "document",
|
|
85
|
+
"search": {
|
|
86
|
+
"kind": "regex",
|
|
87
|
+
"pattern": "处理目的|使用目的|收集目的"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"severity": "medium",
|
|
91
|
+
"confidence_policy": {"exact_match": "high", "absence": "medium"},
|
|
92
|
+
"evidence": ["matched_span", "document_scope"],
|
|
93
|
+
"rationale": "文本出现个人信息相关表述,但未检索到处理目的相关表述;需人工核对。",
|
|
94
|
+
"source": {
|
|
95
|
+
"type": "official",
|
|
96
|
+
"citation": "《中华人民共和国个人信息保护法》第十七条第一款第二项",
|
|
97
|
+
"url": "https://www.npc.gov.cn/npc/c2/c30834/202108/t20210820_313088.html"
|
|
98
|
+
},
|
|
99
|
+
"remediation": "补充个人信息处理目的,并说明处理方式、处理的个人信息种类与保存期限。",
|
|
100
|
+
"test_ids": [
|
|
101
|
+
"PIPL-NOTICE-001-positive",
|
|
102
|
+
"PIPL-NOTICE-001-negative",
|
|
103
|
+
"PIPL-NOTICE-001-boundary"
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 4. 候选匹配
|
|
109
|
+
|
|
110
|
+
`match.operator` 为 `any` 或 `all`,`match.conditions` 不能为空。条件类型:
|
|
111
|
+
|
|
112
|
+
| `kind` | 字段 | 说明 |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `keyword` | `value` | 确定性关键词匹配 |
|
|
115
|
+
| `regex` | `pattern` | Python 正则;同一规则内不得重复同一 pattern |
|
|
116
|
+
| `clause_type` | `value` | 引用 `clause_type_lexicon` 中声明的类型 |
|
|
117
|
+
| `section_anchor` | `value` | 引用结构块标签,如标题或条款号 |
|
|
118
|
+
|
|
119
|
+
候选匹配决定“这条规则是否值得继续判断”。反例与边界例同样要求候选命中,
|
|
120
|
+
用于防止“规则没有运行”被误判为通过。
|
|
121
|
+
|
|
122
|
+
## 5. 断言契约
|
|
123
|
+
|
|
124
|
+
`assert.search` 必填,沿用同一套确定性原语。断言类型:
|
|
125
|
+
|
|
126
|
+
| `operator` | 额外字段 | 行为 |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `absent` | `scope` = `document` / `section` | 搜索条件未命中时输出 finding;必须提供范围证据 |
|
|
129
|
+
| `present` | 无 | 搜索条件命中时输出 finding |
|
|
130
|
+
| `numeric_compare` | `search.group`、`compare.op`、`compare.value` | 解析原文数值并按 `gte` / `lte` / `gt` / `lt` / `eq` / `ne` 比较 |
|
|
131
|
+
| `date_compare` | `search.group`、`compare.op`、`compare.value` | 解析原文日期并按上述操作符比较 |
|
|
132
|
+
| `duration_compare` | 上述字段 + `unit` = `day` / `month` / `year` | 只比较相同单位,不跨单位换算 |
|
|
133
|
+
|
|
134
|
+
compare 系列规则必须满足:
|
|
135
|
+
|
|
136
|
+
- `search.pattern` 含有第 `search.group` 个捕获组;
|
|
137
|
+
- `compare.value` 对 `numeric_compare` 是数字,对 `date_compare` 是可解析日期;
|
|
138
|
+
- `duration_compare` 的原文单位必须与 `unit` 一致,否则进入 `review_items`(`unverifiable`),
|
|
139
|
+
不输出数值结论;
|
|
140
|
+
- 数值或日期无法解析时,记录人工复核项,不自动换算、不补值。
|
|
141
|
+
|
|
142
|
+
`absent` 的 `scope` 必须是 `document` 或 `section`;缺省范围会被判为包损坏。
|
|
143
|
+
|
|
144
|
+
## 6. 证据与置信度
|
|
145
|
+
|
|
146
|
+
| 证据类型 | 内容 |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `matched_span` | 原文 `quote` + `start` / `end` + `line` / `column` + `section_id` |
|
|
149
|
+
| `document_scope` | 全文起止范围与起止行列,不伪造原文引用 |
|
|
150
|
+
| `section_scope` | 命中所在结构块的范围,不伪造原文引用 |
|
|
151
|
+
|
|
152
|
+
证据约束:
|
|
153
|
+
|
|
154
|
+
- `quote` 必须等于原文切片,禁止拼接、改写或从规范化文本复制;
|
|
155
|
+
- `start` / `end` 基于原始文本,不是规范化文本;
|
|
156
|
+
- absence 规则必须给出搜索范围;
|
|
157
|
+
- 没有证据的 finding 不得进入报告。
|
|
158
|
+
|
|
159
|
+
`confidence_policy` 常用字段:
|
|
160
|
+
|
|
161
|
+
| 字段 | 使用场景 |
|
|
162
|
+
|---|---|
|
|
163
|
+
| `exact_match` | `present` 或 compare 断言命中原文时 |
|
|
164
|
+
| `absence` | `absent` 断言未找到检索词时 |
|
|
165
|
+
|
|
166
|
+
absence 类结论建议使用 `medium` 或 `low`;`low` 置信 finding 会强制进入人工复核清单。
|
|
167
|
+
|
|
168
|
+
## 7. 来源可追溯
|
|
169
|
+
|
|
170
|
+
正式规则包的每条规则必须满足:
|
|
171
|
+
|
|
172
|
+
- `source.type` = `"official"`;
|
|
173
|
+
- `citation` 带书名号或法规名,并写到条款号;
|
|
174
|
+
- `source.url` 使用 `https://`;
|
|
175
|
+
- 条款号逐条核对官方全文,不凭记忆或二手摘要编写。
|
|
176
|
+
|
|
177
|
+
运行时不会联网校验来源;来源可信度由规则作者在发布前核对,并由规则包版本记录。
|
|
178
|
+
|
|
179
|
+
## 8. 测试夹具与 test_ids
|
|
180
|
+
|
|
181
|
+
正式规则必须同时具备:
|
|
182
|
+
|
|
183
|
+
- 至少一个正例:命中并给出期望证据;
|
|
184
|
+
- 至少一个反例:候选命中但不触发 finding;
|
|
185
|
+
- 至少一个边界例:缺字段、矛盾值、低置信或词形差异等边界。
|
|
186
|
+
|
|
187
|
+
数值阈值规则可增加 `threshold` 类型用例,覆盖等值边界。
|
|
188
|
+
|
|
189
|
+
夹具位于 `scripts/fixtures/rules/<pack>-cases.json`,示例结构:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"schema_version": "1.0",
|
|
194
|
+
"pack_id": "data-export",
|
|
195
|
+
"cases": [
|
|
196
|
+
{
|
|
197
|
+
"case_id": "EXPORT-SAFEGUARD-001-positive",
|
|
198
|
+
"rule_id": "EXPORT-SAFEGUARD-001",
|
|
199
|
+
"kind": "positive",
|
|
200
|
+
"text": "为提供服务,本平台会将您的个人信息传输至境外服务器。\n",
|
|
201
|
+
"expect": {
|
|
202
|
+
"outcome": "finding",
|
|
203
|
+
"severity": "high",
|
|
204
|
+
"confidence": "medium",
|
|
205
|
+
"evidence_kinds": ["matched_span", "document_scope"],
|
|
206
|
+
"evidence_quote": "传输至境外"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
验收要求:
|
|
214
|
+
|
|
215
|
+
1. 每条规则的 `test_ids` 与夹具中同 id 的正例、反例、边界例逐项相等;
|
|
216
|
+
2. 每个用例显式声明期望结果、severity、confidence、证据类型与 quote;
|
|
217
|
+
3. 反例与边界例也要求候选命中(`status != no_match`);
|
|
218
|
+
4. `matched_span` 的 `start` / `end` 切片必须等于 `quote`;
|
|
219
|
+
5. 同一语料运行两次,除 `generated_at` 外结果完全一致。
|
|
220
|
+
|
|
221
|
+
## 9. 校验与发布
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
python3 scripts/yotta_compliance.py rules validate --pack rules/pipl.json
|
|
225
|
+
python3 scripts/yotta_compliance.py rules validate --pack rules/data-export.json
|
|
226
|
+
python3 scripts/test_yotta_compliance.py
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
规则包变更后还要同步检查:
|
|
230
|
+
|
|
231
|
+
- `references/coverage.md` 的规则清单与来源条款;
|
|
232
|
+
- 夹具中的 `test_ids` 与期望结果;
|
|
233
|
+
- 报告示例与覆盖范围说明;
|
|
234
|
+
- `pack_version` 是否递增。
|
|
235
|
+
|
|
236
|
+
不要编写以下规则:
|
|
237
|
+
|
|
238
|
+
- 需要语义推理、模型评分或真实业务事实才能判断的规则;
|
|
239
|
+
- 需要跨单位换算的人数阈值规则;
|
|
240
|
+
- 需要联网检索法条或实时法规更新的规则;
|
|
241
|
+
- 无法给出原文证据或明确来源的规则。
|