Как добавить новую Go-зависимость¶
Пошаговый рецепт vetting'а и подключения нового модуля. Convention —
../conventions/dependencies.md. Эта
страница — конкретная последовательность команд + checklist для PR.
Содержание¶
- Когда вообще стоит добавлять
- 1. Есть ли уже в стеке?
- 2. Vetting репозитория
- 3. Лицензия
- 4. Добавить в go.mod
- 5. govulncheck
- 6. SBOM-проверка
- 7. Локально прогнать тесты
- 8. PR description
- 9. Update: как апгрейдить
- Чеклист для PR-автора
- Связанные разделы
Когда вообще стоит добавлять¶
Новая зависимость — это чужой код в supply chain сервиса. Прежде чем
делать go get:
- stdlib уже умеет?
net/http,log/slog,encoding/json,errors,contextзакрывают большую часть задач. - Уже есть в стеке? См. §1.
- Можно написать самому за час? Для простых вещей (URL-builder, проверка email) проще 30 строк своих, чем модуль на 5 МБ.
Если «нет, нет, нет» — дальше по шагам.
1. Есть ли уже в стеке?¶
Проверь текущие зависимости:
Сравни с таблицей «Популярные choices» в
../conventions/dependencies.md.
Если нужный функционал уже закрыт — используй его, не тащи дубликат
(две ORM, два JSON-парсера, два HTTP-роутера в одном сервисе —
антипаттерн).
2. Vetting репозитория¶
Открой репозиторий модуля (github/gitlab) и ответь на вопросы.
Активность¶
- Последний commit в main. За 6 месяцев — норма. > 1 года — красный флаг.
- Releases. Есть tagged releases? Или только main-branch'ный код?
- Issues. Бэклог растёт или обрабатывается? Долгие unanswered issues — знак.
Популярность¶
- Stars > 500. Либо это общеизвестный модуль (
golang.org/x/*, частьprometheus/*/cncf-*). - Сколько других проектов используют. На GitHub — кнопка «Used by». На pkg.go.dev — «Imported by».
Авторство¶
- Организация или одиночка. Одиночный автор — не сразу «нет», но нужен дополнительный осмотр кода.
- Denylist. Если был случай supply-chain-атаки от этого автора (event-stream / coa / ua-parser-js и подобные прецеденты в экосистеме) — не тянем.
Код-ревью модуля¶
Бегло прочти:
init()функций быть не должно (или только с очевидным содержимым).init()с сетевыми вызовами / shell-вызовами — стоп.exec.Command("sh", ...),os/execна ровном месте — тоже стоп.- Обфусцированные блоки, base64-кодированные строки на десятки килобайт — однозначный индикатор подозрительного кода.
net/http.Postна неизвестные URL — особенно в constructor'ах.
Это не глубокий аудит, это 10-минутный просмотр на очевидные флаги.
Go-версия¶
go X.Y должна быть совместима с нашей (1.22+, см.
../conventions/dependencies.md).
Модуль с go 1.20 — работает; модуль, требующий go 1.23beta —
проблема.
3. Лицензия¶
Проверь LICENSE в корне репозитория.
| Лицензия | Наш статус |
|---|---|
| MIT, Apache-2.0, BSD-2/3-Clause, ISC, MPL-2.0 | принимаем |
| Unlicense, CC0 | принимаем (public domain) |
| GPL-2.0, GPL-3.0, LGPL, AGPL | нельзя — copyleft, вирусится на наш код |
Любая Non-Commercial |
нельзя |
Нет файла LICENSE |
нельзя — нет права использовать |
| Кастомная лицензия | обсудить с lead |
Почему это важно: AGPL зависимость в prod-сервисе теоретически потребует открыть весь наш код под AGPL.
Для точной классификации — опираемся на
SPDX license list и пакет
licensecheck:
go install github.com/google/go-licenses@latest
go-licenses report ./... 2>/dev/null | grep -i "<module>"
Утилита покажет детектированную лицензию всей цепочки transitive- зависимостей.
4. Добавить в go.mod¶
Последовательность:
- Всегда с явной версией (
@v1.2.3или@latest). Без суффикса Go берёт latest, но не зафиксирует —go mod tidyможет «сдрейфить». - Не редактируй
go.modруками. Только черезgo get/go mod tidy/go mod download. indirectсекция управляется автоматически — вручную туда не пиши.
Проверь размер обновления:
Если один go get притащил 20+ новых модулей — это большая цепочка
transitive-зависимостей, повод подумать, нет ли более узкого
альтернативного модуля.
5. govulncheck¶
Ожидаем:
Если findings есть:
- В новом модуле — не тянем его. Ищем альтернативу, или апгрейдим до патч-версии без CVE.
- В transitive-зависимости —
go getконкретной старшей версии transitive-пакета в свойgo.modкак direct require (Go выберет max(required)). LOW severity— допустимо с документированием в PR description: почему не критично, когда апгрейд.
govulncheck не идеален: он проверяет только используемые
символы. Для полного покрытия — trivy fs --scanners vuln ..
6. SBOM-проверка¶
Software Bill of Materials — список всех компонентов в образе:
# для образа сервиса
syft . -o spdx-json > sbom.json
# посмотреть добавленное
jq '.packages[] | select(.name | test("<module-name>")) | {name, versionInfo, licenseConcluded}' sbom.json
Прикладывается к tagged-релизу (make release). Если отсутствует в CI
— добавь: syft бесплатный, занимает 10 секунд.
7. Локально прогнать тесты¶
Полный цикл:
go build ./... # компиляция
go vet ./... # базовые проверки
golangci-lint run # lint
go test -race ./... # unit + race detector
go test -tags=integration ./... # integration (testcontainers)
Если integration падает — смотри
../troubleshooting/test-hangs.md.
8. PR description¶
Шаблон commit-message:
feat(deps): добавил github.com/<org>/<module> v1.2.3
Что это:
<2-3 строки описания>
Зачем:
<3-4 строки: какую задачу решает, почему не подходит текущий стек>
Vetting:
- Лицензия: <MIT / Apache-2.0 / ...>
- Активность: <X stars, commits N months ago, releases last YY>
- Transitive: <список, если > 3 новых>
- govulncheck: pass
- Альтернативы рассмотрены: <что ещё смотрел, почему не подошло>
Ревьюер смотрит:
- Раздел «Зачем» — действительно нужно.
- Раздел «Альтернативы» — автор реально смотрел, или первая попавшаяся.
- Лицензия и vetting проведены.
- Размер diff'а в
go.sum— соизмерим с ожидаемым.
Ссылка на convention в PR description:
см. conventions/dependencies.md#vetting-checklist.
9. Update: как апгрейдить¶
Патч / minor:
Major (v1 → v2) — отдельная задача со своей процедурой. См.
../conventions/dependencies.md.
Массовый ежемесячный sweep:
Список того, что имеет обновления. Один PR — один модуль (кроме
однотипных пачек типа watermill-*).
Чеклист для PR-автора¶
- Альтернативы в stdlib и текущем стеке рассмотрены и отклонены с обоснованием.
- Лицензия совместима (MIT / Apache-2.0 / BSD / MPL / ISC), не GPL/AGPL/LGPL.
- Последний коммит в main-модуле — не старше 6 месяцев (или обоснование).
-
govulncheck ./...— clean. -
go mod tidy— no-op (изменения только от нашегоgo get). -
go.sumзакоммичен вместе сgo.mod. - Integration-тесты проходят.
- PR description заполнен по шаблону §8.
- Размер transitive-обновления адекватный (не 20+ новых модулей
из-за одного
go get).
Связанные разделы¶
../conventions/dependencies.md— принципы, популярные choices, чего не тянуть, CI-проверки.../conventions/security.md— supply chain в общей security-модели.../conventions/commits-and-prs.md— формат commit-message для dependency-PR.../troubleshooting/test-hangs.md— если integration-тесты повисли после добавления зависимости.