惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AWS News Blog
AWS News Blog
T
Tenable Blog
Project Zero
Project Zero
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
T
Threatpost
Security Latest
Security Latest
C
Cisco Blogs
L
Lohrmann on Cybersecurity
S
Security @ Cisco Blogs
Google Online Security Blog
Google Online Security Blog
NISL@THU
NISL@THU
AI
AI
V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Last Watchdog
The Last Watchdog
G
GRAHAM CLULEY
Cloudbric
Cloudbric
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Hacker News: Front Page
U
Unit 42
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MyScale Blog
MyScale Blog
O
OpenAI News
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术
P
Proofpoint News Feed
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
H
Heimdal Security Blog
S
Schneier on Security
阮一峰的网络日志
阮一峰的网络日志
Help Net Security
Help Net Security
D
DataBreaches.Net
Y
Y Combinator Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
N
News and Events Feed by Topic
WordPress大学
WordPress大学
P
Palo Alto Networks Blog

Lobsters

CIFSwitch: a non-universal Linux local root vulnerability RIPE NCC session fixation: poaching logins with an Atlas probe GNOME 2.20 but its Web Components Agentic Search for Context Engineering – Leonie Monigatti Garnix is shutting down [not OC] akashina.tngl.sh/jjc Concerning Emacs (and Jazz) Nitpicking the shell history scene in ‘Tron: Legacy’ What's cooking on SourceHut? Q2 2026 The tenth OpenPGP email summit Package managers that package package managers Clojure on Fennel part three: parsing WordPress at 23 Finding Miscompiles for Fun, Not Profit GitHub - creusot-rs/creusot: Creusot helps you prove your Rust code is correct. Announcing Rust 1.96.0 | Rust Blog A Love Letter to Neovim sqlite AGENTS.md Am I a Bad Friend? CSS vs. JavaScript • Josh W. Comeau Erlang Ecosystem Foundation - Supporting the BEAM community A brief note about slot access cost in Common Lisp Keyboard latency probe Rethinking the GNOME clipboard issues Back to the Building Blocks’ Building Blocks Tech Notes: Theseus: translating win32 to wasm Fast is better than slow Content-addressed Rust builds (or, what kache actually caches) Intent to Prototype: Embedding API Canada’s Bill C-22 and the security cost of collecting more data 5 PostgreSQL locking behaviors that trip people up okmij.org Stop advertising in your commits! | AksDev GitHub - mplsllc/macsurf: A modern web browser for Classic Mac OS 9 PowerPC. Real CSS3, ES5 JavaScript, native HTTPS — built with CodeWarrior on the Carbon API. Introducing DoomBench - Can Your Data Stack Run DOOM? What are some of your favourite developer tools? Building a Scalable Ingestion Pipeline with Temporal (Part 1) Converting shallow Git bundles into normal repositories Are you a member of any professional associations? What is a harmonic? An interactive comic about additive synthesis How Virtual Tables Work in the Itanium C++ ABI Using SwiftUI to Build a Mac-assed App in 2026 Rust (and Slint) on a jailbroken Kindle. ~jack/lambda-on-lambda - Serverless Haskell on AWS - sourcehut git Human proof for FOSS contributions Extremely simple internet radio controlled via IRC Announcing BABLR Splitting Konsole views from Helix to run tools | AksDev GitHub - yugr/rust-slides Serving files over HTTP three ways: synchronous, epoll, and io_uring update docs with information about building with build.py (#979) · astral-sh/python-build-standalone@c9c40c5 A Simple Makefile Tutorial On C extensions, portability, and alternative compilers Switching to Colemak | Pedro Alves Just How Bad Was The Intel IAPX432? Nix's Substituter List Is Not a Routing Table Accelerating copy_if using SIMD Lambda on Lambda: Serverless Haskell on AWS | Blog Announcing feed-repeat v1.0 Scaling Akvorado BMP RIB with sharding EYG news: A host of CLI improvements, new guides and new effects The social contract of writing JS Crossword C array types are weird; and related topics Flatpak will depend on systemd – OSnews Migrating from Go to Rust | corrode Rust Consulting A portentous reunion Vivado Licensing Options How my minimal, memory-safe Go rsync steers clear of vulnerabilities the entropy layer of a wavelet codec, on its own GitHub - nferhat/fht-compositor: A dynamic tiling Wayland compositor. Debian SE Linux and PinTheft Does bulk memmove speed up std::remove_if? (No.) 声明式部分更新 | Blog | Chrome for Developers Fully in-browser container builds Dianne Skoll's Web Site - Remind The Architecture of Open Source Applications (Volume 1)Berkeley DB Pardon MIE? - ironPeak Blog “Long-Term Support” doesn’t mean what you think Jira IS Turing-Complete May I recommend thinking of Emacs as your Fortress of Solitude hershey Floodgap Gopher-HTTP gateway gopher://thelambdalab.xyz/1cuneiforth/ HP QuickWeb, Singular And Pointless That one time I used Go panics for flow control A new suite of modern tools coming for editing and publishing RFCs From the Tabletop… The Digital Antiquarian Building a Host-Tuned GCC to Make GCC Compile Faster Are we self-sovereign PKI yet? Claw Patrol: an open-source security firewall for agents | Deno Revised^7 Report on Scheme, Large: Procedural Fascicle Draft is now public A Network Allow-List Won't Stop Exfiltration — André Graf From AFSK to Goertzel – µArt.cz Software For My New Home Server Introducing Neptune: Direct3D virtualization for QEMU AI Agent Bankrupted Their Operator While Trying to Scan DN42 - Lan Tian @ Blog mimalloc: A new, high-performance, scalable memory allocator for the modern era Making wl_shm fast The Soul of Maintaining a New Machine - Third Draft | Books in Progress What is Git made of?
The Guix Nix Abomination: Leveraging Guix derivations in Nix
fzakaria.com · 2026-06-06 · via Lobsters

