Guaranteeing software is reproducible and secure is vital for:
Reproducibility can be defined as:
Security can be defined as:
Nix helps us guarantee that our software is both reproducible and secure.
Stemming from the concept that FHS
are fundamentally not reproducible. Paths such as
/bin/python
provide little-known information about the
software that is being run:
One solution commonly used is to use tools such as Docker or Snap etc… that create isolated FHS environments containing a specific version along with its dependencies. However, there is no guarantee you will get an expected build artefacts from build instructions, as putting all the build artefacts in an isolated container only guarantees consistency, never reproducibility, as during the build-phase, tools from host’s FHS are often used, file fetches are made and the dependencies that come from other isolated environments can not be guaranteed to be the same. For example, two machines using the same container image will always get the same results, but two machines building the same container using a Dockerfile can never guarantee the same results.
Nix first computes its derivation (this is usually done by evaluating expressions written in Nix language) for every package before building. This includes:
/nix/store/<hash>-<package-name>-<version>
For example, here are the outputs of the GNU Hello package (some fields have been omitted for brevity):
{
"/nix/store/sg3sw1zdddfkl3hk639asml56xsxw8pf-hello-2.10.drv": {
"outputs": {
"out": {
"path": "/nix/store/dvv4irwgdm8lpbhdkqghvmjmjknrikh4-hello-2.10"
}
},
"inputSrcs": ["/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],
"inputDrvs": {
"/nix/store/8pq31sp946581sbh2m18pb8iwp0bwxj6-stdenv-linux.drv": ["out"],
"/nix/store/cni8m2cjshnc8fbanwrxagan6f8lxjf6-hello-2.10.tar.gz.drv": ["out"],
"/nix/store/md39vwk6mmi64f6z6z9cnnjksvv6xkf3-bash-4.4-p23.drv": ["out"]
},
"platform": "x86_64-linux",
"builder": "/nix/store/kgp3vq8l9yb8mzghbw83kyr3f26yqvsz-bash-4.4-p23/bin/bash",
"args": ["-e", "/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],
"env": {
"buildInputs": "",
"builder": "/nix/store/kgp3vq8l9yb8mzghbw83kyr3f26yqvsz-bash-4.4-p23/bin/bash",
"doCheck": "1",
"name": "hello-2.10",
"nativeBuildInputs": "",
"out": "/nix/store/dvv4irwgdm8lpbhdkqghvmjmjknrikh4-hello-2.10",
"outputs": "out",
"pname": "hello",
"src": "/nix/store/3x7dwzq014bblazs7kq20p9hyzz0qh8g-hello-2.10.tar.gz",
"stdenv": "/nix/store/hn7xq448b49d40zq0xs6lq538qvldls1-stdenv-linux",
"system": "x86_64-linux",
"version": "2.10"
}
}
}
Nix then releaises the derivation by running the build instructions specified in an isolated environment. Packages built with Nix can guarantee that the same inputs will always produce the same outputs (outputs can still different if build instructions make use of hardware-dependent information such as current time etc…).
This provides the following benefits: