nix3/develop: support structured attrs-based output checks

nix develop should ignore output checks in general.

This was done only for the old way of specifying output checks, the
structured attrs way requires rewriting the JSON and removing the output
checks pieces.

We take a brutal approach of removing as many as possible including
non-recommended ways of doing it.

Fixes #997.

Change-Id: Iaf83029016c71b5171e56e15d4eadc1a60a8be98
Signed-off-by: Raito Bezarius <raito@lix.systems>
(cherry picked from commit 992c3ae981)
This commit is contained in:
Raito Bezarius
2025-10-08 16:25:03 +00:00
parent 9bfef6a06c
commit 75c0314204
2 changed files with 46 additions and 0 deletions
@@ -0,0 +1,29 @@
---
synopsis: "Fix nix develop for derivations that rejects dependencies with structured attrs"
issues: [fj#997]
cls: [4182, 4214]
category: Fixes
credits: [raito]
---
For the sake of concision, we refer to `disallowedReferences` in what follows,
but all output checks were equally fixed:
`{dis,}allowed{References,Requisites}`.
Derivations can define *output checks* to reject unwanted dependencies, such as
interpreters like `bash` or compilers like `gcc`. This can be done in two ways:
* **Legacy style**: `disallowedReferences = [ ... ]` in the environment.
* **Structured attrs**: `outputChecks.<output>.disallowedReferences = [ ... ]`,
typically used in `__json`.
Only the structured form supports derivations with multiple outputs.
`nix develop` internally rewrites derivations to create development shells. It
relied on the legacy `disallowedReferences`, and failed to honor the structured
variant. This led to broken shells in cases where `bashInteractive` was
explicitly disallowed using structured output checks, e.g. `nix develop
nixpkgs#systemd` after the "bash-less NixOS" changes.
This fix teaches `nix develop` to respect structured output checks, restoring
support for such derivations.
+17
View File
@@ -6,6 +6,7 @@
#include "lix/libstore/store-api.hh"
#include "lix/libstore/outputs-spec.hh"
#include "lix/libstore/derivations.hh"
#include "lix/libstore/parsed-derivations.hh"
#include "lix/libutil/async.hh"
#include "lix/libutil/json.hh"
#include "run.hh"
@@ -214,6 +215,8 @@ const static std::string getEnvSh =
static kj::Promise<Result<StorePath>> getDerivationEnvironment(ref<Store> store, ref<Store> evalStore, const StorePath & drvPath)
try {
auto drv = TRY_AWAIT(evalStore->derivationFromPath(drvPath));
ParsedDerivation parsedDrv(drvPath, drv);
JSON updatedStructuredAttrs;
auto builder = baseNameOf(drv.builder);
if (builder != "bash")
@@ -230,6 +233,20 @@ try {
drv.env.erase("disallowedRequisites");
drv.env.erase("name");
/* Remove output checks in structured attrs. */
if (auto structuredAttrs = parsedDrv.getStructuredAttrs()) {
drv.env.erase("__json");
updatedStructuredAttrs = *structuredAttrs;
updatedStructuredAttrs.erase("allowedReferences");
updatedStructuredAttrs.erase("allowedRequisites");
updatedStructuredAttrs.erase("disallowedReferences");
updatedStructuredAttrs.erase("disallowedRequisites");
updatedStructuredAttrs.erase("maxSize");
updatedStructuredAttrs.erase("maxClosureSize");
updatedStructuredAttrs.erase("outputChecks");
drv.env.emplace("__json", updatedStructuredAttrs.dump());
}
/* Rehash and write the derivation. FIXME: would be nice to use
'buildDerivation', but that's privileged. */
drv.name += "-env";