Nix and Guix look like rival ecosystems, but under the hood they’re the same “Input Output Machine”.

Need proof? 🕵 How about we build a Guix derivation with Nix.

First let’s create a super basic derivation in Guix: Hello world.

❯ guix repl -- /dev/stdin <<'EOF'
  (use-modules (guix derivations) (guix store))
  (with-store %store
    (let ((drv (derivation %store "simple" "/bin/sh"
                           '("-c" "echo Hello World > $out")
                           #:env-vars '(("PATH" . "/bin"))
                           #:system "x86_64-linux")))
      (format #t "~a\n" (derivation-file-name drv))))
EOF
/gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv

We then ask Nix to build it. 🪄

We ask to use /gnu/store as the Nix store and have it write its state, database and log files in alternate directories, so it does not collide or mess with Guix.

Note It’s slightly more complicated. Nix happens to check its SQLite database for the derivation, so we need to register it first. The version of Guix (v1.5.0) I’m using leverages a guix-daemon user that runs inside a private mount namespace where /gnu/store is writable, but everyone else (including me) sees it as read-only. The unshare --mount creates a new private mount namespace so I can mount it as read-write and run the Nix command against it.


❯ cat > /tmp/register.txt <<'EOF'
/gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv
822a79886102e5ca392cd14358aef0866c36ca526ff1b156f1ded2808a2095df
336

0
EOF

❯ NIX_STORE=/nix/store/fla7gi1dvkw4hvwxar8m7z25p2yv7r40-nix-2.34.7/bin/nix-store

❯ NIX_STORE_DIR=/gnu/store NIX_STATE_DIR=/tmp/nix-gnu/var/nix \
   $NIX_STORE --load-db < /tmp/register.txt

❯ sudo unshare --mount bash -c '
mount -o remount,rw /gnu/store
su -s /bin/bash guix-daemon -c \
    "NIX_STORE_DIR=/gnu/store NIX_STATE_DIR=/tmp/nix-gnu/var/nix \
    NIX_LOG_DIR=/tmp/nix-gnu/var/log/nix \
    /nix/store/fla7gi1dvkw4hvwxar8m7z25p2yv7r40-nix-2.34.7/bin/nix-store \
    --realise /gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv"
'
warning: creating directory "/var/empty/.cache/nix": Permission denied
this derivation will be built:
  /gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv
building '/gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv'...
warning: you did not specify '--add-root'; the result might be removed by the garbage collector
/gnu/store/kd5szqbl9asz5hravhnxgd9plm4a9gzh-simple

❯ cat /gnu/store/kd5szqbl9asz5hravhnxgd9plm4a9gzh-simple
Hello World

We just built a Guix derivation using Nix. 🔥

How is that possible?

Both take a language frontend, Nix or Guile (Scheme), that compiles to a derivation (recipe) and pass that onto a builder (daemon) that executes it to produce an output.

What makes them both special is they both promise the same thing: hermetic builds. Everything needed to build the output is declared in the recipe: sources, environment variables, dependencies, etc.

“Under Nix, a build process will only find resources that have been declared explicitly as dependencies. There’s no way it can build until everything it needs has been correctly declared. If it builds, you will know you’ve provided a complete declaration.” – Nix OS Website

Guix Nix Overview

Guix, specifically the daemon, was forked from Nix early on, and as a result the two are very similar; they both share the same derivation format, ATerm, for instance.

Guix is based on the Nix package manager – Guix Website

That’s why our earlier example of building the Guix derivation with Nix was possible without much translation.

What if we could leverage an existing recipe from Guix in Nix in its traditional /nix/store?

If we could convert from one recipe file to the other, we could use the existing recipes from Guix in Nix and vice versa.

Turns out this is far more feasible than you would think, because Guix is Nix or at least a superset of it.

I, with the help of Claude, built a tool to do just that: guix-transfer 🤯.

guix-transfer is a CLI tool for performing bottom-up translation of GNU Guix derivations into Nix.

Confused? Let us see it in action:

# generate a Guix derivation
❯ guix build hello --derivations
/gnu/store/2nfg943asrl9dv64zrr1a4kpb25mfafd-hello-2.12.2.drv

# translate it
❯ /guix-transfer /gnu/store/2nfg943asrl9dv64zrr1a4kpb25mfafd-hello-2.12.2.drv
Loading Guix derivation graph from /gnu/store/2nfg943asrl9dv64zrr1a4kpb25mfafd-hello-2.12.2.drv ...
Loaded 228 derivations.
Translating bottom-up ...
[228/228] done
Done. Final Nix derivation:
/nix/store/brdd8zw3j9hhq8zf27ixqyi3l61nwppn-hello-2.12.2.drv
Realise it with: nix-store --realise --option filter-syscalls false /nix/store/brdd8zw3j9hhq8zf27ixqyi3l61nwppn-hello-2.12.2.drv

# build it with Nix
# this is a LONG multi-hour build since we build everything from source
❯ nix-store --option filter-syscalls false --realise \
/nix/store/brdd8zw3j9hhq8zf27ixqyi3l61nwppn-hello-2.12.2.drv

❯ /nix/store/j3940mdzr6qmw4ydhyla663s501vb8ns-hello-2.12.2/bin/hello
Hello, world!

Note When you unpack a tarball, tar restores each file’s original permissions, including setuid/setgid bits. Nix’s sandbox installs a seccomp filter that blocks any chmod call that sets these bits, returning “Operation not permitted”. Guix’s early bootstrap uses a Scheme-based tar (gash-utils) that treats this error as fatal, unlike GNU tar which silently skips it. The fix is --option filter-syscalls false, which disables the filter.

If it’s not clear what we just did: we took a Guix derivation and all of its dependencies (down to the bootstrap seeds), translated it to a Nix derivation, and built it with Nix. 😲

What is this abomination and how was this possible!?

It’s important to revisit what a derivation is, and how it’s used in Nix and Guix to better understand how this is possible. Let’s look at the same basic derivation from earlier, Hello World.

You might want to check out my other post on Nix derivations by hand if this interests you 🤓.

derivation {
  name = "simple";
  builder = "/bin/sh";
  system = builtins.currentSystem;
  args = ["-c" ''
    echo "Hello World" > $out
  ''];
}

When we evaluate (nix-instantiate) this derivation, we get a path to a file that contains the derivation in the ATerm format:

❯ nix-instantiate - << 'EOF'
derivation {
  name = "simple";
  builder = "/bin/sh";
  system = builtins.currentSystem;
  args = ["-c" ''
    echo "Hello World" > $out
  ''];
}
EOF
/nix/store/w4mcfbibhjgri1nm627gb9whxxd65gmi-simple.drv

If we look at the contents of the file, we can see the ATerm representation of the derivation:

Derive(
  [("out", "/nix/store/r4c710xzfqrqw2wd6cinxwgmh44l4cy2-simple", "", "")],
  [],
  [],
  "x86_64-linux",
  "/bin/sh",
  ["-c", "echo \"Hello World\" > $out\n"],
  [
    ("builder", "/bin/sh"),
    ("name", "simple"),
    ("out", "/nix/store/r4c710xzfqrqw2wd6cinxwgmh44l4cy2-simple"),
    ("system", "x86_64-linux")
  ]
)

This has all the information we need to build the output by the builder. At this point, it’s really not Nix specific anymore. The same applies for the Guix derivations.

The derivations do not “know” whether they came from Scheme or Nix. It’s a recipe. The insight then is if we rewrite the store paths from /gnu/store to /nix/store, and swap some builtins (i.e. builtin:download for builtin:fetchurl), we can get nix-daemon to build it identically. 💡

The only difference in more complex derivations is that they have dependencies, which are also derivations, and the builder references them so it forms a graph of derivations, each built by the builder in topological order.

The leaves of this tree for any non-trivial derivation are the bootstrap seeds: gcc, awk, bash, tar etc. Guix is famous for bootstrapping itself from a 357-byte binary as source [ref]. Since at no point do the bootstrap seeds depend on /gnu/store being the prefix, the translated chain builds identically under Nix.

guix-transfer walks a Guix .drv graph in post-order and for each derivation:

  1. Guix’s builtin:download is replaced with Nix’s builtin:fetchurl. Same idea, different name.

  2. Source files are added to the Nix store, with embedded /gnu/store paths rewritten to their /nix/store equivalents.

  3. Every /gnu/store reference: input drvs, builder path, args, env vars are rewritten to the mapped /nix/store path.

  4. Output paths are blanked as Nix recomputes them via hashDerivationModulo.

  5. The result is serialised as JSON and registered with nix derivation add.

That’s it. No Nix expressions are generated. No stdenv. No mapping of Guix packages to nixpkgs equivalents. The Guix derivation graph is translated faithfully, and nix-daemon builds it.

Note Interestingly, builtin:fetchurl takes exactly one URL and cannot fall back. Guix derivations carry lists of mirrors, many of which are flaky or dead. Similar to Nix, Guix operates a content-addressed mirror at bordeaux.guix.gnu.org that serves any source its CI has ever seen. We leverage this for the fetchurl instead of the original source URL.

Now that we have a way to slurp Guix packages into Nix, we can start to do some diabolical combinations by combining native Nix and Guix packages together!

We can take our hello package we built in Nix and leverage it in a Nix derivation.

let
guixHello = /nix/store/...-hello-2.12.2;
in
derivation {
  name = "nix-hello-world";
  system = "x86_64-linux";
  builder = "/bin/sh";
  args = [ "-c" "echo \"$(${guixHello}/bin/hello) from Nix\" > $out" ];
}

Nix automatically scans your derivations for anything prefixed with /nix/store and tracks it as an input dependency. This is similar to how store paths are interpolated when you do something like ${pkgs.hello}/bin/hello.

❯ nix-build --no-out-link hello-from-nix.nix

❯ cat /nix/store/...-run-guix-hello
Hello, world! from Nix

If writing the /nix/store paths raw in the Nix expression is a little too raw for you, we can build something more ergonic pretty easily as well. guix-transfer has an --emit-nix mode that instead will emit the Nix expression for the translated .drv.

Let’s look at a slightly more complex example that uses Guix’s guile to build a derivation with dependencies:

❯ guix repl -- /dev/stdin <<'EOF'
  (use-modules (guix derivations) (guix store) (guix packages)
               (gnu packages bootstrap))
  (with-store store
    (let* ((guile-drv (package-derivation store %bootstrap-guile))
           (guile-out (derivation->output-path guile-drv))
           (drv (derivation store "demo" (string-append guile-out "/bin/guile")
                            `("--no-auto-compile" "-c"
                              ,(string-append
                                 "(call-with-output-file (getenv \"out\") "
                                 "  (lambda (p) (display \"Hello from Guix!\\n\" p)))"))
                            #:inputs (list (derivation-input guile-drv))
                            #:system "x86_64-linux")))
      (format #t "~a\n" (derivation-file-name drv))))
EOF

❯ guix build /gnu/store/fln2d17fyqka3gafcdqyhfyl1nzml5jn-demo.drv
successfully built /gnu/store/fln2d17fyqka3gafcdqyhfyl1nzml5jn-demo.drv
/gnu/store/l66zvywi60ljhk3kwwaay156cgsc2ahg-demo

❯ cat /gnu/store/l66zvywi60ljhk3kwwaay156cgsc2ahg-demo
Hello from Guix!

We can now convert this to a Nix expression with guix-transfer.

❯ guix-transfer /gnu/store/fln2d17fyqka3gafcdqyhfyl1nzml5jn-demo.drv --emit-nix /tmp/demo.nix
...
Realise it with: nix-store --realise --option filter-syscalls false /nix/store/fkj4vz6vs85s2x3dwhg5ysfwyr8rv4a5-demo.drv
Emitted Nix expression: /tmp/demo.nix

We realise the derivation with nix-store --realise or we can nix-build the Nix expression. Please notice that both produce the exact same hash: /nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo.

❯ nix-build /tmp/demo.nix
/nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo

❯ nix-store --realise --option filter-syscalls false /nix/store/zgwdbfpigl8cwy5d85p0rdcl21x3bszm-demo.drv
/nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo

❯ cat /nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo
Hello from Guix!

We can now use this Guix derivation like any normal Nix expression, such as the ones you might encounter in Nixpkgs.

let
  guixDemo = import /tmp/demo.nix;
in
derivation {
  name = "use-guix-demo";
  system = "x86_64-linux";
  builder = "/bin/sh";
  args = [ "-c" "echo \"Nix says: $(cat ${guixDemo})\" > $out" ];
}

That means we could even build a flake that is all of Guix packages available for use.

{
  outputs = { self }: {
    packages.x86_64-linux.demo = import ./demo.nix;
  };
}

My mind is blown. 🤯

Nixpkgs is known as the world’s largest package repository, and now we have made a way for it suddenly to become even larger by borrowing any derivation from Guix!

The real power behind Nix are the derivations and that they are hermetic, declaring any dependency needed. We’ve seen that we can transfer these recipes to any store-based system that has similar qualities and preserve the reproducibility.