Skip to content

feat: 基于 Skills + 沙箱 + 数据库存储构建自动代码评审 Agent(#92) - #248

Open
FeatherCheung wants to merge 2 commits into
trpc-group:mainfrom
FeatherCheung:feature/code-review-agent
Open

feat: 基于 Skills + 沙箱 + 数据库存储构建自动代码评审 Agent(#92)#248
FeatherCheung wants to merge 2 commits into
trpc-group:mainfrom
FeatherCheung:feature/code-review-agent

Conversation

@FeatherCheung

@FeatherCheung FeatherCheung commented Jul 28, 2026

Copy link
Copy Markdown

feat: 新增具备沙箱治理、审计和持久化能力的自动代码评审 Agent

关联issue

1. Code Review Skill

新增 skills/code-review/,包含:

  • SKILL.md:定义能力、输入输出和安全边界。
  • rules/:基于 YAML 的可执行规则。
  • references/rules.md:规则依据、误报边界和修复说明。
  • detectors/:正则和 Python AST 检测器。
  • parser/:Diff 和结构化输入解析。
  • scripts/:沙箱执行入口。
  • validators/:候选问题验证脚本。
  • runner.py:规则加载与执行入口。

当前规则覆盖:

  • 危险 Shell 和动态代码执行;
  • 硬编码凭据与敏感信息泄漏;
  • 未跟踪异步任务;
  • 文件及数据库连接生命周期;
  • 生产代码变更缺少相关测试。

2. 输入解析

支持以下输入方式:

  • --diff-file:Unified Diff 或 PR Patch;
  • --repo-path:Git 工作区相对于 HEAD 的变更;
  • --fixture:测试 Fixture;
  • --file-list:项目相对文件路径清单。

解析结果包含:

  • 变更文件;
  • Diff Hunk;
  • 上下文;
  • 候选新增行;
  • 输入摘要;
  • SHA-256 Digest;
  • 输入类型和来源路径。

同时增加路径逃逸、二进制文件和输入大小校验。

3. 沙箱任务规划与执行

新增 ReviewTaskPlanner,根据输入内容规划:

  • Code Review Skill 规则扫描;
  • Ruff 静态检查;
  • 受影响测试执行。

Git 仓库和文件列表输入会将项目源码装载到独立 Workspace。源码快照会排除:

  • .git
  • .venv
  • node_modules
  • __pycache__
  • Python 字节码;
  • 符号链接。

生产默认使用禁网 Container Runtime,同时支持 Cube Runtime

每项任务均具备:

  • 超时限制;
  • CPU、内存和 PID 限制;
  • 输出长度限制;
  • 执行异常记录;
  • Workspace 清理。

单项检查失败时报告进入 partial,不会丢失其他检查结果。

4. Filter 前置治理

所有 SandboxTask 在执行前都会转换为 ExecutionRequest 并经过 Filter。

Filter 检查范围包括:

  • 命令白名单和黑名单;
  • Shell 管道与危险参数;
  • Workspace 路径逃逸;
  • .env.ssh 和 credentials 等受保护路径;
  • 网络目标白名单;
  • 环境变量白名单;
  • 单次及累计资源预算。

决策结果包括:

  • allow
  • deny
  • needs_human_review

只有 allow 可以进入沙箱执行器。Filter 决策会写入报告、独立审计文件和数据库。

5. Finding 归一化与降噪

Finding 包含以下字段:

severity
category
file
line
title
evidence
recommendation
confidence
source
rule_id
rule_version
validation_status

归一化流程包括:

  1. 校验严重级别和问题类别;
  2. 校验文件及候选新增行号;
  3. 对标题、证据和建议进行脱敏;
  4. 按文件、行号和类别生成稳定指纹;
  5. 合并重复 Finding;
  6. 优先保留置信度更高、证据更完整的结果;
  7. 将低置信度或位置无效的问题放入 needs_human_review

6. 敏感信息脱敏

报告、数据库和执行日志写入前统一进行脱敏。

当前覆盖:

  • API Key;
  • OpenAI Token;
  • GitHub Token;
  • Bearer Token;
  • JWT;
  • AWS Access Key;
  • Password、Secret 和 Token 赋值;
  • PostgreSQL、MySQL、MariaDB 和 MongoDB URL 密码。

7. 数据库存储

默认使用 SQLite,并保留切换其他 SQL 后端的能力。

主要数据表:

review_task
├── skill_execution
├── sandbox_run
│   └── filter_event
├── finding
├── review_report
└── telemetry

数据库支持通过 task_id 查询:

  • 评审任务状态;
  • Skill 执行记录;
  • 沙箱执行摘要;
  • Filter 决策;
  • Findings;
  • 最终报告;
  • Telemetry 指标。

SQLite 显式启用外键,并为任务状态、创建时间、Finding Task ID 和严重级别增加索引。

8. 监控与审计

每次评审记录:

  • 总耗时;
  • 各检查阶段耗时;
  • 工具调用次数;
  • Filter 拦截次数;
  • Finding 数量;
  • Severity 分布;
  • 异常类型分布;
  • 沙箱任务状态;
  • 退出码;
  • 输出截断状态。

9. 结构化报告

报告按 Task ID 分目录保存,避免覆盖历史结果:

result/<task_id>/
├── review_report.json
├── review_report.md
└── filter_events.json

报告包含:

  • 任务状态和最终结论;
  • Finding 摘要;
  • Severity 统计;
  • 人工复核项;
  • Filter 决策;
  • 沙箱执行摘要;
  • 监控指标;
  • 修复建议;
  • Dry-run 标识;
  • 规则集 Digest。

10. Dry-run 与确定性模式

支持:

  • --dry-run:完成输入解析、任务规划和 Filter 决策,但不执行沙箱命令;
  • --deterministic-only:不依赖真实模型,仅运行确定性规则;
  • --fake-model:兼容原有无模型测试入口;
  • --task-id:指定稳定任务 ID,便于重放和生成固定示例。

Dry-run 报告会明确说明检查未实际执行,不会将零 Finding 表述为代码没有问题。

测试情况

新增和完善 39 项测试,覆盖:

  • 无问题 Diff;
  • 安全问题;
  • 异步资源泄漏;
  • 数据库连接生命周期;
  • 测试缺失;
  • 重复 Finding;
  • 沙箱执行失败;
  • 敏感信息脱敏;
  • 文件列表输入;
  • 路径逃逸;
  • Filter 命令拦截;
  • 网络和资源预算拦截;
  • needs_human_review 禁止执行;
  • Dry-run;
  • 任务规划;
  • 数据库持久化;
  • 报告生成;
  • 8 个公开 Fixture。

验证命令:

PYTHONPATH=. pytest -q tests/code_review

验证结果:

39 passed

同时通过:

python3 -m compileall -q examples/skills_code_review_agent
git diff --check

使用方式

Container 模式

python3 examples/skills_code_review_agent/run_agent.py \
  --diff-file examples/skills_code_review_agent/fixtures/security.diff \
  --runtime container \
  --deterministic-only

Git 工作区

python3 examples/skills_code_review_agent/run_agent.py \
  --repo-path . \
  --runtime container \
  --deterministic-only

Dry-run

python3 examples/skills_code_review_agent/run_agent.py \
  --fixture examples/skills_code_review_agent/fixtures/security.diff \
  --runtime container \
  --dry-run \
  --deterministic-only

本地开发回退

python3 examples/skills_code_review_agent/run_agent.py \
  --fixture examples/skills_code_review_agent/fixtures/security.diff \
  --runtime local \
  --fake-model

兼容性与影响范围

  • 新增独立示例目录,不改变现有 Agent 的默认行为;
  • Local Runtime 仍可用于开发和单元测试;
  • 默认生产 Runtime 为 Container;
  • 数据库默认使用 SQLite,可通过 --db-url 更换;
  • 运行结果目录已加入 .gitignore
  • 示例报告单独保存在 sample_output/

后续计划

  • 接入真实模型和可注入 Fake Analyzer;
  • 扩展数据库事务、异步资源和安全规则;
  • 增加依赖关系驱动的受影响测试选择;
  • 增加 Validator 动态确认和驳回流程;
  • 补充真实 Container/Cube E2E;
  • 增加 PostgreSQL、Tracing、告警和任务恢复能力。

Checklist

  • 新增 Code Review Skill
  • 支持 Diff、Git、Fixture 和文件列表输入
  • 接入 Container、Cube 和 Local Runtime
  • 所有沙箱任务经过 Filter
  • 实现 Finding 校验、脱敏和去重
  • 实现 SQLite/SQLAlchemy 持久化
  • 输出 JSON、Markdown 和 Filter 审计文件
  • 支持 Dry-run 和无模型测试模式
  • 提供 8 个公开 Diff Fixture
  • 补充中文 README 和示例报告
  • 39 项测试通过
  • 在 CI 中完成 Container/Cube E2E
  • 使用正式隐藏数据集验证检出率和误报率

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@81c798a). Learn more about missing BASE report.

Additional details and impacted files
@@            Coverage Diff             @@
##             main        #248   +/-   ##
==========================================
  Coverage        ?   87.86456%           
==========================================
  Files           ?         482           
  Lines           ?       45157           
  Branches        ?           0           
==========================================
  Hits            ?       39677           
  Misses          ?        5480           
  Partials        ?           0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@helloopenworld

Copy link
Copy Markdown
Contributor

AI Code Review

现在我已经掌握了所需的所有信息。让我来编写审查报告。

发现的问题

🚨 严重问题

  • examples/skills_code_review_agent/agent/storage.py:301-317:在处理 needs_human_review 时,Finding 记录被静默丢弃
    • all_findings 同时包含 report.findings(已采纳)与 report.needs_human_review(人工复核项)。在 normalize_findings 中,同一 (file,line,category) 键的候选可分别落入 accepted 与 human 两个集合(例如一条 0.9 置信度被采纳、另一条 0.5 因低于阈值进入人工复核)。存储时先写入 accepted 行,再处理 human 行:此时 existing 已存在且 existing.confidence < finding.confidence 为 False(已采纳项置信度更高),not existing 也为 False,human 行既不更新也不插入,被丢弃。结果是报告中存在的人工复核项永远无法持久化到数据库,与报告内容不一致。
    • 修复方向:在去重比较中纳入 needs_human_review 维度(例如以 (task_id,file,line,category,needs_human_review) 为键),或在存在 existingfinding.needs_human_review 不同时仍执行 insert/update,确保两类记录独立存储。

⚠️ 警告

  • examples/skills_code_review_agent/agent/storage.py:335-341telemetry.sandbox_duration 恒为 0

    • sandbox_duration 取自 stage_duration_ms.get("sandbox", 0),但 record_stage 实际写入的键是 task.task_typecustom_rule/static_check/test),从不写入 "sandbox" 键,导致该字段永远为 0,监控/回放语义错误。建议改为对各 sandbox 任务耗时求和,或在记录阶段统一写入一个 sandbox 汇总键。
  • examples/skills_code_review_agent/run_agent.py:99-101:仅 cube runtime 会被销毁,container/local 资源未释放

    • finally 分支只在 args.runtime == "cube" 时调用 runtime.destroy()container runtime 同样可能持有容器/客户端资源却不被清理,存在资源泄漏与不一致。建议对所有支持 destroy() 的 runtime 统一释放(或在 finally 中无判断地调用并捕获不支持的情况)。
  • examples/skills_code_review_agent/run_agent.py:84-98examples/skills_code_review_agent/agent/storage.py:194-207:使用 --task-id 回放会触发主键冲突

    • README/CLI 声明 --task-id 用于“稳定标识便于回放”,但 create_task 是无条件 INSERTreview_task 主键,save_review_resultreview_report/telemetrytask_id 唯一约束)也是 INSERT。同一 task_id 二次运行会直接抛 IntegrityError,回放路径不可用。建议对 task 做存在性判断或 upsert,对 report/telemetry 先删后插或使用 INSERT ... ON CONFLICT

