From f986f7e89bd5d97a20933007f187bcbdcc52e309 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 13 Dec 2024 16:49:48 +0100 Subject: [PATCH] EvalState::realiseContext(): Allow access to the entire closure Fixes #11030. (cherry picked from commit 08361f031d65703aa35cb3b7e7715ff63256e311) # Conflicts: # src/libexpr/eval.cc # tests/functional/import-from-derivation.nix # tests/functional/import-from-derivation.sh --- src/libexpr/eval.cc | 14 ++++++ src/libexpr/eval.hh | 5 ++ src/libexpr/primops.cc | 8 ++- tests/functional/import-from-derivation.nix | 52 +++++++++++++++++++ tests/functional/import-from-derivation.sh | 55 +++++++++++++++++++++ 5 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 tests/functional/import-from-derivation.nix create mode 100755 tests/functional/import-from-derivation.sh diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 0bb1a5ea6..823fb4ce7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -379,6 +379,16 @@ void EvalState::allowPath(const StorePath & storePath) rootFS2->allowPrefix(CanonPath(store->toRealPath(storePath))); } +void EvalState::allowClosure(const StorePath & storePath) +{ + if (!rootFS.dynamic_pointer_cast()) return; + + StorePathSet closure; + store->computeFSClosure(storePath, closure); + for (auto & p : closure) + allowPath(p); +} + void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value & v) { allowPath(storePath); @@ -3113,10 +3123,14 @@ std::optional EvalState::resolveLookupPathPath(const LookupPath::Pa allowPath(path); if (store->isInStore(path)) { try { +<<<<<<< HEAD StorePathSet closure; store->computeFSClosure(store->toStorePath(path).first, closure); for (auto & p : closure) allowPath(p); +======= + allowClosure(store->toStorePath(path.path.abs()).first); +>>>>>>> 08361f031 (EvalState::realiseContext(): Allow access to the entire closure) } catch (InvalidPath &) { } } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index ddf5dcf94..8b3d34601 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -392,6 +392,11 @@ public: */ void allowPath(const StorePath & storePath); + /** + * Allow access to the closure of a store path. + */ + void allowClosure(const StorePath & storePath); + /** * Allow access to a store path and return it as a string. */ diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 8536eb359..2b785a193 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -113,11 +113,9 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS if (store != buildStore) copyClosure(*buildStore, *store, outputsToCopyAndAllow); if (isIFD) { - for (auto & outputPath : outputsToCopyAndAllow) { - /* Add the output of this derivations to the allowed - paths. */ - allowPath(outputPath); - } + /* Allow access to the output closures of this derivation. */ + for (auto & outputPath : outputsToCopyAndAllow) + allowClosure(outputPath); } return res; diff --git a/tests/functional/import-from-derivation.nix b/tests/functional/import-from-derivation.nix new file mode 100644 index 000000000..770dd86cf --- /dev/null +++ b/tests/functional/import-from-derivation.nix @@ -0,0 +1,52 @@ +with import ; + +rec { + bar = mkDerivation { + name = "bar"; + builder = builtins.toFile "builder.sh" + '' + echo 'builtins.add 123 456' > $out + ''; + }; + + value = + # Test that pathExists can check the existence of /nix/store paths + assert builtins.pathExists bar; + import bar; + + result = mkDerivation { + name = "foo"; + builder = builtins.toFile "builder.sh" + '' + echo -n FOO${toString value} > $out + ''; + }; + + addPath = mkDerivation { + name = "add-path"; + src = builtins.filterSource (path: type: true) result; + builder = builtins.toFile "builder.sh" + '' + echo -n BLA$(cat $src) > $out + ''; + }; + + step1 = mkDerivation { + name = "step1"; + buildCommand = '' + mkdir -p $out + echo 'foo' > $out/bla + ''; + }; + + addPathExpr = mkDerivation { + name = "add-path"; + inherit step1; + buildCommand = '' + mkdir -p $out + echo "builtins.path { path = \"$step1\"; sha256 = \"7ptL+pnrZXnSa5hwwB+2SXTLkcSb5264WGGokN8OXto=\"; }" > $out/default.nix + ''; + }; + + importAddPathExpr = import addPathExpr; +} diff --git a/tests/functional/import-from-derivation.sh b/tests/functional/import-from-derivation.sh new file mode 100755 index 000000000..a00761235 --- /dev/null +++ b/tests/functional/import-from-derivation.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +source common.sh + +TODO_NixOS + +clearStoreIfPossible + +export NIX_PATH=config="${config_nix}" + +if nix-instantiate --readonly-mode ./import-from-derivation.nix -A result; then + echo "read-only evaluation of an imported derivation unexpectedly failed" + exit 1 +fi + +outPath=$(nix-build ./import-from-derivation.nix -A result --no-out-link) + +[ "$(cat "$outPath")" = FOO579 ] + +# Check that we can have access to the entire closure of a derivation output. +nix build --no-link --restrict-eval -I src=. -f ./import-from-derivation.nix importAddPathExpr -v + +# FIXME: the next tests are broken on CA. +if [[ -n "${NIX_TESTS_CA_BY_DEFAULT:-}" ]]; then + exit 0 +fi + +# Test filterSource on the result of a derivation. +outPath2=$(nix-build ./import-from-derivation.nix -A addPath --no-out-link) +[[ "$(cat "$outPath2")" = BLAFOO579 ]] + +# Test that IFD works with a chroot store. +if canUseSandbox; then + + store2="$TEST_ROOT/store2" + store2_url="$store2?store=$NIX_STORE_DIR" + + # Copy the derivation outputs to the chroot store to avoid having + # to actually build anything, as that would fail due to the lack + # of a shell in the sandbox. We only care about testing the IFD + # semantics. + for i in bar result addPath; do + nix copy --to "$store2_url" --no-check-sigs "$(nix-build ./import-from-derivation.nix -A "$i" --no-out-link)" + done + + clearStore + + outPath_check=$(nix-build ./import-from-derivation.nix -A result --no-out-link --store "$store2_url") + [[ "$outPath" = "$outPath_check" ]] + [[ ! -e "$outPath" ]] + [[ -e "$store2/nix/store/$(basename "$outPath")" ]] + + outPath2_check=$(nix-build ./import-from-derivation.nix -A addPath --no-out-link --store "$store2_url") + [[ "$outPath2" = "$outPath2_check" ]] +fi