feat: support reading external files as Code Review rules via use_file_path#87
feat: support reading external files as Code Review rules via use_file_path#87zephyrq-z wants to merge 4 commits into
use_file_path#87Conversation
- Added 'rule_file' field to ProjectRuleEntry in rule.json - Implemented resolveRuleFiles to read, validate, and merge external rule files - Security: prevents path traversal (../) outside the base directory - Limits supported extensions to .md and .txt, max size 100KB - Merges contents if both 'rule' and 'rule_file' are provided - Added unit tests for security, missing files, large files, etc. - Updated README.md and README.zh-CN.md Resolves alibaba#67
|
|
| "path": "**/*mapper*.xml", | ||
| "rule": "检查 SQL 注入风险、参数错误和缺少闭合标签" | ||
| "rule": "docs/sql-rules.md", | ||
| "use_file_path": true |
There was a problem hiding this comment.
感觉需要放在顶层,不然每个子项都需要配置一遍。
| // Security check: prevent directory traversal | ||
| if !strings.HasPrefix(absFile+string(filepath.Separator), absBase) && absFile != strings.TrimSuffix(absBase, string(filepath.Separator)) { |
There was a problem hiding this comment.
Security: Symlink-based directory traversal bypass. filepath.Abs only performs lexical path cleaning — it does NOT resolve symlinks. An attacker (or a malicious repo) could place a symlink inside .opencodereview/ that points to an arbitrary file outside the base directory. The prefix check on the string path would pass because the symlink itself lives within the base dir, but os.ReadFile follows the symlink and reads the target file.
To fix this, resolve symlinks before performing the prefix check:
resolvedFile, err := filepath.EvalSymlinks(absFile)
if err != nil {
fmt.Fprintf(os.Stderr, "[WARN] Failed to resolve symlinks for rule file %s: %v\n", filePath, err)
continue
}Then use resolvedFile for both the security check and subsequent reads. You should also resolve absBase with EvalSymlinks to handle the case where the base directory itself contains symlinks.
| if !entry.UseFilePath || entry.Rule == "" { | ||
| continue | ||
| } |
There was a problem hiding this comment.
Silent skip without warning when UseFilePath is true but Rule is empty. A user who sets "use_file_path": true but forgets to specify the "rule" field will get no feedback at all, making configuration debugging difficult. Consider adding a warning here similar to the other error paths.
Suggestion:
| if !entry.UseFilePath || entry.Rule == "" { | |
| continue | |
| } | |
| if !entry.UseFilePath { | |
| continue | |
| } | |
| if entry.Rule == "" { | |
| fmt.Fprintf(os.Stderr, "[WARN] Rule entry has use_file_path=true but empty rule path, skipping\n") | |
| continue | |
| } |
…erability - Move use_file_path from per-entry to top-level ProjectRule field (simplifies config: no need to repeat flag for every rule entry) - Add filepath.EvalSymlinks to prevent symlink-based directory traversal (resolves symlinks on both file path and base directory for consistent prefix matching across platforms like macOS /var -> /private/var) - Add warning when use_file_path=true but rule path is empty - Update tests to use new top-level UseFilePath structure - Update README.md and README.zh-CN.md with new config format
|
|
||
| ```json | ||
| { | ||
| "use_file_path": true, |
There was a problem hiding this comment.
感觉这个说明会误导用户,同时存在 path 和字符串应该会报错吧,use_file_path开关应该是控制用户使用其中一种。
There was a problem hiding this comment.
另外其他语言的 readme 也需要补充下
…g in README files
Description
Closes #67
📝 Background & Motivation
In practice, inlining complex Code Review rules directly into
rule.jsonmakes the configuration file bloated and hard to maintain. Issue #67 requested the ability to extract rules into separate.mdor.txtdocuments and reference them withinrule.json.🚀 Core Changes
To keep the configuration concise, the initially discussed standalone
rule_filefield was discarded in favor of a more intuitiveuse_file_pathboolean toggle:use_file_path: true, therulefield is treated as a file path. The program reads the file's content and directly overwrites therulefield.false, therulefield continues to act as a standard inline string rule, fully compatible with legacy configurations.🛡️ Security & Robustness
To prevent misconfigurations or malicious exploitation, strict defense mechanisms are implemented in the
resolveRuleFilesfunction:.opencodereviewdirectory via../(e.g.,../../etc/passwd)..mdand.txtrule files, preventing the accidental loading of executable scripts or other sensitive formats.[WARN]log and retains the originalrulestring (falling back to system default rules).💻 Configuration Example
In
.opencodereview/rule.json:{ "rules": [ { "path": "**/*.py", "rule": "docs/python_security_rules.md", "use_file_path": true }, { "path": "**/*.java", "rule": "【Inline Rule】Please check for NullPointerException risks." } ] }🧪 Testing & Verification
All changes include comprehensive test coverage:
reproduce_test.sh: Verifies via a local Mock LLM Server that external rule file contents are successfully injected into the LLM Context.observable_test.sh: Intuitively validates text changes before and after rule parsing using the nativeocr rules checkcommand.security_test.sh: Conducts security boundary testing specifically targeting malicious paths like../../etc/passwd.