SynLethHub 全量代码审计报告
📊 评分面板
Security / 安全
有 beta 门禁、cookie 使用 httpOnly;但 lockfile 中存在高危前端依赖,且邀请码被写入 localStorage 并作为 header 复用。
Stability / 稳定性
后端 45 个测试通过且外部 HTTP 有 timeout;但 KG 降级与多处 broad except/pass 会隐藏真实故障。
Performance / 性能
API 参数有多处 limit 上界;但前端单 JS chunk 达 5.77 MB,图谱/Plotly/Cytoscape 没有路由级拆包。
Testing / 测试
后端测试较真实且全部通过;但前端没有 test/typecheck/lint 脚本,npm ci 当前不可复现。
Maintainability / 可维护性
核心文件过大:api.py 3369 行、Workspace.tsx 2267 行,多个函数/组件职责过宽。
Design / 设计原则
SRP、Fail-fast、显式依赖和错误上下文原则被多处违反,主要集中在 API 工厂与前端巨型页面。
Release / 发布
部署文档存在,但缺 CI/CD 与 rollback 自动化;package-lock 不同步且 npm audit 仍报告 6 个漏洞。
Overall / 总体
B:可运行、后端测试扎实,但发布可复现性、前端体积和结构性维护债需要先处理。
📝 总体评估
📋 总体评估
项目概况:SynLethHub 是 React + TypeScript + Vite 前端与 FastAPI + SQLite/Neo4j 后端组成的封闭 beta 代码库,当前功能面覆盖 Copilot、Workspace 图谱、文献 feed、Cases、Trace replay/export 与 beta invite gate。
主要风险:最大阻断项是发布可复现性:跟踪的 package-lock 与 package.json 不同步,npm ci 失败且 npm audit 仍报告 6 个依赖漏洞。其次是证据产品特有的风险:KG/Evidence fallback 会把依赖失败显示为局部或空数据,容易误导研究结论。
亮点:后端测试基础较好,本次实测 45 passed;SQL 多数参数化;FastAPI response_model 覆盖主要端点;部署文档对 beta 拓扑、cookie secret、invite code、反向代理和 smoke test 有明确说明。
优先修复:先修 npm ci/audit、beta invite code 持久化、fallback 显式状态、POST payload 边界;再拆 api.py/Workspace.tsx、补前端测试、做 bundle 拆包。
总评:5.3 / 10,等级 B。这是“能跑且后端有真实测试”的 beta 代码库,不是不可用的项目;但距离稳定公开发布仍有明确工程风险,需要先补发布门禁、前端 QA 和结构性拆分。
12
总发现
0
Critical
1
High
9
Medium
2
Low
0
Info
⚠️ 顶级风险
| # | 发现 | 严重程度 | 类别 |
|---|---|---|---|
| 1 | 前端 lockfile 不可复现且锁定存在已知漏洞的依赖版本 | High | Release / Security |
| 2 | Beta 邀请码被保存在 localStorage 并作为 x-slh-beta-key 注入请求 | Medium | Security |
| 3 | KG 不可用时图 API 静默降级为 SQLite SL fallback,可能给出不完整图谱 | Medium | Stability / Fallback |
| 4 | 核心 API 工厂和前端页面违反文件/函数大小与 SRP 原则 | Medium | Maintainability / Architecture |
| 5 | 前端生产包为单一 5.77 MB JS chunk,缺少路由级拆包 | Medium | Performance |
| 6 | 多处 broad except/pass 吞掉初始化、缓存和关闭错误,故障不可观测 | Medium | Stability / Observability |
| 7 | POST 请求模型缺少大小和数值边界,trace/export 可接收过大嵌套 payload | Medium | Backend API / Type Safety |
| 8 | SQLite 连接缺少 WAL/busy_timeout,写入与读取并发下存在锁等待风险 | Medium | Stability / Performance |
| 9 | 前端 EvidenceTab 对多个证据接口 catch(() => null),把失败伪装成缺层 | Medium | Fallback / Frontend State |
| 10 | 前端缺少自动化测试、typecheck、lint 脚本,发布验证依赖人工 smoke | Medium | Testing / Release |
| 11 | 健康检查端点在 beta public allowlist 中,暴露配置状态与内部层状态 | Low | Security / Configuration |
| 12 | 文档与代码边界存在不一致,发布说明依赖人工约束 | Low | Documentation / Code Consistency |
🔍 详细发现
1. 前端 lockfile 不可复现且锁定存在已知漏洞的依赖版本
High Confirmed问题:发布构建无法用 npm ci 从受控 lockfile 复现,同时 lockfile 对应的依赖图存在已知漏洞。虽然 npm install --package-lock=false 后能拉到更新版本并成功构建,但这恰好证明当前仓库记录的锁文件不是发布可信来源。
原则:配置与发布可复现性;Configuration Safety 9.2;Release readiness
原则:配置与发布可复现性;Configuration Safety 9.2;Release readiness
- File: frontend/package.json:23-34
- Function / Module: npm dependency resolution
- Relevant behavior: package.json 允许 react-router-dom ^6.28.0、postcss ^8.4.49、vite ^7.3.1;跟踪的 package-lock 锁定 vite 7.3.1、postcss 8.5.8、react-router 6.30.3、picomatch 2.3.1、protocol-buffers-schema 3.6.0。
- Runtime behavior: npm ci 失败:Missing: source-map@0.6.1 from lock file。npm audit --json 报告 6 个漏洞,其中 2 high、4 moderate,涉及 Vite dev server 文件读取/deny 绕过、picomatch ReDoS、React Router open redirect、PostCSS XSS 等。
最小修复 / 长期修复
最小修复:运行 npm install 更新 package-lock,使 lockfile 包含 source-map@0.6.1 并升级到 npm audit clean 的 vite/postcss/react-router/picomatch/protocol-buffers-schema 版本;CI 固定使用 npm ci。
长期修复:添加 GitHub Actions 或等价 CI:npm ci、npm run build、npm audit --audit-level=high;发布前要求 lockfile 零 drift。
为什么重要:稳定公开发布依赖可复现安装;如果 CI 或服务器使用 npm ci,会直接失败;如果使用 npm install,则每次可能解析到不同依赖版本,安全和回滚都不可控。
现实失败场景:beta 分支部署时执行 npm ci 失败;运维改用 npm install 绕过后拉到未审计的较新版本,线上行为与开发机不一致,且旧 lockfile 仍持续触发依赖漏洞扫描。
⏱ 估算: 2-4 小时 · 回归测试: 在干净目录运行 npm ci && npm run build && npm audit --audit-level=high。
2. Beta 邀请码被保存在 localStorage 并作为 x-slh-beta-key 注入请求
Medium Confirmed问题:后端已经发放 httpOnly cookie,但前端仍保留 JS 可读的邀请码并在所有 API 调用中复用。邀请码实际上承担 beta 访问凭证功能,localStorage 对任何 XSS、第三方脚本或浏览器扩展都是可读的。
原则:Secret handling;Explicit security boundaries
原则:Secret handling;Explicit security boundaries
- File: frontend/src/app/betaAccess.ts:15-38
- Function / Module: readBetaInviteCode, writeBetaInviteCode, betaInviteHeaders
- Relevant behavior: 邀请码写入 window.localStorage,并在 betaInviteHeaders 中读取后作为 x-slh-beta-key 返回。
- File: frontend/src/lib/api/client.ts:21-34
- Function / Module: apiFetchJson
- Relevant behavior: 每个 API 请求都会合并 betaInviteHeaders,并设置 credentials: include。
最小修复 / 长期修复
最小修复:授权成功后立即 clearBetaInviteCode,只依赖后端 httpOnly cookie;如需自动重试,仅在提交表单前短暂持有 invite code,不持久化。
长期修复:把 beta key 视为一次性兑换码:后端签发 session cookie 后,邀请码不再作为长期 bearer 凭证。
为什么重要:这不是完整生产认证,但它仍保护封闭 beta 数据面;一旦邀请码泄露,攻击者可绕过 invite gate,直到运维轮换邀请列表。
现实失败场景:某个页面或依赖未来引入 XSS,攻击脚本读取 slh_beta_invite_code_v1 并发送给外部,随后可用 x-slh-beta-key 访问受保护 API。
⏱ 估算: 2-3 小时 · 回归测试: BetaInviteGate 成功授权后断言 localStorage 不含 slh_beta_invite_code_v1,后续 /api/session 仅靠 cookie 通过。
3. KG 不可用时图 API 静默降级为 SQLite SL fallback,可能给出不完整图谱
Medium Confirmed问题:图谱 API 的语义是 KG exploration,但 KG 不可用时返回 SQLite SL pair 的轻量图,客户端难以区分“真实 KG 结果为空”和“后端降级后的局部结果”。
原则:Fail Fast 4.4;Don’t hide failure 6.1
原则:Fail Fast 4.4;Don’t hide failure 6.1
- File: backend/src/slh_lit_agent/api.py:1759-1761, 1779-1781
- Function / Module: kg_neighbors, kg_paths
- Relevant behavior: app.state.kg_client 为 None 时,neighbors 返回 _fallback_neighbors_from_sl_pairs,paths 返回 _fallback_paths_from_sl_pairs,而不是暴露 KG 不可用状态。
- Related behavior: /api/health/ready 会把 kg 标记为 not_ready,但业务 API 仍返回 fallback 数据。
最小修复 / 长期修复
最小修复:在 fallback 响应中加入 explicit degraded 字段、source=fallback_sqlite、missing_layers=[kg],并在前端以警告样式展示。
长期修复:把 KG required/optional 做成配置;生产 beta 若 KG 是核心功能,缺失时直接 503,而 demo 模式才允许 fallback。
为什么重要:研究型产品中,不完整证据被展示为正常图谱会误导候选排序、路径解释和用户结论。
现实失败场景:生产 Neo4j 连接失败,用户在 Workspace 查询基因路径,系统展示 fallback 结果且没有明显失败标记,用户误以为 KG 没有更多关系。
⏱ 估算: 4-6 小时 · 回归测试: 模拟 app.state.kg_client=None 调 /api/graph/neighbors,断言响应包含 degraded=true 或返回 503。
4. 核心 API 工厂和前端页面违反文件/函数大小与 SRP 原则
Medium Confirmed问题:核心变更都汇聚到少数巨型文件,导致测试边界不清、重构风险高、多人协作冲突概率大。
原则:SRP 1.1;File Size 1.2;Function Size 1.3;Cohesion 2.2
原则:SRP 1.1;File Size 1.2;Function Size 1.3;Cohesion 2.2
- File: backend/src/slh_lit_agent/api.py:1103-3369
- Function / Module: create_app
- Relevant behavior: create_app 长 2267 行,内部声明路由、认证中间件、KG fallback、Copilot、文献趋势、case/export/report 等多种职责。api.py 总长 3369 行。
- File: frontend/src/pages/Workspace.tsx:896-2267
- Function / Module: WorkspacePage
- Relevant behavior: WorkspacePage 文件 2267 行,组件内约 20 个 useState 与 20 个 useEffect,混合查询状态、图布局、trace、context menu、evidence panel 和 UI 渲染。
最小修复 / 长期修复
最小修复:按路由域拆分 api.py:beta/session、graph、sl-pairs、copilot、literature、cases、exports;Workspace 抽出 useGraphWorkspace、GraphPanel、ExpandBrowser、DetailsPanel。
长期修复:建立“路由模块 + service + schema”后端边界,以及“hook + presentational components”前端边界。
为什么重要:这类结构性债务不会立即导致崩溃,但会使后续功能、修 bug、审计安全边界都变慢。
现实失败场景:新增一个 Copilot 证据类型时需要同时修改 api.py 内嵌函数、Workspace 状态、EvidenceTab 展示和 trace 记录;一个小改动容易波及多条路径。
⏱ 估算: 2-4 天 · 回归测试: 拆分前先保留现有 45 个后端测试;为 Workspace hook 加入状态转换单元测试。
5. 前端生产包为单一 5.77 MB JS chunk,缺少路由级拆包
Medium Confirmed问题:首页、邀请码页或轻量页面也会被迫加载图谱和 Plotly 等重依赖,首屏网络、解析和执行成本偏高。
原则:Performance scalability;YAGNI/KISS for dependency weight
原则:Performance scalability;YAGNI/KISS for dependency weight
- File: frontend/package.json:16-22
- Function / Module: dependency graph
- Relevant behavior: cytoscape、cytoscape-fcose、plotly.js-dist-min、react-cytoscapejs 等重依赖作为普通依赖进入单入口应用。
- Runtime behavior: npm run build 产物 dist/assets/index-BUivia9l.js = 5,774.56 kB,gzip 1,730.72 kB,并触发 Vite “Some chunks are larger than 500 kB” 警告。
最小修复 / 长期修复
最小修复:用 React.lazy/lazy route 对 Workspace、Copilot、Plot 相关页面做 route-level dynamic import;Plotly/Cytoscape 只在对应页面加载。
长期修复:设置 Rollup manualChunks,增加 bundle analyzer 和 chunk size budget。
为什么重要:封闭 beta 用户可能位于不同网络环境;1.7 MB gzip 的单入口 JS 会拉长首屏时间,也增加缓存失效后的回归成本。
现实失败场景:用户只访问 Guide 或 Beta gate,但浏览器仍下载并解析 Workspace/Copilot/Plotly/Cytoscape 相关代码。
⏱ 估算: 1 天 · 回归测试: 构建后断言入口 chunk < 800 kB gzip 或核心首屏 chunk 不包含 plotly/cytoscape。
6. 多处 broad except/pass 吞掉初始化、缓存和关闭错误,故障不可观测
Medium Confirmed问题:系统在多个关键位置用 broad except 把错误降级为无上下文状态或直接忽略,导致健康检查、缓存一致性和配置加载问题难以定位。
原则:Don’t Swallow Errors 6.1;Don’t Lose Error Context 6.2
原则:Don’t Swallow Errors 6.1;Don’t Lose Error Context 6.2
- File: backend/src/slh_lit_agent/api.py:1139-1141
- Function / Module: create_app
- Relevant behavior: Neo4j init 异常被替换为固定字符串 “Neo4j client init failed”。
- File: backend/src/slh_lit_agent/api.py:2884-2888, 3069-3091
- Function / Module: literature_keyword_trends
- Relevant behavior: cache JSON 解析失败和 cache 写入失败均 pass。
- File: backend/src/slh_lit_agent/env.py:49-62
- Function / Module: load_env_files
- Relevant behavior: 读取 .env 文件失败直接 continue,没有日志或返回错误。
最小修复 / 长期修复
最小修复:至少记录 exception class、配置键或 cache_key;对生产关键初始化失败增加 app.state diagnostics 并暴露到内部 ready endpoint。
长期修复:引入结构化日志和错误分类,区分 optional dependency degraded 与 required dependency failed。
为什么重要:错误吞掉后,测试和运维只能看到“功能降级/数据为空”,看不到触发条件、路径和原始异常。
现实失败场景:SLDB3 路径权限错误或 cache 表写入失败,用户看到趋势结果每次重算或缺层,日志没有足够信息定位根因。
⏱ 估算: 1 天 · 回归测试: 模拟 cache payload 无效、.env 读取失败、Neo4j 初始化失败,断言日志/diagnostic payload 包含错误类型。
7. POST 请求模型缺少大小和数值边界,trace/export 可接收过大嵌套 payload
Medium Confirmed问题:GET 参数多数有 Query 上界,但 POST 请求模型没有同等约束;trace payload 可携带大量 steps/artifacts/任意嵌套对象并触发 DB 写入或导出。
原则:Type Safety boundary;Unbounded Resources 10.2
原则:Type Safety boundary;Unbounded Resources 10.2
- File: backend/src/slh_lit_agent/api.py:537-562
- Function / Module: TracePayload / TraceStepPayload
- Relevant behavior: request、response_summary、data_version、inputs、outputs 使用 dict/list/str/int/float/bool/None 或 dict[str, Any],没有字段大小限制。
- File: backend/src/slh_lit_agent/api.py:830-836
- Function / Module: CopilotQueryRequest
- Relevant behavior: neighbors_limit、paths_k、paths_max_len 是普通 int,POST body 没有 Query 的 ge/le 限制。
- File: backend/src/slh_lit_agent/api.py:3290-3319
- Function / Module: trace_export_case_markdown / trace_export_report_pdf
- Relevant behavior: 接收完整 TracePayload 后生成 markdown/PDF artifacts。
最小修复 / 长期修复
最小修复:为 Pydantic model 加 Field(max_length, ge, le),限制 steps/artifacts 数量与嵌套 JSON 总大小;超过限制返回 413/422。
长期修复:对导出端点增加后台任务队列、速率限制和 artifact quota。
为什么重要:公开 API 面即使有 beta gate,也应限制资源消耗;否则单个请求可能导致内存、SQLite payload_json 或 PDF 渲染成本失控。
现实失败场景:恶意或损坏的客户端上传数万条 trace steps 并请求 report-pdf,服务端同步构造 markdown/PDF,占用 CPU、内存和磁盘。
⏱ 估算: 1-2 天 · 回归测试: 构造超长 query、neighbors_limit=100000、steps=10000 的请求,断言 422/413 且不写 artifact。
8. SQLite 连接缺少 WAL/busy_timeout,写入与读取并发下存在锁等待风险
Medium Suspected问题:SQLite 默认 journal/timeout 在多请求写入、读写交错时容易出现 database is locked;当前代码没有显式 busy_timeout 或 WAL 来缓冲并发。
原则:Resource management;No shared mutable state without synchronization 5.4
原则:Resource management;No shared mutable state without synchronization 5.4
- File: backend/src/slh_lit_agent/db.py:20-26
- Function / Module: connect
- Relevant behavior: 每次连接只设置 PRAGMA foreign_keys = ON,没有 busy_timeout、journal_mode=WAL 或连接池策略。
- File: backend/src/slh_lit_agent/db.py:371-407
- Function / Module: upsert_trace_payload
- Relevant behavior: trace upsert 在请求路径中执行 INSERT/UPDATE 并 commit。
- File: backend/src/slh_lit_agent/api.py:1360-1364
- Function / Module: home_stats
- Relevant behavior: 请求路径刷新 snapshot,也会写入数据库。
最小修复 / 长期修复
最小修复:connect 时设置 PRAGMA busy_timeout=5000 和 WAL(如果部署文件系统支持),把 home_stats refresh 从每请求写入改成按 data_version 条件更新。
长期修复:高并发或多进程部署时将写入任务队列化,或迁移到服务型数据库。
为什么重要:beta 用户的 trace sync、report export、home stats refresh 都可能在同一数据库上并发执行。
现实失败场景:多个浏览器同时触发 trace upsert 和 home stats refresh,SQLite 短时间写锁冲突,部分请求 500 或丢失 trace 同步。
⏱ 估算: 4-8 小时 · 回归测试: 并发发起 trace_upsert/home_stats 请求,断言无 database is locked 且响应时间可接受。
9. 前端 EvidenceTab 对多个证据接口 catch(() => null),把失败伪装成缺层
Medium Confirmed问题:多个证据层失败时,UI 只看到 null,而非“接口失败/未配置/暂无数据”的明确区别。
原则:Don’t Swallow Errors 6.1;Fail Fast 4.4
原则:Don’t Swallow Errors 6.1;Fail Fast 4.4
- File: frontend/src/components/workspace/EvidenceTab.tsx:41-49
- Function / Module: EvidenceTab
- Relevant behavior: slPairLiterature、depmap、tcga、gtex、predictionsPair 均使用 .catch(() => null),只有 slPairEvidence 失败才会让 Promise.all 进入整体 error。
- File: frontend/src/components/workspace/EvidenceTab.tsx:50-57
- Relevant behavior: 成功回调把 null 当作正常 data 层写入。
最小修复 / 长期修复
最小修复:把每个子请求包装成 {ok,data,error},UI 显示“未配置/请求失败/暂无数据”三种状态。
长期修复:后端统一 evidence layer status schema,前端按状态渲染。
为什么重要:研究证据产品必须区分缺证据和取证失败;否则用户会把服务故障解释成生物学证据缺失。
现实失败场景:/api/evidence/tcga 500,EvidenceTab 仍渲染其他层并把 tcga=null,当作没有 TCGA 证据展示。
⏱ 估算: 4-6 小时 · 回归测试: mock tcga 返回 500,断言 EvidenceTab 展示 TCGA 请求失败而不是空数据。
10. 前端缺少自动化测试、typecheck、lint 脚本,发布验证依赖人工 smoke
Medium Confirmed问题:后端有 17 个测试文件且 45 个测试通过;前端没有同等自动化回归保护。Workspace/Copilot/Home 是风险最高的交互面,却只能靠构建和人工检查发现问题。
原则:Testing authenticity 8.x;Release readiness
原则:Testing authenticity 8.x;Release readiness
- File: frontend/package.json:6-11
- Function / Module: npm scripts
- Relevant behavior: 只有 preinstall、dev、dev:lit-agent、build、preview;没有 test、typecheck、lint。
- File: DEPLOY_BETA.md:111-117
- Function / Module: Frontend build deployment
- Relevant behavior: 发布步骤只列 npm install 和 npm run build;浏览器检查在文档后续以人工 smoke 形式描述。
最小修复 / 长期修复
最小修复:添加 npm run typecheck、lint、Vitest/RTL smoke;至少覆盖 BetaInviteGate、apiFetchJson、queryState、EvidenceTab 错误状态。
长期修复:加 Playwright e2e,覆盖邀请码、Home、Copilot、Workspace、Trace export 的 beta smoke。
为什么重要:TypeScript strict 只能覆盖编译时类型,不能覆盖路由状态、API 错误、邀请码流程、图谱交互与 trace 导出。
现实失败场景:重构 api endpoints 或 queryState 后,npm run build 仍通过,但 BetaInviteGate 登录流或 Workspace 选中节点状态损坏,直到 tester 反馈才发现。
⏱ 估算: 1-2 天 · 回归测试: CI 中运行 npm ci、npm run typecheck、npm test、npm run build。
11. 健康检查端点在 beta public allowlist 中,暴露配置状态与内部层状态
Low Confirmed问题:代码默认把健康端点作为无需邀请码的 public API,而文档把公开健康端点列为部署侧需关闭事项。
原则:Least exposure;Configuration Safety 9.1
原则:Least exposure;Configuration Safety 9.1
- File: backend/src/slh_lit_agent/api.py:193-199
- Function / Module: _BETA_PUBLIC_PATHS
- Relevant behavior: /api/health 和 /api/health/ready 被列为 beta public paths。
- File: backend/src/slh_lit_agent/api.py:1296-1312
- Function / Module: health_ready
- Relevant behavior: 响应包含 kg、llm、sldb3、beta_access invite_count 等内部状态。
- File: DEPLOY_BETA.md:52-54
- Relevant behavior: 部署文档提醒不要公开代理 health endpoint,除非有意。
最小修复 / 长期修复
最小修复:保留 /api/health 的最小 ok 响应;ready 仅内网或要求管理 key;不要返回 invite_count。
长期修复:区分 public liveness、internal readiness、admin diagnostics 三个端点。
为什么重要:这类信息泄露不等同于凭证泄露,但会帮助外部观察系统依赖状态、配置是否完成和可攻击时间窗口。
现实失败场景:公网代理未按文档 deny /api/health/ready,外部可直接看到 KG/LLM/SLDB3 是否配置、invite_count。
⏱ 估算: 2-4 小时 · 回归测试: 启用 beta_access_required 后无 invite code 请求 /api/health/ready,应返回 403 或最小化响应。
12. 文档与代码边界存在不一致,发布说明依赖人工约束
Low Confirmed问题:关键发布边界靠文档提醒而不是代码/配置强制;README 对 API 面和 cancer 语义的描述落后于当前代码。
原则:Documentation accuracy;Least surprise 3.1
原则:Documentation accuracy;Least surprise 3.1
- File: backend/README.md:13-16
- Function / Module: Backend README
- Relevant behavior: 文档仍描述 “Serve API for SynLethHub Home/Download”,而当前 beta surface 已包含 Copilot、Workspace、Database、Cases、Trace。
- File: backend/README.md:127
- Relevant behavior: 文档说明 cancer accepted but schema-agnostic;代码中 fallback/SL pair paths 已对 cancer/PAN 做过滤和排序。
- File: DEPLOY_BETA.md:52-54 vs backend/src/slh_lit_agent/api.py:193-199
- Relevant behavior: 文档要求不要公开 health,代码默认 public allowlist。
最小修复 / 长期修复
最小修复:更新 README 的 API surface、cancer/filter 语义、测试命令;把 health 公开策略从文档转为配置。
长期修复:为发布文档增加机器可执行 smoke 脚本,减少人工解释空间。
为什么重要:运维和后续 agent 依赖文档执行;不一致会导致错误部署、错误测试范围或重复修复已变化的行为。
现实失败场景:新部署人员按 README 理解为文献 feed MVP,遗漏 Copilot/Workspace/Trace 的 smoke;或未关闭 health endpoint。
⏱ 估算: 2-4 小时 · 回归测试: 文档中的命令在干净 checkout 上可执行;CI 校验 smoke script。
🏗️ 架构与模块边界
已确认/疑似 · 1 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 核心 API 工厂和前端页面违反文件/函数大小与 SRP 原则 | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ 后端 API、KG、DB、LLM、导出模块职责可识别;前后端目录边界清晰。
✓ SQLite schema 初始化集中,FastAPI response_model 覆盖大多数 GET/POST 响应。
🔒 安全
已确认/疑似 · 3 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 前端 lockfile 不可复现且锁定存在已知漏洞的依赖版本 | High | Confirmed |
| Beta 邀请码被保存在 localStorage 并作为 x-slh-beta-key 注入请求 | Medium | Confirmed |
| 健康检查端点在 beta public allowlist 中,暴露配置状态与内部层状态 | Low | Confirmed |
✅ 已验证 / 正向证据
✓ FastAPI docs/ReDoc/OpenAPI 默认关闭。
✓ Beta cookie 使用 httponly、secure 可配置、samesite=lax。
✓ SQL 查询主要使用参数绑定,未发现直接字符串拼接用户输入执行 SQL。
⚡ 稳定性与错误处理
已确认/疑似 · 3 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| KG 不可用时图 API 静默降级为 SQLite SL fallback,可能给出不完整图谱 | Medium | Confirmed |
| 多处 broad except/pass 吞掉初始化、缓存和关闭错误,故障不可观测 | Medium | Confirmed |
| SQLite 连接缺少 WAL/busy_timeout,写入与读取并发下存在锁等待风险 | Medium | Suspected |
✅ 已验证 / 正向证据
✓ 后端测试 45 passed。
✓ 外部 HTTP 客户端有 timeout、retry 与 user-agent。
✓ GET 查询参数多处使用 Query ge/le 上界。
🚀 性能与可扩展性
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 前端生产包为单一 5.77 MB JS chunk,缺少路由级拆包 | Medium | Confirmed |
| SQLite 连接缺少 WAL/busy_timeout,写入与读取并发下存在锁等待风险 | Medium | Suspected |
✅ 已验证 / 正向证据
✓ 后端列表/图谱端点设置 limit 上界。
✓ 关键词趋势有 keyword_trends_cache 缓存表。
✓ Vite 生产构建能完成。
🧪 测试质量
已确认/疑似 · 1 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 前端缺少自动化测试、typecheck、lint 脚本,发布验证依赖人工 smoke | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ 后端有 17 个测试文件,覆盖 beta access、Copilot、exports、keyword trends、case markdown、db migration。
✓ 后端测试真实执行 FastAPI TestClient 和 SQLite in-memory 场景。
📐 可维护性
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 核心 API 工厂和前端页面违反文件/函数大小与 SRP 原则 | Medium | Confirmed |
| 文档与代码边界存在不一致,发布说明依赖人工约束 | Low | Confirmed |
✅ 已验证 / 正向证据
✓ 类型文件与 API endpoints 有独立目录。
✓ 后端数据写入 helper 多数集中在 db.py,便于后续拆分。
📋 设计原则符合度
已确认/疑似 · 4 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| KG 不可用时图 API 静默降级为 SQLite SL fallback,可能给出不完整图谱 | Medium | Confirmed |
| 核心 API 工厂和前端页面违反文件/函数大小与 SRP 原则 | Medium | Confirmed |
| 多处 broad except/pass 吞掉初始化、缓存和关闭错误,故障不可观测 | Medium | Confirmed |
| 前端 EvidenceTab 对多个证据接口 catch(() => null),把失败伪装成缺层 | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ 前后端基本按 backend/frontend 分层。
✓ 多数数据库操作使用参数化 SQL,避免把数据访问完全散落在前端。
🚢 发布与部署流程
已确认/疑似 · 3 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 前端 lockfile 不可复现且锁定存在已知漏洞的依赖版本 | High | Confirmed |
| 前端缺少自动化测试、typecheck、lint 脚本,发布验证依赖人工 smoke | Medium | Confirmed |
| 文档与代码边界存在不一致,发布说明依赖人工约束 | Low | Confirmed |
✅ 已验证 / 正向证据
✓ DEPLOY_BETA.md 描述了 beta branch、nginx、systemd、smoke test 和双服务器拓扑。
✓ 构建在 npm install --package-lock=false 后通过。
📚 文档准确性
已确认/疑似 · 1 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 文档与代码边界存在不一致,发布说明依赖人工约束 | Low | Confirmed |
✅ 已验证 / 正向证据
✓ 存在 README、DEPLOY_BETA.md、LOCAL_CODEBASE_STATUS.md 和 env.example。
✓ 部署文档明确提示不要直接公开后端、要设置真实 cookie secret 和 invite codes。
⚙️ 配置安全
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 前端 lockfile 不可复现且锁定存在已知漏洞的依赖版本 | High | Confirmed |
| 健康检查端点在 beta public allowlist 中,暴露配置状态与内部层状态 | Low | Confirmed |
✅ 已验证 / 正向证据
✓ 后端 .env.example 明确列出 beta、CORS、LLM、Neo4j、SLDB3 配置。
✓ 缺失 LLM/KG 时 app.state 有配置错误状态。
📡 可观测性
已确认/疑似 · 1 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 多处 broad except/pass 吞掉初始化、缓存和关闭错误,故障不可观测 | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ ready endpoint 能展示 DB/KG/LLM/SLDB3 层状态。
✓ Trace 功能记录 route_context、steps、artifacts 并支持导出。
🧯 Fallback / 防御式代码
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| KG 不可用时图 API 静默降级为 SQLite SL fallback,可能给出不完整图谱 | Medium | Confirmed |
| 前端 EvidenceTab 对多个证据接口 catch(() => null),把失败伪装成缺层 | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ Copilot 在 LLM 未配置时有确定性结构化回答 composer。
✓ 文献抓取对 PubMed/PubTator/fulltext 有 timeout 与 retry。
🧪 测试真实性
已确认/疑似 · 1 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 前端缺少自动化测试、typecheck、lint 脚本,发布验证依赖人工 smoke | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ 后端测试不是纯快照:测试 API beta access、exports、keyword filters/trends、DB migration 等行为。
✓ pytest 实测 45 passed。
🧷 类型安全
已确认/疑似 · 1 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| POST 请求模型缺少大小和数值边界,trace/export 可接收过大嵌套 payload | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ 前端 tsconfig strict=true。
✓ 后端大量 API response_model 使用 Pydantic BaseModel。
🖥️ 前端状态
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 核心 API 工厂和前端页面违反文件/函数大小与 SRP 原则 | Medium | Confirmed |
| 前端 EvidenceTab 对多个证据接口 catch(() => null),把失败伪装成缺层 | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ queryState 集中处理 URL 状态。
✓ localTrace 以固定 schema 维护本地 trace 并有过期时间。
🔌 后端 API 设计
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| KG 不可用时图 API 静默降级为 SQLite SL fallback,可能给出不完整图谱 | Medium | Confirmed |
| POST 请求模型缺少大小和数值边界,trace/export 可接收过大嵌套 payload | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ 大多数 GET 参数使用 Query 限制范围,例如 graph limit、paths k/max_len、case pagination。
✓ response_model 覆盖主要端点。
📦 依赖重量
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 前端 lockfile 不可复现且锁定存在已知漏洞的依赖版本 | High | Confirmed |
| 前端生产包为单一 5.77 MB JS chunk,缺少路由级拆包 | Medium | Confirmed |
✅ 已验证 / 正向证据
✓ 项目依赖数量总体不大:前端 package.json 直接生产依赖 10 个,后端声明依赖 6 个。
✓ 重依赖集中在图谱/绘图相关功能,来源可解释。
🧭 代码一致性
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 核心 API 工厂和前端页面违反文件/函数大小与 SRP 原则 | Medium | Confirmed |
| 文档与代码边界存在不一致,发布说明依赖人工约束 | Low | Confirmed |
✅ 已验证 / 正向证据
✓ 前端 API 调用集中在 endpoints.ts 与 apiFetchJson。
✓ 后端时间戳、JSON helper、SL pair 规范化有复用函数。
💬 注释与说明覆盖
已确认/疑似 · 2 个发现
| 发现 | 严重程度 | 状态 |
|---|---|---|
| 多处 broad except/pass 吞掉初始化、缓存和关闭错误,故障不可观测 | Medium | Confirmed |
| 文档与代码边界存在不一致,发布说明依赖人工约束 | Low | Confirmed |
✅ 已验证 / 正向证据
✓ 关键部署约束在 DEPLOY_BETA.md 中有清晰文字说明。
✓ 部分复杂 fallback/PDF writer 有注释解释约束。
📋 设计原则违规
原则违规汇总
| 原则 | 数量/强度 | 严重程度 | 区域 |
|---|---|---|---|
| 1.1 Single Responsibility / SRP | 4 个核心热点 | Medium | api.py create_app、WorkspacePage、CopilotPage、db.py init_db |
| 1.2 File Size Limit | 6 个 >500 行文件 | Medium | api.py、Workspace.tsx、kg.py、Home.tsx、db.py、Copilot.tsx |
| 1.3 Function/Method Size | 多处 >100 行函数 | Medium | create_app、copilot_query、write_basic_pdf、runner run 等 |
| 4.4 Fail Fast | 2 个主要 fallback | Medium | KG fallback、EvidenceTab catch-to-null |
| 6.1 Don’t Swallow Errors | 多处 broad except/pass | Medium | api.py、env.py、http.py、kg.py |
| 9.2 Fail on Missing Configuration | 生产配置依赖文档提醒 | Low | health readiness、beta env、SLDB3 自动猜路径 |
| 10.2 Unbounded Resources | 2 个 POST 面 | Medium | TracePayload、export/report payload |
✅ 已遵守原则 / 正向模式
✓ 参数化 SQL 使用广泛,未发现明显 SQL 注入路径。
✓ 后端 API 大多声明 response_model,客户端类型文件也较完整。
✓ 外部 HTTP 调用默认有 timeout/retry。
✓ 部署文档明确区分 beta、frontend proxy、backend private topology。
🎯 修复顺序
⚡ 立即修复高优先级
| # | 修复项 | 估算 | 风险 |
|---|---|---|---|
| 1 | 修复 package-lock,同步到 npm ci 可复现;清理 npm audit high。 | 2-4 小时 | 阻断 CI/发布可复现性 |
| 2 | 移除 localStorage 中长期保存的 beta invite code,只使用 httpOnly cookie。 | 2-3 小时 | 降低访问凭证泄露面 |
| 3 | 让 KG/Evidence fallback 显式返回 degraded/layer_error 状态。 | 0.5-1 天 | 避免误导研究结论 |
| 4 | 为 POST 模型增加 Field 上界和 payload size guard。 | 1 天 | 限制单请求资源消耗 |
📅 排期修复中优先级
| # | 修复项 | 估算 |
|---|---|---|
| 5 | 拆分 api.py 与 Workspace.tsx,先抽 service/hook,不改行为。 | 2-4 天 |
| 6 | 添加前端 typecheck/test/lint 与 Playwright beta smoke。 | 1-2 天 |
| 7 | 前端路由级 code splitting,拆出 Plotly/Cytoscape 重 chunk。 | 1 天 |
| 8 | SQLite connect 增加 busy_timeout/WAL,并压测并发写路径。 | 0.5-1 天 |
| 9 | 更新 README/DEPLOY_BETA,并把 health endpoint 策略配置化。 | 0.5 天 |
⚡ Quick Wins
npm ci 绿灯
清 localStorage 邀请码
ready endpoint 最小化
EvidenceTab layer status
route lazy loading
添加 npm run typecheck
报告生成于 2026-06-04;审计范围:/Users/davidlee/Downloads/SynLethHub,模式:full,输出:HTML。验证:backend pytest 45 passed;frontend build passed after npm install --package-lock=false;npm ci failed due lockfile mismatch;npm audit reported 6 vulnerabilities.