Files
iAOP/docs/_check_isolation_doc.py
T

85 lines
2.8 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
"""采集网只读隔离与网闸配置文档一致性检查 + 代码级只读自检(issue #27)。
检查项:
1. 文档必备章节齐全(只读隔离设计 / 单向网闸配置 / 防火墙规则集 / 验证方法);
2. 红线关键词存在(只读 / 不反控 / 零控制指令 / 反向 DROP);
3. 引用文件(#19 拓扑策略文档 / edge-gateway 目录)存在;
4. **代码级只读自检**:扫描 `core/edge-gateway/drivers/*.py`,确认驱动
无任何写/控制方法(write / set_value / control 等),对齐 PRD 9 章。
用法:python _check_isolation_doc.py
"""
import os
import re
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
REPO_ROOT = os.path.dirname(HERE)
DOC_PATH = os.path.join(HERE, "采集网只读隔离与网闸配置.md")
DRIVERS_DIR = os.path.join(REPO_ROOT, "core", "edge-gateway", "drivers")
REQUIRED_SECTIONS = [
"## 2. 只读隔离设计",
"## 3. 单向网闸配置",
"## 4. 防火墙规则集示例",
"## 5. 验证方法",
]
REDLINE_KEYWORDS = ["只读", "不反控", "零控制指令", "DROP", "反向"]
# 写/控制方法名黑名单(驱动只读约束)
WRITE_METHOD_PATTERN = re.compile(
r"def (write|write_points|set_value|control|set_point|write_register)"
r"|class .*Writer\b", re.IGNORECASE)
def scan_drivers_readonly() -> list:
"""扫描 drivers/ 源码,返回命中写/控制方法的行描述。"""
hits = []
if not os.path.isdir(DRIVERS_DIR):
return ["drivers 目录不存在"]
for name in sorted(os.listdir(DRIVERS_DIR)):
if not name.endswith(".py") or name.startswith("_"):
continue
path = os.path.join(DRIVERS_DIR, name)
for no, line in enumerate(
open(path, "r", encoding="utf-8").read().splitlines(), 1):
if WRITE_METHOD_PATTERN.search(line):
hits.append(f"{name}:{no}: {line.strip()}")
return hits
def main() -> int:
failures = []
text = open(DOC_PATH, "r", encoding="utf-8").read()
for sec in REQUIRED_SECTIONS:
if sec not in text:
failures.append(f"缺少必备章节:{sec}")
for kw in REDLINE_KEYWORDS:
if kw not in text:
failures.append(f"缺少红线关键词:{kw}")
for ref in ("网络拓扑与隔离策略.md",):
if not os.path.isfile(os.path.join(HERE, ref)):
failures.append(f"引用文档缺失:{ref}")
# 代码级只读自检:drivers/ 零写方法
hits = scan_drivers_readonly()
if hits:
failures.append(f"驱动存在写/控制方法:{hits}")
if failures:
print("FAIL")
for f in failures:
print(" -", f)
return 1
print("OK: 章节/红线关键词/引用/驱动只读自检(零写方法)全部通过")
return 0
if __name__ == "__main__":
sys.exit(main())