Guix by Nix

ingve1 pts0 comments

Guix by Nix | Farid Zakaria’s Blog

Skip to content

I have been working more on GuixPkgs in preparation for a talk at nix.vegas for DEFCON34. At the end of my previous GuixPkgs post I left a teaser:

We can then build a NixOS machine where every package is the Guix equivalent 😱.

Well, adeci11It has been extremely fun and rewarding to work with Alex on this project. We nix-pilled him at PlanetNix 2 years ago and since then he has been pushing the boundaries of what Nix can do and is currently employed at Shopify working on Nix.  took the bait and we went even further than that. 😈

Say hello to Guix by Nix: a bootable VM where the kernel is Guix’s Linux-libre, the userland is translated Guix packages, and PID 1 is GNU Shepherd .

No systemd. No D-Bus. No NixOS activation. Not even a nix or guix binary in the guest. It’s Guile all the way down and Nix built all of it.

$ nix run --accept-flake-config github:adeci/guix-by-nix<br>...<br>Starting Guix-derived initrd<br>GUIX_BY_NIX_INITRD_MODULES_READY modules=virtio_pci,virtio_blk,...,overlay<br>GUIX_BY_NIX_INITRD_ROOT_READY device=/dev/vda<br>Starting Guix by Nix activation<br>GUIX_BY_NIX_ACTIVATION_READY<br>Starting Guix Shepherd as PID 1<br>SHEPHERD_NETWORK_READY address=10.0.2.15 gateway=10.0.2.2 resolver=10.0.2.3<br>SHEPHERD_PID1 parent=1 child=690

Welcome to Guix by Nix (experimental)<br>guix-by-nix login: root

Log in with root / guix-by-nix and poke around:

bash-5.2# ps -p 1<br>PID TTY TIME CMD<br>1 ? 00:00:00 shepherd

bash-5.2# uname -r<br>6.12.62-gnu

bash-5.2# readlink -f "$(command -v ls)"<br>/nix/store/...-coreutils-9.1/bin/ls

As a reminder, even though these binaries live in /nix/store, they are not Nixpkgs packages. They were translated from Guix derivations using guix-transfer and built by the nix-daemon.

That coreutils was built from Guix’s package definition, source bootstrap and all , but it lives in /nix/store, because nix-daemon built it.

If you want to try out any of these packages on your own machine, you can use GuixPkgs.

$ nix run --accept-flake-config github:fzakaria/guixpkgs#coreutils

Tip<br>Guix offers all packages built from source where Nix may offer it as a prebuilt binary. You can use GuixPkgs to get a source-built bootstrapped version of OpenJDK for example and all the whacky steps to get there.

§How it works

How does this actually work? The project is a three-stage pipeline:

guix-transfer is the tool that translates Guix derivation graphs into Nix derivations.

GuixPkgs is the flake with all Guix packages, all built from the 357-byte seed, although there is a Cachix cache provided.

Guix by Nix assembles ~42 of those packages, a subset of the overall set, into a useable machine.

Warning<br>AI was leveraged to write the initrd and activation scripts.<br>That seems to trigger people lately, so consider yourself warned.

The initrd is a custom shell script, interpreted by Guix Bash, that loads eight modules, mounts the root disk and the 9p store, and switch_roots.

Activation (accounts, /etc, the setuid sudo copy) is another custom Nix-generated script run by Guix Bash.

PID 1 is shepherd from Guix, with a small Scheme config that starts eudev, dhcpcd, openresolv, and a serial getty. herd status works like you’d expect.

/etc/profile is compiled from Guix’s own search-path specifications, so GUILE_LOAD_PATH and friends point where Guix intended.

Every program that can be executed, every ELF file, every script interpreter, all traces back to a translated Guix derivation. The only things Nix authored are text files: the init scripts, the Shepherd config, /etc.

This is Guix by Nix.

§Don’t trust me. Read the receipt.

“Every executable byte comes from Guix” is exactly the kind of claim that’s easy to say and easy to fudge. 🤥

A booted demo is great but that can’t prove it. A VM where ls secretly came from Nixpkgs boots identically.

The flake ships an audit-check that classifies every store path in the shipped closure by provenance, unpacks the compressed initrd22Nix’s reference scanner can’t see inside archives and sneaky paths hide there. , and inspects every executable payload. The audit derivation fails if anything is unclassified, any ELF file or script interpreter doesn’t trace to a translated Guix output, any /gnu/store reference survived translation, or anything systemd-shaped appears anywhere.

$ nix build --accept-flake-config github:adeci/guix-by-nix#status-report<br>$ jq '{rejected, claims}' result/status.json<br>"rejected": {<br>"wrapperPaths": 0,<br>"nonGuixElf": 0,<br>"externalScriptInterpreters": 0,<br>"untranslatedGnuStoreReferences": 0,<br>"unclassifiedPaths": 0,<br>"systemdDbusLogindPaths": 0<br>},<br>"claims": {<br>"translatedLinuxLibre": true,<br>"wrapperFreeGuest": true,<br>"allElfFromGuix": true,<br>"allScriptInterpretersGuixDerived": true,<br>"systemdFreeGuest": true,<br>"fullyClassified": true,<br>"emptyFirmwareBoundary": true

The report includes a lot more information such as the exact Guix channel commit everything was translated from. There’s also some NixOS VM tests for good-measure....

guix from built true guixpkgs packages

Related Articles