libcmd/profiles: keep derivations if keep-env-derivations = true

nix3 CLI never honored that setting.

When we update a nix3 profile element with new built store paths for
which we know the deriver (the derivation path which built it), we add
the derivation paths to the profile element to prevent garbage
collection the same way the nix2 CLI logic does.

Fixes #1095.

Change-Id: Icc236d174c5ce5ffe042d1c8e1968f6cb5b50359
Signed-off-by: Raito Bezarius <raito@lix.systems>
This commit is contained in:
Raito Bezarius
2026-03-03 22:13:02 +00:00
parent fc649250ec
commit e8015836e3
3 changed files with 54 additions and 0 deletions
@@ -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.
+4
View File
@@ -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()
+37
View File
@@ -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()