68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
# tools/check_sensitive.py —— 提交前扫描暂存区内容
|
|
# 不自动运行:作为 pre-commit 钩子在仓库根目录执行;加 --self-test 可以单独自检
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
PATTERNS = {
|
|
"内网 IP": re.compile(r"\b10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b|\b192\.168\.\d{1,3}\.\d{1,3}\b|\b172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}\b"),
|
|
"疑似密钥": re.compile(r"(?i)\b(?:sk|ak|api[_-]?key|secret|token)[\w-]*\s*[:=]\s*['\"]?[A-Za-z0-9_\-]{16,}"),
|
|
"私钥": re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----"),
|
|
"root 绝对路径": re.compile(r"(?<![\w/])/root/\S+"), # sensitive-ok
|
|
}
|
|
WORDS_FILE = Path("notes/private/sensitive-words.txt")
|
|
ALLOW_MARK = "sensitive-ok" # 行内写这个标记表示人工确认过,可以放行(比如文档里讲解正则的例子)
|
|
|
|
|
|
def load_words() -> list[str]:
|
|
if not WORDS_FILE.exists():
|
|
return []
|
|
return [w.strip() for w in WORDS_FILE.read_text(encoding="utf-8").splitlines() if w.strip() and not w.startswith("#")]
|
|
|
|
|
|
def scan_text(name: str, text: str, words: list[str]) -> list[str]:
|
|
problems = []
|
|
for no, line in enumerate(text.splitlines(), start=1):
|
|
if ALLOW_MARK in line:
|
|
continue
|
|
for label, pat in PATTERNS.items():
|
|
if pat.search(line):
|
|
problems.append(f"{name}:{no} {label}")
|
|
for w in words:
|
|
if w.lower() in line.lower():
|
|
problems.append(f"{name}:{no} 敏感词(见私有清单)") # 不打印敏感词本身
|
|
return problems
|
|
|
|
|
|
def staged_files() -> list[str]:
|
|
out = subprocess.run(["git", "diff", "--cached", "--name-only", "--diff-filter=ACM"],
|
|
capture_output=True, text=True, check=True).stdout
|
|
return [f for f in out.splitlines() if f]
|
|
|
|
|
|
def main() -> int:
|
|
words = load_words()
|
|
problems = []
|
|
for f in staged_files():
|
|
content = subprocess.run(["git", "show", f":{f}"], capture_output=True).stdout # 读暂存区版本
|
|
try:
|
|
problems += scan_text(f, content.decode("utf-8"), words)
|
|
except UnicodeDecodeError:
|
|
continue # 跳过二进制文件
|
|
for p in problems:
|
|
print("✗", p)
|
|
if problems:
|
|
print("发现疑似敏感内容,已阻止提交。确认无误的行可加注释 sensitive-ok。")
|
|
return 1 if problems else 0
|
|
|
|
|
|
if __name__ == "__main__" and "--self-test" in sys.argv:
|
|
sample = "url: http://192.168.1.20:8080\napi_key = 'abcdefghijklmnopqrstuvwxyz'\n正常的一行\n" # sensitive-ok
|
|
found = scan_text("demo.md", sample, ["某客户"])
|
|
assert len(found) == 2, found
|
|
assert scan_text("demo.md", "某客户的需求", ["某客户"]) == ["demo.md:1 敏感词(见私有清单)"]
|
|
print("自检通过:", found)
|
|
elif __name__ == "__main__":
|
|
sys.exit(main())
|