• 1 Post
  • 18 Comments
Joined 1 year ago
cake
Cake day: May 6th, 2025

help-circle
  • It’s really powerful.

    As a proponent of better, faster, more foolproof, and more elegant, I’m often jealous of some of the features that our brothers in GUIX are building with the benefit of hindsight. Also, I will admit that it really feels like NixOS is doing the hard work exploring a paradigm (and its inherent rough edges) that will effectively obsolete FHS entirely in the Linux world someday.


  • NixOS is surely what I’d recommend.

    I like to tinker with an Arch Linux install using a VM to iterate quickly then translate almost ALL of the home dotfiles and preferences to deterministic nix code that absolutely LOCKS everything into place.

    Some essential features/projects to incorporate into a decent nix config:

    • nix flakes
    • home-manager
    • content-addressed and dynamic derivations (Eelco’s original paper writes about CA derivations as the holy grail)
    • cachix (local cache) and community substituters
    • forgejo (local forge with local CI to test nix flake updates for breakage and warm the local cache) I call it my “update canary”)
    • nixos-anywhere/netboot/initrd boot scripting influenced by NixOS-anywhere but extended
    • disko
    • impermanance (lots of work up front declaring what persists between boots but this one is ESSENTIAL. This module makes it virtually impossible for a compromised package or virus to survive a reboot if things are done right.)
    • sops-nix
    • nixos-needs-reboot
    • devenv/direnv





  • No. There’s no way to force it.

    And the understanding is off in one spot: nothing gets “automatically pulled without verification.” Every source fetch has a pinned sha256 and fails loudly if it doesn’t match. It’s just that a hash proves the bytes didn’t change, not that upstream authored them.

    Signatures do exist in Nix, but only on binary cache paths. Fixed-output derivations (every fetchurl, every fetchFromGitHub) are exempt by design, because the hash is the identity. That’s not a setting, it’s the model.

    And there’s no signature to check even if you wanted one. Almost no nixpkgs package records an upstream key. So a hypothetical “signed only” mode would reject basically all of nixpkgs.

    Guix does what you’re asking with guix git authenticate. Nix has no equivalent.….yet.


  • Yes. Thats how I do it actually (not with apt). You can even point the runner at the nix community cache to prevent overly long build times. I have never trusted the Docker style of “I crammed everything I needed into this amorphous, way-too-capable, badly sandboxed, portable Alpine Linux box. Trust me bro, it’s secure” and prefer “here’s code showing exactly how I build this software with pinned, hashed versions that pass checks and you can use them too” with a simple flake file.

    Here’s some pseudo code demonstrating it:

    flake.nix

    {
      description = "hello-cli: pinned end to end by a lockfile, built in a sandbox";
    
      inputs = {
        nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
        flake-utils.url = "github:numtide/flake-utils";
      };
    
      outputs = { self, nixpkgs, flake-utils }:
        flake-utils.lib.eachDefaultSystem (system:
          let
            pkgs = import nixpkgs { inherit system; };
          in {
            packages.default = pkgs.rustPlatform.buildRustPackage {
              pname = "hello-cli";
              version = "0.1.0";
              src = ./.;
    
              # No magic hash to paste. The committed Cargo.lock IS the pin:
              # Nix reads it and fetches every crate as a fixed-output
              # derivation. Change a dep, the lock changes, the build changes.
              cargoLock.lockFile = ./Cargo.lock;
    
              meta.mainProgram = "hello-cli";
            };
    
            devShells.default = pkgs.mkShell {
              packages = with pkgs; [ cargo rustc rust-analyzer clippy ];
            };
          });
    }
    

    And a pertinent example runner.yml file:

    
    when:
      - event: [push, pull_request, tag]
    
    steps:
      - name: build
        image: nixos/nix:2.28.3
        environment:
          NIX_CONFIG: |
            experimental-features = nix-command flakes
            accept-flake-config = false
            sandbox = true
            substituters = https://cache.nixos.org/ https://nix-community.cachix.org/
            trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=
        commands:
          # stale lock is a hard failure, so CI can never silently float
          - nix build .#default --no-update-lock-file --print-build-logs
          - ./result/bin/hello-cli nix
          # the money shot
          - nix path-info -r --closure-size --human-readable ./result
          # prove it again from scratch with zero cache and zero network
          - nix build .#default --rebuild --option substituters "" --print-build-logs