open-code-review 审查规则体系完全指南:优先级链、rule.json 配置与文件过滤原理
【免费下载链接】open-code-reviewFast, efficient, battle-tested at Alibaba's scale. Hybrid architecture code review tool: deterministic pipelines + LLM Agent, precise line-level comments, built-in multi-language ruleset (NPE, thread-safety, XSS, SQL injection), OpenAI & Anthropic compatible.项目地址: https://gitcode.com/GitHub_Trending/op/open-code-review
导读
本篇指南基于 open-code-review(OCR)的官方规则文档 pages/src/content/docs/ko/review-rules.md 展开,结合仓库源码与测试,系统讲解 OCR 的审查规则(Review Rules)机制:规则如何通过四层优先级链决定"每个文件该被 LLM 用什么标准审查",rule.json的三个独立字段(include/exclude/rules)如何编写,以及五道关卡的文件过滤算法如何把 diff 中的文件送到模型面前。读完本篇,你将能够为任意项目编写项目级、全局级甚至单 PR 级别的自定义规则,并能用ocr rules check与ocr review --preview调试规则生效路径。
规则是什么:告诉 LLM "审什么"
规则(Rules)是 OCR 审查时的注意力控制器。它回答一个问题:当审查src/api/user.go或UserMapper.xml这类文件时,Agent 应该重点关注哪些风险——是 NPE、线程安全、XSS,还是 SQL 注入?规则并不直接执行静态检查,而是以 JSON 形式组织、经路径匹配后把规则正文注入到模型提示词中,让 Agent 带着明确的检查清单去读代码。
这些规则分布在三个层次的 JSON 文件中,再加上内嵌在二进制里的系统默认规则,构成完整规则体系。系统默认规则位于 internal/config/rules/system_rules.json,通过go:embed编译进二进制(见 internal/config/rules/system_rules.go#L89-L91),因此任何环境下都必然存在一层兜底规则。
四层优先级链:谁先匹配谁赢
OCR 用四层优先级链解释规则。对每一个文件路径,它按顺序逐层扫描,第一次匹配到的模式即获胜:
| 优先级 | 来源 | 路径 | 说明 |
|---|---|---|---|
| 1(最高) | --rule标志 | 用户指定 | CLI 层覆盖。一旦指定,总是获胜 |
| 2 | 项目配置 | <repoDir>/.opencodereview/rule.json | 项目级规则,可随仓库提交 |
| 3 | 全局配置 | ~/.opencodereview/rule.json | 用户机器级别的个人偏好 |
| 4(最低) | 系统默认 | 内嵌system_rules.json | 覆盖主流语言的内置规则 |
优先级更高的层如果文件不存在,会静默跳过、不报错。所以一个没有.opencodereview/rule.json的项目,会自然回落到全局层和系统层。
从源码看,这一链条由 internal/config/rules/system_rules.go#L265-L347 中的composedResolver实现:NewResolver依次加载customRulePath(--rule)、项目级、全局级规则,并解析内嵌系统规则;Resolve则按custom → project → global → system顺序调用matchProjectRuleEntry,命中即返回(system_rules.go#L447-L457)。注释中特别说明:monorepo 场景下RepoDir锚定在 git 顶层目录,ocr review从子目录运行时加载的是仓库根部的规则文件,路径匹配也以仓库根为基准。
值得注意的细节:buildFileFilter在合并include/exclude时,只取优先级最高且配置了 include/exclude 的那一层(system_rules.go#L349-L369),并将所有模式统一转为小写——这与下文要讲的"大小写不敏感匹配"一脉相承。
rule.json 文件格式(1~3 层通用)
--rule指定文件、项目级、全局级三个层次的 JSON 结构完全一致,一个典型示例:
{ "include": ["src/**/*.{ts,tsx}", "src/**/*.go"], "exclude": ["**/*.test.ts", "**/generated/**"], "rules": [ { "path": "src/api/**/*.go", "rule": "All exported handlers must validate request bodies before use." }, { "path": "**/*mapper*.xml", "rule": "Check SQL for injection risks, parameter errors, and missing closing tags." } ] }三个字段彼此独立,语义如下:
include(可选)——glob 模式列表,作用是跳过(skip)内建默认排除模式(如测试文件排除)。它不是白名单:未命中任何include模式的文件仍会继续经受unsupported_ext(扩展名)与default_path(默认路径)两道关卡,仍可能被审查。代码中对应FileFilter.HasInclude/IsUserIncluded(system_rules.go#L226-L263),Include为空时IsUserIncluded一律返回false。exclude(可选)——OCR不应审查的文件的 glob 模式。在过滤算法内部它拥有最高优先级:只要命中exclude就立刻排除(对应FileFilter.IsUserExcluded,同样大小写不敏感)。rules——{path, rule}条目数组,按声明顺序评估。对某文件,第一个命中的path决定该文件审查时模型收到的提示词。数据结构见 system_rules.go#L205-L217 的ProjectRule/ProjectRuleEntry,其Rule字段还支持merge_system_rule布尔标记(见下文进阶章节)。
此外,rule值若形如单行文件路径(无空格、以.md/.txt/.markdown结尾),会被当作规则文件引用并读取其内容替换(resolveRuleEntries,system_rules.go#L572-L630);文件需满足扩展名白名单、512KB 大小上限,且不得逃逸仓库目录(readRuleFileSafe)。
glob 语法
OCR 使用bmatcuk/doublestar/v4与 system_rules.go#L15):
*——匹配除/外的任意字符;**——跨越目录边界匹配(src/**/*.go可命中任意深度的 Go 文件);{a,b,c}——花括号展开,*.{ts,tsx,js,jsx}会展开为四个模式依次对比;?——匹配单个字符;[abc]——字符类。
模式匹配大小写不敏感(路径会先转小写再匹配)。源码中
resolveDetail与matchProjectRuleEntry都执行strings.ToLower(system_rules.go#L166-L177、system_rules.go#L535-L553),花括号展开由expandBraces完成。拿不准时用ocr rules check <path>验证。
文件如何被过滤:五道关卡
过滤器是位于 internal/agent/preview.go 的五道关卡算法(whyExcluded,preview.go#L34-L60)。对 diff 中的每个文件,OCR 依次询问:
binary——是二进制文件吗?是则排除。user_exclude——路径命中用户exclude模式吗?命中则排除。user_include——用户定义了include时,路径命中吗?命中则直接放行(跳过下面的unsupported_ext与default_path关卡)。unsupported_ext——文件扩展名在允许列表中吗?不在则排除。default_path——路径命中内建测试文件排除模式吗(如**/*_test.go、**/*.test.{js,jsx,ts,tsx}、**/*_spec.rb等)?命中则排除。
通过全部五道关卡的文件才进入 LLM。deleted(删除)不算关卡:它是Preview()单独计算的——当新路径为/dev/null(effectivePath逻辑,preview.go#L114-L119),表示该文件没有值得审查的新内容。不想消耗 token、只想看过滤结果,用ocr review --preview(该命令在 cmd/opencodereview/review_cmd.go 中实现,调用agent.Preview,review_cmd.go#L494-L506)。
内建默认路径排除列表
文档列出的内建排除模式(完整清单见 internal/config/allowlist/default_exclude_patterns.json):
**/*_test.go**/src/test/java/**/*.java**/src/test/**/*.kt**/*.test.{js,jsx,ts,tsx}**/*.spec.{js,jsx,ts,tsx}**/__tests__/****/test/**/*_test.py**/tests/**/*_test.py**/*_test.py**/*_spec.rb**/spec/**/*_spec.rb**/*Test.java**/*Tests.java**/*_test.rs**/oh_modules/****/*.test.ets
实际 JSON 文件中的清单比文档表格更长,还包含
**/src/test/**/*.{kt,kts}、**/__snapshots__/**、**/*.snap、**/testdata/**、**/fixtures/**、**/*.generated.*、**/*.pb.go、**/*.pb.cc、**/kitex_gen/**/*.go、各类*_tbRTL 测试文件、.sol/.vy测试目录等 50 余条,覆盖测试文件、快照、生成代码、协议桩等多类噪音。
另外,过滤vendor/、node_modules/、target/这类高噪音目录发生在更早的 diff 阶段(文件级过滤器之前),由 internal/diff/git.go 处理。
想让命中这些测试文件模式的文件也参与审查?把它加进用户include列表即可——include会覆盖默认路径关卡。
每文件的规则解析:最终提示词从哪来
过滤器决定"审不审"之后,OCR 开始决定"用什么规则审"。对每个文件:
- 按声明顺序查
--rule(custom)层; - 按声明顺序查
<repo>/.opencodereview/rule.json; - 按声明顺序查
~/.opencodereview/rule.json; - 落到内建系统规则层。
系统层内建system_rules.json的模式与规则文档对应关系如下(按相对对比顺序整理):
| 模式 | 规则文档 |
|---|---|
**/*.properties | properties.md —— i18n / 配置文件 |
**/*{mapper,dao}*.xml | mapper_dao_xml.md —— MyBatis 风格 Mapper SQL |
**/pom.xml | pom_xml.md —— Maven 依赖 |
**/build.gradle | build_gradle.md —— Gradle 依赖 |
**/package.json | package_json.md —— NPM 依赖 / 脚本 |
**/Cargo.toml | cargo_toml.md —— Rust 清单 |
**/composer.json | composer_json.md —— Composer 依赖、自动加载、脚本、插件 |
**/*.{json,json5} | json.md —— 通用 JSON(含.json5) |
.github/workflows/**/*.{yaml,yml} | github_workflows.md —— GitHub Actions 工作流 YAML |
.github/**/*.{yaml,yml} | github_config.md —— 其他.github配置 YAML |
**/*.{yaml,yml} | yaml.md |
**/*.java | java.md |
**/*.go | go.md —— Go 源码 |
**/*.{ftl,ftlh,ftlx} | freemarker.md —— FreeMarker 模板(SSTI / XSS / null 处理) |
**/*.{hbs,mustache} | handlebars_mustache.md —— Handlebars / Mustache 模板 |
**/*.ets | arkts.md —— ArkTS / HarmonyOS |
**/*.astro | astro.md —— Astro 组件与岛屿 |
**/*.{ts,js,tsx,jsx,mjs,cjs} | ts_js_tsx_jsx.md |
**/*.{kt,kts} | kotlin.md |
**/*.rs | rust.md |
**/*.R | r.md |
**/*.{cpp,cc,cxx,hpp,hxx} | cpp.md |
**/*.c | c.md |
**/*.{py,ipynb} | python.md —— Python 源码 |
**/*.{php,phtml} | php.md —— PHP 源码与模板 |
**/*.proto | protobuf.md —— Protocol Buffers 通信兼容性 |
**/*.po | po.md —— gettext 翻译源目录 |
**/*.pot | pot.md —— gettext 模板 |
**/*.{graphql,gql} | graphql.md —— GraphQL schema 与操作 |
**/*.prisma | prisma.md —— Prisma schema |
**/*.jl | julia.md —— Julia 源码 |
**/*.{tf,hcl,tfvars} | terraform.md —— Terraform / HCL |
**/*.bicep | bicep.md —— Bicep(Azure)模板 |
**/*.elm | elm.md —— Elm 源码 |
**/*.{jsonnet,libsonnet} | jsonnet.md —— Jsonnet 配置模板与库 |
**/*.thrift | thrift.md —— Apache Thrift IDL 通信兼容性 |
**/*.capnp | capnp.md —— Cap'n Proto schema 通信兼容性 |
**/*.{v,sv,vh} | verilog.md —— Verilog / SystemVerilog RTL |
**/*.{vhd,vhdl} | vhdl.md —— VHDL RTL |
**/*.m | matlab.md(或经内容嗅探转 objc.md) |
**/*.mm | objc.md —— Objective-C++ 源码 |
**/*.sol | solidity.md —— Solidity 智能合约 |
**/*.vy | vyper.md —— Vyper 智能合约 |
| (兜底) | default.md |
实际 system_rules.json 中还有文档表格未列出的模式,如
**/*.pug→pug.md、**/*.nix→nix.md、**/*.{hs,lhs}→haskell.md、**/*.{nim,nims,nimble}→nim.md、**/*.swift→swift.md、**/*.zig→zig.md、**/*.{ml,mli}→ocaml.md、**/*.{re,rei}→ocaml.md等。
以 mapper_dao_xml.md 为例,这类规则文档是高质量的审查指令:它会要求 Agent 检查 SQL 关键词拼写、<if test="">动态 SQL 逻辑、JOIN 条件错误、缺 WHERE 的全表扫描风险、无分页的大查询、${}直接拼接导致的 SQL 注入等,同时强调"上下文不清时宁可漏报也不误报、只报告有明确证据的问题"——这正是规则文本注入模型后要执行的检查清单。
解析出的规则正文会被注入到 plan 与 main 任务提示词的{{system_rule}}占位符处(模板见 internal/config/template/prompts/plan_task_system.md 与 main_task_system.md)。
.m文件的内容嗅探
.m扩展名被 MATLAB 与 Objective-C 共用。OCR 通过查看文件第一个非空行来区分二者:若看起来像 Objective-C(如#import、@implementation、C 风格注释等),则改用objc.md而非matlab.md;无法读取内容时回落到matlab.md。
源码层面,这一逻辑在 internal/config/rules/sniffer.go 的sniffer装饰器中实现:sniffsAsObjC只对.m路径触发(sniffer.go#L87-L92),通过peekFirstLine读取首个非空行,再与objcSniffPrefixes前缀表(#import、#include、#pragma、#if、#define、@import、@interface、@implementation、@class、@protocol、//、/*)比对(sniffer.go#L153-L172)。注释中解释了设计取舍:故意不把裸#视为 ObjC 信号,因为 Octave 也用.m且把#当注释符,会误分类。review 场景下还会通过git show <ref>:<path>读取指定 ref 的内容(showAtRef,sniffer.go#L120-L142),超时上限 5 秒。
稳定性提示:此嗅探行为可能随 OCR 版本变化。若想对
.m路径强制固定规则,请在项目级规则中显式声明——项目规则永远优先于系统层(嗅探只包裹 system 层,见 system_rules.go#L335-L346 的注释,这正是为了不干扰用户自定义.m规则)。
检查哪条规则生效:ocr rules check
规则行为与预期不符时,用ocr rules check查看哪个层级、哪个模式最终胜出:
$ ocr rules check src/main/java/com/example/UserService.java File: src/main/java/com/example/UserService.java Source: System built-in Pattern: **/*.java Rule: ──────────────────────────────────────── …contents of java.md… ────────────────────────────────────────$ ocr rules check --rule custom.json src/main/resources/mapper/UserMapper.xml File: src/main/resources/mapper/UserMapper.xml Source: Custom (--rule) Pattern: **/*mapper*.xml Rule: ──────────────────────────────────────── …contents of your custom rule… ────────────────────────────────────────实现上,runRulesCheck通过rules.NewResolver构建解析器,调用ResolveDetail拿到RuleDetail(含 Rule 文本、Source 层级、Pattern 模式,嗅探时额外输出Note:标注),再格式化打印(cmd/opencodereview/rules_cmd.go#L45-L82)。命令还支持--repo指定仓库目录。相关测试见 cmd/opencodereview/rules_check_test.go,覆盖了真实 git 仓库下的规则解析与非法仓库目录报错两条路径。
实战配方
项目级:强制编码标准
保存为<repo>/.opencodereview/rule.json并随仓库提交:
{ "rules": [ { "path": "src/api/**/*.go", "rule": "Every public handler must `defer tx.Rollback()` immediately after starting a transaction." }, { "path": "**/*mapper*.xml", "rule": "Check SQL for injection risks, missing parameter binding, and unclosed XML tags." } ] }从源码看,项目层还支持merge_system_rule: true(system_rules.go#L489-L504)——默认用户规则替换系统规则,而开启此标记后会把命中的系统规则与用户规则合并输出,形成 "System-Specific Rules (Mandatory)" 与 "User-Specific Rules (Mandatory)" 两段,适合"既要系统默认检查、又要团队补充要求"的场景。
项目级:跳过生成代码,聚焦 src
{ "include": ["src/**/*.{ts,tsx,js,jsx}"], "exclude": ["**/*.gen.ts", "**/generated/**"] }指定include后,src/内的文件即使命中内建默认排除模式(如测试文件)也会保留;src/外的文件照常经过扩展名与默认检查。再次强调:include是"跳过默认排除"的机制,不是白名单。
PR 级覆盖
ocr review --rule ./.review-rules-only-for-this-pr.json该命令跳过项目层与全局层,为单个 PR提供一套完全不同的审查清单(例如只看安全问题的审查)。用法细节可参考 CLI 参考文档 中ocr review --rule的说明。
个人全局偏好
放在~/.opencodereview/rule.json,该机器上的所有仓库都会继承:
{ "rules": [ { "path": "**/*.{ts,tsx,js,jsx}", "rule": "Always check for unhandled promise rejections; warn on `// eslint-disable` without a reason comment." } ] }相关文档
- CLI 参考 ——
ocr review --rule、--preview、ocr rules check等命令完整说明 - 配置指南 —— 配置文件位置与层级解析链
- 架构文档 —— 解析后的规则如何进入 Agent 提示词
【免费下载链接】open-code-reviewFast, efficient, battle-tested at Alibaba's scale. Hybrid architecture code review tool: deterministic pipelines + LLM Agent, precise line-level comments, built-in multi-language ruleset (NPE, thread-safety, XSS, SQL injection), OpenAI & Anthropic compatible.项目地址: https://gitcode.com/GitHub_Trending/op/open-code-review
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考