5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

go.sumって何のためにあんの?

5
Last updated at Posted at 2026-07-24

はじめに

go.modgo.sum
最近、Goの脆弱性チェックで落ちていてモジュールのバージョンを更新しろとCIに怒られたのをキッカケに改めて整理しました。

1. バージョンを決めるのは go.mod と MVS

go.mod はモジュールのバージョンを管理するファイル。
中にある、require ブロックは、「どのモジュールの、どのバージョンを下限として要求するか」を宣言しています。

go.mod
module gosumdemo

go 1.26.4

require golang.org/x/text v0.38.0 // indirect

// indirect というコメントが付いた行は、自分のコードが直接 import していない「間接依存(依存先のライブラリがさらに依存しているライブラリ)」を表します。

Goにロックファイルはない

Node.js(npm)などでは、package.json に「許容するバージョン範囲(例: ^1.2.0)」を書き、実際にインストールされた正確なバージョンを package-lock.json に書きます1

対して、Goは go.mod でバージョンが確定させます。
バージョン指定には、MVS(Minimal Version Selection:最小バージョン選択)という仕組みが使われています2
「依存しているモジュールの中で要求されたバージョンのうち、最大のものを選択する」 というだけのシンプルなアルゴリズムです。

モジュールA「C は v1.3 以上でよろ」
モジュールB「C は v1.4 以上で。」
MVS「じゃ、C は v1.4 ね」

みたいな感じで、仮に C モジュールの最新版が v1.6 だったとしても、
誰もそれを求めていなければ、Goは勝手に v1.6 を使いません
要求を満たす範囲で、最小のバージョンが選ばれます。

バージョンを動かすのは「明示的なコマンド」のみ

Goでは、新しいバージョンが出たからといって勝手に上がることはなく、コマンドで明示的にバージョンを上げます。

コマンド 何ができるか
go get example.com/mod@v1.2.3 指定したバージョンを明示的に取得・更新する
go mod tidy コード内で使っていない依存の削除と、足りない依存の追加を行い、go.mod/go.sumを整理する

2. go.sum は「同じバージョン名で違う中身」を検知する

go mod tidy で謎に更新され、また謎の文字列が含まれるgo.sum は改竄検知用のファイルです。

go.sum には、1モジュールにつき2行のハッシュが記録されます。

go.sum
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=

h1: は SHA-256 ベースのハッシュ形式です3

Goはモジュールをダウンロードするたびに中身のハッシュを計算し、go.sum の記録と照合し、異なればビルドを強制ストップします。
おかげで、以下のような致命的な事態を防いでくれます。

  1. 改竄検知:モジュールの置き場である GitHub などのリポジトリや、配信を中継するプロキシサーバが乗っ取られ、悪意あるコードが含まれたみたいなケース。
  2. タグの付け直しミス:ライブラリ作者が「v1.0.0」として公開したあと、バグに気づいてこっそりコミットを修正し、同じ「v1.0.0」タグを付け直したみたいなケース4

初回ダウンロード時のチェックサム・データベース

「自分が一番最初にダウンロードした時点で、すでに改ざんされていたら?」

調べたところ、Goは以下の仕組みで対応しているようです。

  • 公開データベースとの照合: デフォルトでGoogleが運営している sum.golang.org と照合し、ハッシュの正当性を確認する5
  • 一度公開されたら取り消せない: ミラーサーバー(proxy.golang.org)にキャッシュされるため、後から作者がリポジトリを消去・改変しても利用者のビルドは問題なく行える5

「そんなに堅牢なら、手元の go.sum は要らなくない?」と思ったのですが、
どうやらsum.golang.org に問い合わせるのは初回ダウンロードの瞬間だけで、以降のビルドは手元の go.sum とのローカル照合で完結するみたいです(毎回 Google に聞きに行くわけではない)。

3. 再現

実際に go.sum の検知が働く瞬間を再現してみました(Go 1.26で確認)。

# 作業用ディレクトリを作ってモジュールを初期化する
mkdir /tmp/gosumdemo && cd /tmp/gosumdemo
go mod init gosumdemo

# 依存を1つ追加する(go.mod と go.sum が生成される)
go get golang.org/x/text@v0.38.0

動作確認用の最小コード(main.go)を作成します。

main.go
package main

import (
    "fmt"

    "golang.org/x/text/language"
)

func main() {
    // BCP 47 の言語タグをパースして表示するだけの確認用コード
    tag := language.MustParse("ja-JP")
    fmt.Println(tag)
}

一度実行してみます。

go mod tidy   # 依存関係を整理
go run .      # => ja-JP と表示されれば成功

ここで攻撃者になったつもりで、go.sum を直接書き換えてみます
エディタで go.sum を開き、1行目のハッシュ h1:sXmwo9... の先頭の sX に変えて保存。

その状態で実行(ビルド)すると、以下のように怒られました。

image.png

SECURITY ERROR でビルドが停止しました。

壊してしまった go.sum は消して作り直せばすぐに復旧します(再生成されるハッシュも sum.golang.org(公開チェックサムデータベース)との照合で検証されるため)。

rm go.sum
go mod tidy   # go.sum を再生成する
go build .    # 今度は通る

まとめ

  • バージョンを決めるのは go.mod と MVS。 要求の中から「最大のものを一つ選ぶ」という deterministic(決定的)なアルゴリズム。
  • go.sum は改ざん検知用。
  • 公開済みタグは変更してはならない。 モジュール利用者の go.sum とハッシュが食い違い、全員のビルドが失敗する。

Gitのコンフリクト解消時などに、go.sum のコンフリクトを真面目に手作業で直さず「一度消して go mod tidy で作り直す」という運用ができるのも、こういう事情があるからなのですね。

参考文献

  1. npm Docs — package-lock.json

  2. Go Modules Reference — Minimal version selection

  3. golang.org/x/mod/sumdb/dirhash — Hash1

  4. 渋川よしき、辻大志郎、真野隼記、後藤玲雄『実用 Go言語 第2版』オライリー・ジャパン、7.2節

  5. sum.golang.org — Go Checksum Database 2

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?