diff options
Diffstat (limited to 'doc/manual/src/advanced-topics/diff-hook.md')
-rw-r--r-- | doc/manual/src/advanced-topics/diff-hook.md | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/doc/manual/src/advanced-topics/diff-hook.md b/doc/manual/src/advanced-topics/diff-hook.md new file mode 100644 index 000000000..2c9896fa5 --- /dev/null +++ b/doc/manual/src/advanced-topics/diff-hook.md @@ -0,0 +1,141 @@ +# Verifying Build Reproducibility + +Specify a program with Nix's [???](#conf-diff-hook) to compare build +results when two builds produce different results. Note: this hook is +only executed if the results are not the same, this hook is not used for +determining if the results are the same. + +For purposes of demonstration, we'll use the following Nix file, +`deterministic.nix` for testing: + + let + inherit (import <nixpkgs> {}) runCommand; + in { + stable = runCommand "stable" {} '' + touch $out + ''; + + unstable = runCommand "unstable" {} '' + echo $RANDOM > $out + ''; + } + +Additionally, `nix.conf` contains: + + diff-hook = /etc/nix/my-diff-hook + run-diff-hook = true + +where `/etc/nix/my-diff-hook` is an executable file containing: + + #!/bin/sh + exec >&2 + echo "For derivation $3:" + /run/current-system/sw/bin/diff -r "$1" "$2" + +The diff hook is executed by the same user and group who ran the build. +However, the diff hook does not have write access to the store path just +built. + +# Spot-Checking Build Determinism + +Verify a path which already exists in the Nix store by passing `--check` +to the build command. + +If the build passes and is deterministic, Nix will exit with a status +code of 0: + + $ nix-build ./deterministic.nix -A stable + this derivation will be built: + /nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv + building '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'... + /nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable + + $ nix-build ./deterministic.nix -A stable --check + checking outputs of '/nix/store/z98fasz2jqy9gs0xbvdj939p27jwda38-stable.drv'... + /nix/store/yyxlzw3vqaas7wfp04g0b1xg51f2czgq-stable + +If the build is not deterministic, Nix will exit with a status code of +1: + + $ nix-build ./deterministic.nix -A unstable + this derivation will be built: + /nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv + building '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'... + /nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable + + $ nix-build ./deterministic.nix -A unstable --check + checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'... + error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs + +In the Nix daemon's log, we will now see: + + For derivation /nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv: + 1c1 + < 8108 + --- + > 30204 + +Using `--check` with `--keep-failed` will cause Nix to keep the second +build's output in a special, `.check` path: + + $ nix-build ./deterministic.nix -A unstable --check --keep-failed + checking outputs of '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv'... + note: keeping build directory '/tmp/nix-build-unstable.drv-0' + error: derivation '/nix/store/cgl13lbj1w368r5z8gywipl1ifli7dhk-unstable.drv' may not be deterministic: output '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable' differs from '/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable.check' + +In particular, notice the +`/nix/store/krpqk0l9ib0ibi1d2w52z293zw455cap-unstable.check` output. Nix +has copied the build results to that directory where you can examine it. + +> **Note** +> +> Check paths are not protected against garbage collection, and this +> path will be deleted on the next garbage collection. +> +> The path is guaranteed to be alive for the duration of +> [???](#conf-diff-hook)'s execution, but may be deleted any time after. +> +> If the comparison is performed as part of automated tooling, please +> use the diff-hook or author your tooling to handle the case where the +> build was not deterministic and also a check path does not exist. + +`--check` is only usable if the derivation has been built on the system +already. If the derivation has not been built Nix will fail with the +error: + + error: some outputs of '/nix/store/hzi1h60z2qf0nb85iwnpvrai3j2w7rr6-unstable.drv' are not valid, so checking is not possible + +Run the build without `--check`, and then try with `--check` again. + +# Automatic and Optionally Enforced Determinism Verification + +Automatically verify every build at build time by executing the build +multiple times. + +Setting [???](#conf-repeat) and [???](#conf-enforce-determinism) in your +`nix.conf` permits the automated verification of every build Nix +performs. + +The following configuration will run each build three times, and will +require the build to be deterministic: + + enforce-determinism = true + repeat = 2 + +Setting [???](#conf-enforce-determinism) to false as in the following +configuration will run the build multiple times, execute the build hook, +but will allow the build to succeed even if it does not build +reproducibly: + + enforce-determinism = false + repeat = 1 + +An example output of this configuration: + + $ nix-build ./test.nix -A unstable + this derivation will be built: + /nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv + building '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' (round 1/2)... + building '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' (round 2/2)... + output '/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable' of '/nix/store/ch6llwpr2h8c3jmnf3f2ghkhx59aa97f-unstable.drv' differs from '/nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable.check' from previous round + /nix/store/6xg356v9gl03hpbbg8gws77n19qanh02-unstable |