diff --git a/.envrc b/.envrc index 28bfe57..692b0fb 100644 --- a/.envrc +++ b/.envrc @@ -1,2 +1,4 @@ watch_file devshell/{default,commands,install,vm-tasks}.nix -use flake +# --accept-flake-config trusts the flake's nixConfig (our Harmonia cache) non-interactively, so +# direnv doesn't stall on the trust prompt. +use flake . --accept-flake-config diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index ab2dac8..d61dd91 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -10,17 +10,22 @@ jobs: runs-on: ubuntu-26.04 steps: - uses: actions/checkout@v6 - - uses: cachix/install-nix-action@v31 + - uses: DeterminateSystems/determinate-nix-action@v3 with: - # Gitea will supply a token in GITHUB_TOKEN, which this action will - # try to pass to Nix when downloading from GitHub - github_access_token: ${{ secrets.GH_PULL_TOKEN }} - extra_nix_config: | + # Gitea will supply a token in GITHUB_TOKEN, which this action passes to + # Nix (as access-tokens) when downloading from GitHub + github-token: ${{ secrets.GH_PULL_TOKEN }} + extra-conf: | # Make sure we're using sandbox sandbox-fallback = false # Big C++ projects fill up memory... cores = 6 + # Determinate performance features + lazy-trees = true + eval-cores = 0 + + accept-flake-config = true extra-substituters = https://nix-cache.nul.ie extra-trusted-public-keys = nix-cache.nul.ie-1:BzH5yMfF4HbzY1C977XzOxoPhEc9Zbu39ftPkUbH+m4= diff --git a/devshell/default.nix b/devshell/default.nix index 6a92814..892d132 100644 --- a/devshell/default.nix +++ b/devshell/default.nix @@ -12,6 +12,9 @@ in NIX_USER_CONF_FILES = toString (pkgs.writeText "nix.conf" '' experimental-features = nix-command flakes ca-derivations + lazy-trees = true + eval-cores = 0 + accept-flake-config = true connect-timeout = 5 fallback = true ${lib.my.c.nix.cache.conf} @@ -22,7 +25,7 @@ in packages = with pkgs; [ coreutils - nixVersions.stable + determinate-nix rage wireguard-tools (pkgs.writeShellScriptBin "deploy" '' diff --git a/devshell/install.nix b/devshell/install.nix index a8c6a78..6afa202 100644 --- a/devshell/install.nix +++ b/devshell/install.nix @@ -29,7 +29,7 @@ let coreutils gnugrep openssh - nixVersions.stable + determinate-nix jq ]; text = diff --git a/docs/deployment.md b/docs/deployment.md index 416f1ff..67d6334 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -110,6 +110,31 @@ VM's unix sockets from `/run/vms//` on `` over SSH): | `vm-monitor ` | QEMU monitor socket in `minicom`. | | `vm-viewer ` | SPICE display in `virt-viewer` (not on Darwin). | +## Nix implementation + +Every context uses **Determinate Nix** as its `nix.package`, for its performance features +(parallel evaluation and lazy trees) — not `determinate-nixd`; the daemon and `nix.conf` model +are unchanged, and the Determinate NixOS module is deliberately not imported. + +- **Input and package.** The [`determinate-nix`](../flake.nix) input is the `nix-src` flake + (`flakehub.com/f/DeterminateSystems/nix-src`), with `nixpkgs.follows = "nixpkgs-unstable"`. We + build it ourselves against our pinned nixpkgs — FlakeHub's own cache needs authentication, so + there is nothing to gain from leaving it unpinned — and it then flows through the Harmonia cache + like everything else. `determinateOverlay` exposes it under the stable attr `determinate-nix`, + added to both the devshell `pkgs'` and the config `configPkgs'` overlay lists, so systems, homes + and the devshell all resolve the same package (`pkgs'.mine.determinate-nix`). +- **Settings.** `lib.my.c.nix.determinateSettings` (`lazy-trees`, `eval-cores = 0`) is merged into + `nix.settings` for systems and homes and into the devshell's `nix.conf`. These keys are only + understood by the Determinate binary. +- **Consumers follow automatically.** Everything that shells out to Nix references + `config.nix.package` (deploy-rs, containers, `build`, netboot, Harmonia), so they inherit + Determinate without further change. +- **`accept-flake-config`.** Set true only in the devshell `nix.conf`, `.envrc` (as + `--accept-flake-config`, for direnv) and CI — the contexts that build this flake — so its + `nixConfig` (the Harmonia cache) is trusted without an interactive prompt. It is deliberately not + set system-wide: boxes already trust that cache via `nix.settings`, so a global setting would only + blanket-trust every flake's `nixConfig` for no gain. + ## Secrets Secrets are age-encrypted files in [`secrets/`](../secrets), managed with **ragenix** (a fork @@ -152,8 +177,10 @@ GitHub/Gitea Actions workflows live in [`.gitea/workflows/`](../.gitea/workflows ### `ci.yaml` -On pushes to `master`, this runs `nix flake check --no-build`, then builds every attribute of -`.#ci.x86_64-linux`: systems as `system-`, homes as `home-` (with `@` changed to +On pushes to `master`, this installs Determinate Nix on the runner (via +`DeterminateSystems/determinate-nix-action`, configured with the same performance settings and +Harmonia substituter as the boxes), runs `nix flake check --no-build`, then builds every attribute +of `.#ci.x86_64-linux`: systems as `system-`, homes as `home-` (with `@` changed to `-at-`), packages as `package-`, and the development `shell`. Each result is pushed to the Harmonia cache with [`ci/push-to-cache.sh`](../ci/push-to-cache.sh). diff --git a/flake.lock b/flake.lock index 535b672..8b31fa2 100644 --- a/flake.lock +++ b/flake.lock @@ -163,6 +163,29 @@ "type": "github" } }, + "determinate-nix": { + "inputs": { + "flake-parts": "flake-parts", + "git-hooks-nix": "git-hooks-nix", + "nixpkgs": [ + "nixpkgs-unstable" + ], + "nixpkgs-23-11": "nixpkgs-23-11", + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1785428605, + "narHash": "sha256-wfaiSRLM1wDb4MV+NEzbyheK9Y03/oe56NR2I84UF7E=", + "rev": "0ff46631f69584c9f76792cae595ea253bd482c3", + "revCount": 26288, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/DeterminateSystems/nix-src/3.21.9/019fb409-4d6e-7243-8a88-23ceee2520e9/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/DeterminateSystems/nix-src/%2A" + } + }, "devshell": { "inputs": { "flake-utils": "flake-utils", @@ -256,6 +279,42 @@ "type": "github" } }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "determinate-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1748821116, + "narHash": "sha256-F82+gS044J1APL0n4hH50GYdPRv/5JWm34oCJYmVKdE=", + "rev": "49f0870db23e8c1ca0b5259734a02cd9e1e371a1", + "revCount": 377, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/hercules-ci/flake-parts/0.1.377%2Brev-49f0870db23e8c1ca0b5259734a02cd9e1e371a1/01972f28-554a-73f8-91f4-d488cc502f08/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/hercules-ci/flake-parts/0.1" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -460,6 +519,30 @@ "type": "github" } }, + "git-hooks-nix": { + "inputs": { + "flake-compat": "flake-compat_2", + "gitignore": [ + "determinate-nix" + ], + "nixpkgs": [ + "determinate-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1747372754, + "narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=", + "rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46", + "revCount": 1026, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/cachix/git-hooks.nix/0.1.1026%2Brev-80479b6ec16fefd9c1db3ea13aeb038c60530f46/0196d79a-1b35-7b8e-a021-c894fb62163d/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/cachix/git-hooks.nix/0.1.941" + } + }, "harmonia": { "inputs": { "crane": "crane", @@ -655,6 +738,22 @@ "type": "github" } }, + "nixpkgs-23-11": { + "locked": { + "lastModified": 1717159533, + "narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + } + }, "nixpkgs-mine": { "locked": { "lastModified": 1781356656, @@ -687,6 +786,22 @@ "type": "github" } }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, "nixpkgs-stable": { "locked": { "lastModified": 1780902259, @@ -847,6 +962,7 @@ "borgthin": "borgthin", "copyparty": "copyparty", "deploy-rs": "deploy-rs", + "determinate-nix": "determinate-nix", "devshell": "devshell_3", "flake-utils": "flake-utils_6", "harmonia": "harmonia", diff --git a/flake.nix b/flake.nix index eb28674..d333dbb 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,19 @@ { description = "System configs"; + # Offer our Harmonia cache when building the flake itself, so `nix develop` / `nix build` don't + # rebuild from source. Nix reads `nixConfig` before the flake evaluates and rejects any computed + # value (imports/thunks), so these must stay literal — keep them in sync with `lib.my.c.nix.cache`. + # Consumers must trust these (accept-flake-config / a trusted user) for them to take effect. + nixConfig = { + extra-substituters = [ + "https://nix-cache.nul.ie" + ]; + extra-trusted-public-keys = [ + "nix-cache.nul.ie-1:BzH5yMfF4HbzY1C977XzOxoPhEc9Zbu39ftPkUbH+m4=" + ]; + }; + inputs = { flake-utils.url = "github:numtide/flake-utils"; # libnet.url = "github:reo101/nix-lib-net"; @@ -21,6 +34,12 @@ home-manager-stable.url = "home-manager/release-26.05"; home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable"; + # Determinate Nix, used as the common Nix implementation across systems, homes, the devshell and + # CI (see lib.my.c.nix). We build it ourselves against our pinned nixpkgs (FlakeHub's cache needs + # auth), so it flows through our own Harmonia cache like everything else. + determinate-nix.url = "https://flakehub.com/f/DeterminateSystems/nix-src/*"; + determinate-nix.inputs.nixpkgs.follows = "nixpkgs-unstable"; + # Stuff used by the flake for build / deployment # ragenix.url = "github:yaxitech/ragenix"; ragenix.url = "github:devplayer0/ragenix/add-rekey-one-flag"; @@ -83,6 +102,11 @@ }; pkgsLibOverlay = final: prev: { lib = prev.lib.extend libOverlay; }; myPkgsOverlay = final: prev: import ./pkgs { lib = final.lib; pkgs = prev; }; + # Exposes Determinate Nix under a stable attr name so systems, homes and the devshell all + # resolve the exact same package (referenced as `pkgs'.mine.determinate-nix` in configs). + determinateOverlay = final: prev: { + determinate-nix = inputs.determinate-nix.packages.${prev.stdenv.hostPlatform.system}.default; + }; # Override the flake-level lib since we're going to use it for non-config specific stuff pkgsFlakes = mapAttrs (_: pkgsFlake: pkgsFlake // { lib = pkgsFlake.lib.extend libOverlay; }) { @@ -111,6 +135,7 @@ pkgsLibOverlay myPkgsOverlay + determinateOverlay inputs.devshell.overlays.default inputs.ragenix.overlays.default inputs.deploy-rs.overlays.default @@ -126,6 +151,7 @@ pkgsLibOverlay myPkgsOverlay + determinateOverlay ]; config = { @@ -187,7 +213,13 @@ nixosModules = nixfiles.config.nixos.modules; homeModules = nixfiles.config.home-manager.modules; - nixosConfigurations = mapAttrs (_: s: s.rendered) nixfiles.config.nixos.systems; + # Containers and the installer override `rendered` with a bare `extendModules` config + # (`my.asContainer` / `my.asISO`) that lacks the `pkgs`/`lib` attrs `eval-config` exposes on a + # normal system. Determinate Nix's flake schemas read `machine.pkgs.stdenv.system` for every + # `nixosConfigurations` entry, so re-attach them from the full system eval (`configuration`). + nixosConfigurations = mapAttrs + (_: s: s.rendered // { inherit (s.configuration) pkgs lib; }) + nixfiles.config.nixos.systems; homeConfigurations = mapAttrs (_: s: s.configuration) nixfiles.config.home-manager.homes; deploy = nixfiles.config.deploy-rs.rendered; diff --git a/home-manager/modules/common.nix b/home-manager/modules/common.nix index 072d259..8ee5fe8 100644 --- a/home-manager/modules/common.nix +++ b/home-manager/modules/common.nix @@ -50,7 +50,7 @@ in }; nix = { - settings = with lib.my.c.nix; { + settings = with lib.my.c.nix; determinateSettings // { experimental-features = [ "nix-command" "flakes" "ca-derivations" ]; max-jobs = mkDefault "auto"; @@ -256,13 +256,13 @@ in ssh.authKeys.files = [ lib.my.c.sshKeyFiles.me ]; }; - nix.package = pkgs.nix; + nix.package = pkgs'.mine.determinate-nix; fonts.fontconfig.enable = true; home = { packages = with pkgs; [ - pkgs'.mine.nix + pkgs'.mine.determinate-nix ]; # Without this, we are at the mercy of whatever version of nix is in $PATH... diff --git a/lib/constants.nix b/lib/constants.nix index 984ca8e..f1d97fc 100644 --- a/lib/constants.nix +++ b/lib/constants.nix @@ -111,6 +111,13 @@ rec { extra-trusted-public-keys = ${concatStringsSep " " keys} ''; }; + + # Determinate-specific settings enabling its performance features. Only understood by the + # Determinate Nix binary, so they must not be emitted for a base-Nix package. + determinateSettings = { + lazy-trees = true; + eval-cores = 0; + }; }; pubDomain = "nul.ie"; diff --git a/nixos/modules/common.nix b/nixos/modules/common.nix index 671a661..dbc1cd1 100644 --- a/nixos/modules/common.nix +++ b/nixos/modules/common.nix @@ -50,9 +50,9 @@ in }; nix = { - package = pkgs'.mine.nix; + package = pkgs'.mine.determinate-nix; channel.enable = false; - settings = with lib.my.c.nix; { + settings = with lib.my.c.nix; determinateSettings // { trusted-users = [ "@wheel" ]; experimental-features = [ "nix-command" "flakes" "ca-derivations" ]; extra-substituters = cache.substituters;