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 成员与职责

成员层级主要职责本迭代典型交付
成员 AA 层VS Code 插件开发、用户交互、界面展示命令注册与激活、关联文件确认模态框、Problems 诊断与行装饰、explanationPanel Webview、resultPresenter 风险行格式化、与 C 层约定的 presentUnifiedAnalysisOutcome 展示通道对接
成员 BB 层后端分析服务、AST 解析、规则引擎、数据流追踪POST /analyze-project 路由与请求校验、build_python_project_index、跨文件 ProjectCallResolver、flow 分析器接入 project_indexcontext_files / analysis_warnings 出证、/enrich-explanations 解释服务
成员 CC 层上下文补全、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.1Python 关联文件 BFS 收集C
6.2/analyze-project 请求编排CB 提供接口契约与硬上限
6.3用户提示文案(能力对齐)C(文案与分流逻辑)A 模态框与交互承载
6.4project / cross_file 统一展示A(面板与诊断呈现)C 定义 CompletionKindanalysisPresentation 日志
6.5context_files 等字段解析CB 定义响应 schema
6.6跨文件 enrich 按 sink 分组C(插件编排)B explanation_service + LLM
6.7crossFileCompletionMaxFiles 等配置C(语义与上限对齐)A package.json 配置项注册
6.8插件侧收集与解析测试CB 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-projectPython 入口 + 关联文件联合分析
POST /enrich-explanationsC 层解释增强(资料摘录 + 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 → 二级 → 三级依赖;
  • 直接依赖优先入队,再扩展间接依赖;
  • 支持相对 importfrom .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 依赖层级广度优先收集;由后端建立跨文件传播链
JavaScriptimport / require 顺序独立检查关联文件;建立传播链
const analysisDescription =
  language === "python"
    ? `将按 import 依赖层级广度优先收集本地 Python 文件,直接依赖优先,并由后端建立跨文件传播链(最多 ${maxFiles} 个关联文件)。`
    : `将按源码中 import / require 出现的顺序,独立检查本地 ${moduleHint}(最多 ${maxFiles} 个)。`;

6.4 项目分析结果展示

**主责:**成员 C(analysisPresentation.tsCompletionKind 与输出日志)
文件: vscode-extension/src/analysisPresentation.tsresultPresenter.tsexplanationPanel.ts

新增完成类型 CompletionKind

含义
standard普通单文件 / 选区分析
in_file文件内上下文扩窗补全
cross_fileJavaScript(或旧路径)关联文件独立扫描汇总
projectPython 跨文件联合分析

输出面板(project)额外展示:

  • [补全类型] 跨文件联合分析
  • [跨文件联合分析] 入口文件 1 个,关联文件 N 个,合计 M 个
  • [分析警告] ...(来自 analysis_warnings
  • [说明] 以上结果由后端在同一次项目请求中建立跨文件 source 到 sink 传播链

cross_file 的说明文案明确区分:后者注明「独立分析汇总,不代表已建立传播链」。

展示通道统一: Problems 诊断、编辑器行高亮、右侧解释面板、Toast 通知——与主分析、文件内补全共用 presentUnifiedAnalysisOutcome


6.5 响应字段解析扩展

主责: 成员 C;协作: 成员 B 定义响应 schema
文件: types.tsresponseParser.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 / 资料只优化 reasonhow_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.jsimport BFS 顺序、直接依赖优先、maxFiles 截断、多行 import
vscode-extension/test/riskConfidence.test.jscontext_filesanalysis_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 跨文件联合分析

B层(分析引擎) C层(上下文编排) A层(交互与界面) 用户 B层(分析引擎) C层(上下文编排) A层(交互与界面) 用户 opt [解释来源(A 层 UI)] 分析当前文件(无明确漏洞) 触发跨文件补全流程 请求展示「是否检查关联文件」 模态确认 同意 用户确认结果 findRelatedPythonFiles(BFS ≤29) POST /analyze-project 索引 + 调用解析 + 跨文件传播 AnalyzeResponse + context_files maybeEnrichProjectResponse(可选) presentUnifiedAnalysisOutcome(project) 按 file_path 分组 /enrich-explanations 增强 reason / how_to_fix 更新后的响应 Problems + 解释面板 + 输出日志

7.2 JavaScript(当前策略)

收集一层 require/import
  → 每个关联文件 POST /analyze
  → buildCrossFileMergedResponse
  → presentUnifiedAnalysisOutcome(cross_file)

八、测试与验证建议

场景操作预期
Python BFS 收集打开多层 import 的入口 .py,同意检查关联文件输出 [关联文件收集] 列表,直接依赖在前
联合传播漏洞在 import 模块的 sinkcompletionKind=projectcontext_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.tsProblems 诊断、行装饰、风险行展示
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.pyenrich 与 LLM 解释增强
tests/test_python_project_analysis.py后端项目分析用例

10.3 C 层(成员 C)

文件变更要点
crossFileResolution.tsPython BFS、相对 import、JS 一层收集
extension.ts(编排部分)runPythonProjectAnalysis、分流、enrich 分组、提示文案
analysisPresentation.tsproject 完成类型、日志与说明
types.ts / responseParser.tscontext_filesanalysis_warnings
package.json(语义配置)maxFiles 29、与后端上限对齐的说明
test/crossFileResolution.test.js收集逻辑测试
test/riskConfidence.test.js响应解析测试

十一、项目小结

本次迭代由 3 人小组协作,完成了 CodeGuard Tutor 在 Python 跨文件场景从「多文件独立扫描」到「单次项目联合分析」的升级:

  1. 成员 B(B 层) 提供 /analyze-project,建立真实的跨模块污点传播与 context_files 证据链,并维持 enrich 不篡改检测事实的契约;
  2. 成员 C(C 层) 实现 BFS 上下文收集、项目请求编排、响应字段解析,以及按 sink 文件分组的 LLM enrich 编排;
  3. 成员 A(A 层)standard / in_file / cross_file / project 四类结果以统一的 Problems、解释面板与输出日志形态呈现,避免用户混淆联合分析与独立扫描;
  4. JavaScript 明确维持独立扫描路径,配置与文案与 Python 联合分析区分,避免能力误导。

整体上,A 层负责「怎么呈现」、C 层负责「送什么与怎么 enrich」、B 层负责「分析事实与传播链」,三层职责清晰,形成了可演示、可测试、可扩展的跨文件分析闭环。


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