CodeGuard Tutor 进度更新:测试问题调优丨项目博客第八篇
0、序:关于测试
首先感谢一下B侧队友,测试检查出不少问题。在测试阶段让每个人人去测试其他人的部分还是挺有必要的,不会因为思维定式漏掉问题,而且因为每个人负责部分不同,能找到当前修改与自己部分衔接问题。比如开发时B侧本来存在一个needs_more_context字段用于告知需要上下文补全,不过这个字段在 RiskCandidate 转成最终 RiskItem 时丢失了,所以我在C侧开发时逻辑部分变成了插件通过 risks.length 判断是否继续补全。这样会导致 B 返回 low 级疑似风险时,插件误认为已经确认风险并停止扩展。目前我们在返回中增加 needs_more_context 字段,也修改了停止条件。
一、项目背景
CodeGuard Tutor 是面向课程与实验场景的 VS Code 安全分析插件,由 3 人小组按 A / B / C 三层协作开发,主链路为:
A 层交互触发 → B 层检测与传播 → C 层上下文编排与解释衔接 → A 层统一展示 → 用户修复
在跨文件场景下,早期实现存在明显能力缺口:
- 插件仅解析当前文件直接 import,每个关联文件单独调用
POST /analyze; - 各文件结果在后端互不可见,无法建立
source → 跨模块调用 → sink的传播链; - 界面提示「检查关联文件」,但实际仍是独立扫描,与用户对「跨文件分析」的预期不一致。
本次迭代的目标,是在 B 层提供 Python 项目级联合分析接口,在 C 层完成文件收集、请求编排、响应解析与大模型 enrich 衔接,并由 A 层将结果以统一交互与界面形态呈现给用户,形成端到端可用的跨文件能力。
二、团队组建与分工
2.1 成员与职责
| 成员 | 层级 | 主要职责 | 本迭代典型交付 |
|---|---|---|---|
| 成员 A | A 层 | VS Code 插件开发、用户交互、界面展示 | 命令注册与激活、关联文件确认模态框、Problems 诊断与行装饰、explanationPanel Webview、resultPresenter 风险行格式化、与 C 层约定的 presentUnifiedAnalysisOutcome 展示通道对接 |
| 成员 B | B 层 | 后端分析服务、AST 解析、规则引擎、数据流追踪 | POST /analyze-project 路由与请求校验、build_python_project_index、跨文件 ProjectCallResolver、flow 分析器接入 project_index、context_files / analysis_warnings 出证、/enrich-explanations 解释服务 |
| 成员 C | C 层 | 上下文补全、AI 对接、解释生成编排、修复建议衔接、测试样例 | Python BFS 关联文件收集、runPythonProjectAnalysis 请求编排、响应字段解析、maybeEnrichProjectResponse 按 sink 分组 enrich、analysisPresentation 完成类型与日志文案、插件侧测试与文档 |
2.2 协作边界(避免重复建设)
┌──────────────────────────────────────────────────────────────────┐
│ A 层:用户看得见、点得着的一切 │
│ · 何时弹窗、按钮与设置项长什么样 │
│ · Problems / 装饰器 / 解释面板 / Toast 的最终呈现 │
│ · 不决定「送哪些文件、调哪个 API」——由 C 层编排后交给 A 层展示 │
└────────────────────────────┬─────────────────────────────────────┘
│ 结构化 AnalyzeResponse + completionKind
┌────────────────────────────▼─────────────────────────────────────┐
│ C 层:送什么、怎么调、怎么 enrich │
│ · crossFileResolution、extension 内项目/跨文件分支 │
│ · types / responseParser、enrich 分组与 LLM 模式选择 │
│ · analysisPresentation 中的完成类型语义与输出通道日志 │
└────────────────────────────┬─────────────────────────────────────┘
│ HTTP(/analyze-project、/enrich-explanations)
┌────────────────────────────▼─────────────────────────────────────┐
│ B 层:分析事实与传播链 │
│ · 索引、调用解析、污点 source→sink │
│ · 风险候选、context_files、needs_more_context │
│ · enrich 时只改写说明性字段,不篡改检测事实 │
└──────────────────────────────────────────────────────────────────┘
2.3 本迭代八项改动与分工对照
| 序号 | 改动主题 | 主责 | 协作 |
|---|---|---|---|
| 6.1 | Python 关联文件 BFS 收集 | C | — |
| 6.2 | /analyze-project 请求编排 | C | B 提供接口契约与硬上限 |
| 6.3 | 用户提示文案(能力对齐) | C(文案与分流逻辑) | A 模态框与交互承载 |
| 6.4 | project / cross_file 统一展示 | A(面板与诊断呈现) | C 定义 CompletionKind 与 analysisPresentation 日志 |
| 6.5 | context_files 等字段解析 | C | B 定义响应 schema |
| 6.6 | 跨文件 enrich 按 sink 分组 | C(插件编排) | B explanation_service + LLM |
| 6.7 | crossFileCompletionMaxFiles 等配置 | C(语义与上限对齐) | A package.json 配置项注册 |
| 6.8 | 插件侧收集与解析测试 | C | B test_python_project_analysis.py |
三、建设目标
| 目标 | 说明 |
|---|---|
| 真实跨文件传播 | 一次请求内完成多文件索引、调用解析与污点传播 |
| 上下文收集合理 | 按 import 依赖广度优先扩展,直接依赖优先,最多 30 个文件 |
| 接口与体验一致 | 提示文案、输出面板、完成类型与后端能力对齐 |
| 解释层可延续 | 项目分析检出风险后,仍支持资料 / LLM enrich,且不篡改 B 侧风险事实 |
| 兼容与分语言策略 | 单文件 /analyze 保持兼容;JavaScript 暂维持逐文件独立分析 |
四、系统架构与职责边界
4.1 三层职责(本次迭代)
┌─────────────────────────────────────────────────────────────┐
│ A 层(成员 A:插件交互与界面) │
│ · 命令、设置、关联文件确认模态框 │
│ · Problems、编辑器装饰、解释面板 Webview、Toast │
│ · 消费 C 层传入的 AnalyzeResponse 做统一视觉呈现 │
└──────────────────────────┬──────────────────────────────────┘
│ 展示数据
┌──────────────────────────▼──────────────────────────────────┐
│ C 层(成员 C:上下文与解释编排) │
│ · 收集哪些文件送入分析(BFS / 一层 import) │
│ · 构造 /analyze-project 或逐文件 /analyze 请求 │
│ · 解析 context_files、analysis_warnings 等字段 │
│ · completionKind 语义、输出通道日志、enrich 分组调用 │
└──────────────────────────┬──────────────────────────────────┘
│ HTTP
┌──────────────────────────▼──────────────────────────────────┐
│ B 层(成员 B:分析引擎) │
│ · 校验项目文件集与体积上限 │
│ · build_python_project_index:路径、AST、import、函数索引 │
│ · ProjectCallResolver:调用落到项目内具体函数 │
│ · flow 分析器:跨文件 source → sink 传播 │
│ · 生成 RiskCandidate、context_files、analysis_warnings │
│ · /enrich-explanations:LLM 与资料摘录增强 reason / how_to_fix │
└─────────────────────────────────────────────────────────────┘
4.2 关键接口
| 接口 | 用途 |
|---|---|
POST /analyze | 单文件 / 选区分析(Python、JavaScript) |
POST /analyze-project | Python 入口 + 关联文件联合分析 |
POST /enrich-explanations | C 层解释增强(资料摘录 + LLM) |
成员 B 的设计详见 B阶段跨文件联合分析设计.md;下文第五节摘要 B 层交付物,第六节展开 成员 C 依据参考材料整理的八项改动,以便项目全貌完整。
五、B 层交付摘要(成员 B)
本节为 成员 B 交付摘要,便于理解 C 层改动的上游依赖与 A 层展示的风险事实来源。
新增路由:
@router.post("/analyze-project")
def analyze_project(request: ProjectAnalysisRequest):
try:
evaluation = dispatch_project_analysis(request)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
...
response = convert_intermediate_result_to_response(
evaluation,
source_by_path=source_by_path,
)
return response.model_dump()
请求模型:
class ProjectAnalysisRequest:
language: Literal["python"]
entry_file: str
files: list[ProjectFile] # 每项含 file_path + code
workspace_root: Optional[str]
硬限制: 最多 30 个文件(含入口)、单文件 300 KB、总代码 2 MB、仅 .py。
分析范围: SQLInjection、XSS、DangerousFunction 走跨文件调用链;HardcodedSecret 项目模式下逐文件检测后合并。
响应增强: 风险项可带 context_files(传播经过的文件列表)、needs_more_context(低置信候选)、顶层 analysis_warnings。
六、C 层改动说明(成员 C,含与 A 层协作项)
以下八项与项目仓库实现一一对应;表中 主责 与第二节分工表一致。
6.1 关联文件收集升级
主责: 成员 C
文件: vscode-extension/src/crossFileResolution.ts
职责: C 层「上下文文件收集」
改前
- 只解析当前文件直接
import; - 按 import 出现顺序收集;
- Python 对每个关联文件分别
POST /analyze。
改后(Python)
- 广度优先(BFS):当前文件 → 直接 import → 二级 → 三级依赖;
- 直接依赖优先入队,再扩展间接依赖;
- 支持相对 import(
from .module import x); - 不越过
workspaceRoot; seen去重,避免同一文件重复收集;- 关联文件最多 29 个,加入口共 30,与后端硬上限一致。
核心实现:
// 队列初始化:从入口文件源码开始
const queue = [{ source, filePath: currentFilePath }];
while (queue.length > 0 && out.length < maxFiles) {
const current = queue.shift();
const modules = collectPythonImportModulesOrdered(current.source);
for (const mod of modules) {
const resolved = resolvePythonModuleToPath(mod, roots, dirname(current.filePath));
if (resolved && !seen.has(resolved)) {
out.push(resolved);
queue.push({ source: fs.readFileSync(resolved, "utf8"), filePath: resolved });
}
}
}
相对 import 解析要点: 根据模块名前缀 . 的个数向父目录回溯,再拼接 .py / __init__.py 候选路径。
JavaScript: 仍为按源码顺序收集一层 import / require 相对路径,未做 BFS,与后端暂无 /analyze-project 的策略一致。
6.2 插件请求方式调整
主责: 成员 C(协作: 成员 B 提供 /analyze-project 契约)
文件: vscode-extension/src/extension.ts
Python 改前
关联文件1 → POST /analyze
关联文件2 → POST /analyze
关联文件3 → POST /analyze
→ 合并独立结果(cross_file)
Python 改后
入口文件 + 全部关联文件
→ 一次 POST /analyze-project
→ B 层建立跨文件传播链
→ 返回统一 AnalyzeResponse(completionKind: project)
新增函数:
| 函数 | 作用 |
|---|---|
buildAnalyzeProjectUrl() | 将 .../analyze 替换为 .../analyze-project |
postProjectAnalysisRequest() | 发送项目 JSON 请求体 |
runPythonProjectAnalysis() | 读盘组装 files[]、调用接口、附加元数据、触发 enrich 与展示 |
请求体示例:
await postProjectAnalysisRequest(projectUrl, {
language: "python",
entry_file: document.uri.fsPath,
files: [
{ file_path: entryPath, code: entrySource },
{ file_path: relatedPath, code: relatedSource },
// ...
],
workspace_root: workspaceRoot
}, timeoutMs);
语言分流:
if (language === "python") {
await runPythonProjectAnalysis({ ... });
} else {
await runCrossFileAnalysis({ ... }); // JavaScript:逐文件 /analyze
}
失败回退: 项目请求异常时记录日志并提示用户,保留当前文件已有分析结果,不阻断主流程。
6.3 用户提示文案调整
主责: 成员 C(文案与语言分流),协作成员A(展示界面调优)
目的: 避免界面描述与实际分析深度不一致。
| 语言 | 提示要点 |
|---|---|
| Python | 按 import 依赖层级广度优先收集;由后端建立跨文件传播链 |
| JavaScript | 按 import / require 顺序独立检查关联文件;不建立传播链 |
const analysisDescription =
language === "python"
? `将按 import 依赖层级广度优先收集本地 Python 文件,直接依赖优先,并由后端建立跨文件传播链(最多 ${maxFiles} 个关联文件)。`
: `将按源码中 import / require 出现的顺序,独立检查本地 ${moduleHint}(最多 ${maxFiles} 个)。`;
6.4 项目分析结果展示
**主责:**成员 C(analysisPresentation.ts、CompletionKind 与输出日志)
文件: vscode-extension/src/analysisPresentation.ts、resultPresenter.ts、explanationPanel.ts
新增完成类型 CompletionKind:
| 值 | 含义 |
|---|---|
standard | 普通单文件 / 选区分析 |
in_file | 文件内上下文扩窗补全 |
cross_file | JavaScript(或旧路径)关联文件独立扫描汇总 |
project | Python 跨文件联合分析 |
输出面板(project)额外展示:
[补全类型] 跨文件联合分析[跨文件联合分析] 入口文件 1 个,关联文件 N 个,合计 M 个[分析警告] ...(来自analysis_warnings)[说明] 以上结果由后端在同一次项目请求中建立跨文件 source 到 sink 传播链
与 cross_file 的说明文案明确区分:后者注明「独立分析汇总,不代表已建立传播链」。
展示通道统一: Problems 诊断、编辑器行高亮、右侧解释面板、Toast 通知——与主分析、文件内补全共用 presentUnifiedAnalysisOutcome。
6.5 响应字段解析扩展
主责: 成员 C;协作: 成员 B 定义响应 schema
文件: types.ts、responseParser.ts
新增 / 强化字段:
// RiskItem
context_files?: string[]; // 风险传播实际经过的文件
needs_more_context: boolean; // 低置信候选
// AnalysisResponse
analysis_warnings?: string[]; // 模块解析失败、检测器降级等
explanation_source?: string; // enrich 后的来源标签
context_files 语义示例:
[
"app/routes.py",
"app/service.py",
"app/repository.py"
表示污点从路由层经服务层到达 repository 中的 sink。
解析代码:
context_files: Array.isArray(obj.context_files)
? obj.context_files.filter((item): item is string => typeof item === "string")
: undefined,
analysis_warnings: Array.isArray(raw.analysis_warnings)
? raw.analysis_warnings.filter((item): item is string => typeof item === "string")
: undefined,
6.6 跨文件大模型解释(enrich)
主责: 成员 C(插件侧分组编排);协作: 成员 B(explanation_service、LLM);
项目分析可能在多个 sink 文件产生风险。C 层在原有「解释资料来源」三选一流程上,增加 按 RiskItem.file_path 分组 enrich:
async function maybeEnrichProjectResponse(...) {
const risksByFile = new Map<string, Record<string, unknown>[]>();
for (const risk of risks) {
const key = path.normalize(risk.file_path);
risksByFile.get(key)?.push(risk) ?? risksByFile.set(key, [risk]);
}
for (const [filePath, fileRisks] of risksByFile) {
await callEnrichForRisks({
risks: fileRisks,
sourceCode: sourceByPath.get(filePath) ?? "",
filePath,
language: "python",
...
});
}
}
约束(与全项目 enrich 契约一致):
- LLM / 资料只优化
reason、how_to_fix等说明性字段; - 不修改 B 侧给出的风险类型、等级、行号、
needs_more_context等事实字段。
6.7 插件配置调整
主责: 成员 C(上限语义与后端对齐);协作: 成员 A(package.json 配置项注册)
文件: vscode-extension/package.json
| 配置项 | 变更 |
|---|---|
crossFileCompletionMaxFiles | 上限由 50 收紧为 29(加入口 30) |
enableCrossFileCompletion 描述 | 明确 Python 联合传播、JavaScript 独立扫描 |
"maximum": 29,
"description": "跨文件补全单次最多收集的关联文件数量。加上当前文件后,后端硬上限为 30 个文件。"
6.8 C 层测试
| 测试文件 | 覆盖内容 |
|---|---|
vscode-extension/test/crossFileResolution.test.js | import BFS 顺序、直接依赖优先、maxFiles 截断、多行 import |
vscode-extension/test/riskConfidence.test.js | context_files、analysis_warnings 解析、explanation_source 透传 |
运行方式(开发):
cd vscode-extension
npm run compile
node test/crossFileResolution.test.js
node test/riskConfidence.test.js
后端项目分析用例见 backend/tests/test_python_project_analysis.py。
七、端到端流程
7.1 Python 跨文件联合分析
7.2 JavaScript(当前策略)
收集一层 require/import
→ 每个关联文件 POST /analyze
→ buildCrossFileMergedResponse
→ presentUnifiedAnalysisOutcome(cross_file)
八、测试与验证建议
| 场景 | 操作 | 预期 |
|---|---|---|
| Python BFS 收集 | 打开多层 import 的入口 .py,同意检查关联文件 | 输出 [关联文件收集] 列表,直接依赖在前 |
| 联合传播 | 漏洞在 import 模块的 sink | completionKind=project,context_files 含多文件路径 |
| 30 文件上限 | 配置 crossFileCompletionMaxFiles=29 | 关联文件 ≤29,后端不返回 400 |
| 独立扫描对比 | 打开 5-caller-module.js,跨文件补全 | cross_file 说明,非 project |
| enrich | 项目检出风险后选「仅大模型」 | 按 sink 文件分组 enrich,风险事实不变 |
| 失败回退 | 故意停后端再触发项目分析 | 警告提示,保留当前文件结果 |
Python 样例: 仓库内 tests/cases/python/vulnerability_samples/crossfile_entry.py 及关联 fixture。
JavaScript 样例: tests/cases/javascript/javascript/5-caller-module.js。
九、已知限制与后续方向
| 项目 | 说明 |
|---|---|
| 语言范围 | /analyze-project 仅 Python;JS 无项目级传播 |
| 文件收集 | JS 仅一层相对路径;Python 不扫描 node_modules 式包名 |
| 文件来源 | 后端只分析请求体中的 files,不自行扫盘 |
| 硬编码密钥 | 项目模式下主要为逐文件合并,不参与调用链传播 |
| 性能 | 大项目 + 多轮 enrich 受 requestTimeoutMs 影响 |
后续可扩展:
- JavaScript
/analyze-project与 BFS 依赖收集; - 解释面板展示完整
context_files链路 UI; - 与课程 RAG 资料按
context_files精准引用。
十、涉及文件清单(按成员)
10.1 A 层(成员 A)
| 文件 | 变更要点 |
|---|---|
explanationPanel.ts | 解释面板 Webview,消费统一分析结果 |
resultPresenter.ts | Problems 诊断、行装饰、风险行展示 |
extension.ts(交互部分) | 命令注册、模态确认、与 C 层编排的衔接调用 |
package.json(UI 配置项) | 命令、设置项注册与描述展示 |
10.2 B 层(成员 B)
| 文件 | 变更要点 |
|---|---|
api/routes/analyze_project.py | 项目分析路由 |
schemas/project_request_schema.py | 请求模型 |
core/project/project_dispatcher.py | 项目调度 |
core/project/python/indexer.py | 模块索引 |
core/project/python/call_resolver.py | 跨文件调用解析 |
core/flow/python/*/analyzer.py | 接入 project_index |
core/context/explanation_service.py | enrich 与 LLM 解释增强 |
tests/test_python_project_analysis.py | 后端项目分析用例 |
10.3 C 层(成员 C)
| 文件 | 变更要点 |
|---|---|
crossFileResolution.ts | Python BFS、相对 import、JS 一层收集 |
extension.ts(编排部分) | runPythonProjectAnalysis、分流、enrich 分组、提示文案 |
analysisPresentation.ts | project 完成类型、日志与说明 |
types.ts / responseParser.ts | context_files、analysis_warnings |
package.json(语义配置) | maxFiles 29、与后端上限对齐的说明 |
test/crossFileResolution.test.js | 收集逻辑测试 |
test/riskConfidence.test.js | 响应解析测试 |
十一、项目小结
本次迭代由 3 人小组协作,完成了 CodeGuard Tutor 在 Python 跨文件场景从「多文件独立扫描」到「单次项目联合分析」的升级:
- 成员 B(B 层) 提供
/analyze-project,建立真实的跨模块污点传播与context_files证据链,并维持 enrich 不篡改检测事实的契约; - 成员 C(C 层) 实现 BFS 上下文收集、项目请求编排、响应字段解析,以及按 sink 文件分组的 LLM enrich 编排;
- 成员 A(A 层) 将
standard/in_file/cross_file/project四类结果以统一的 Problems、解释面板与输出日志形态呈现,避免用户混淆联合分析与独立扫描; - JavaScript 明确维持独立扫描路径,配置与文案与 Python 联合分析区分,避免能力误导。
整体上,A 层负责「怎么呈现」、C 层负责「送什么与怎么 enrich」、B 层负责「分析事实与传播链」,三层职责清晰,形成了可演示、可测试、可扩展的跨文件分析闭环。
更多推荐


所有评论(0)