言語パッケージマネージャーにおける再現可能なビルド
公開されたパッケージが、主張するソースコードから実際にビルドされたことを検証する仕組みについて説明しています。
キーポイント
再現可能ビルド(Reproducible Builds)は、ソフトウェアサプライチェーンの信頼性を確保するための重要な技術であり、パッケージが公式ソースから正しくビルドされたことを検証可能にする。
Debianプロジェクトを中心に2013年から始まった取り組みは、当初24%だった再現性を10年以上の継続的な改善により96%まで向上させ、複数のディストリビューションに広がる業界横断的な運動に発展した。
ビルドの非再現性の主な原因は、タイムスタンプの埋め込み、ファイル順序、パス依存性、ロケール依存など多岐にわたり、個別のパッケージに対する地道な修正作業の積み重ねが成功の鍵となった。
検証には.buildinfoによる環境記録、diffoscopeによる差異分析、strip-nondeterminismによる標準化ツールが用いられ、実用的な検証プロセスが確立されている。
影響分析・編集コメントを表示
影響分析
この記事は、ソフトウェアサプライチェーンセキュリティの基盤技術である「再現可能ビルド」の10年にわたる発展と実用化の歴史を詳細に描いている。単なる技術的課題ではなく、オープンソースエコシステム全体の信頼性を高める社会的・技術的運動として定着した点が重要であり、AIモデルの依存関係管理やMLOpsにおける再現性確保にも応用可能な知見を提供する。
編集コメント
AIモデルの配布や依存ライブラリの信頼性が重大関心事となる中、10年前から始まったこの取り組みは、現代のMLシステムの再現性確保にも直接関連する重要な基盤技術。技術的完璧主義と現実的な実装努力のバランスが成功の秘訣。
レジストリからパッケージをダウンロードすると、そのパッケージは特定の Git コミットからビルドされたものだとレジストリは言いますが、受け取った tarball や wheel、あるいは crate は、誰かが自分のマシンでビルドしてアップロードした不透明なアーティファクトです。再現可能なビルド(Reproducible Builds)を使えば、自分でソースコードから再ビルドして比較することで検証でき、同じバイト列が得られれば、そのアーティファクトは主張通りのものであると確認できます。これを機能させるには、ビルド環境とアーティファクトの出自(プロベナンス)の両方を制御する必要があり、歴史的に見てほとんどの言語パッケージマネージャーはどちらも制御していませんでした。
再現可能なビルドプロジェクトは 2013 年からこの取り組みを開始しており、その際 Lunar(Jérémy Bobbio)が DebConf13 でセッションを組織し、Debian のビルドツールチェーンの修正に取りかかりました。Snowden による情報開示によりソフトウェアの信頼性が緊急の課題となり、Bitcoin の Gitian ビルダーが単一プロジェクトに対してこのアプローチが実現可能であることを示しており、Tor プロジェクトも Tor Browser の決定論的ビルド(deterministic builds)の生産を開始していました。Lunar は同じ考え方をオペレーティングシステム全体に適用したかったのです。
2013 年 9 月の Debian パッケージにおける最初の大量再ビルドでは、24% が再現可能であることが判明し、dpkg および一般的なビルドヘルパーの最も簡単な課題を修正した後の 2014 年 1 月には、その割合は 67% に跳ね上がりました。現在、Debian のテストインフラストラクチャでは、trixie のパッケージの約 96% が制御された条件下で再現可能にビルドされていることが示されており、reproduce.debian.net は ftp.debian.org が配布する実際のバイナリを再ビルドすることで、クリーンルームでのテストビルドよりも厳しいテストを実行しています。
このプロジェクトは、Arch Linux、NixOS、GNU Guix、FreeBSD など他の多くのディストリビューションが数年のうちに参画したことで、クロスディストリビューション型の取り組みへと成長しました。サミットは 2015 年以降ほぼ毎年開催されており、最も最近のものでは 2025 年 10 月にウィーンで開催されました。2017 年から 2019 年に Debian プロジェクトリーダーを務めた Chris Lamb は、このプロジェクトに関する IEEE Software の論文を共著し、それが 2022 年の最優秀論文賞を受賞しました。Lunar は 2024 年 11 月に逝去しました。2015 年から継続的に発表されているプロジェクトの週報は、関与する作業の規模感を示しています:各報告書には、タイムスタンプ、ファイル順序、パス埋め込み、ロケール依存性といった問題を修正するためのパッチが、一度に一つのアップストリームパッケージ宛てに送信されたリストが記載されており、年間数百のパッケージに及んでいます。24% から 96% への達成は、単一のアーキテクチャ的修正によるものではなく、Debian アーカイブ全体にわたるこの種の清掃的なパッチ適用を十年間継続した結果です。
検証の仕組み
異なる環境で同じソースコードを二度ビルドし、出力を比較します。もしバイト列が一致すれば、ソースと配布物の間で誰かがアーティファクトを改ざんしていないことを意味します。実際にはこれにはビルド環境に関するすべての情報を記録する必要があり、Debian では .buildinfo ファイルを用いてそれを行っています。
ハッシュ値が一致しない場合、その理由を見つける手段として diffoscope が用いられます(元々は Lunar によって debbindiff として開発されました)。
このプロジェクトはまた、strip-nondeterminism も維持管理しています。
ビルドが非再現的になる要因
Benedetti らは、reprotest を用いて 6 つのエコシステムそれぞれから 4,000 パッケージずつテストしました。
3 つの失敗したエコシステムすべてに共通する主な原因は、パッケージアーカイブに埋め込まれたタイムスタンプであり、これは RubyGems の失敗の 97.1%、Maven の失敗の 92.4%、PyPI の失敗の 87.7% を引き起こしていました。標準的な解決策は SOURCE_DATE_EPOCH です。
この問題のほとんどは、パッケージごとの作業ではなくインフラストラクチャの変更によって修正可能であることがわかりました。SOURCE_DATE_EPOCH を設定するだけで十分です。
os.path.expanduser
ファイル順序も同様の問題を発生させます。readdir() 関数の結果がホストシステムやユーザー環境に依存するためです。例えば、/home/alice/project と /home/bob/project のようなパスの違いが問題となります。
2023 年 8 月の Go 1.21 以降、Russ Cox 氏のチームがマップの反復順序、埋め込まれたソースパス、アーカイブ内のファイルメタデータ、ARM フローティングポイントモードのデフォルトなど、10 の異なる非決定性要因を排除した結果、ホスト OS、アーキテクチャ、ビルド時間に関係なく、ビット単位で完全に同一の出力が生成されるようになりました。
Go は go.dev/rebuild 上で gorebuild を使用して毎晩検証を実行しています。
Maven の公式ガイドには手順が記載されています:project.build.outputTimestamp を設定し、mvn clean verify artifact:compare コマンドを実行します。
ただし、タイムスタンプが機能するのはチェーン内のすべてのプラグインがこれを尊重する場合に限られます。多くのサードパーティ製プラグインはこれに対応していません。異なる JDK バージョンではバイトコードが異なり、ZIP エントリの順序も実装によって異なります。また、Maven ビルドは数十のプラグインから構成されており、それぞれが独自の潜在的な非決定性をもたらします。研究者たちは Java ビルドの再現不可能性の 6 つの根本原因を正規化するために Chains-Rebuild を構築しました。これは、単一のビルドシステム内でどれほど多くの別々のことが失敗し得るかを示す指標となっています。
Rust の RFC 3127 は、trim-paths(パスのトリミング)を導入しました。
/home/alice/.cargo/registry/src/crates.io-abc123/serde-1.0.200/src/lib.rs
serde-1.0.200/src/lib.rs
手動マクロおよびビルドスクリプト(build.rs)
Benedetti 氏らの研究では、PyPI パッケージの約 12.2% がそのまま再現可能であることが判明しましたが、その違いはビルドバックエンドに起因していました。flit を使用するパッケージは……
PyPI はまた、2024 年 10 月にリリースされた PEP 740(注:デジタル証明書の付与に関する提案)を通じて、他のレジストリよりも一歩先を行く取り組みを進めています。これにより、パッケージと共にアップロードされる Sigstore 署名付きのデジタルアテステーション(証明)がサポートされます。これにより、各アーティファクトを生成した OIDC 識別子と紐付けられ、信頼できる公開機能と組み合わせることで、PyPI は特定の CI ワークフロー内で特定のコミットからパッケージがビルドされたことを記録し、アーティファクトとソースコードを暗号学的に結びつける署名を付与できます。
RubyGems 3.6.7 では、デフォルトで SOURCE_DATE_EPOCH(ビルド日時の統一環境変数)を設定することで、gem のビルドプロセスの再現性を向上させました。
npm レジストリは、ソースとの関連性もビルドの出自証明もない任意の tarball を受け入れており、パッケージを独立して再構築して公開されたものと比較する方法がありません。package-lock.json(依存関係の固定ファイル)
Homebrew は、GitHub Actions でビルドされ、GitHub リリースアーティファクトとしてホストされている「bottles」と呼ばれる事前ビルド済みバイナリを配布しています。このプロジェクトには、formula 作者が利用可能なメカニズムを文書化した再現可能ビルドのページがあり、SOURCE_DATE_EPOCH(ビルド日時の統一環境変数)や @@HOMEBREW_PREFIX@@(Homebrew のインストール先パス)、Utils::Gzip.compress(gzip 圧縮ユーティリティ関数)などが紹介されています。
2024 年 5 月の Homebrew 4.3.0 以降、すべてのボトルには Sigstore に基づくアテステーションが付帯しており、それを構築した特定の GitHub Actions ワークフローとリンクされています。これは SLSA Build Level 2 の要件を満たすものです。ユーザーは HOMEBREW_VERIFY_ATTESTATIONS=1 を設定することで、アテステーションを検証できます。
信頼できる公開(Trusted publishing)
従来、メンテナは API トークンで認証し、ローカルマシンでビルドしてアップロードしていました。信頼できる公開ではこれを CI からの OIDC トークンに置き換え、レジストリがパッケージを単に適切な権限を持つ誰かがアップロードしたのではなく、特定のレポジトリ内の特定の GitHub Actions ワークフローによって構築されたものであることを確認できるようにします。
PyPI は 2023 年 4 月に信頼できる公開を開始しました。これは Trail of Bits によって構築され、Google のオープンソースセキュリティチーム(Open Source Security Team)の資金提供を受けています。RubyGems.org は 2023 年 12 月に追随し、npm は 2023 年に Sigstore を介してプロベナンスアテステーション(provenance attestations)を、そして 2025 年 7 月に完全な信頼できる公開を実装しました。crates.io も 2025 年 7 月に開始され、NuGet は 2025 年 9 月に追随しています。現在、PyPI のアップロードの 25% 以上でこの仕組みが利用されています。
プロベナンスにより、パッケージが特定のコミット abc123(github.com/foo/bar)から構築されたことが判明すれば、
Google の OSS Rebuild
OSS Rebuild は、Google のオープンソースセキュリティチームによって 2025 年 7 月に発表されました。これは、ほとんどのビルドがまだビット単位で再現可能ではないという事実に実用的なアプローチを採用しています。具体的には、パッケージをソースから再構築し、タイムスタンプやファイル順序といった既知の不安定要素を正規化した上で、意味のあるコンテンツが一致するかどうかを検証します。
開始当初、この取り組みは PyPI、npm、crates.io にわたる数千のパッケージをカバーしており、公開されたメタデータからビルド定義を推論するための自動化とヒューリスティックを使用し、コンテナ内で再構築を行い、Sigstore を介して署名された SLSA Level 3 のプロベナンス証明(provenance attestations)を公開していました。安定化
Matthew Suozzo 氏の FOSDEM 2026 での講演は、純粋な再現可能性を超えてビルドの可観測性へと踏み込み、隠れたリモート依存関係を検出するためのネットワークプロキシと、ビルドが実際に実行時に何を行っているかを回答するための eBPF ベースのビルドトレーシングを追加しました。これは、出力が決定論的であるかどうかに関わらず、独立して有用な情報です。
現状
言語パッケージマネージャーは、Debian がビルドインフラストラクチャを制御しその環境への変更を義務付けられる一方で、言語レジストリはどこからのアップロードも受け入れ、歴史的にアーティファクトがどのように生成されたかを知る手段を持っていなかったため、Linux ディストリビューションに比べて再現可能なビルドにおいて数年分の遅れがあります。信頼できる公開(Trusted publishing)は、レジストリがプロセスを把握できるようになるよう、ビルドをローカルマシンから CI 環境へ移行させることでこの状況を転換しています。これにビルドのプロベナンスと SLSA 証明を組みわせることで、ビルドツール自体が追いついていない場合でも、独立した検証が可能となる条件が整います。Go はコンパイラを決定論的にすることでその地位を確立しましたが、これは最もクリーンな解決策である一方で、最初からツールチェーン全体を制御する必要があります。
原文を表示
You download a package from a registry and the registry says it was built from a particular git commit, but the tarball or wheel or crate you received is an opaque artifact that someone built on their machine and uploaded. Reproducible builds let you check by rebuilding from source yourself and comparing, and if you get the same bytes, the artifact is what it claims to be. Making this work requires controlling both the build environment and the provenance of artifacts, and most language package managers historically controlled neither.
The Reproducible Builds project has been working on this since 2013, when Lunar (Jérémy Bobbio) organized a session at DebConf13 and began patching Debian’s build tooling. The Snowden disclosures had made software trust an urgent concern, Bitcoin’s Gitian builder had shown the approach was viable for a single project, and the Tor Project had begun producing deterministic builds of Tor Browser. Lunar wanted to apply the same thinking to an entire operating system.
The first mass rebuild of Debian packages in September 2013 found that 24% were reproducible, and by January 2014, after fixing the lowest-hanging fruit in dpkg and common build helpers, that jumped to 67%. Today Debian’s testing infrastructure shows around 96% of packages in trixie building reproducibly under controlled conditions, while reproduce.debian.net runs a stricter test by rebuilding the actual binaries that ftp.debian.org distributes rather than clean-room test builds.
The project grew into a cross-distribution effort as Arch Linux, NixOS, GNU Guix, FreeBSD, and others joined over the following years. Summits have been held most years since 2015, most recently in Vienna in October 2025. Chris Lamb, who served as Debian Project Leader from 2017 to 2019, co-authored an IEEE Software paper on the project that won Best Paper for 2022. Lunar passed away in November 2024. The project’s weekly reports, published continuously since 2015, give a sense of the scale of work involved: each one lists patches sent to individual upstream packages fixing timestamps, file ordering, path embedding, locale sensitivity, one package at a time, hundreds of packages a year. Getting from 24% to 96% was not a single architectural fix but a decade of this kind of janitorial patching across the entire Debian archive.
How verification works
You build the same source twice in different environments and compare the output, and if the bytes match, nobody tampered with the artifact between source and distribution. In practice this requires recording everything about the build environment, which Debian does with .buildinfo
When hashes don’t match, diffoscope is how you find out why. Originally written by Lunar as debbindiff
The project also maintains strip-nondeterminism
What makes builds non-reproducible
Benedetti et al. tested 4,000 packages from each of six ecosystems using reprotest
The dominant cause across all three failing ecosystems was timestamps embedded in the package archive, responsible for 97.1% of RubyGems failures, 92.4% of Maven failures, and 87.7% of PyPI failures. The standard fix is SOURCE_DATE_EPOCH
Most of this turned out to be fixable with infrastructure changes rather than per-package work. Simply configuring SOURCE_DATE_EPOCH
os.path.expanduser
File ordering causes similar problems because readdir()
/home/alice/project
/home/bob/project
Since Go 1.21 in August 2023, the toolchain produces bit-for-bit identical output regardless of the host OS, architecture, or build time, after Russ Cox’s team eliminated ten distinct sources of nondeterminism including map iteration order, embedded source paths, file metadata in archives, and ARM floating-point mode defaults.
Go runs nightly verification at go.dev/rebuild using gorebuild
Maven’s official guide documents the steps: set project.build.outputTimestamp
mvn clean verify artifact:compare
The timestamp only works if every plugin in the chain respects it, though, and many third-party plugins don’t. Different JDK versions produce different bytecode, ZIP entry ordering varies by implementation, and Maven builds are assembled from dozens of plugins that each introduce their own potential nondeterminism. Researchers built Chains-Rebuild to canonicalize six root causes of Java build unreproducibility, which gives a sense of how many separate things can go wrong in a single build system.
Rust’s RFC 3127 introduced trim-paths
/home/alice/.cargo/registry/src/crates.io-abc123/serde-1.0.200/src/lib.rs
serde-1.0.200/src/lib.rs
Procedural macros and build scripts (build.rs
The Benedetti et al. study found only 12.2% of PyPI packages reproducible out of the box, and the split came down to build backend: packages using flit
PyPI has also moved further than most registries on attestations through PEP 740, shipped in October 2024, which adds support for Sigstore-signed digital attestations uploaded alongside packages. These link each artifact to the OIDC identity that produced it, so combined with trusted publishing, PyPI can record that a package was built in a specific CI workflow from a specific commit with a cryptographic signature binding artifact to source.
RubyGems 3.6.7 made the gem building process more reproducible by default, setting a default SOURCE_DATE_EPOCH
The npm registry accepts arbitrary tarballs with no connection to source, no build provenance, and no way to independently rebuild a package and compare it against what’s published. package-lock.json
Homebrew distributes prebuilt binaries called bottles, built on GitHub Actions and hosted as GitHub release artifacts. The project has a reproducible builds page documenting the mechanisms available to formula authors: SOURCE_DATE_EPOCH
@@HOMEBREW_PREFIX@@
Utils::Gzip.compress
Since Homebrew 4.3.0 in May 2024, every bottle comes with a Sigstore-backed attestation linking it to the specific GitHub Actions workflow that built it, meeting SLSA Build Level 2 requirements. Users can verify attestations by setting HOMEBREW_VERIFY_ATTESTATIONS=1
Trusted publishing
Traditionally a maintainer authenticates with an API token, builds on their laptop, and uploads. Trusted publishing replaces that with OIDC tokens from CI so that the registry knows the package was built by a specific GitHub Actions workflow in a specific repository, not just uploaded by someone who had the right credentials.
PyPI launched trusted publishing in April 2023, built by Trail of Bits and funded by Google’s Open Source Security Team. RubyGems.org followed in December 2023, npm shipped provenance attestations via Sigstore in 2023 and full trusted publishing in July 2025, crates.io launched in July 2025, and NuGet followed in September 2025. Over 25% of PyPI uploads now use it.
Once provenance tells you that a package was built from commit abc123
github.com/foo/bar
Google’s OSS Rebuild
OSS Rebuild, announced by Google’s Open Source Security Team in July 2025, takes a pragmatic approach to the fact that most builds aren’t bit-for-bit reproducible yet by rebuilding packages from source and performing semantic comparison, normalizing known instabilities like timestamps and file ordering before checking whether the meaningful content matches.
At launch it covered thousands of packages across PyPI, npm, and crates.io, using automation and heuristics to infer build definitions from published metadata, rebuilding in containers, and publishing SLSA Level 3 provenance attestations signed via Sigstore. The stabilize
Matthew Suozzo’s FOSDEM 2026 talk pushed beyond pure reproducibility into build observability, adding a network proxy for detecting hidden remote dependencies and eBPF-based build tracing to answer not just whether a build can be reproduced but what the build is actually doing at runtime, which is useful independently of whether the output happens to be deterministic.
Where things stand
Language package managers are years behind Linux distributions on reproducible builds because Debian controls its build infrastructure and can mandate changes to that environment, while language registries accept uploads from anywhere and historically had no way to know how an artifact was produced. Trusted publishing is shifting that by moving builds from laptops into CI where the registry has visibility into the process, and combined with build provenance and SLSA attestations, this creates conditions where independent verification becomes possible even when the build tooling itself hasn’t caught up. Go got there by making the compiler deterministic, which is the cleanest solution but requires controlling the entire toolchain from the start.
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み