diff --git a/.claude/agents/jellybit-review-gate.md b/.claude/agents/jellybit-review-gate.md index 3c594a6..7e94851 100644 --- a/.claude/agents/jellybit-review-gate.md +++ b/.claude/agents/jellybit-review-gate.md @@ -19,8 +19,8 @@ color: red 1. Определи базу диффа: `git merge-base HEAD master` (на master — `HEAD~1`) или возьми её из задания. 2. Запусти `task gate BASE=<база>` (обёртка над `scripts/gate.sh`). Он гонит все - шаги до конца и печатает сводку `OK`/`FAIL`/`SKIP`; подробности — в - `tmp/gate/<шаг>.log`. + шаги до конца и печатает сводку `OK`/`FAIL`/`WARN`/`SKIP`; подробности — в + `tmp/gate/<шаг>.log`. Краснит гейт только `FAIL`. 3. По каждому `FAIL` открой лог и прочитай **реальную** причину. Не пересказывай строку «FAIL» — назови упавший тест, файл и утверждение. 4. **Отдели новое от унаследованного.** Если отказ выглядит не связанным с @@ -45,6 +45,13 @@ color: red - **`SKIP` любого шага** — идёт в границы покрытия дословно, с причиной. Молча пропущенная проверка — это ложное ощущение проверенности, ровно то, ради чего гейт и заводился. +- **`WARN` от `govulncheck`** — гейт не краснеет, но находка нужна. Открой + `tmp/gate/govulncheck.log` и посмотри трассы вызовов: уязвимость, приехавшая с + зависимостью **этого** change, — `major`; уязвимость в стандартной библиотеке + или в давно стоящей зависимости — `minor` с пометкой «унаследовано» и с + конкретным лекарством (версия тулчейна или модуля, в которой исправлено). + Недостижимые из нашего кода уязвимости в отчёт не выноси — только строкой в + границах покрытия. - **Правило есть в конвенциях, но не в линтере.** Если по ходу видно, что `FAIL`/замечание могло быть поймано правилом — пиши `Promote candidate` по процедуре `references/promote.md`. diff --git a/Taskfile.yml b/Taskfile.yml index bf84336..b062cc4 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -8,8 +8,9 @@ version: '3' vars: BINARY: jellybit PKG: ./cmd/jellybit - # Версия линтера для воспроизводимой установки (см. задачу setup). + # Версии инструментов для воспроизводимой установки (см. задачу setup). GOLANGCI_VERSION: v2.12.2 + GOVULNCHECK_VERSION: v1.6.0 tasks: default: @@ -86,7 +87,8 @@ tasks: - rm -f {{.BINARY}} setup: - desc: Установка инструментов разработки (линтер + git-хуки lefthook) + desc: Установка инструментов разработки (линтер, govulncheck + git-хуки lefthook) cmds: - go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@{{.GOLANGCI_VERSION}} + - go install golang.org/x/vuln/cmd/govulncheck@{{.GOVULNCHECK_VERSION}} - lefthook install diff --git a/scripts/gate.sh b/scripts/gate.sh index 90d9b2e..e2aa4cd 100755 --- a/scripts/gate.sh +++ b/scripts/gate.sh @@ -9,7 +9,10 @@ # # Коды возврата: 0 — все обязательные шаги зелёные, 1 — есть красные. # Пропущенные шаги (нет инструмента) НЕ красят гейт, но попадают в сводку: -# молча пропущенная проверка — это ложное ощущение проверенности. +# молча пропущенная проверка — это ложное ощущение проверенности. То же с WARN: +# отказ, который почти всегда унаследован (уязвимость в зависимости или в +# стандартной библиотеке), не должен краснить каждый прогон ревью — иначе +# красный гейт перестают читать. Разбирает такой отказ агент. set -u @@ -127,10 +130,17 @@ else fi # --- Уязвимости зависимостей --- +# Не блокирует: находка тут — состояние зависимостей и тулчейна, а не диффа. +# Исключение (уязвимость приехала с новой зависимостью в этом change) разбирает +# агент по списку вызовов. if command -v govulncheck >/dev/null; then - step govulncheck "" govulncheck ./... + if govulncheck ./... >"$OUT_DIR/govulncheck.log" 2>&1; then + record OK govulncheck "" + else + record WARN govulncheck "достижимо из кода уязвимостей: $(grep -c '^Vulnerability #' "$OUT_DIR/govulncheck.log") → $OUT_DIR/govulncheck.log" + fi else - record SKIP govulncheck "govulncheck не установлен (go install golang.org/x/vuln/cmd/govulncheck@latest)" + record SKIP govulncheck "govulncheck не установлен (task setup)" fi echo @@ -144,4 +154,4 @@ if [ "$FAILED" -eq 1 ]; then echo "ГЕЙТ КРАСНЫЙ — опиниативные проходы не запускаются" exit 1 fi -echo "гейт зелёный (пропущенные шаги см. в сводке — они идут в границы покрытия)" +echo "гейт зелёный (шаги WARN и SKIP см. в сводке — они идут в находки и в границы покрытия)"