From fc9367a9ec8ce3527291fc3bfc1b12c0260bc676 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:14:24 +0000 Subject: [PATCH 01/12] nix-gc: check for `nix.enable` This was added to Nixpkgs in eb8b70c020e6693b29634660fa173d7f14f882eb. --- modules/services/nix-gc/default.nix | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/services/nix-gc/default.nix b/modules/services/nix-gc/default.nix index 44278e649..b8d5c4d91 100644 --- a/modules/services/nix-gc/default.nix +++ b/modules/services/nix-gc/default.nix @@ -56,13 +56,18 @@ in ###### implementation - config = mkIf cfg.automatic { - - launchd.daemons.nix-gc = { + config = { + assertions = [ + { + assertion = cfg.automatic -> config.nix.enable; + message = ''nix.gc.automatic requires nix.enable''; + } + ]; + + launchd.daemons.nix-gc = mkIf cfg.automatic { command = "${config.nix.package}/bin/nix-collect-garbage ${cfg.options}"; serviceConfig.RunAtLoad = false; serviceConfig.StartCalendarInterval = cfg.interval; }; - }; } From 0176a5082ba8450e1480204a824ed188cdc81600 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:15:18 +0000 Subject: [PATCH 02/12] nix-optimise: check for `nix.enable` This was added to Nixpkgs in eb8b70c020e6693b29634660fa173d7f14f882eb. --- modules/services/nix-optimise/default.nix | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/services/nix-optimise/default.nix b/modules/services/nix-optimise/default.nix index 4eefc480b..addf0467c 100644 --- a/modules/services/nix-optimise/default.nix +++ b/modules/services/nix-optimise/default.nix @@ -52,15 +52,20 @@ in ###### implementation - config = mkIf cfg.automatic { - - launchd.daemons.nix-optimise = { + config = { + assertions = [ + { + assertion = cfg.automatic -> config.nix.enable; + message = ''nix.optimise.automatic requires nix.enable''; + } + ]; + + launchd.daemons.nix-optimise = mkIf cfg.automatic { command = "${lib.getExe' config.nix.package "nix-store"} --optimise"; serviceConfig = { RunAtLoad = false; StartCalendarInterval = cfg.interval; }; }; - }; } From 7cca8f95f7761bff239066306148714e560cbc2e Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:25:18 +0000 Subject: [PATCH 03/12] linux-builder: check for `nix.enable` --- modules/nix/linux-builder.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/nix/linux-builder.nix b/modules/nix/linux-builder.nix index ae39547f6..36a41310e 100644 --- a/modules/nix/linux-builder.nix +++ b/modules/nix/linux-builder.nix @@ -160,6 +160,13 @@ in }; config = mkIf cfg.enable { + assertions = [ + { + assertion = config.nix.enable; + message = ''`nix.linux-builder.enable` requires `nix.enable`''; + } + ]; + system.activationScripts.preActivation.text = '' mkdir -p ${cfg.workingDirectory} ''; From 147ed950e382ef45d083f060b4529df817077069 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:28:56 +0000 Subject: [PATCH 04/12] nixpkgs-flake: check for `nix.enable` --- modules/nix/nixpkgs-flake.nix | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/modules/nix/nixpkgs-flake.nix b/modules/nix/nixpkgs-flake.nix index bb7c1b0a2..bc00c78d2 100644 --- a/modules/nix/nixpkgs-flake.nix +++ b/modules/nix/nixpkgs-flake.nix @@ -37,8 +37,8 @@ in setNixPath = mkOption { type = types.bool; - default = cfg.source != null; - defaultText = "config.nixpkgs.flake.source != null"; + default = config.nix.enable && cfg.source != null; + defaultText = literalExpression ''config.nix.enable && nixpkgs.flake.source != null''; description = '' Whether to set {env}`NIX_PATH` to include `nixpkgs=flake:nixpkgs` such that `` @@ -57,8 +57,8 @@ in setFlakeRegistry = mkOption { type = types.bool; - default = cfg.source != null; - defaultText = "config.nixpkgs.flake.source != null"; + default = config.nix.enable && cfg.source != null; + defaultText = literalExpression ''config.nix.enable && config.nixpkgs.flake.source != null''; description = '' Whether to pin nixpkgs in the system-wide flake registry (`/etc/nix/registry.json`) to the @@ -85,6 +85,18 @@ in be set, since it is implemented in terms of indirection through the flake registry. ''; } + + # TODO: Upstream these to NixOS. + + { + assertion = cfg.setNixPath -> config.nix.enable; + message = ''`nixpkgs.flake.setNixPath` requires `nix.enable`''; + } + + { + assertion = cfg.setFlakeRegistry -> config.nix.enable; + message = ''`nixpkgs.flake.setFlakeRegistry` requires `nix.enable`''; + } ]; } (mkIf cfg.setFlakeRegistry { From 57c93ffe6cbb627e5c9d10ceae7b31e68ba945ac Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:31:28 +0000 Subject: [PATCH 05/12] hercules-ci-agent: check for `nix.enable` --- modules/services/hercules-ci-agent/default.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/services/hercules-ci-agent/default.nix b/modules/services/hercules-ci-agent/default.nix index 391250659..47368294c 100644 --- a/modules/services/hercules-ci-agent/default.nix +++ b/modules/services/hercules-ci-agent/default.nix @@ -22,6 +22,14 @@ in }; config = mkIf cfg.enable { + # TODO: Upstream this to NixOS. + assertions = [ + { + assertion = config.nix.enable; + message = ''`services.hercules-ci-agent.enable` requires `nix.enable`''; + } + ]; + launchd.daemons.hercules-ci-agent = { script = "exec ${cfg.package}/bin/hercules-ci-agent --config ${cfg.tomlFile}"; From aba0c60ebab549f69ece1622d99ffc5e6ad81af3 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:41:14 +0000 Subject: [PATCH 06/12] lorri: check for `nix.enable` --- modules/services/lorri.nix | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/services/lorri.nix b/modules/services/lorri.nix index 0c1230043..c4e1acee2 100644 --- a/modules/services/lorri.nix +++ b/modules/services/lorri.nix @@ -29,6 +29,14 @@ in }; config = mkIf cfg.enable { + # TODO: Upstream this to NixOS. + assertions = [ + { + assertion = config.nix.enable; + message = ''`services.lorri.enable` requires `nix.enable`''; + } + ]; + environment.systemPackages = [ pkgs.lorri ]; launchd.user.agents.lorri = { command = with pkgs; "${lorri}/bin/lorri daemon"; @@ -43,4 +51,4 @@ in }; }; }; -} \ No newline at end of file +} From f4e2805e19f84420538590ff4e91b1bfa2e79784 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:49:48 +0000 Subject: [PATCH 07/12] ofborg: check for `nix.enable` --- modules/services/ofborg/default.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/services/ofborg/default.nix b/modules/services/ofborg/default.nix index 8959cc846..acd6974fb 100644 --- a/modules/services/ofborg/default.nix +++ b/modules/services/ofborg/default.nix @@ -46,6 +46,13 @@ in }; config = mkIf cfg.enable { + assertions = [ + { + assertion = config.nix.enable; + message = ''`services.ofborg.enable` requires `nix.enable`''; + } + ]; + warnings = mkIf (isDerivation cfg.configFile) [ "services.ofborg.configFile is a derivation, credentials will be world readable" ]; From e3bde1588bc6b4cf774197228330139338a4a12c Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:51:42 +0000 Subject: [PATCH 08/12] github-runner: check for `nix.enable` --- modules/services/github-runner/service.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/services/github-runner/service.nix b/modules/services/github-runner/service.nix index 029f863e2..3668a7216 100644 --- a/modules/services/github-runner/service.nix +++ b/modules/services/github-runner/service.nix @@ -13,6 +13,11 @@ in { config.assertions = flatten ( flip mapAttrsToList config.services.github-runners (name: cfg: map (mkIf cfg.enable) [ + # TODO: Upstream this to NixOS. + { + assertion = config.nix.enable; + message = ''`services.github-runners.${name}.enable` requires `nix.enable`''; + } { assertion = (cfg.user == null && cfg.group == null) || (cfg.user != null); message = "`services.github-runners.${name}`: Either set `user` and `group` to `null` to have nix-darwin manage them or set at least `user` explicitly"; From 42e16f31c6faf29a51a2aa15aeff64934bf5d157 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 19:53:25 +0000 Subject: [PATCH 09/12] cachix-agent: check for `nix.enable` --- modules/services/cachix-agent.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/services/cachix-agent.nix b/modules/services/cachix-agent.nix index d9e4a909c..508261afc 100644 --- a/modules/services/cachix-agent.nix +++ b/modules/services/cachix-agent.nix @@ -51,6 +51,14 @@ in { }; config = mkIf cfg.enable { + # TODO: Upstream this to NixOS. + assertions = [ + { + assertion = config.nix.enable; + message = ''`services.cachix-agent.enable` requires `nix.enable`''; + } + ]; + launchd.daemons.cachix-agent = { script = '' . ${cfg.credentialsFile} From d677e3e844e21789c6f39a90aacadf6dc777ca42 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 20:14:17 +0000 Subject: [PATCH 10/12] nix-tools: only pass `config.nix.nixPath` through if `nix.enable` --- modules/nix/nix-darwin.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nix/nix-darwin.nix b/modules/nix/nix-darwin.nix index a064f49a4..9c78f3a6a 100644 --- a/modules/nix/nix-darwin.nix +++ b/modules/nix/nix-darwin.nix @@ -4,7 +4,7 @@ let nix-tools = pkgs.callPackage ../../pkgs/nix-tools { inherit (config.system) profile; inherit (config.environment) systemPath; - nixPath = lib.concatStringsSep ":" config.nix.nixPath; + nixPath = lib.optionalString config.nix.enable (lib.concatStringsSep ":" config.nix.nixPath); }; darwin-uninstaller = pkgs.callPackage ../../pkgs/darwin-uninstaller { }; From cd445c546561d5ca4e9124cb4668ce80939ac0c9 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 10 Feb 2025 20:54:52 +0000 Subject: [PATCH 11/12] nix: catch reads of unmanaged defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we’re not managing the Nix installation, these defaults aren’t used out of the box and won’t accurately represent the state of any unmanaged Nix or the desired Nix package, so reading the option defaults is a bug. This was previously a warning for `nix.package` and a silent failure for all the others. Now that all the problematic accesses in nix-darwin have been appropriately conditionalized, and since a throw gives a backtrace where a warning doesn’t, give throwing defaults to all the `nix.*` options that don’t reflect reality and that that modules shouldn’t be reading when `nix.enable` is off. I’m not in love with the implementation strategy here… ideally we’d think of something better than this and then upstream it to NixOS. `nix.nrBuildUsers` growing a fake default that is never used is particularly unfortunate. But this should hopefully catch mistakes in module code reasonably reliably. --- modules/nix/default.nix | 43 +++++++++++++++++++++++++---------------- tests/nix-enable.nix | 1 - 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/modules/nix/default.nix b/modules/nix/default.nix index b201a692e..270bae43b 100644 --- a/modules/nix/default.nix +++ b/modules/nix/default.nix @@ -156,6 +156,14 @@ let }) ]; + managedDefault = name: default: { + default = if cfg.enable then default else throw '' + ${name}: accessed when `nix.enable` is off; this is a bug in + nix-darwin or a third‐party module + ''; + defaultText = default; + }; + in { @@ -221,9 +229,7 @@ in package = mkOption { type = types.package; - default = warnIf (!cfg.enable) - "nix.package: accessed when `nix.enable` is off; this is a bug" - pkgs.nix; + inherit (managedDefault "nix.package" pkgs.nix) default; defaultText = literalExpression "pkgs.nix"; description = '' This option specifies the Nix package instance to use throughout the system. @@ -232,7 +238,7 @@ in distributedBuilds = mkOption { type = types.bool; - default = false; + inherit (managedDefault "nix.distributedBuilds" false) default defaultText; description = '' Whether to distribute builds to the machines listed in {option}`nix.buildMachines`. @@ -242,7 +248,7 @@ in # Not in NixOS module daemonProcessType = mkOption { type = types.enum [ "Background" "Standard" "Adaptive" "Interactive" ]; - default = "Standard"; + inherit (managedDefault "nix.daemonProcessType" "Standard") default defaultText; description = '' Nix daemon process resource limits class. These limits propagate to build processes. `Standard` is the default process type @@ -257,7 +263,7 @@ in # Not in NixOS module daemonIOLowPriority = mkOption { type = types.bool; - default = false; + inherit (managedDefault "nix.daemonIOLowPriority" false) default defaultText; description = '' Whether the Nix daemon process should considered to be low priority when doing file system I/O. @@ -385,7 +391,7 @@ in }; }; }); - default = [ ]; + inherit (managedDefault "nix.buildMachines" [ ]) default defaultText; description = '' This option lists the machines to be used if distributed builds are enabled (see {option}`nix.distributedBuilds`). @@ -399,12 +405,13 @@ in envVars = mkOption { type = types.attrs; internal = true; - default = { }; + inherit (managedDefault "nix.envVars" { }) default defaultText; description = "Environment variables used by Nix."; }; nrBuildUsers = mkOption { type = types.int; + inherit (managedDefault "nix.nrBuildUsers" 0) default defaultText; description = '' Number of `nixbld` user accounts created to perform secure concurrent builds. If you receive an error @@ -432,11 +439,13 @@ in # Definition differs substantially from NixOS module nixPath = mkOption { type = nixPathType; - default = lib.optionals cfg.channel.enable [ - # Include default path . - { darwin-config = "${config.environment.darwinConfig}"; } - "/nix/var/nix/profiles/per-user/root/channels" - ]; + inherit (managedDefault "nix.nixPath" ( + lib.optionals cfg.channel.enable [ + # Include default path . + { darwin-config = "${config.environment.darwinConfig}"; } + "/nix/var/nix/profiles/per-user/root/channels" + ] + )) default; defaultText = lib.literalExpression '' lib.optionals cfg.channel.enable [ @@ -458,7 +467,7 @@ in checkConfig = mkOption { type = types.bool; - default = true; + inherit (managedDefault "nix.checkConfig" true) default defaultText; description = '' If enabled (the default), checks for data type mismatches and that Nix can parse the generated nix.conf. @@ -519,7 +528,7 @@ in }; } )); - default = { }; + inherit (managedDefault "nix.registry" { }) default defaultText; description = '' A system-wide flake registry. ''; @@ -527,7 +536,7 @@ in extraOptions = mkOption { type = types.lines; - default = ""; + inherit (managedDefault "nix.extraOptions" "") default defaultText; example = '' keep-outputs = true keep-derivations = true @@ -696,7 +705,7 @@ in }; }; }; - default = { }; + inherit (managedDefault "nix.settings" { }) default defaultText; description = '' Configuration for Nix, see diff --git a/tests/nix-enable.nix b/tests/nix-enable.nix index 0828834f1..e052aa2f4 100644 --- a/tests/nix-enable.nix +++ b/tests/nix-enable.nix @@ -2,7 +2,6 @@ { nix.enable = false; - nix.package = throw "`nix.package` used when `nix.enable` is turned off"; test = '' printf >&2 'checking for unexpected Nix binary in /sw/bin\n' From 731910af010086c4dbe23eb6ae79d81bcec703aa Mon Sep 17 00:00:00 2001 From: Emily Date: Tue, 11 Feb 2025 19:46:21 +0000 Subject: [PATCH 12/12] {activation-scripts,activate-system}: check `gcroots` before linking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `nix.enable` is off, we don’t necessarily have an active Nix installation, so there won’t necessarily be an active `/nix/var/nix/gcroots` directory to link things into. NixOS just skips this unconditionally when `nix.enable` is off, but that doesn’t work well with a context in which we usually expect `nix.enable` to be coupled with an unmanaged system installation of Nix. --- modules/services/activate-system/default.nix | 4 +++- modules/system/activation-scripts.nix | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/services/activate-system/default.nix b/modules/services/activate-system/default.nix index d8d868313..df0b48e4b 100644 --- a/modules/services/activate-system/default.nix +++ b/modules/services/activate-system/default.nix @@ -21,7 +21,9 @@ ln -sfn $(cat ${config.system.profile}/systemConfig) /run/current-system # Prevent the current configuration from being garbage-collected. - ln -sfn /run/current-system /nix/var/nix/gcroots/current-system + if [[ -d /nix/var/nix/gcroots ]]; then + ln -sfn /run/current-system /nix/var/nix/gcroots/current-system + fi ${config.system.activationScripts.etcChecks.text} ${config.system.activationScripts.etc.text} diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix index 341e782e0..c8ad20adc 100644 --- a/modules/system/activation-scripts.nix +++ b/modules/system/activation-scripts.nix @@ -106,7 +106,9 @@ in ln -sfn "$(readlink -f "$systemConfig")" /run/current-system # Prevent the current configuration from being garbage-collected. - ln -sfn /run/current-system /nix/var/nix/gcroots/current-system + if [[ -d /nix/var/nix/gcroots ]]; then + ln -sfn /run/current-system /nix/var/nix/gcroots/current-system + fi ''; # FIXME: activationScripts.checks should be system level