4 ms·
Reproducible builds are adjacent, but ultimately orthogonal, to what Nix does. Reproducible builds provide strong evidence that a given set of inputs were used
by jchw 1y ago
Reproducible builds are adjacent, but ultimately orthogonal, to what Nix does.
Reproducible builds provide strong evidence that a given set of inputs were used to produce a specific output. A lot of the work to be done here by each of these individual projects is beneficial to the entire ecosystem, including Nix. A lot of it is just fixing bugs and removing accidental non-determinism from builds. The main value this provides is that it allows a third-party to verify with relatively good certainty that binaries provided by some entity match the expected source code.
Nix provides a hermetic environment to build software with every single input from the bootstrap seed to the final build fully accounted for. Builds can't access the Internet or the host filesystem, they can only access files from their inputs. Impurities must go through the FODs, and the outputs from FODs have to match a prerecorded cryptographic hash, so they must be fully bit-reproducible or the build fails. When you have a reproducible Nix derivation, it is a strict superset of a reproducible package virtually everywhere else, because you can have a very high assurance that you can know and can audit individually every input to the derivation. This is useful for both auditing and reproducible builds.
Reproducible builds are important, but reproducible builds alone are not a panacea. They obviously don't tell you if your source code is free of defects, accidental or otherwise, and neither does Nix. Still, Nix does something basically nothing else does, by making the entire build process fully hermetic.
(Guix, being inspired by Nix, is, as far as I know, roughly the same, although Guix has put more effort into the bootstrap and package reproducibility. Still, Guix and Nix stand in a class of their own as far as usefulness to supply chain security go, even if they probably won't fit neatly into the compliance theater version of supply chain security.)
- transpute 1y agoThanks for the detailed explanation. Yocto has offline builds, but is missing host filesystem isolation. Are you familiar with StageX, https://codeberg.org/stagex/stagex/#comparison https://codeberg.org/stagex/stagex/#comparison? There's a comparison chart on that page which claims that Nix(OS?) is not fully reproducible. It would be useful to know which subset, if any, is not reproducible.
- jchw 1y agoIt is correct that NixOS is not fully reproducible. Regarding Nix vs NixOS vs Nixpkgs: - Nix is the name of the programming language (that Nix derivations are written in) and the package manager/build tool. (Though at times the term 'Nix' is just used to refer to the broader ecosystem including NixOS and Nixpkgs.) - NixOS is an operating system that is built on top of Nix derivations. - Nixpkgs is a giant repository of Nix derivations, including NixOS (NixOS and Nixpkgs used to be separate, but they were merged together in history.) The reason why NixOS+Nixpkgs are not fully reproducible, despite all of the guarantees Nix gives you, is simply because there are derivations with non-determinism during the build process. An example of how this might play out is that you could wind up with the order in which operations complete in a parallel build process somehow getting encoded into the final package. Unfortunately, I don't think there's funding or a ton of interest going into improving the reproducibility of NixOS at the moment, so progress towards squashing reproducibility issues has been slow for a while. You can see relatively up-to-date progress on getting the install media fully reproducible here: https://reproducible.nixos.org/nixos-iso-minimal-runtime/ https://reproducible.nixos.org/nixos-iso-minimal-runtime/ StageX also correctly points out that the Nix bootstrap is inferior to some of the more extreme reproducibility projects. The Nix bootstrap is fairly large, unfortunately. The Guix team has put a substantial amount of effort into minimizing the bootstrap seed and reproducibility of packages. The Nixpkgs bootstrap seed (for my machine, anyway) is currently 27 MiB. The GuixSD bootstrap seed is, I believe, 357 bytes, which is a stunning accomplishment. StageX considers NixOS trust to be centralized and GuixSD trust to be distributed; this is likely because of the Hydra binary cache which Nix is typically configured to trust by default. You can turn off the Hydra cache to remove this centralized entity, at the cost of obviously needing to build almost everything from scratch. I'm not sure what "distributed" trust actually means here, versus "decentralized". StageX uses OCI image building as a base. It also doesn't seem to talk about sandboxing anywhere, so it is presumed that StageX is using Dockerfile OCI builds as their only sandboxing, which still allows Internet access. Having Internet access during builds is convenient, but it makes it pretty hard to guarantee that all inputs are accounted for. Their Rust example is pretty interesting: > RUN ["cargo", "add", "regex"] There's nothing inherently wrong about this, but despite all of the effort to make the base StageX OCI images reproducible, if you were to build this exact same OCI image months apart, you would presumably be liable to get different results here: you could, for example, get an entirely different version of the regex crate. With Nix, if you make a derivation to build a Rust package, you have to account for the Cargo dependencies in the build, as Nix builds aren't allowed to access the Internet, with the exception of fixed-output derivations. While this doesn't result in Nix derivations being bit-for-bit reproducible, it does ensure that every (external) input is bit-for-bit identical across builds to the same exact derivation, something you can't really easily achieve without a custom build tool like Nix or Guix. If it were possible to sneak an impurity into a Nix build, it is likely a CVE. (There are some exceptions on macOS due to limitations in Darwin sandboxing, but on Linux I believe this holds true. None of the exceptions would make it possible to easily accidentally introduce impurities on macOS, though; you'd pretty much need to do it on purpose.) Even that aside, StageX uses the same impressive 357 byte bootstrap seed as GuixSD, so it is pretty cool for what it does. It's just a bit lower in scope than Nixpkgs and GuixSD. Nixpkgs is probably the largest single software repository ever built with over 100,000 packages, all of which having to follow this schema of hermetic builds.
- pveierland 1y agoThis usage of `orthogonal` feels misleading. Nix is built to be a purely functional software distribution model where the outputs can be computed from the specified set of inputs. Although it is possible for derivations to not be reproducible, it seems incorrect to say that Nix is orthogonal to reproducible builds, as the point of the functional model is to nominally be able to get the same outputs given a set of inputs. Sure, Nix doesn't guarantee reproducibility of builds, but it certainly is designed to facilitate them (i.e. clearly correlated with reproducible builds and not being orthogonal to them).
- jchw 1y agoReproducible builds really are orthogonal to Nix, even if it seems like they're not. Nix was not built with reproducible builds in mind, and the problems it solves are ultimately independent even though they are related in some ways. The Nix PhD thesis by Eelco Dolstra, the founder of Nix, lays out the motivations for Nix very plainly. I decided I'd probably be better off quoting it directly than summarizing it poorly, so here goes: From The Purely Functional Software Deployment Model, "1.3. Motivation"[1]: From the previous discussion of existing deployment systems it should be clear that they lack important features to support safe and efficient deployment. In particular, they have some or all of the following problems: • Dependency specifications are not validated, leading to incomplete deployment. • Dependency specifications are inexact (e.g., nominal). • It is not possible to deploy multiple versions or variants of a component side-by-side. • Components can interfere with each other. • It is not possible to roll back to previous configurations. • Upgrade actions are not atomic. • Applications must be monolithic, i.e., they must statically contain all their depen- dencies. • Deployment actions can only be performed by administrators, not by unprivileged users. • There is no link between binaries and the sources and build processes that built them. • The system supports either source deployment or binary deployment, but not both; or it supports both but in a non-unified way. • It is difficult to adapt components. • Component composition is manual. • The component framework is narrowly restricted to components written in a specific programming language or framework. • The system depends on non-portable techniques. The objective of the research described in this thesis is to develop a deployment system that does not have these problems. Of course, part of the reason why reproducible builds was not considered for this is probably because it was simply not a hot topic at the time (had the term 'reproducible builds' even been coined yet?) and there were much bigger fish to fry with package management than reproducibility at that time, considering how relatively poorly packages were specified. Since then, "traditional" package managers and package repositories have put substantial work into cleaning up their package manifests and ensuring that they have accurate dependencies and other specifications such that today highly reproducible systems can be and have been built on top of them, limitations from the lack of hermetic guarantees notwithstanding. Despite this, because Nix does guarantee bit-exact external inputs to a derivation, it does indeed make an excellent starting point for reproducible builds, but Nix itself as a tool is definitely orthogonal to reproducible builds, as it solves an entirely different problem that just happens to be related. You don't need the purity guarantees Nix gives you to get reproducible builds, and having those purity guarantees don't automatically give you reproducible builds (though as seen by Nixpkgs, it isn't uncommon for a build to coincidentally be reproducible just as a result of packaging it into a Nix derivation... just, not really specifically guaranteed by anything.) [1]: https://edolstra.github.io/pubs/phd-thesis.pdf https://edolstra.github.io/pubs/phd-thesis.pdf