💡 建议

  • examples/skills_code_review_agent/agent/input_parser.py:147-149path.is_symlink() 为无效检查

    • path = (project_root / relative).resolve() 已解析符号链接,path.is_symlink() 必为 False,该判断形同虚设;真正的越界防护依赖 is_relative_to(project_root)。建议删除冗余判断或在 resolve() 前检查符号链接,避免误导维护者。
  • examples/skills_code_review_agent/agent/input_parser.py:181-192git diff --binary 与二进制拒绝逻辑自相矛盾

    • 显式传 --binary 会令二进制文件产生含 \0 的补丁,随后又因 b"\0" in result.stdout 抛错;对纯文本 diff --binary 无意义。建议去掉 --binary,与“不支持二进制 diff”的策略保持一致。

总结

整体架构清晰、安全边界(白名单命令/网络/环境、路径 containment、fail-closed filter、脱敏与原子写)较为完备,但存在一个 Critical 的数据一致性缺陷:needs_human_review 的 Finding 无法落库,会被同位置的已采纳项静默丢弃;另有 telemetry 汇总错误、runtime 清理不完整、--task-id 回放不可用等问题建议一并修复。

测试建议

  • 补充“同一位置同时存在 accepted 与 needs_human_review 候选”的用例,断言 repository.get_task(task_id)["findings"] 同时包含 openneeds_human_review 两行。
  • 补充“同一 task_id 二次运行 run_review”的回放用例,验证不抛 IntegrityError 且 trace 可更新。
  • 增加断言 trace["telemetry"]["sandbox_duration"] 与实际 sandbox 任务耗时一致(当前应为 0 的缺陷暴露点)。

