feat(ssa): Complete QPER architecture - Query, Planner, Execute, Reflection layers
Implement the full QPER intelligent analysis pipeline: - Phase E+: Block-based standardization for all 7 R tools, DynamicReport renderer, Word export enhancement - Phase Q: LLM intent parsing with dynamic Zod validation against real column names, ClarificationCard component, DataProfile is_id_like tagging - Phase P: ConfigLoader with Zod schema validation and hot-reload API, DecisionTableService (4-dimension matching), FlowTemplateService with EPV protection, PlannedTrace audit output - Phase R: ReflectionService with statistical slot injection, sensitivity analysis conflict rules, ConclusionReport with section reveal animation, conclusion caching API, graceful R error classification End-to-end test: 40/40 passed across two complete analysis scenarios. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# **SSA-Pro R 服务代码深度审查报告**
|
||||
|
||||
**审查对象:** SSA-Pro R Service Source Code (v1.0)
|
||||
|
||||
**审查文件:** Dockerfile, plumber.R, data\_loader.R, guardrails.R, etc.
|
||||
|
||||
**审查时间:** 2026-02-18
|
||||
|
||||
**审查结论:** 🟡 **总体优秀,但存在阻断性缺失 (Blocker)**
|
||||
|
||||
## **1\. 🚨 阻断性问题 (Critical Issues)**
|
||||
|
||||
**这些问题会导致服务无法启动或无法下载数据,必须在联调前修复。**
|
||||
|
||||
### **1.1 data\_loader.R 中缺失 OSS 签名函数**
|
||||
|
||||
* **问题描述**:在 data\_loader.R 第 63 行调用了 generate\_oss\_signature(config, "GET", oss\_key),但我翻遍了上传的所有文件,**没有找到这个函数的定义**。
|
||||
* **风险**:代码运行到下载 OSS 步骤时会直接报错 Error: could not find function "generate\_oss\_signature"。
|
||||
* **修复建议**:
|
||||
1. **方案 A (推荐)**:在 utils/ 下新建 oss\_signer.R,实现阿里云 OSS 的 HMAC-SHA1 签名逻辑(需要引入 digest 和 base64enc 包)。
|
||||
2. **方案 B (替代)**:如果不想手写签名,可以使用系统调用 awscli (配置阿里云 endpoint) 或寻找现成的 R 包(如 aliyunr,但需验证维护状态)。
|
||||
|
||||
### **1.2 plumber.R 的动态加载性能隐患**
|
||||
|
||||
* **问题描述**:在 plumber.R 的 POST /api/v1/skills/\<tool\_code\> 接口中,第 38 行使用了 source(tool\_file)。这意味着**每次请求都会重新从磁盘读取并解析 R 脚本**。
|
||||
* **风险**:
|
||||
* **开发环境**:这是好事,支持热重载。
|
||||
* **生产环境**:这是性能杀手。在高并发下,频繁的磁盘 I/O 和语法解析会显著增加延迟。
|
||||
* **修复建议**:
|
||||
* 引入 DEV\_MODE 变量判断。
|
||||
* **生产环境**:在服务启动时(第 13 行左右)预先加载所有 tools/ 下的脚本,或者使用 environment 缓存已加载的函数。
|
||||
* **开发环境**:保持现有的动态 source 逻辑。
|
||||
|
||||
## **2\. 工程与安全隐患 (Engineering & Security Risks)**
|
||||
|
||||
### **2.1 Docker 容器的 Root 权限风险**
|
||||
|
||||
* **问题描述**:Dockerfile 未指定用户,默认使用 root 运行 R 服务。
|
||||
* **风险**:如果 R 代码中存在漏洞(如允许执行系统命令 system()),攻击者将获得容器的 Root 权限,可能逃逸或破坏文件系统。
|
||||
* **修复建议**:在 Dockerfile 末尾添加非特权用户切换:
|
||||
RUN useradd \-m appuser
|
||||
USER appuser
|
||||
|
||||
### **2.2 路径遍历攻击 (Path Traversal)**
|
||||
|
||||
* **问题描述**:plumber.R 第 33 行:
|
||||
tool\_file \<- file.path("tools", paste0(tolower(gsub("ST\_", "", tool\_code)), ".R"))
|
||||
虽然做了 gsub,但如果 tool\_code 包含 ../ 等字符,仍可能尝试访问上层目录。
|
||||
* **修复建议**:增加严格的白名单校验,或者校验 tool\_code 只能包含字母、数字和下划线。
|
||||
if (\!grepl("^\[A-Z0-9\_\]+$", tool\_code)) {
|
||||
return(list(status="error", message="Invalid tool code format"))
|
||||
}
|
||||
|
||||
## **3\. 最佳实践点赞 (Highlights) ✅**
|
||||
|
||||
1. **依赖锁定 (renv.lock)**:使用了 renv 进行包管理,这是 R 工程化的基石,做得非常棒。
|
||||
2. **护栏设计 (guardrails.R)**:
|
||||
* 包含了 LARGE\_SAMPLE\_THRESHOLD (5000) 的抽样逻辑,避免了大样本下 Shapiro 检验过敏的问题,非常专业的统计学处理。
|
||||
* 接口设计清晰 (passed, action, reason)。
|
||||
3. **结果格式化 (result\_formatter.R)**:统一处理了 P 值 \< 0.001 的显示,符合 APA 规范。
|
||||
4. **环境隔离 (docker-compose.yml)**:正确使用了环境变量注入 OSS 配置,且区分了开发/生产环境。
|
||||
|
||||
## **4\. 优化代码清单 (Code Improvement Snippets)**
|
||||
|
||||
### **补全 OSS 签名逻辑 (utils/oss\_signer.R)**
|
||||
|
||||
*这部分逻辑比较复杂,我直接提供一个简版实现供参考:*
|
||||
|
||||
library(digest)
|
||||
library(base64enc)
|
||||
|
||||
generate\_oss\_signature \<- function(config, verb, resource) {
|
||||
date \<- format(Sys.time(), "%a, %d %b %Y %H:%M:%S GMT", tz="GMT")
|
||||
content\_type \<- ""
|
||||
content\_md5 \<- ""
|
||||
|
||||
canonicalized\_resource \<- paste0("/", config$bucket, "/", resource)
|
||||
string\_to\_sign \<- paste(verb, content\_md5, content\_type, date, "", canonicalized\_resource, sep="\\n")
|
||||
|
||||
signature \<- base64encode(hmac(config$access\_key\_secret, string\_to\_sign, algo="sha1", raw=TRUE))
|
||||
auth\_header \<- paste0("OSS ", config$access\_key\_id, ":", signature)
|
||||
|
||||
return(c("Authorization" \= auth\_header, "Date" \= date))
|
||||
}
|
||||
|
||||
*注意:需要在 renv.lock 中补充 digest 包。*
|
||||
|
||||
## **5\. 总结**
|
||||
|
||||
这份代码作为 MVP 已经达到了 **85分** 的水平。
|
||||
|
||||
**接下来的行动指南:**
|
||||
|
||||
1. **必须做**:补全 generate\_oss\_signature 函数(或相关文件)。
|
||||
2. **必须做**:在 renv 中添加 digest 依赖。
|
||||
3. **建议做**:优化 plumber.R 的生产环境加载逻辑。
|
||||
|
||||
请将这份报告发给 R 开发工程师,让他们快速修正,然后就可以开始构建镜像了。
|
||||
Reference in New Issue
Block a user