diff --git a/doc/manual/rl-next/keep-env-derivations-for-nix3.md b/doc/manual/rl-next/keep-env-derivations-for-nix3.md new file mode 100644 index 000000000..a0009cb20 --- /dev/null +++ b/doc/manual/rl-next/keep-env-derivations-for-nix3.md @@ -0,0 +1,13 @@ +--- +synopsis: "keep-env-derivations is now supported for nix3 CLI (nix profile)" +cls: [5332] +issues: [fj#1095] +category: "Features" +credits: [raito] +--- + +The `keep-env-derivations` feature is now available for `nix profile`. This allows users to prevent the garbage collection of derivations used to install a profile, even when `keep-derivations = false` (set to `true` by default). + +Previously, `nix-env` supported this feature, but `nix profile` **never** did. This caused issues when garbage collection removed the associated `.drv` files, which are required, for example, by vulnerability management tools (e.g. [vulnix](https://github.com/nix-community/vulnix)) for proper operation. + +This issue has now been resolved. diff --git a/lix/libcmd/cmd-profiles.cc b/lix/libcmd/cmd-profiles.cc index e41b37d37..8dc00f19b 100644 --- a/lix/libcmd/cmd-profiles.cc +++ b/lix/libcmd/cmd-profiles.cc @@ -98,6 +98,10 @@ void ProfileElement::updateStorePaths( for (auto & output : bfd.outputs) { storePaths.insert(output.second); } + + if (settings.envKeepDerivations) { + storePaths.insert(bfd.drvPath.path); + } }, }, buildable.raw() diff --git a/tests/functional2/cli/test_profile.py b/tests/functional2/cli/test_profile.py index cdca0df4d..2cb22c7da 100644 --- a/tests/functional2/cli/test_profile.py +++ b/tests/functional2/cli/test_profile.py @@ -2,6 +2,7 @@ import re import json import pytest from textwrap import dedent +from pathlib import Path from testlib.fixtures.file_helper import File, with_files from testlib.fixtures.nix import Nix @@ -279,3 +280,39 @@ def test_conflict_resolution_cppnix_8284(nix: Nix): expr = f'(builtins.getFlake "./flake2").packages.{system}.default' nix.nix(["profile", "install", "--impure", "--expr", expr]).run().expect(1) + + +class TestKeepEnvDerivations: + @with_files({"flake1": flake}) + def test_keep_derivations_enabled(self, nix: Nix, env: ManagedEnv): + nix.settings["keep-env-derivations"] = "true" + nix.settings["keep-derivations"] = "false" # NOTE: This defaults to `true`. + + nix.nix(["profile", "install", "./flake1", "-L"]).run().ok() + assert run_hello(env) == "Hello World\n" + res = nix.nix(["eval", "--raw", "./flake1#default.drvPath"]).run().ok() + drv_path = Path(res.stdout_s.strip()) + + assert drv_path.exists() + + # The derivation should NOT be collected because `keep-env-derivations` is true + nix.nix(["store", "gc"]).run().ok() + + assert drv_path.exists() + + @with_files({"flake1": flake}) + def test_keep_derivations_disabled(self, nix: Nix, env: ManagedEnv): + nix.settings["keep-derivations"] = "false" # NOTE: This defaults to `true` + + nix.nix(["profile", "install", "./flake1", "-L"]).run().ok() + assert run_hello(env) == "Hello World\n" + + res = nix.nix(["eval", "--raw", "./flake1#default.drvPath"]).run().ok() + drv_path = Path(res.stdout_s.strip()) + + assert drv_path.exists() + + # The derivation should be collected because `keep-env-derivations` is false AND `keep-derivations` is false. + res = nix.nix(["store", "gc"]).run().ok() + + assert not drv_path.exists()