Comment thread examples/skills_code_review_agent/agent/storage.py
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

- 实现基于 Skill 的确定性代码评审规则
- 增加沙箱任务规划与隔离执行
- 接入 Filter 策略、敏感信息脱敏和资源限制
- 持久化 Finding、监控指标和执行审计记录
- 支持 Diff、Git 仓库、Fixture 和文件列表输入
- 补充结构化报告、测试样例和中文文档
修复回放、资源清理与遥测统计
按实际 sandbox 任务汇总执行耗时
统一释放支持 destroy() 的 runtime
支持相同 task_id 重复回放并更新执行轨迹
删除无效的符号链接检查和冲突的二进制 diff 参数
补充 Finding 状态、回放及遥测回归测试
@FeatherCheung
FeatherCheung force-pushed the feature/code-review-agent branch from e0da24a to 31c472b Compare July 28, 2026 13:00
@helloopenworld

Copy link
Copy Markdown
Contributor

AI Code Review

现在我已经有了完整且经过验证的全貌。让我来写这份审查报告。

发现的问题

🚨 Critical

未发现 Critical 级别问题。

⚠️ Warning

  • examples/skills_code_review_agent/agent/input_parser.py:180-186git diff 子进程超时未单独处理

    • subprocess.run(..., timeout=30) 在超时时会抛出 TimeoutExpired,此处既未捕获也未在文档中约定,异常会一路冒泡到 run_review 的兜底 except 并被标记为 failed。虽然不会崩溃,但 git 卡死场景下错误类型只会记成 TimeoutExpired、且无重试。建议捕获 TimeoutExpired 转为带语义的 ValueError("git diff timed out"),或对大型仓库提高/参数化超时。
  • examples/skills_code_review_agent/sandbox/runner.py:29-37:dry-run 仍会消耗执行预算

    • ReviewExecutionFilter(...).run(request) 在判定为 ALLOW 时即 budget.calls_used += 1,随后因 dry_run=True 提前返回。多次 dry-run 会逐步耗尽 max_calls,导致后续真实执行被 budget_exceeded 拦截。建议在 SandboxRunner.run 中 dry-run 分支跳过预算累加,或在 FilterEngine 内对 dry-run 不计入 calls_used
  • examples/skills_code_review_agent/agent/sandbox.py:78-82:custom_rule 失败但 status 非 failed 时静默丢弃 findings

    • 仅在 result.status == "completed" 时解析 stdout 为 findings;当任务 timed_out/blocked/输出被截断时 findings 保持为空 [],但若一次规划中出现多个 custom_rule 任务,findings = [...](赋值而非 extend)会覆盖前者。当前 planner 只产生一个 custom_rule 暂不触发,但若后续扩展为多规则文件并行会产生数据丢失。建议改用 extend 并在解析失败时显式记录,避免覆盖语义。
  • examples/skills_code_review_agent/governance/policy/loader.py:19-23sandbox/runner.py:29:每次过滤决策都重新读取并解析策略 YAML

    • ReviewExecutionFilter 在每个 sandbox task 都新建并调用 load_policy(),每次都做文件 IO + YAML 解析 + Pydantic 校验。单次评审任务量小尚可接受,但在 max_calls=10、每任务多检查的场景下属于可避免的重复开销。建议在 SandboxRunnerFilterEngine 层缓存 GovernancePolicy 实例。

