审计报告自审计 — AUDIT_REPORT_20260406_FULL.md
审计对象:docs/AUDIT_REPORT_20260406_FULL.md
审计时间:2026-04-06
方法:逐条对照源代码验证报告中的每一条事实声明
总评
报告整体质量中等偏上。事实核查基本准确,修复状态更新及时。但存在以下系统性问题:
| 维度 | 评分 | 说明 |
|---|---|---|
| 事实准确性 | 7/10 | 6 处过时/错误 |
| 行号引用 | 4/10 | 大量行号已过时,未随修复更新 |
| 严重性判定 | 8/10 | 基本合理,一处分级有争议 |
| 完整性 | 5/10 | 漏掉 4 个值得审计的问题 |
| 结构一致性 | 6/10 | "修复后"评分与正文矛盾 |
一、事实错误(6 处)
错误 1:行号引用全部过时
位置:报告全文,至少 8 处行号引用
| 报告中的引用 | 报告声称的行号 | 实际行号(修复后) | 偏差 |
|---|---|---|---|
contacts_tracker.py TOCTOU 代码示例 |
§3.1 L82-90 | update() 现在在 L163-220 |
+30 行 |
contacts_tracker.py:128 SQL 拼接 |
§3.2 | 实际在 L142 | +14 |
contacts_tracker.py:196 SQL 拼接 |
§3.2 | 实际在 L215 | +19 |
contacts_tracker.py:149-199 update 函数 |
§4.1 | 实际在 L163-220 | +14 到 +21 |
metrics.py:82-95 fetch_repo |
§2.3 | 实际在 L92-111 | +10 到 +16 |
metrics.py:98-135 collect_metrics |
§4.2 | 实际在 L114-151 | +16 |
metrics.py:190-222 format 函数 |
§4.3 | 实际在 L206-238 | +16 |
metrics.py:20-27 REPOS 字典 |
§4.4 | ✅ 正确,未变 | 0 |
contacts_tracker.py:74-75 _row_to_contact |
§3.4 | 实际在 L85-86 | +11 |
contacts_tracker.py:257-282 import_targets_md |
§2.4 | 实际在 L278-312 | +21 到 +30 |
根因:报告先写修复前代码,后做修复,但未同步更新行号。这是审计报告最严重的质量问题——行号对不上会让后续开发者按图索骥时产生困惑,降低报告的可信度。
错误 2:§2.1 明文写出了 npm token 明文
位置:报告 L29
问题:审计报告的目的是指出安全风险,而不是复现安全风险。将完整 token 明文写入审计报告 = 审计报告本身成了泄露载体。如果这份报告被提交到 git(它是未被追踪的 docs/ 文件,但可能被 git add . 误加),token 就进入版本历史了。
应该:只写 npm_<前4位>...<后4位> 或 npm_gW...pq(脱敏处理)。
错误 3:§2.2 权限声称已过时
位置:报告 L41
实际:权限已修复为 600。但报告第二节的正文仍然描述旧状态 644,只在第七节修复表中标注了 "✅ 已修复"。读者只看第二节会得到错误印象。
应该:在 §2.2 正文中添加 (已修复为 600) 的标注,或使用删除线标记旧值。
错误 4:§2.4 解析器行号和描述均过时
位置:报告 L59
实际:修复后函数在 L278-312。同时报告正文描述的是修复前的行为("只看 - **xxx** 格式,不验证内容"),但代码已经添加了 _TABLE_HEADERS 过滤、长度检查、空名称检查。读者会以为这个 bug 还存在。
错误 5:§3.3 描述了已修复的问题但未标注
位置:报告 L113-114
实际:add() 现在有空名称检查和 200 字符截断(L100-102);update() 现在有 VALID_STATUSES 枚举校验(L173-175)。这两条已不成立。
错误 6:§6.1 __pycache__ 描述不准确
位置:报告 L233
实际:src/__pycache__/ 从未被 git 追踪。git ls-files src/__pycache__/ 返回空。.gitignore 中已有 __pycache__/ 规则。这条在 P1 修复表中已更正为"✅ 不需要",但 §6.1 正文仍写"在 git 追踪中",事实矛盾。
二、遗漏问题(4 处)
遗漏 1:_db_initialized 的进程内全局变量问题
文件:contacts_tracker.py:44、metrics.py:49
修复 P1 #9 引入了 _db_initialized 标志来避免重复 CREATE TABLE。但这引入了新问题:
- 如果数据库文件被手动删除后重新创建,
_db_initialized仍为True,后续连接不会执行 CREATE TABLE → 所有操作报no such table错误 - 该标志是进程内的,重启 Python 进程后重置为
False,所以实际上 CREATE TABLE 仍然会在每次进程启动的第一次调用时执行——性能收益仅限于同一进程内的第二次及后续调用,对于 CLI 场景(每次命令一个进程)几乎无意义 - PRAGMA journal_mode=WAL 同理,每次进程启动仍会执行
审计报告声称的性能问题"浪费"(§3.1)被夸大了——对于 SQLite,CREATE TABLE IF NOT EXISTS 在表已存在时是极快的元数据检查(微秒级)。真正的"浪费"是打开连接的开销,而这个问题并未被修复。
遗漏 2:_LINE_PATTERNS 定义了但从未使用
文件:contacts_tracker.py:285
这个集合被创建但从未在 import_targets_md() 中引用。报告 §2.4 说修复了解析器,但实际上遗漏了一个本应使用的过滤机制。这是一个死代码问题,也意味着报告声称的修复不完全——包含"邀请相关领域大V讨论"这样的操作建议文本理论上仍然能通过(只要它匹配 - **xxx** 格式且不在 _TABLE_HEADERS 中)。
遗漏 3:os.chmod() 每次调用都执行
文件:contacts_tracker.py:74-77、metrics.py:77-80
修复 P0 #2 在 _get_db() 中添加了 os.chmod()。但这意味着每次数据库操作都执行一次 chmod 系统调用。对于频繁调用(如 import_targets_md() 导入 20 个联系人 = 60 次 chmod),这是不必要的 I/O。正确做法是在数据库创建时执行一次,或检查当前权限后再决定是否修改。
遗漏 4:docstring 中的 Usage 示例是错误的
文件:contacts_tracker.py:5-12
"""
Usage:
from contacts_tracker import ContactsTracker
tracker = ContactsTracker()
tracker.add("Hacker News", "Show HN", channel="hn", priority="P0")
"""
问题:代码中不存在 ContactsTracker 类。所有函数都是模块级函数。这个 docstring 示例会导致 ImportError 或 AttributeError。审计报告 §3.5 提到"无测试",但没有注意到 docstring 中的代码示例本身就是错的——如果有人尝试按文档使用,会立刻失败。
三、严重性判定争议(1 处)
§2.3 GitHub API 无 Token — 不应归为 P0
报告将此放在"二、安全问题(P0)"章节中,标题为"GitHub API 无 Token — 信息泄露反向风险"。但报告自己的描述承认"不是泄露风险,而是可靠性风险"。
P0 应该是"安全 + 数据完整性"。速率限制问题: - 不涉及安全漏洞 - 不涉及数据损坏 - 最坏情况是采集数据缺失(静默返回 None)
这应该是 P1 或 P2 级别。放在 P0 章节拉低了 P0 的严肃性。
四、结构问题(3 处)
结构问题 1:修复前后状态混在同一份报告中
报告同时包含"修复前的问题描述"和"修复后的状态更新",但没有用删除线或版本标记区分。读者无法区分哪些描述是历史状态、哪些是当前状态。
建议做法:
- 在每个已修复的问题标题后加 (✅ 已修复)
- 或将修复状态统一移到 §七,§二~§六保持原始审计快照不动
结构问题 2:§七 P2 表格格式不完整
报告 L281-283:
|| 12 | 添加 CLI 入口点 | 2h | 可用性 |
|| 13 | 添加基本测试 | 3h | 回归保护 |
|| 14 | 标记/归档未审核的发布文件 | 30min | 防止误发有问题的内容 |
缺少"状态"列(P0/P1 表格有,P2 没有),且 #14 与 P1 #7 功能重复。
结构问题 3:§一评分表用了箭头符号但不一致
有些维度有修复前后对比,有些没有。"内容真实性"评了 7/10 但没有箭头,暗示没变,但旧文件现在已标记 UNREVIEWED——这算不算改进?评分逻辑不透明。
五、修复质量评价
对报告声称"✅ 已修复"的 9 个项目逐一验证:
| # | 问题 | 报告声称 | 实际验证 | 质量评价 |
|---|---|---|---|---|
| P0 #2 | DB 权限 | ✅ chmod 600 + 自动修复 | 权限确实是 600 | ⚠️ 自动修复每次调用都 chmod,有性能开销 |
| P0 #3 | 解析器 | ✅ 过滤表头、短名称、空名称 | 过滤确实生效 | ⚠️ _LINE_PATTERNS 未使用,操作建议文本仍可通过 |
| P0 #4 | TOCTOU | ✅ 单连接读+写 | 确实只用一个连接 | ✅ 修复质量好 |
| P1 #7 | UNREVIEWED 标记 | ✅ 3 个文件添加 HTML 注释 | 标记确实存在 | ✅ 够用 |
| P1 #8 | GitHub Token | ✅ 支持 GITHUB_TOKEN 环境变量 | 确实支持 | ✅ 修复质量好 |
| P1 #9 | _get_db 优化 | ✅ _db_initialized 标志 | 确实加了 | ⚠️ 仅进程内有效,CLI 场景无收益 |
| P1 #10 | LICENSE | ✅ MIT License | 文件存在 | ✅ 正确 |
| P1 #5 | pycache | ✅ 不需要(未被追踪) | 确实未被追踪 | ✅ 判定正确 |
| P1 #6 | .gitignore | ✅ 已存在 | 确实存在 | ✅ 正确 |
修复合格率:6/9 完全合格,3/9 有瑕疵但可用。
六、一句话总结
审计报告的事实基底正确,但自审失败——报告描述的是修复前的代码快照,却没有标注"这是历史状态"。 6 处行号过时、4 处遗漏、npm token 明文写入报告本身。建议:要么将报告拆为"审计快照"和"修复状态"两份文档,要么在每个已修复的问题标题加 (✅ 已修复) 并标注实际行号。
自审计人:灵扬 LingYang (Crush GLM-5.1)