Feature/rule link to files (#226)

* feat: support inline content and file path resolution for rule field

- rule field auto-detects: .md/.txt/.markdown ending = file path, otherwise inline
- file paths: project-relative first, then as absolute path
- safety: stat before read (512KB cap), extension whitelist, symlink resolution
- tightened heuristic: values with spaces treated as inline to avoid false positives
- guard against empty repoDir to avoid CWD-relative resolution
- 5-language README docs updated with file path usage and first-match-wins behavior
- 15 new unit tests covering all resolution branches

Closes #67
Supersedes #87

* update readme

* feat: update rule resolution logic to clear rules for missing or invalid files

* feat: update rule field description to clarify file path detection criteria

* feat: enhance rule file resolution to block path traversal and improve validation

* fix: clean up tryReadRuleFile and add missing blank line

- Add blank line between matchProjectRuleEntry and allowedRuleExts (Issue 1)
- Remove dead code '|| repoDir == ' in tryReadRuleFile (Issue 2)
- Remove unnecessary warning when repoDir is empty but path is absolute (Issue 3)
This commit is contained in:
zephyrq-z 2026-06-27 11:06:38 +08:00 committed by GitHub
parent 30c083c0de
commit b109baf0c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 711 additions and 0 deletions

View file

@ -567,6 +567,45 @@ OCR разрешает правила ревью по цепочке приор
- Внутри каждого уровня правила проверяются в порядке объявления — побеждает первое совпадение.
- Если файл правил не существует, он молча пропускается.
**Поле `rule` поддерживает как встроенный текст, так и пути к файлам.** Система определяет тип автоматически:
1. Если значение содержит переносы строк → **встроенный текст** (многострочные правила никогда не считаются путями).
2. Если значение — одна строка, без пробелов, и заканчивается на `.md` / `.txt` / `.markdown`**путь к файлу**.
- Абсолютные пути (начинающиеся с `/`) используются напрямую.
- Относительные пути проверяются в корне проекта. Выход за пределы директории (например, `../../etc/passwd.md`) блокируется. Если не найдены — выводится `[WARN]` и правило очищается (без fallback на inline).
- Файл должен пройти проверку: допустимое расширение, ≤ 512KB, цель симлинка также должна иметь допустимое расширение. При ошибке проверки правило очищается.
3. Иначе → **встроенный текст**.
```json
{
"rules": [
{
"path": "**/*mapper*.xml",
"rule": "docs/sql-rules.md"
},
{
"path": "**/*.java",
"rule": "Always check for null safety and resource leaks"
},
{
"path": "**/*.go",
"rule": "shared/go-concurrency.md"
},
{
"path": "**/*.py",
"rule": "/Users/me/team-rules/python.md"
}
]
}
```
- `docs/sql-rules.md` — относительный путь, загружается из `<project>/docs/sql-rules.md`.
- `Always check for null safety…` — встроенная строка, используется напрямую.
- `shared/go-concurrency.md` — относительный путь, аналогично.
- `/Users/me/team-rules/python.md` — абсолютный путь, используется напрямую.
> Абсолютные пути могут указывать на файлы вне директории проекта — это сделано намеренно. `rule.json` пишут мейнтейнеры проекта, это доверенный ввод. Команды могут хранить общие правила по единому пути (например, `/opt/company-rules/`) и не копировать их в каждый проект.
### Фильтрация путей
Файлы правил также поддерживают поля `include` и `exclude`, управляющие тем, какие файлы попадают в область ревью: