TGViewer
Go Update Go Update @go_update · 3.23K subscribers
Post #111 3.38K
Про go mod tidy | verify | download

Задумывались ли вы о том, как именно Go проверяет целостность ваших скаченных модулей? Как наш тулчейн проверяет, что зависимости которые вы видите в своем проекте, соответствуют зависимостям которые видят другие разработчики?

Я думаю, что нет, ибо работает простой принцип: работает — не трогай. Однако мне, по роду деятельности, пришлось залезть внутрь и прочитать (несколько раз) спеку и посмотреть реализацию. И для того, чтоб структурировать свои изыскания я пишу сей пост.

Все начинается с попытки получить модуль. После первого скачивания модуля (через вызов go mod tidy или go mod download на проекте) в формате zip архива с прокси для модулей, Go делает следующее

• Сортирует имена файлов в архиве и пробегает sha256 по каждому файлу. Получившийся набор пар "hash filepath" он прогоняет через sha256 еще раз, кодирует его в base64, добавляет префикс h1: и запоминает результат. В общем виде это выглядит как вызов вот такой команды:


sha256sum $(find . -type f | sort) | sha256sum


• Далее он сравнивает получившийся хеш с записью о зависимости которая хранится в go.sum внутри вашего проекта. Если её нет (или нет go.sum, т.е. вы только начали проект) то он идет в GOSUMDB и спрашивает хеш у него. В обоих случаях, после совпадения хешей, zip файл модуля пишется в локальные загрузки ($GOPATH/pkg/mod/cache/download/<url>) и распаковывается в локальный кеш ($GOPATH/pkg/mod/cache/<url>). Если не совпало, ничего не пишем и кидаем ошибку. Побочный вывод — нельзя называть модуль cache или sumdb, о чем ниже.

- Если модуль приватный (выставлены переменные окружения GOPRIVATE и/или GONOSUMDB) или вообще отключена связь с сервером хешсумм через GOSUMDB=off, то проверять хешсумму он будет исключительно с тем, что есть в go.sum внутри проекта. Если там такого модуля нет, то мы доверяем полученным данным и добавляем полученную хешсумму в go.sum.

- Если нет прокси для модулей (например вы берёте файлы напрямую с гита) то Go сам создает zip архив и помещает его в скаченное.

- Подсчет хеша архива модуля недешевая операция в общем смысле, особенно если её постоянно вызывать. Поэтому, кроме zip файла модуля мы рядом храним полученный хеш в файле c суффиксом .ziphash.

• Во время сборки бинаря наш компилятор, чтобы не терять время, не проверяет целостность архива и распакованных данных, а только сравнивает, что строчки в go.sum проекта совпадают с тем, что у нас лежит в ziphash файлах.

И тут наступает вопрос: а как проверить, что никто не трогал наш кеш модулей? В дело вступает go mod verify, который пробегаясь по всем модулям из go.mod делает следующее:

• Сначала он читает хеш из ziphash файла.
• Затем он читает и хеширует распакованные файлы модуля, сравнивая их итоговый хеш с полученным на прошлом этапе. Затем тоже самое повторяется для zip архива модуля. Операция аналогична тому, что происходит при скачивании.
• Если не совпало, то verify кидает ошибку на модуль и выходит.

Обратите внимание, что здесь go.sum проекта нигде не участвует. Проверяется целостность именно кеша.

А что если мне подменили ziphash вместе с файлами модуля и zip архивом? На это есть ряд ответов:

• Во время скачивания предполагается, что между нами и БД хешсумм установленно защищенное соединение.
• Сама БД хешей, это даже не БД в общем смысле, а дерево, где каждый новый элемент зависит от прошлых вставок. Поэтому при попытке поменять запись развалятся записи о всех хешах модулей которые были вставлены после. Кому интересны подробности рекомендую вот эту статью https://research.swtch.com/tlog и погуглить Merkle Tree.
• Когда мы скачиваем хеш, мы получаем не отдельное значение, а некое «поддерево» хешей которое необходимо нам для валидации нашего модуля. Это дерево мы помещаем в $GOPATH/pkg/mod/cache/download/sumdb/ (тот самый) и используем для проверки локального модуля. И тут происходит интересное: если удалить ziphash файл то даже без соединения с интернетом, go mod download сможет восстановить хеши из частей большого дерева лежащих в $GOPATH/pkg/mod/cache/download/sumdb/ и записать их обратно в ziphash.
  • 👍 22
  • ❤ 4
  • 🤯 3
  • 🔥 1
More from @go_update
  1. Aug 22, 2026Об изоляции LLM Да, это ещё один пост про работу с Codex/Claude/GLM/Qwen/DeepSeek и прочая…
  2. Aug 11, 2026И вот эти два минуса выглядят нерешенными (на данный момент времени). Можно ли их решить в…
  3. Aug 11, 2026🎂 Вечерний пост о том, что сегодня мне исполнилось 34. Прошёл еще один год, а значит врем…
  4. Jul 13, 2026📝 testing: allow examples with any signature Небольшое «Quality of Life» предложение. Сут…
  5. May 14, 2026📝 net/http/httptest: synctest support Я уже писал про пакет synctest и его возможности. Э…
  6. May 13, 2026Я редко пишу сюда о вещах которые не относятся к Go, но тут у меня появилась хорошая стать…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →