diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index e4d5906bdab6..7b8fe43f4e7d 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -605,6 +605,31 @@ struct EvalSettings : Config builds to take place. )"}; + // TODO: (RFC 92) Add dynamic derivations as a use case here. Review the final assertion about non-buildable paths. + Setting enableStorePathReferences{ + this, true, "allow-store-path-references", + R"( + Whether to allow references to store paths in the Nix language. + + Usually, store paths are created by adding files to the store and + by using the `derivation` primitive. However, the `storePath` + primitive allows you to merely assert that a store path exists or + can be substituted, and allows you to use it in subsequent expressions. + + This lets you use pre-built derivations, such as pre-built packages + that are passed into a NixOS VM test or closed source software that + is built and distributed with Nix. + + However, unlike most expressions, it does not inherently provide a + means of obtaining, modifying and rebuilding the store path. + Unless these needs are covered by some process outside the current + evaluation context, use of this primitive suggests a lack of + reproducibility. You may disable this option to enforce that all + store paths are created by the current Nix evaluator. This ensures + that any non-reproducible content in your closure comes from + individual local files, built-in fetchers, or fixed-output derivations. + )"}; + Setting allowedUris{this, {}, "allowed-uris", R"( A list of URI prefixes to which access is allowed in restricted diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 7003c3d896b2..ca849c44ac4d 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1449,8 +1449,9 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Path path = state.coerceToPath(pos, *args[0], context, "while evaluating the argument of builtins.storePath"); /* The following branch permits a dependency on a store path to be declared, - but in restrict-eval, extending the allowed paths would not be desirable. */ - if (evalSettings.pureEval && !evalSettings.restrictEval) { + but in restrict-eval, extending the allowed paths would not be desirable + regardless. */ + if (evalSettings.pureEval && evalSettings.enableStorePathReferences && !evalSettings.restrictEval) { /* Reading from the store behaves like a pure function, but we want to be careful about symlink resolution, which would otherwise be done diff --git a/src/libexpr/primops/fetchClosure.cc b/src/libexpr/primops/fetchClosure.cc index 0dfa97fa33aa..21980feef959 100644 --- a/src/libexpr/primops/fetchClosure.cc +++ b/src/libexpr/primops/fetchClosure.cc @@ -103,12 +103,12 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg toPath = fromPath; } - /* In pure mode, require a CA path. */ - if (evalSettings.pureEval) { + /* In pure mode without enable-store-path-references, require a CA path. */ + if (evalSettings.pureEval && !evalSettings.enableStorePathReferences) { auto info = state.store->queryPathInfo(*toPath); if (!info->isContentAddressed(*state.store)) throw Error({ - .msg = hintfmt("in pure mode, 'fetchClosure' requires a content-addressed path, which '%s' isn't", + .msg = hintfmt("in pure mode, with option 'enable-store-path-references' disabled, 'fetchClosure' requires a content-addressed path, which '%s' isn't", state.store->printStorePath(*toPath)), .errPos = state.positions[pos] });