lockfileで依存を固定してもreproducible buildにはならない
lockfileは再現性に重要だが、lockfileがあることとreproducible buildであることは同義ではない。
Pixiの--frozenはlockfileに定義されたenvironmentをinstallし、--lockedはmanifestとlockfileが一致していなければ中断する。これは「dependency resolutionの結果を固定する」仕組みであり、同じpackage version/buildを再選択する助けになる。
しかしReproducible Builds projectの定義では、reproducible buildとは、同じsource code・build environment・build instructionsから、誰でもbit-for-bit同一のartifactを再生成できることである。dependency versionを固定することは、その条件の一部にすぎない。
Nixのstore pathは通常content-addressedではない でも同じ区別が必要になる。Nixのinput-addressed derivationはbuild-time dependency graphをaddressへ反映するが、それだけで実際のoutput bytesがdeterministicになるわけではない。
典型的な非決定性には次がある。
- build時刻をbinary/archiveへ埋め込む
- filesystemから列挙したfileの順序が毎回異なる
- localeやtimezoneでsorting・生成結果が変わる
- random seedやgenerated identifierが毎回変わる
- build directoryのabsolute pathがdebug info等へ埋め込まれる
- parallel buildの実行順でoutputが変わる
Reproducible Builds projectは、timestampを最大の再現性問題の一つとして挙げ、SOURCE_DATE_EPOCHによってbuild時の「現在時刻」をsourceに由来する固定値へ置き換える方法を標準化している。またfile orderingやrandomnessも独立した問題として扱っている。
したがって「再現性」には少なくとも三段階ある。
- resolution reproducibility — 同じdependency/version集合を選ぶ
- environment reproducibility — compiler、system dependency、environment variable等も同じ条件にする
- artifact reproducibility — 最終的なbytesまでbit-for-bit一致する
lockfileが直接保証するのは主として1であり、package formatやsolverによっては2の一部まで記録できる。3にはbuild process自体のdeterminismが必要になる。
この区別はbinary cacheのtrustにも関係する。binary cacheの公開鍵を追加することはbuilderを信頼することに近い のcacheから取得したartifactが本当にsourceから再生成できるかを第三者が確認したい場合、単に同じderivationやlockfileを持っているだけでは足りず、独立rebuildで同じbytesを得られる必要がある。
一方、checksum・signature・provenanceは別の保証をする のprovenanceは「どう作られたか」を記録するが、それ自体もreproducibilityではない。SLSA Build Provenanceはrebuildに必要な情報を提供し得るが、同じinputsから必ず同一bytesが生成されることを要求する概念とは分けて考えるべきである。
package managerの比較では、「lockfileあり」「hermetic build」「content addressed」「reproducible build」を一つの再現性スコアにまとめず、どの段階を保証しているのかを確認する必要がある。