Is NixOS truly reproducible?
luj.fr
luj.fr
I think people in this thread are focusing on the wrong thing. Sure, not all packages are reproducible, but the project is systematically increasing the percentage of projects that are reproducible while ALSO adding new projects and demonstrating conclusively that what was considered infeasible is actually readily achievable.
> The interesting aspect of these causes is that they show that even if nixpkgs already achieves great reproducibility rates, there still exists some low hanging fruits towards improving reproducibility that could be tackled by the Nix community and the whole FOSS ecosystem.
This work is helpful I think for the community to tackle the sources of unreproducible builds to push the percentage up even further. I think it also highlights the need for automation to validate that there aren't systematic regressions or regressions in particularly popular packages (doing individual regressions for all packages is a futile effort unless a lot of people volunteer to be part of a distributed check effort).
nix build nixpkgs#vim
nix build nixpkgs#vim --rebuild
The first invocation will substitute binaries, and the second will rebuild those locally and validate the bit for bit reproducibility of the results.In Debian there is significant ceremony and special tools/wrappers required to set up the reproducible environment, so no one would bother to use it unless they were specifically working on the https://wiki.debian.org/ReproducibleBuilds initiative.
https://tests.reproducible-builds.org/debian/reproducible.ht...
Nix on its own doesn't fully resolve supply chain concerns about binaries, but it can provide answers to a myriad of other problems. I think most people like Nix reproducibility, and it is marketed as such, for the sake of development: life is much easier when you know for sure you have the exact same version of each dependency, in the exact same configuration. A build on one machine may not be bit-exact to a build on another machine, but it will be exactly the same source code all the way down.
The quest to get every build process to be deterministic is definitely a bigger problem and it will never be solved for all of Nixpkgs. NixOS does have a reproducibility project[1], and some non-trivial amount of NixOS actually is properly reproducible, but the observation that Nixpkgs is too vast is definitely spot-on, especially because in most cases the real issues lie upstream. (and carrying patches for reproducibility is possible, but it adds even more maintainer burden.)
Not least because of unfree and/or binary-blob packages that can't be reproducible because they don't even build anything. As much as Guix' strict FOSS and build-from-source policy can be an annoyance, it is a necessary precondition to achieve full reproducibility from source, i.e. the full-source bootstrap.
In any case, it's all a bit imperfect anyway, since it's from the perspective of the package manager, which can't be absolutely sure there's no blobs. Anyone who follows Linux-libre releases can see how hard it really is to find all of those needles in the haystack. (And yeah, it would be fantastic if we could have machines with zero unfree code and no blobs, but the majority of computers sold today can't meaningfully operate like that.)
I actually believe there's plenty of value in the builds still being reproducible even when blobs are present: you can still verify that the supply chain is not compromised outside of the blobs. For practical reasons, most users will need to stick to limiting the amount of blobs rather than fully eliminating them.
[1]: https://nixos.org/manual/nixpkgs/stable/#sec-meta-license
[2]: https://nixos.org/manual/nixpkgs/stable/#sec-meta-sourceProv...
Then you'd have a 100% reproduceable OS if you have the flag set (assuming that required base packages are reproduceable)
How so? Bazel produces the same results for the same inputs.
The Nix sandbox does completely obscure the host filesystem and limit network access to processes that can produce a bit-exact output only.
(Bazel also obviously uses the system compilers and headers. Nix does not.)
Bazel allows hermetic toolchains, and uses it for most languages: Java, Python, Go, Rust, Node.js, etc. You can do the same for C++, but Bazel doesn't provide that out-of-the-box. [1]
Bazel sandboxing can restrict system access on Linux with --experimental_use_hermetic_linux_sandbox and --sandbox_add_mount_pair. [2]
Every "reproducible builds" discussion requires an understand of what is permitted to vary. E.g. Neither Nix nor Bazel attempts to make build products the same for x86 host environments vs ARM host environments. Bazel is less aggressive than Nix in that it does not (by default) attempt to make build products the same for different host C++ compilers.
[1] https://github.com/bazelbuild/bazel/discussions/18332
[2] https://bazel.build/reference/command-line-reference#flag--e...
Bazel absolutely prevents network access and filesystem access (reads) from builds. (only permitting explicit network includes from the WORKSPACE file, and access to files explicitly depended on in the BUILD files).
Maybe you can write some “rules_” for languages that violate this, but it is designed purposely to be hermetic and bit-perfect reproducible.
EDIT:
From the FAQ[0]:
> Will Bazel make my builds reproducible automatically?
> For Java and C++ binaries, yes, assuming you do not change the toolchain.
The issues with Docker's style of "reproducible" (meaning.. consistent environment; are also outlined in the same FAQ[1]
> Doesn’t Docker solve the reproducibility problems?
> Docker does not address reproducibility with regard to changes in the source code. Running Make with an imperfectly written Makefile inside a Docker container can still yield unpredictable results.
[0]: https://bazel.build/about/faq#will_bazel_make_my_builds_repr...
[1]: https://bazel.build/about/faq#doesn’t_docker_solve_the_repro...
Check out the previous discussion at https://news.ycombinator.com/item?id=23184843 and below:
> Under the hood there's a default auto-configured toolchain that finds whatever is installed locally in the system. Since it has no way of knowing what files an arbitrary "cc" might depend on, you lose hermeticity by using it.
https://bazel.build/docs/sandboxing
(Actually, it can: that documentation suggests it's optionally supported, at least on the Linux sandbox. That said, it's optional. There's definitely actions that use the network on purpose and can't participate in this.)
This may seem pointless, because in many situations this would only matter in somewhat convoluted cases. In C++ the toolchain probably won't connect to the network. This isn't the case for e.g. Rust, where proc macros can access the network. (In practical terms, I believe the sqlx crate does this, connecting to a local Postgres instance to do type inference.) Likewise, you could do an absolute file inclusion, but that would be very much on purpose and not an accident. So it's reasonable to say that you get a level of reproducibility when you use Bazel for C++ builds...
Kind of. It's not bit-for-bit because it uses the system toolchain, which is just an arbitrary choice. On Darwin it's even more annoying: with XCode installed via Mac App Store, the XCode version can change transparently under Bazel in the background, entirely breaking the hermeticity, and require you to purge the Bazel cache (because the dependency graph will be wrong and break the build. Usually.)
Nix is different. The toolchain is built by Nix and undergoes the same sandboxed build process with sandboxing and cryptographically verified inputs. Bazel does not do that.
There are mechanisms for opting out/breaking that, just as with Nix or any other system.
> macOS
What does nix do on these systems?
Ultimately, I still think that Nix provides a greater degree of isolation and reproducibility than Bazel overall, and especially out of the box, but I was definitely incorrect when I said that Bazel's sandbox doesn't/can't block the network. I did dive a little deeper into the nuances in another comment.[1]
> What does nix do on these systems?
On macOS, Nix is not exactly as solid as it is on Linux. It uses sandbox-exec for sandboxing, which achieves most of what the Nix sandbox does on Linux, except it disallows all networking rather than just isolated networking. (Some derivations need local network access, so you can opt-in to having local network access per-derivation. This still doesn't give Internet access, though: internet access still requires a fixed-output derivation.) There's definitely some room for improvement there but it will be hard to do too much better since xnu doesn't have anything similar to network namespaces afaik.
As for the toolchain, I'm not sure how the Nix bootstrap works on macOS. It seems like a lot of effort went in to making it work and it can function without XCode installed. (Can't find a source for this, but I was using it on a Mac Mini that I'm pretty sure didn't have XCode installed. So it clearly has its own hermetic toolchain setup just like Linux.)
Bazel enables sandboxing by default, including network isolation. [1] [2]
The exception would be in environments that don't support it (Windows, unprivileged Docker container, etc.)
(It's hard to figure out exactly what's going on based on the documentation and some crawling around, but I wouldn't be surprised if specifically tests defaulted to blocking the network.)
[1]: https://bazel.build/reference/command-line-reference#flag--s...
[2]: https://bazel.build/reference/be/common-definitions#common.t...
The very doc you link hints at that, while also giving many caveats where the build will become non-reproducible. So it boils down to “yes, but only if you configure it correctly and do things right”.
Meanwhile, if you want to forcibly block network access for a specific action, you can pass `block-network` as an execution requirement[2]. You can also explicitly block network access with flags, using --nosandbox_default_allow_network[3]. Interestingly though, an action can also `require-network` to bypass this, and I don't think there's any way to account for that.
Maybe more importantly, Bazel lacks the concept of a fixed-output action, so when an impure action needs `require-network` the potentially-impure results could impact downstream dependents of actions.
I was still ultimately incorrect to say that Bazel's sandbox can't sandbox the network. The actual reality is that it can. If you do enable the sandbox, while it's not exactly pervasive through the entire ecosystem, it does look like a fair number of projects at least set the `block-network` tag--about 700 as of writing this[4]. I think the broader point I was making (that Nix adheres to a stronger standard of "hermetic" than Bazel) is ultimately true, but I did miss on a bit of nuance initially.
[1]: https://bazel.build/docs/user-manual#spawn-strategy
[2]: https://bazel.build/reference/be/common-definitions#common.t...
[3]: https://bazel.build/reference/command-line-reference#flag--s...
[4]: https://github.com/search?q=language%3Abzl+%22block-network%...
Maybe Bazel forbid these things right away and Googlers actually talking about Blaze will be inadvertently lying thinking they are similar enough.
Bazel is really sophisticated and I'd be lying if I said I understood it well, but I have spent time looking at it.
It's an important constituent, but only complete OS-emulation with deterministic scheduling could (at a huge overhead) actually result in bit-by-bit reproducible artifacts with arbitrary build steps.
There are an endless source of impurities/randomness and most compilers haven't historically cared much about this.
That all said, in practice, many of the cases where Nixpkgs builds are not deterministic are actually fairly trivial. Despite not being a specific goal necessarily, compilers are more deterministic than not, and in practice the sources of non-determinism are fewer than you'd think. Case in point, I'm pretty sure the vast majority of Nixpkgs packages that are bit-for-bit reproducible just kind of are by accident, because nothing in the build is actually non-deterministic. Many of the cases of non-deterministic builds are fairly trivial, such as things just linking in different orders depending on scheduling.
Running everything under a deterministic VM would probably be too slow and/or cumbersome, so I think Nix is the best it's going to get.
Nonetheless, I agree that Nix does the optimum here, full-on emulation would be prohibitively expensive.
Perhaps it's an area worth researching.
Say, a compiler uses multiple threads and even if you assign some fixed amount of fuel to each thread, and mandate that after n instructions, thread-2 must follow for another n, how would that work with, say, a kernel interrupt? Would that be emulated completely only at given fixed times?
But I do like the idea of running multiple builds in parallel to not take as big of a hit from single-threaded builds, though it would only increase throughput not latency.
The point is that Nix will catch a lot more of them than Bazel does, since Nix manages the toolchain used to build, whereas Bazel just runs the host system cc.
This does actually exist; check out antithesis's product. I'm not sure how much is public information but their main service is a deterministic (...I'm not sure to what extent this is true, but that was the claim I heard) many-core vm on which otherwise difficult testing scenarios can be reproduced (clusters, databases, video games, maybe even kernels?) to observe bugs that only arise in extremely difficult to reproduce circumstances.
It does seem like overkill just to get a marginally more reproducible build system, though.
If you don’t know, the intensional model is an alternative way to structure the NixOS store so that components are content-addressable (store hash is based on the targets) as opposed to being addressed based on the build instructions and dependencies. IIUC, the entire purpose of the intensional model is to make Nix stores shareable so that you could just depend on Cachix and such without the worry of a supply-chain attack. This approach was an entire chapter in the Nix thesis paper (chapter 6) and has been worked on recently (see https://github.com/NixOS/rfcs/pull/62 and https://github.com/NixOS/rfcs/pull/17 for current progress).
The intensional store makes the store shareable without also sharing trust relationships ('kind of trustless' in that sense), but only because it moves trust relationships out of the store, not because it gets rid of them. You still need to trust signatures which map an hash of inputs to a hash of the output, just like in the extensional model. You can however get really powerful properties for supply chain security from the intensional store model (and a few extra things). You can read about that in this recent paper of mine: https://dl.acm.org/doi/10.1145/3689944.3696169. I'm still working on this stuff and trying to find ways to get that work funded (see https://groundry.org/).
The real win with content addressing in Nix is being able to proactively dedupe the store and also cut off rebuild cascades, like if you have dependency chain A -> B -> C, and A changes, but you can demonstrate that the result of B is identical, then there's no longer a need to also rebuild C. With input addressing, you have to rebuild everything downtree of A when it changes, no exceptions.
That's one way to read the statistic. Another way you could read the graph is that they still have about the same number (~5k) of non-reproducible builds, which has been pretty constant over the time period. Adding a bunch of easily reproducible additional builds maybe doesn't make me believe it's solving the original issues.
> We knew that it was possible to achieve very good reproducibility rate in smaller package sets like Debian, but this shows that achieving very high bitwise reproducibility is possible at scale, something that was believed impossible by practitioners.
Maybe I miss some nuance here, but why is Debian written off as being so much smaller scale? The top end of the graph here suggests a bit over 70k packages, Debian apparently also currently has 74k packages available (https://www.debian.org/doc/manuals/debian-reference/ch02.en....); I guess there's maybe a bit of time lag here but I'm not sure that is enough to claim Debian is somehow not "at scale".
It's a bit like asking what percentage of Nix-packaged programs have Hungarian translation -- if Nix packages some more stuff the rate might decrease, but it's not Nix's task to add that to the programs that lack it.
Nix does everything in its power to provide a sandboxed environment in which builds can happen. Given the way hardware works, there are still sources of non-determinism that are impossible to prevent, most importantly timing. Most programs depend on it, even compilers, and extra care should be taken by them to change that. The only way to prevent it would be to go full-on CPU and OS emulation, but that would be prohibitively expensive.
How so?
For ref I used a Gentoo distcc chroot inside a devuan VM to bootstrap gentoo on a 2009 netbook. It worked fine. I did this around Halloween.
There are infinite number of binaries that do the same thing (e.g. just padding random zeros in certain places wouldn't cause a functional problem).
Nix is very good at doing functionally reproducible builds, that's its whole thing. But there are build steps which are simply not deterministic, and they might produce correct, but not always the same outputs.
I know it seems like i don't know what i am talking about, often, on here. The reason is i don't live on HN so i type a comment and rarely remember the words i want to use before the edit/delete window closes.
The idea that i can't control when things occur during a compilation seems suspect. Is there a certain "code size" or other bellwether where this non-determinism starts to crop up? I ask because i get the feeling if i start compiling trivial stuff it will all be bit-perfect and if i say so i'll get lambasted for "well obviously trivial stuff can be reproducible," so i am heading that off at the pass, first.
That seems to be the crux of it.
For the record, even in the land of Guix I semi-regularly see reports on the bug-guix mailing list that some package isn't reproducible. It seems to get treated as a bug and fixed then. With that in mind, and personally considering Guix kind of the flagship of these efforts, it doesn't surprise me if anyone else doesn't have perfectly reproducible builds yet either. Especially Nix with the huge number of things in nixpkgs. It's probably easier for stuff to fall through the cracks with that many packages to manage.
I could be wrong (and I probably am) but I feel like the term "reproducible build" has shifted/solidified since 2006 when Dolstra's thesis was first written (which itself doesn't really use that term all that much). As evidence the first wikipedia page on "Reproducible builds" seems to have appeared in 2016, a decade after Dolstra's thesis, and even that stub from 2016 appears to prefer to use the term "Deterministic compilation".
Anyhow, when the Nix project originally spoke about "reproducible builds", what I understood was meant by that term was "being able to repeat the same build steps with the same inputs". Because of the lack of determinstic compilation, this doesn't always yield bit-by-bit identical outputs, but are simply presumed to be "functionally identical". There is, of course, no reason to believe that they will necessarily be functionally identical, but it is what developers take for granted every day, and if otherwise would be considered a bug somewhere in the package.
With Nix, when some software "doesn't work for me, but works for you", we can indeed recursively compare the nix derivation files locating and eliminating potential differences, a debugging process I have used on occasion.
I agree that "reproducible builds" now means something different, but that isn't exactly the fault of Nix advocates. I guess a new term for "being able to repeat the same build steps with the same inputs" is needed.
Yes, the only possible differences result from either a compiler bug or a program bug that depends on undefined behaviour, in which case "anything can happen" as they say. As others have noted, parallel compilation depends on non-deterministic thread-scheduling, so this non-determinism can't be solved unless you restrict all compilation to be single-threaded. It's still not the only possible source of non-determinism though.
I've usually seen "repeatable builds" used for that.
Honestly, I believe every software developer owes it to themselves to read the original Nix paper. It's quite digestible and lays out a lot of what it brings to the table. I came away from it wondering why it took so long to realize it... which is a property I've found true of every new important discovery.
https://edolstra.github.io/pubs/nspfssd-lisa2004-final.pdf
If you want, you can even ask an LLM to sum up its main points for you. Or to sell it to you. =)
https://chatgpt.com/share/67ae1a08-7354-8004-8200-e956cb6b59...
I would like to say one thing about using Docker to "solve" this problem though: Once you think of builds in terms of functions, you realize that a Docker image is basically just the cached artifacts of a build that "just so happened" to work correctly. Consider a function that only occasionally produces a correct value: A Docker image is one of those values.
In the final binaries created by compiled with gcc 2.6.3 and assembled with a custom assembler there appear to be unused, uninitialized data that is whatever was in RAM when whoever compiled the game created the release build.
Since the goal is a matching (reproducible) binary, we have tools to restore that random data at specific offsets. Fortunately our targets are fixed
As far as we know at this time, they’re just uninitialized bytes that would have been padding for alignment or other reasons anyway. Maybe if we move to an official build tool chain we’ll find they are deterministic, but for now, we believe they are garbage that happened to make it into the final binary.
0 - https://github.com/Xeeynamo/sotn-decomp/blob/master/tools/di...
1 - https://github.com/Xeeynamo/sotn-decomp/blob/master/config/d...
Every artifact is reproduced and signed by multiple maintainers on independently controlled hardware and this has been the case since our first release around this time last year.
I've seen it pointed out (by mjg59, perhaps?) that if you have a trusted builder, why don't you just use their build? That seems to be the actual model in practice.
Reproducibility seems only to be useful if you have a pool of mostly trustworthy builders and somehow want to build a consensus out of that. Which I suppose is useful for a distributed community but does seem like a stretch for the amount of work going in to reproducible builds.
maintainers build the packages, other people check: https://wiki.archlinux.org/title/Rebuilderd#Package_rebuilde...
Pardon my tinfoil hat, but doing this would make them a high-value target. If I like them enough to trust their builds, I probably also like them enough to avoid focusing the attentions of the bad guys on them.
Better would be to have a lot of trusted builders all comparing hashes... like, every NixOS user you know (and also the ones they know) so that there's nobody in particular to target.
If you bulld the directed graph made by the symlinks in the nix store, and walk it backwards, a sha256 of the source files is what you'll find, both in the form of a nix store path and possibly in a derivation that relies on a remote resource but provides a hash of that resource so we can know it's unchanged when downloaded later.
The missing piece is that they're not gossipped between users. So if I find some code in a dark alley somewhere and it has a nix flake to make building it easy, I've got no way to take the hashes and determine who else has experience with the same code and can help me decide if it's trustworthy.
Hmm that feels a bit too much like a root of trust, those make me uncomfortable. I'm more interested in tooling for gathering metadata re: the trustworthiness of some code without the author's participation. If the author wants to be involved, all the better.
The root of trust has to lay at the source code origin for a pure implementation of reproducible builds and for the security reasons I mentioned earlier.
In general it doesn't help much IMO to have distributions take a silo view of the problem. But those are just my ideas and thoughts on the matter.
Good point but even in the case of a larger monolithic systems you want to be sure it is possible to forensically analyze your source, to audit it. Once you can trust that one hash relates to this specific thing you can sign it, etc. This can then be "sold" with some added value of trust down the stream. Tracking of hashes also becomes easier once they are reproducible because they mean much more than just a "version".
That stuff is useful to humans, but it is also really useful for cold hard automated logical reasoning about dependency trees.
Not for NixOS as far as I can tell. You only have this for source derivations where a hash is (usually in a PR) submitted and must be reproducable in CI. This specific example however has the problem that linkrot can be hard to detect unless you regularly check upstream sources.
What you should be able to do in the future with a system like nix plus a few changes is use nix as a common underlying mechanism for precisely describing build steps, and then use whatever policy you like to determine who you trust.
One policy can be about having an attestation for every build step, another one can be about two different builders being in agreement about the output of a specific build step.
That way you can construct a policy that expresses reproducibility, and reproducibility strengthens any other verification mechanism you have, because it makes it so that you can aggregate evidence from different sources. and then have different build hosts
You can actually, changes to stdenv are possible and "just" a lot of work. You will regularly see them between releases or on unstable and they cause mass rebuilds. This doesn't just affect a compiler but also all stdenv tooling as these changes tend to cause rebuilds across nixpkgs. This would be verifiable but it obviously multiples the amount of compute spent.
Hint: If you look at PRs for nixpkgs you will notice labels indicating the required amounts of rebuilds, e. G., rebuild-darwin:1-10. See for example https://github.com/NixOS/nixpkgs/pull/377186 with the rebuild-darwin:5001+ label.
What works better is keep track of those hashes as part of the signatures, which is already happening. There's a lot of interesting things that can be done with that kind of information, I'm one of the people working on that kind of stuff.
Basically I have a paper out about how verifiable and reproducible can come together like that in Nix:
So if that process is reproducible, it's a different statement from a Debian package being reproducible, which requires build inputs in the preferred form of modification (source code).
Has anyone done any better?
It's not solving the underlying problem: that build systems are often impure and sometimes nondeterministic. It also tries to solve a bunch of adjacent problems, like providing a common interface for building many different types of package, providing a common configuration language for builds as well as system services and user applications in the case of NixOS and home-manager, and providing end-user CLI tools to manage the packages built with it. It's trying to be a build wrapper, a package manager, a package repository, a configuration language, and more.
It's not Nix's job, imo. Those compilers should be fixed.
And all the other "features" come for free from Nix's fundamental abstractions, I don't feel it would overstep its boundaries anywhere.
Imagine constant time compute and constant memory constrains, required in cryptography, being applied to the nix ecosystem.
Yes, this is an artifical example but it shows that purity is harder to define and come by, then some people think. Maybe someday these constraints actually do apply to nix goal of reproducibility.
With ever changing hardware that purity is a moving target so nix imo will always be an approach to purity and bundling so much tooling is to be expected. Still, you can legitimately call it a hack :)
https://github.com/NixOS/nix/blob/master/doc/manual/source/s...
I am working on the docs for this as we speak.
In Gentoo
`emerge -e <package name>` will do it, add binpkgs if you know what you're doing (I do, and I do).
* there're maven and gradle plugins to make builds reproducible.
https://bugs.openjdk.org/browse/JDK-8264449 https://reproducible-builds.org/docs/source-date-epoch/
You can remove those with some extra work.
Wouldn't that work?
(-- A Nix maintainer)
I think it would be fairly easy to do this monitoring with a bit of community participation. At least I'd enable telemetry ¯\_(ツ)_/¯.
By default the pkz57 in /nix/store/pkz57...-nushell-0.97.1 is a hash of the build inputs for that package. If you hash the contents of that dir, you get an identifier for the build output.
If we then make a big list of such pairs as built by different people on different machines at different times, and capture the frequency of each pair we'll either see this:
/nix/store/pkz5..., sha256:0drrxa..., 121 users
or we'll see this: /nix/store/pkz5..., sha256:0drrxa..., 100 users
/nix/store/pkz5..., sha256:gvpbk5..., 20 users
/nix/store/pkz5..., sha256:1fwwfe..., 1 user
The former being an indicator that the build is reproducible, and the latter giving hints about why not (supposing these users are willing to share a bit more about the circumstances of that build). I'd call it a "build chromatograph". I expect that knowing whether you're one of the 100 or the odd-man-out could be relevant for certain scenarios.A single compiler that does some parallel work and collect the results of that work in a list in order of completion (and similar) are probably the most common cause of non-determinism.
Given that, your chromatograph would be mostly "determined" by the source code's peculiarities, instead of the offending compiler itself. (E.g. I have n classes a compiler would process in parallel, so given a single point of timing non-determinism n! different combinations could possibly exist (assuming they all cause a different outputs). The only information I could conclude from such a distribution is that there is a common sequence of completing tasks).
But your idea is cool, and simply reporting back non-matching local builds would be helpful (I believe the binary property of whether a different output could be built is the only relevant fact) -- also, if we were to mark a package as non-reproducible, we could recursively mark everything else that has it as a (transitive) input.
- one hash to rule them all, perfectly reproducible
- a big mess, consider avoiding it
- just two or four cohorts, package maintainer may want to investigate
- everbody agrees on the output hash except for you, something local is compromized
I don't anticipiate peering into the mess and coming up with many useful conclusions.
> if we were to mark a package as non-reproducible, we could recursively mark everything else that has it as a (transitive) input.
I like that idea, to sort of carve out a space within the already-pretty-reliable nixpkgs which can be expected upon to be perfectly reproducible. I'd strive to get my packages included in that set, and to select my dependencies from it.
But what did it cost? Usability.
Why spend only 6 years on the most interesting topic of all mankind? I spent 10 years analyzing this.
Just running KDE litters a bunch of dotfiles into your user folder, even for settings you didn't adjust. This is true for many applications.
If you had an empty home folder and passively tried a handful of desktops, you'd no longer have an empty home folder. Hopefully your environment is resilient to clutter being leaked into your home folder, but if your filesystem isn't truly immutable, rolling back to a particular Nix config might not get you the exact state your system was in when you first built that.
There's a project that wipes all local changes when you restart your machine, with the goal of making Nix systems more reproducible. I think it's called Impermanence.
If the point of Nix is to keep a filesystem immutable as long as every app sticks to certain rules, is it actually the right till for the job?
Sorry… I actually don’t know much about Nix given I’ve been using VMs and now containers for over a decade, so just trying to understand the problem that nix actually solves
It can still write to folders, so it's not completely silo'd off like a full-on Docker container, but I still really like it.
At the moment I’m using Ansible for the host and Docker for guests, but I see NixOS as combining these two lasers so everything just runs on the host? Is that fair to say how NixOS works? If so and I have it wrong, maybe I should check it out and I’ve been sleeping on Nix all this time
My recommendation would be to test it out and look at how it does things. Maybe checkout the live installer with a gui to get a feel for a desktop system.
Edit: ok I HAVE been sleeping on NixOS! I couldn’t understand how isolation worked with /etc files, but it turns out /etc is not modified but you do it all through modifying the nix config and rebuild the system which generates /etc! Ok, super interesting