From aa74c7b0bcd31a6c0f75f5fa09f417bcbef4ad14 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 17 Apr 2023 11:22:31 -0400 Subject: [PATCH] Gate experimental features in `DerivationOutput::fromJSON` This is an entry point for outside data, so we need to check enabled experimental features here. --- src/libstore/derivations.cc | 5 +++- src/libstore/derivations.hh | 6 ++++- src/libstore/tests/derivation.cc | 42 +++++++++++++++++++++++++------- tests/ca/derivation-json.sh | 3 +++ tests/impure-derivations.sh | 9 +++++++ 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index 0de36504b..15f3908ed 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -989,7 +989,8 @@ nlohmann::json DerivationOutput::toJSON( DerivationOutput DerivationOutput::fromJSON( const Store & store, std::string_view drvName, std::string_view outputName, - const nlohmann::json & _json) + const nlohmann::json & _json, + const ExperimentalFeatureSettings & xpSettings) { std::set keys; auto json = (std::map) _json; @@ -1028,6 +1029,7 @@ DerivationOutput DerivationOutput::fromJSON( } else if (keys == (std::set { "hashAlgo" })) { + xpSettings.require(Xp::CaDerivations); auto [method, hashType] = methodAlgo(); return DerivationOutput::CAFloating { .method = method, @@ -1040,6 +1042,7 @@ DerivationOutput DerivationOutput::fromJSON( } else if (keys == (std::set { "hashAlgo", "impure" })) { + xpSettings.require(Xp::ImpureDerivations); auto [method, hashType] = methodAlgo(); return DerivationOutput::Impure { .method = method, diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index ccdde36ca..d00b23b6d 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -136,11 +136,15 @@ struct DerivationOutput : _DerivationOutputRaw const Store & store, std::string_view drvName, std::string_view outputName) const; + /** + * @param xpSettings Stop-gap to avoid globals during unit tests. + */ static DerivationOutput fromJSON( const Store & store, std::string_view drvName, std::string_view outputName, - const nlohmann::json & json); + const nlohmann::json & json, + const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings); }; typedef std::map DerivationOutputs; diff --git a/src/libstore/tests/derivation.cc b/src/libstore/tests/derivation.cc index 80ee52fd0..6f94904dd 100644 --- a/src/libstore/tests/derivation.cc +++ b/src/libstore/tests/derivation.cc @@ -1,6 +1,7 @@ #include #include +#include "experimental-features.hh" #include "derivations.hh" #include "tests/libstore.hh" @@ -9,10 +10,32 @@ namespace nix { class DerivationTest : public LibStoreTest { +public: + /** + * We set these in tests rather than the regular globals so we don't have + * to worry about race conditions if the tests run concurrently. + */ + ExperimentalFeatureSettings mockXpSettings; }; -#define TEST_JSON(NAME, STR, VAL, DRV_NAME, OUTPUT_NAME) \ - TEST_F(DerivationTest, DerivationOutput_ ## NAME ## _to_json) { \ +class CaDerivationTest : public DerivationTest +{ + void SetUp() override + { + mockXpSettings.set("experimental-features", "ca-derivations"); + } +}; + +class ImpureDerivationTest : public DerivationTest +{ + void SetUp() override + { + mockXpSettings.set("experimental-features", "impure-derivations"); + } +}; + +#define TEST_JSON(FIXTURE, NAME, STR, VAL, DRV_NAME, OUTPUT_NAME) \ + TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _to_json) { \ using nlohmann::literals::operator "" _json; \ ASSERT_EQ( \ STR ## _json, \ @@ -22,7 +45,7 @@ class DerivationTest : public LibStoreTest OUTPUT_NAME)); \ } \ \ - TEST_F(DerivationTest, DerivationOutput_ ## NAME ## _from_json) { \ + TEST_F(FIXTURE, DerivationOutput_ ## NAME ## _from_json) { \ using nlohmann::literals::operator "" _json; \ ASSERT_EQ( \ DerivationOutput { VAL }, \ @@ -30,10 +53,11 @@ class DerivationTest : public LibStoreTest *store, \ DRV_NAME, \ OUTPUT_NAME, \ - STR ## _json)); \ + STR ## _json, \ + mockXpSettings)); \ } -TEST_JSON(inputAddressed, +TEST_JSON(DerivationTest, inputAddressed, R"({ "path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name" })", @@ -42,7 +66,7 @@ TEST_JSON(inputAddressed, }), "drv-name", "output-name") -TEST_JSON(caFixed, +TEST_JSON(DerivationTest, caFixed, R"({ "hashAlgo": "r:sha256", "hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f", @@ -56,7 +80,7 @@ TEST_JSON(caFixed, }), "drv-name", "output-name") -TEST_JSON(caFloating, +TEST_JSON(CaDerivationTest, caFloating, R"({ "hashAlgo": "r:sha256" })", @@ -66,12 +90,12 @@ TEST_JSON(caFloating, }), "drv-name", "output-name") -TEST_JSON(deferred, +TEST_JSON(DerivationTest, deferred, R"({ })", DerivationOutput::Deferred { }, "drv-name", "output-name") -TEST_JSON(impure, +TEST_JSON(ImpureDerivationTest, impure, R"({ "hashAlgo": "r:sha256", "impure": true diff --git a/tests/ca/derivation-json.sh b/tests/ca/derivation-json.sh index 3615177e9..c1480fd17 100644 --- a/tests/ca/derivation-json.sh +++ b/tests/ca/derivation-json.sh @@ -16,6 +16,9 @@ drvPath3=$(nix derivation add --dry-run < $TEST_HOME/foo.json) # With --dry-run nothing is actually written [[ ! -e "$drvPath3" ]] +# But the JSON is rejected without the experimental feature +expectStderr 1 nix derivation add < $TEST_HOME/foo.json --experimental-features nix-command | grepQuiet "experimental Nix feature 'ca-derivations' is disabled" + # Without --dry-run it is actually written drvPath4=$(nix derivation add < $TEST_HOME/foo.json) [[ "$drvPath4" = "$drvPath3" ]] diff --git a/tests/impure-derivations.sh b/tests/impure-derivations.sh index c7dadf397..39d053a04 100644 --- a/tests/impure-derivations.sh +++ b/tests/impure-derivations.sh @@ -10,6 +10,15 @@ clearStore # Basic test of impure derivations: building one a second time should not use the previous result. printf 0 > $TEST_ROOT/counter +# `nix derivation add` with impure derivations work +drvPath=$(nix-instantiate ./impure-derivations.nix -A impure) +nix derivation show $drvPath | jq .[] > $TEST_HOME/impure-drv.json +drvPath2=$(nix derivation add < $TEST_HOME/impure-drv.json) +[[ "$drvPath" = "$drvPath2" ]] + +# But only with the experimental feature! +expectStderr 1 nix derivation add < $TEST_HOME/impure-drv.json --experimental-features nix-command | grepQuiet "experimental Nix feature 'impure-derivations' is disabled" + nix build --dry-run --json --file ./impure-derivations.nix impure.all json=$(nix build -L --no-link --json --file ./impure-derivations.nix impure.all) path1=$(echo $json | jq -r .[].outputs.out)