121 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | |
| title: "Lets Learn Nix: Reproducibility"
 | |
| date: 2020-03-17T12:06:47Z
 | |
| draft: true
 | |
| ---
 | |
| 
 | |
| I am dedicating this page to defining and disambiguating some terminology. I
 | |
| think it is important to use these terms precisely, so it may be worthwhile to
 | |
| memorize these definitions and ensure that you are clarifying the discourse
 | |
| rather than muddying it.
 | |
| 
 | |
| ## Terms
 | |
| 
 | |
| - repeatable build:
 | |
| - reproducible build:
 | |
| - deterministic build:
 | |
| - pure function:
 | |
| - impure function:
 | |
| - idempotent function:
 | |
| 
 | |
| TODO(wpcarro): Consistently and deliberately use reproducible and
 | |
| deterministic.
 | |
| 
 | |
| ## Repeatable vs. Reproducible
 | |
| 
 | |
| Is NixOS reproducible? Visit [@grhmc][who-grhmc]'s website,
 | |
| [r13y.com](https://r13y.com), to find out.
 | |
| 
 | |
| At the time of this writing, 1519 of 1568 (i.e. 96.9%) of the paths in the
 | |
| `nixos.iso_minimal.x86_64-linux` installation image are reproducible.
 | |
| 
 | |
| ## What hinders reproducibility?
 | |
| 
 | |
| Timestamps.
 | |
| 
 | |
| If package A encodes a timestamp into its build artifact, then we can
 | |
| demonstrate that package A is *not reproducible* simply by building it at two
 | |
| different times and doing a byte-for-byte comparison of the build artifacts.
 | |
| 
 | |
| ## Does Nix protect developers against non-determinism
 | |
| 
 | |
| Yes. But not entirely. How?
 | |
| 
 | |
| ## Deterministic Nix derivation
 | |
| 
 | |
| ```nix
 | |
| { pkgs ? import <nixpkgs> {}, ... }:
 | |
| 
 | |
| with pkgs;
 | |
| 
 | |
| stdenv.mkDerivation {
 | |
|   name = "reproducible";
 | |
|   phases = [ "buildPhase" ];
 | |
|   buildPhase = "echo reproducible >$out";
 | |
| }
 | |
| ```
 | |
| 
 | |
| ## Non-deterministic Nix derivation
 | |
| 
 | |
| We can introduce some non-determinism into our build using the `date` function.
 | |
| 
 | |
| ```nix
 | |
| # file: /tmp/test.nix
 | |
| { pkgs ? import <nixpkgs> {}, ... }:
 | |
| 
 | |
| with pkgs;
 | |
| 
 | |
| stdenv.mkDerivation {
 | |
|   name = "non-reproducible";
 | |
|   phases = [ "buildPhase" ];
 | |
|   buildPhase = "date >$out";
 | |
| }
 | |
| ```
 | |
| 
 | |
| Then run...
 | |
| 
 | |
| ```shell
 | |
| $ nix-build /tmp/test.nix
 | |
| $ nix-build /tmp/test.nix --check --keep-failed
 | |
| ```
 | |
| 
 | |
| ## How do you test reproducibility?
 | |
| 
 | |
| We can use `cmp` to compare files byte-for-byte. The following comparison should
 | |
| fail:
 | |
| 
 | |
| ```shell
 | |
| $ echo foo >/tmp/a
 | |
| $ echo bar >/tmp/b
 | |
| $ cmp --silent /tmp/{a,b}
 | |
| $ echo $?
 | |
| ```
 | |
| 
 | |
| And the following comparison should succeed:
 | |
| 
 | |
| ```shell
 | |
| $ echo hello >/tmp/a
 | |
| $ echo hello >/tmp/b
 | |
| $ cmp --silent /tmp/{a,b}
 | |
| $ echo $?
 | |
| ```
 | |
| 
 | |
| ## Reproducible vs. deterministic
 | |
| 
 | |
| Reproducible builds *are* deterministic builds and deterministic build
 | |
| 
 | |
| ## Deterministic, Reproducible, Pure, Idempotent, oh my
 | |
| 
 | |
| - A pure function has no side-effects.
 | |
| 
 | |
| - An idempotent function can be executed more than once with the same arguments
 | |
|   without altering the side-effects.
 | |
| 
 | |
| - A deterministic function ensures that
 | |
| 
 | |
| ## Deterministic vs. Reproducible
 | |
| 
 | |
| I can check if a build is reproducible using [these tools][wtf-repro-tools].
 | |
| 
 | |
| [wtf-repro-tools]: https://reproducible-builds.org/tools/
 | |
| [who-grhmc]: https://twitter.com/grhmc
 |