💡 Suggestion

  • examples/skills_code_review_agent/agent/review.py:54analyzer 参数与 fake_model=True 的关系未在调用侧接线
    • run_review 支持 analyzer 注入模型分析,但 run_agent.py 调用时永远传 fake_model=True 且不提供 analyzer,模型分析路径实际永不触发。若是有意保持确定性示例,可在 README/SKILL.md 中明确说明,避免后续使用者误以为模型评审已生效。

总结

整体为新增示例代码,安全边界(fail-closed 过滤、路径校验、敏感信息脱敏、参数化 SQL、无 shell 拼接)实现得当,未发现必须修复的 Critical 问题。存在若干稳定性与资源管理类 Warning(子进程超时未捕获、dry-run 消耗预算、policy 重复加载),建议合入前修复前两条以避免线上回归。

测试建议

  • 补充一条用例:git diff 超时(monkeypatch subprocess.runTimeoutExpired)时,run_review 将任务标记为 failed/partial 且不崩溃。
  • 补充一条用例:连续多次 dry_run=True 评审后,真实(非 dry-run)评审仍能正常执行而不被 budget_exceeded 拦截。

@FeatherCheung

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@FeatherCheung

Copy link
Copy Markdown
Author

recheck

Rook1ex added a commit to trpc-group/cla-database that referenced this pull request Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants