diff --git a/nixos/modules/system/activation/test.nix b/nixos/modules/system/activation/test.nix new file mode 100644 index 000000000000..8cf000451c6e --- /dev/null +++ b/nixos/modules/system/activation/test.nix @@ -0,0 +1,27 @@ +{ lib +, nixos +, expect +, testers +}: +let + node-forbiddenDependencies-fail = nixos ({ ... }: { + system.forbiddenDependenciesRegex = "-dev$"; + environment.etc."dev-dependency" = { + text = "${expect.dev}"; + }; + documentation.enable = false; + fileSystems."/".device = "ignore-root-device"; + boot.loader.grub.enable = false; + }); + node-forbiddenDependencies-succeed = nixos ({ ... }: { + system.forbiddenDependenciesRegex = "-dev$"; + system.extraDependencies = [ expect.dev ]; + documentation.enable = false; + fileSystems."/".device = "ignore-root-device"; + boot.loader.grub.enable = false; + }); +in +lib.recurseIntoAttrs { + test-forbiddenDependencies-fail = testers.testBuildFailure node-forbiddenDependencies-fail.config.system.build.toplevel; + test-forbiddenDependencies-succeed = node-forbiddenDependencies-succeed.config.system.build.toplevel; +} diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 55ff98db5382..64e97b510b06 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -77,7 +77,7 @@ let ${config.system.systemBuilderCommands} - echo -n "${toString config.system.extraDependencies}" > $out/extra-dependencies + echo -n "$extraDependencies" > $out/extra-dependencies ${config.system.extraSystemBuilderCmds} ''; @@ -105,6 +105,8 @@ let dryActivationScript = config.system.dryActivationScript; nixosLabel = config.system.nixos.label; + inherit (config.system) extraDependencies; + # Needed by switch-to-configuration. perl = pkgs.perl.withPackages (p: with p; [ ConfigIniFiles FileSlurp ]); } // config.system.systemBuilderArgs); @@ -223,6 +225,16 @@ in ''; }; + system.forbiddenDependenciesRegex = mkOption { + default = ""; + example = "-dev$"; + type = types.str; + description = lib.mdDoc '' + A POSIX Extended Regular Expression that matches store paths that + should not appear in the system closure, with the exception of {option}`system.extraDependencies`, which is not checked. + ''; + }; + system.extraSystemBuilderCmds = mkOption { type = types.lines; internal = true; @@ -298,8 +310,26 @@ in config.system.copySystemConfiguration ''ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" }' \ "$out/configuration.nix" + '' + + optionalString + (config.system.forbiddenDependenciesRegex != "") + '' + if [[ $forbiddenDependenciesRegex != "" && -n $closureInfo ]]; then + if forbiddenPaths="$(grep -E -- "$forbiddenDependenciesRegex" $closureInfo/store-paths)"; then + echo -e "System closure $out contains the following disallowed paths:\n$forbiddenPaths" + exit 1 + fi + fi ''; + system.systemBuilderArgs = lib.optionalAttrs (config.system.forbiddenDependenciesRegex != "") { + inherit (config.system) forbiddenDependenciesRegex; + closureInfo = pkgs.closureInfo { rootPaths = [ + # override to avoid infinite recursion (and to allow using extraDependencies to add forbidden dependencies) + (config.system.build.toplevel.overrideAttrs (_: { extraDependencies = []; closureInfo = null; })) + ]; }; + }; + system.build.toplevel = system; }; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 70cd995ececa..b372ae20480b 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -194,6 +194,7 @@ in { ergo = handleTest ./ergo.nix {}; ergochat = handleTest ./ergochat.nix {}; etc = pkgs.callPackage ../modules/system/etc/test.nix { inherit evalMinimalConfig; }; + activation = pkgs.callPackage ../modules/system/activation/test.nix { }; etcd = handleTestOn ["x86_64-linux"] ./etcd.nix {}; etcd-cluster = handleTestOn ["x86_64-linux"] ./etcd-cluster.nix {}; etebase-server = handleTest ./etebase-server.nix {};