灵扬 LingYang — 上帝视角审计报告
审计范围:全项目代码、数据、发布内容、架构设计
审计时间:2026-04-06
审计基线:commit c6cd3c7 + 未提交的 src/ 变更
一、总览
| 维度 | 评分 | 趋势 |
|---|---|---|
| 安全 | 2/10 → 6/10 | 🟡→🟢 修复后 |
| 代码质量 | 5/10 → 7/10 | 🟡→🟢 修复后 |
| 业务逻辑 | 4/10 → 6/10 | 🟡 仍有改进空间 |
| 架构 | 4/10 | 🟡 早期阶段 |
| 合规规范 | 3/10 → 7/10 | 🔴→🟢 修复后 |
| 内容真实性 | 7/10 | 🟢 旧文件已标记 |
核心结论:P0 和 P1 问题已修复。剩余 P2(配置系统、CLI 入口、测试)为中期改进项。唯一需手动操作:npm token 轮换。
二、安全问题(P0)
2.1 npm 认证令牌暴露
文件:~/.npmrc
内容://registry.npmjs.org/:_authToken=npm_gW...pq(已脱敏)
风险:令牌以明文存储。虽然 .npmrc 不在 git 仓库中,但:
- 该令牌对 npm registry 有发布权限(ling-term-mcp@1.0.0 就是用它发的)
- 任何以 ai 用户身份运行的进程都能读取
- 如果项目被克隆到其他机器,令牌不会随之复制,但 .npmrc 的存在可能被遗忘
建议:令牌应轮换(revoke + regenerate),并考虑使用环境变量 NPM_TOKEN 替代文件存储。
2.2 数据库无访问控制 ✅ 已修复
文件:~/.lingyang/contacts.db、~/.lingyang/metrics.db
原权限:644 (ai:ai) — 所有用户可读
修复后权限:600 (ai:ai) — 仅 owner 可读写
风险(原状态):
- 联系人数据库包含对外联络策略(优先级、状态、备注)
- 任何本地进程/用户都能直接 sqlite3 ~/.lingyang/contacts.db 读取全部数据
- 无加密、无密码保护
修复方式:手动 chmod 600 + _get_db() 中自动执行 os.chmod()
2.3 GitHub API 无 Token — 信息泄露反向风险
文件:src/metrics.py:82-95
现状:无认证调用 GitHub API,速率限制 60 次/小时。
风险:不是泄露风险,而是可靠性风险——6 个仓库 × 每小时 1 次采集 = 占用 10% 配额。超过配额后静默失败(返回 None),无重试机制,数据缺失无声无息。
2.4 import_targets_md() 解析器制造脏数据 ✅ 已修复
文件:src/contacts_tracker.py:278-312(修复后)
原问题:解析器将 Markdown 表格的列标题("网址"、"版块"、"策略")和操作建议("邀请相关领域大V讨论")当作联系人导入。
已确认影响:38 条导入中 17 条是垃圾数据(已在会话中清理)。
修复方式:添加 _TABLE_HEADERS 黑名单、空名称/超长名称检查、短中文名称过滤。
三、代码质量问题
3.1 数据库连接管理:每次操作开关
文件:contacts_tracker.py 全局、metrics.py 全局
模式:每个函数 conn = _get_db() → 操作 → conn.close()
问题:
- 无连接池,频繁开关有性能开销(当前规模可忽略)
- ~~_get_db() 每次都执行 CREATE TABLE IF NOT EXISTS 和 PRAGMA journal_mode=WAL——浪费~~ ✅ 已修复:使用 _db_initialized 模块级标志,CREATE TABLE 仅首次执行
- ~~update() 函数存在 TOCTOU 竞态~~ ✅ 已修复:改为单连接内读+写(L163-220)
def update(contact_id, ...):
conn = _get_db() # 连接 1
contact = get(contact_id) # get() 内部又开一个连接 2,读完后关掉连接 2
if not contact:
conn.close() # 关掉连接 1
return None
# 此时另一个进程可能已删除该联系人
conn.execute(f"UPDATE ...") # 在连接 1 上操作——如果数据已变,结果不可预测
3.2 SQL 拼接
文件:contacts_tracker.py:142、contacts_tracker.py:215
# contacts_tracker.py:142
rows = conn.execute(f"SELECT * FROM contacts{where} ORDER BY priority, updated_at DESC", params).fetchall()
# contacts_tracker.py:215
conn.execute(f"UPDATE contacts SET {', '.join(sets)} WHERE id = ?", params)
风险等级:🟡 低。where 和 sets 由代码内部控制,不接受外部输入。但 f-string SQL 是反模式,容易被后续开发者误用。
3.3 无错误处理
文件:两文件全部函数
表现:
- fetch_repo() 吞掉所有异常:except (HTTPError, URLError, TimeoutError): return None
- _get_db() 不处理 sqlite3.OperationalError(磁盘满、权限不足等)
- ~~add() 不校验参数(空名称、超长字符串)~~ ✅ 已修复:空名称检查 + 200 字符截断(L100-102)
- ~~update() 不校验 status 是否在枚举范围内~~ ✅ 已修复:VALID_STATUSES 枚举校验(L173-175)
3.4 无类型校验的 dataclass 滥用
文件:contacts_tracker.py:85-86
问题:如果数据库 schema 和 dataclass 定义不同步(加字段、改类型),这里会静默失败或抛出不可预测的异常。没有版本迁移机制。
3.5 无测试
文件:不存在测试文件
整个项目零测试。对于一个"对外宣传"工具,可能影响不大。但如果解析器和 API 采集出问题(已经出过了),没有回归保护。
四、业务逻辑缺陷
4.1 联系人状态机无约束
文件:contacts_tracker.py:163-220(修复后)
status 字段没有状态机——可以从任意状态跳到任意状态(replied → pending 是合法的)。notes 字段只追加不编辑(f"{existing}\n{now}: {notes}"),只能越来越长。
注意:update() 现在校验 status 必须在 VALID_STATUSES 枚举内(L173-175),但状态转换顺序无约束。
4.2 指标采集只写不删
文件:metrics.py:114-151
每次 collect_metrics() 都是 INSERT,从不清理旧数据。metrics_history() 默认 LIMIT 30,但数据库会无限增长。对于 6 个仓库、每天采集 1 次,一年约 2,190 行——不严重但不够干净。
注意:已添加 cleanup_old_metrics() 函数(L241-262)可在手动调用时清理,但未自动触发。
4.3 format_report() 和 format_growth() 硬编码中文
文件:metrics.py:206-238
输出字符串硬编码中文标题("灵字辈 GitHub 指标"、"合计")。与"去灵字辈化"原则矛盾——如果这些函数被外部调用,输出会暴露灵字辈品牌。
4.4 REPOS 字典与实际项目不对应
文件:metrics.py:20-27
REPOS = {
"LingFlow": "guangda88/LingFlow",
"LingClaude": "guangda88/LingClaude",
"LingYi": "guangda88/LingYi",
"LingMessage": "guangda88/LingMessage",
"LingMinOpt": "guangda88/LingMinOpt",
"Ling-term-mcp": "guangda88/Ling-term-mcp", # ← 注意这个名字
}
Ling-term-mcp与 npm 包名ling-term-mcp大小写不一致- 缺少
LingYan(灵研)、ZhiBridge(智桥)、LingTongAsk(灵通问道)等项目 LingYang自身也未包含
4.5 发布内容中仍存在审计报告标记的问题
文件:releases/hn_launch_post.md、releases/reddit_launch_post.md、releases/researcher_email_template.md
这些文件尚未经过本轮审计修复,仍包含 docs/AUDIT_REPORT_20260405.md 中标记的多个问题:
| 问题 | 文件 | 状态 |
|---|---|---|
| "Show HN" 标题过于 clickbait | hn_launch_post.md |
❌ 未修 |
| "world's first" 隐含断言 | hn_launch_post.md |
❌ 未修 |
| GitHub 链接可能 404 | reddit_launch_post.md |
❌ 未验证 |
| 过度拟人化("genuinely"、"re-enacted") | hn_launch_post.md |
❌ 未修 |
| 研究者邮件模板过于营销化 | researcher_email_template.md |
❌ 未修 |
| 指向不存在的 GitHub 路径 | researcher_email_template.md L28-29 |
❌ 未验证 |
五、架构风险
5.1 单文件数据库无并发保护
两个 SQLite 数据库(contacts.db、metrics.db)虽然用了 WAL 模式,但:
- 无文件锁检查
- 如果两个进程同时运行 collect_metrics(),可能写入重复数据
- 如果两个进程同时 import_targets_md(),会重复导入(find() 查重不原子)
5.2 配置硬编码
表现:
- DB 路径硬编码 Path.home() / ".lingyang"
- GitHub API 地址硬编码
- REPOS 列表硬编码
- 无 .env / config.yaml / 环境变量支持
影响:不可配置 = 不可测试 = 不可移植。
5.3 stdlib-only 的双刃剑
决策:项目坚持不用第三方依赖(stdlib-only)。
好处:零安装、简单。
代价:
- urllib.request 比 requests/httpx 难用 10 倍,且无连接池
- 无日志框架(用 print)
- 无 CLI 框架(无入口命令)
- 如果项目增长,这个约束会成为瓶颈
5.4 无入口点
项目没有 __main__.py、没有 CLI 命令、没有 if __name__ == "__main__"。所有功能只能通过 python3 -c "from src.xxx import ..." 调用。这不是一个可用的工具,而是一个库——但也没有 setup.py / pyproject.toml,所以也不是一个正经的库。
六、合规与规范
6.1 Git 中不应存在的内容
检查结果:contacts/ 目录在 .gitignore 中(正确),contacts/targets.md 未被 git 追踪(正确)。但:
- ~~
src/__pycache__/在 git 追踪中~~ ✅ 实际未被追踪(git ls-files返回空),.gitignore已有规则 - 无
.editorconfig、无 linter 配置、无 CI
6.2 许可证 ✅ 已修复
项目 README 提到 MIT 许可证。
- ~~根目录无 LICENSE 文件~~ ✅ 已添加 LICENSE(MIT)
- 源文件头部无许可证声明(可选改进)
- src/__init__.py 有 docstring 但无版权信息(可选改进)
6.3 发布内容的法律风险
文件:releases/researcher_email_template.md
邮件模板将 AI 系统的输出描述为"observations"和"research-relevant aspects",暗示学术研究发现。如果发送给真实研究者: - 未披露这些"观察"来自 AI 生成的内容 - 可能构成学术不端(misrepresentation) - "We operate a network..." 暗示有一个研究团队,实际是个人项目
七、修复优先级
P0 — 立即修复(安全 + 数据完整性)
| # | 问题 | 工作量 | 影响 | 状态 |
|---|---|---|---|---|
| 1 | 轮换 npm token | 5min | 防止供应链攻击 | ⏳ 需手动:npmjs.com → Access Tokens → Regenerate |
| 2 | DB 文件权限改为 600 | 1min | 防止本地信息泄露 | ✅ 已修复 — chmod 600 + _get_db() 自动修复 |
| 3 | 修复 import_targets_md() 解析器 |
30min | 防止再次导入垃圾数据 | ✅ 已修复 — 过滤表头、短名称、空名称 |
| 4 | 修复 update() 的 TOCTOU 竞态 |
15min | 数据一致性 | ✅ 已修复 — 单连接读+写,移除 get() 调用 |
P1 — 近期修复(代码质量 + 可靠性)
| # | 问题 | 工作量 | 影响 | 状态 |
|---|---|---|---|---|
| 5 | 移除 __pycache__ from git |
2min | 仓库清洁 | ✅ 不需要 — pycache/ 尚未被 git 追踪 |
| 6 | 添加 .gitignore 规则 __pycache__/ |
1min | 防止再次提交 | ✅ 已存在 — .gitignore 已包含规则 |
| 7 | 为旧发布文件添加"未审核"警告 | 5min | 防止误发 | ✅ 已修复 — 3个文件添加 UNREVIEWED HTML 注释 |
| 8 | fetch_repo() 添加 GitHub Token 支持 |
15min | 可靠性 | ✅ 已修复 — 支持 GITHUB_TOKEN 环境变量 |
| 9 | _get_db() 移除重复的 CREATE TABLE |
5min | 性能 | ✅ 已修复 — 模块级 _db_initialized 标志 |
| 10 | 添加 LICENSE 文件 | 2min | 合规 | ✅ 已修复 — MIT License |
P2 — 中期改进(架构)
| # | 问题 | 工作量 | 影响 | 状态 |
|---|---|---|---|---|
| 11 | 提取配置到 .env 或 config.json |
1h | 可维护性 | ⏳ 待做 |
| 12 | 添加 CLI 入口点 | 2h | 可用性 | ⏳ 待做 |
| 13 | 添加基本测试 | 3h | 回归保护 | ⏳ 待做 |
八、一句话总结
P0/P1 已修复,项目从"不能公开"升级到"可用但需打磨"。 下一步:轮换 npm token(手动),然后决定 P2 架构改进的优先级。
审计人:灵扬 LingYang (Crush GLM-5.1)
审计基线:commit c6cd3c7
修复时间:2026-04-06(同日修复 P0 #2-4, P1 #5-10)