Skip to content

examples: add skills-based code review agent example (#92) - #268

Open
xiyue1753 wants to merge 3 commits into
trpc-group:mainfrom
xiyue1753:feat/code-review-agent
Open

examples: add skills-based code review agent example (#92)#268
xiyue1753 wants to merge 3 commits into
trpc-group:mainfrom
xiyue1753:feat/code-review-agent

Conversation

@xiyue1753

@xiyue1753 xiyue1753 commented Jul 30, 2026

Copy link
Copy Markdown

概述

基于 trpc-agent-python 的 Skill 体系、CodeExecutor 沙箱、SQLite 持久化和
Filter 治理能力,构建一个面向 Python 项目的自动代码评审 Agent 示例。

该示例不依赖 LLM API 即可在 dry-run 模式下运行,也可通过 --model 接入
OpenAI 兼容的 LLM(如 DeepSeek)实现 Agent 驱动的 skill_load / skill_run 编排。

主要修改

新增 examples/skills_code_review_agent/ 目录,包含:

  • CR Skill:SKILL.md + 4 类规则(security / resource_leak / error_handling / testing)+ 2 个沙箱脚本(parse_diff.py / static_check.py)
  • 规则引擎:10 条确定性规则,覆盖硬编码密钥、命令注入、不安全反序列化、资源泄漏、异常吞噬、缺少测试等场景。每条 finding 含 10 字段(severity / category / file / line / title / evidence / recommendation / confidence / rule_id / source)
  • 沙箱执行:Docker container(network=none、memory-limit)+ local subprocess fallback + Cube/E2B([cube] extra)。支持 timeout(30s)、output 大小限制(100KB)、环境变量 whitelist(--strict-env)、全局 budget(--agent-budget,默认 300s)、禁止路径检查
  • 三级 Filter 治理:classify_command() 将命令分为 deny(rm -rf /、mkfs、fork bomb)、ask(sudo、iptables、chown)和 needs_human_review(pip install、curl、wget)。Agent 模式下通过 CodeReviewSafetyFilter(BaseFilter) + @register_tool_filter 挂载到 skill_run 工具(SkillToolSet run_tool_kwargs),deny/ask/needs_human_review 均在执行前强制人工决策
  • SQLite 持久化:6 张表(review_task / finding / sandbox_run / filter_decision / monitoring / report),is_warning 字段区分 findings 与 warnings,PRAGMA foreign_keys = ON。提供独立 init_db.py 初始化脚本
  • 结构化报告:JSON + Markdown 双格式,Markdown 报告含 8 段(Summary / Findings / Warnings / Needs Human Review / Filter Intercepts / Sandbox Execution / Monitoring / Recommendations)
  • 敏感信息脱敏:7 类正则 + 香农熵检测,在 findings evidence、sandbox stdout/stderr、报告内容和数据库写入前多层脱敏
  • 三种输入模式:--diff-file(unified diff 文件)、--repo-path(git diff HEAD,含暂存变更)、--files(文件路径列表生成 synthetic diff)
  • Agent 模式:--agent 切换到 LlmAgent + SkillToolSet + Runner.run_async() 驱动,FakeModel 预录制回放(无需 API Key),支持 --model 接入真实 LLM;LLM 结构化输出(FINDINGS_JSON)与规则引擎结果合并
  • 88+ 条单元测试(3 条框架依赖 e2e 在无 trpc_agent_sdk 环境跳过)+ 8 条 diff fixture

Filter 治理语义与验收标准 #7

  • deny(rm -rf /、mkfs、fork bomb)— 硬拦截(is_continue=False),永不执行,决策落库
  • ask(sudo、iptables、chown)— 执行前交互确认(y/N):批准则执行并记录 approved,拒绝则拦截并记录 denied (no human confirmation);--non-interactive 自动拒绝
  • needs_human_review(pip install、curl、wget)— 与 ask 相同的执行前人工决策:未经人工批准不进入沙箱执行,批准/拒绝均记录(filter_decision 表 + 报告 Filter Intercepts 章节)

验收标准 #7 要求 "deny / needs_human_review 不能直接进入沙箱执行":本示例严格满足——deny 始终拦截,ask/needs_human_review 必须经人工确认(或 --non-interactive 自动拒绝)后才可能执行,所有决策完整落库供审计。confirm/record 回调可注入,便于测试与自动化接入。

验证

  • python -m pytest test_code_review_agent.py → 88 passed + 3 skipped(无 trpc_agent_sdk 环境跳过框架依赖 e2e)
  • python run_review.py --diff-file fixtures/<name>.diff → 8/8 通过
  • python run_review.py --agent --model deepseek-chat → skill_load ✅
  • python run_review.py --repo-path <repo> → git diff HEAD → review ✅
  • python run_review.py --files a.py b.py → synthetic diff ✅
  • 沙箱 stdout/stderr 入库前脱敏验证通过(sandbox_run 表无明文)
  • python storage/init_db.py --db-path review.db → 6 张业务表, foreign keys ON

关联 Issue

Fixes #92

提交清单

  • pytest 88 passed + 3 skipped
  • 遵循项目规范(copyright headers、type annotations、DESIGN.md)
  • Agent 模式通过 DeepSeek API 验证(15+ tool calls,后处理管线正常)
  • 脱敏覆盖沙箱输出、findings、报告、数据库
  • README.md 含快速开始、双模式对比与 Filter 治理取舍说明

RELEASE NOTES: 新增 skills_code_review_agent 示例,集成 Skills、Docker/Cube 沙箱执行、SQLite 持久化和三级 Filter 治理(deny/ask/needs_human_review 执行前人工决策),支持自动 Python diff 代码评审。

Add a skills_code_review_agent example under examples/ that composes
Skill loading, deterministic rule engine (10 rules covering security,
resource leaks, error handling, and testing), Docker container/local
subprocess sandbox with timeout/output limits, three-level Filter
governance (deny/ask/needs_human_review), SQLite persistence (6 tables),
and JSON/Markdown dual-format structured reports.

Supports --diff-file, --repo-path, and --files input modes. Agent mode
via LlmAgent + SkillToolSet with FakeModel (no API key required) or
real LLM (OpenAI-compatible). Includes 40 unit tests and 8 diff fixtures
covering clean code, security issues, resource leaks, DB lifecycle,
missing tests, deduplication, sandbox failure, and sensitive info.

Fixes trpc-group#92

RELEASE NOTES: New code review agent example integrates Skills, sandbox
execution, SQLite persistence, and three-level Filter governance for
automated Python diff review.

Signed-off-by: xiyue1753 <xiyuekl@qq.com>
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

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

@helloopenworld

Copy link
Copy Markdown
Contributor

AI Code Review

Docker 在沙箱环境中不可用。我很确定 docker run 使用的是 --stop-timeout 而不是 --timeout;将 --timeout=N 作为参数传给 docker run 会报错。让我通过知识库确认一下:docker run 支持 --stop-timeout(容器停止超时),而不是 --timeout。因此 f"--timeout={int(timeout)}" 很可能会导致 docker run 报错。不过,这仅影响容器后端(需要 Docker 和 --no-dry-run),且代码仅在非默认路径下运行。我将其标记为警告。

现在我已经有足够的信息来撰写审查报告了。让我完成最终定稿。

发现的问题

🚨 Critical

  • examples/skills_code_review_agent/agent/filter_agent.py:55-56:安全过滤器对 deny 级命令仅设置 rsp.is_continue=False 并写入 error,但 ask/needs_human_review 级别(sudo、pip install、curl 等)仅 pass 放行,未做任何阻断或确认。
    • DESIGN 与 docstring 都宣称三级治理,实际上 Agent 模式下只有 deny 被拦截,提权与可疑命令会直接执行;sync 流水线虽标注 filter_action 但仍执行 allowed。建议在 _before 中对 ask 至少设置 rsp.is_continue=False 并触发人工确认,或在执行前由编排层强制校验 filter_action

⚠️ Warning

  • examples/skills_code_review_agent/sandbox/runner.py:120-124:Docker 后端使用 f"--timeout={int(timeout)}" 作为 docker run 参数,docker run 并无 --timeout 子参数(应使用 --stop-timeout 或外部 timeout)。--no-dry-run--sandbox container 时该命令会因非法 flag 直接失败,容器后端不可用。建议改用 timeout 包装或 --stop-timeout

  • examples/skills_code_review_agent/sandbox/runner.py:44:脚本目录以只读挂载(/scripts:ro),但 parse_diff.py 通过 argv 接收 diff 路径,而 diff 临时文件写入 output_dir(未挂载进容器),容器内 Path(sys.argv[1]) 不存在,parse_diff.py 直接 sys.exit(1)。需将 diff 临时文件也挂载进容器或改用 stdin 传递。

  • examples/skills_code_review_agent/run_review.py:366-417run_agent_pipeline_async):Agent 执行产生的 sandbox 结果从未调用 store.save_sandbox_run,报告中 sandbox_runs 恒为空;且后续结构化 findings 完全脱离 Agent 输出从 diff_text 重算,Agent 模式的 skill_run 结果被丢弃。建议落库 Agent 沙箱运行记录,或明确说明 Agent 输出与报告的关系,避免监控数据失真。

  • examples/skills_code_review_agent/skills/code-review/scripts/static_check.py:219json.loads(open(input_path, encoding='utf-8').read()) 未关闭文件句柄。建议 with open(...) as f: json.loads(f.read())

  • examples/skills_code_review_agent/agent/filter.py:42-44classify_commandchown/chmod 同时列入 ASK_PATTERNS 与 REVIEW_PATTERNS,靠先匹配 ASK 优先级勉强一致;但 chmod 777 在 DENY(chmod 777 /)与 ASK(chmod 777)间靠子串长度区分,普通 chmod 644 file 会被 REVIEW 判为可疑。匹配为朴素子串且大小写归一,误报面较大;建议对权限/路径类改用更精确的 token 级匹配,降低误拦截。

  • examples/skills_code_review_agent/run_review.py:58-60input_sourcehasattr(args,'repo_path') 判断,但三者属同一 mutually_exclusive_group,属性恒存在,hasattr 判断无意义;当仅传 --filesargs.diff_file/args.repo_path 为 None,逻辑虽能走到 files 分支,但表达式冗余且易在新增输入源时出错。建议直接按 args.diff_file / args.repo_path / args.files 的 None 判断。

💡 Suggestion

  • examples/skills_code_review_agent/agent/diff_parser.pyskills/code-review/scripts/parse_diff.py 存在两套重复的 diff 解析实现且行号计算方式不同(前者用 _line_counter 自增,后者用 new_start + len(added_lines))。两套实现漂移会造成 skill 脚本与 agent 内置解析结果不一致,建议复用同一解析模块。

总结

存在一个 Critical 安全问题:三级命令治理在 Agent/sync 执行路径上实际只拦截 deny,提权与可疑命令会被放行执行。另有 Docker 后端 flag 错误、diff 文件未挂载、Agent 沙箱结果未落库等稳定性/兼容性问题需修复。

测试建议

  • 补充 Agent 模式端到端测试:构造含 sudo/pip install 的命令,断言其被 ask/needs_human_review 拦截或标注,而非放行执行。
  • 补充 --no-dry-run --sandbox container 路径测试(或 mock docker),验证 --timeout flag、只读挂载与 diff 输入可达性。

args = part.function_call.args or {}
command = str(args.get('command', '') or args.get('cmd', ''))
if command:
level, pattern = classify_command(command)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

三级命令治理仅拦截 deny,ask/needs_human_review 被放行

安全过滤器对 deny 级仅设置 is_continue=False 并写 error,但 ask/needs_human_review(sudo、pip install、curl 等)仅 pass 放行,未阻断或确认。建议在 _before 中对 ask 至少设置 rsp.is_continue=False 并触发人工确认,或由编排层在执行前强制校验 filter_action。

- filter_agent: block ask-level commands in Agent mode
- sandbox/runner: replace docker --timeout with timeout command
- parse_diff.py: accept stdin when no file argument (Docker compat)
- run_review: pass diff via stdin to sandbox scripts
- run_review: save sandbox_run records in Agent event loop
- static_check.py: fix open() without with statement
- filter.py: remove duplicate chmod/chown from REVIEW_PATTERNS
- run_review: drop redundant hasattr() in input_source logic

Signed-off-by: xiyue1753 <xiyuekl@qq.com>
@xiyue1753

Copy link
Copy Markdown
Author

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

@codecov

codecov Bot commented Jul 31, 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        #268   +/-   ##
==========================================
  Coverage        ?   88.43489%           
==========================================
  Files           ?         491           
  Lines           ?       46035           
  Branches        ?           0           
==========================================
  Hits            ?       40711           
  Misses          ?        5324           
  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

这确认了 skill_run 接收一个 command 字符串。Agent 过滤器检查 args.get('command') — 字段名正确,但该过滤器是 FilterType.AGENT(其中 req=None),而非 FilterType.TOOL。现在我已经完全确认了。让我来写审查报告。

发现的问题

🚨 Critical

  • examples/skills_code_review_agent/agent/filter_agent.py:47-55:Agent 安全过滤器完全失效,deny 级命令无法被拦截
    • 该过滤器通过 register_agent_filter 注册为 FilterType.AGENT,但框架在 BaseAgent.run_async 中调用 Agent 过滤器时传入的 req 恒为 None(见 trpc_agent_sdk/agents/_base_agent.py:288run_stream_filters(ctx.agent_context, None, ...),且 AgentCallbackFilter._before 也把该参数标为 _: Any)。因此 hasattr(req, 'contents') 永远为 False,整个 _before 提前退出,rsp.is_continue 不会被置 False,skill_runcommand 参数(含 rm -rfsudo 等危险命令)直接放行执行。这是 Agent 模式下命令注入/破坏性命令的拦截缺失,应改为 register_tool_filter 注册的 TOOL 级过滤器并校验 skill_run 入参。
    if hasattr(req, 'contents') and req.contents:   # req 恒为 None,永不进入
        ...

⚠️ Warning

  • examples/skills_code_review_agent/agent/filter_agent.py:60-69needs_human_review 分支为不可达死代码

    • elif level == 'ask' 命中后即 break,导致后续 elif level in ('ask', 'needs_human_review') 永远不会被触发,pip install/curl 等需人工复核的命令即使过滤器被修复也不会记录 blocked_reason。应将 ask 分支改为不 break(仅记录),或合并条件使 needs_human_review 也能进入审计分支。
  • examples/skills_code_review_agent/run_review.py:470-476--repo-path 使用裸 git diff,遗漏已暂存和已提交变更

    • 无参数 git diff 只对比工作区与索引,不包含 git add 过的暂存内容,也无法审查已提交的 commit。作为“审查 git 仓库”的入口会导致大量真实变更被漏审。建议使用 git diff HEAD 或提供 --staged/commit 范围参数。
  • examples/skills_code_review_agent/agent/filter.py:65-71:危险命令匹配基于纯子串、且大小写归一后未做边界处理,易绕过也易误报

    • _check_patternsp.lower() in lower 判断,'su ''curl '(带尾空格)这类模式对 subprocess.run(...)curl\turl 等变体无法匹配,而 '/root/''/proc/' 又会与代码中正常出现的路径字面量误判为 deny。作为安全边界,建议改为按命令 token 解析(参考框架 _split_command_line)而非裸子串匹配。
  • examples/skills_code_review_agent/run_review.py:329-353:Agent 模式下 sandbox_duration_ms 统计依赖函数调用配对,错配会丢弃计时

    • 仅当 skill_run/skill_exec 的 function_call 与随后的 function_response 严格成对出现时才累加耗时;若 LLM 在一次响应里同时发起多个调用、或响应缺失(被过滤器拦截、报错),sandbox_start 会被覆盖或残留,导致监控数据不准。建议按 part 维度配对或直接用事件时间戳区间统计。

💡 Suggestion

总结

存在 1 个必须修复的 Critical:Agent 模式的安全过滤器因注册层级错误(AGENT 而非 TOOL)整体失效,破坏性命令可绕过拦截直接执行;此外有命令匹配易绕过/误报、git diff 漏审暂存变更、监控统计易错配等 Warning 建议修复。整体功能可用,但 Agent 模式的安全边界需在合入前修复。

测试建议

  • 补充 Agent 模式端到端测试:用 FakeModel 驱动一次 skill_run 调用,其 commandrm -rf /pip install evil,断言前者被拦截(执行未发生)、后者被标记 needs_human_review,以覆盖当前失效的拦截路径。
  • 补充 --repo-path 对含已暂存变更仓库的测试,断言暂存内容出现在审查结果中。

Rook1ex added a commit to trpc-group/cla-database that referenced this pull request Jul 31, 2026
…eptance gaps

Three-level tool filter (deny block / ask+needs_human_review confirm)
attached to skill_run via SkillToolSet run_tool_kwargs. Token-level
command classifier replaces naive substring matching.

Agent-mode safety gap closed: per-command timeout, global budget,
--strict-env whitelist, --non-interactive flag, local runtime
isolation warning, cube backend (sync + agent, clear error without
credentials), cube sandbox destroy on cleanup.

LLM findings merged (FINDINGS_JSON parse + dedup) into report findings.
Hard truncation replaced with size-capped full capture.

Fixes: filter wiring, env/budget passthrough, de-truncation,
        token classification, cube sandbox leak
Closes: acceptance criteria trpc-group#2 / trpc-group#4 / trpc-group#7 / trpc-group#8
Signed-off-by: xiyue1753 <xiyuekl@qq.com>
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.

基于 Skills + 沙箱 + 数据库存储构建自动代码评审 Agent

2 participants