diff --git a/src/libstore/build.cc b/src/libstore/build.cc index cf4218a26..676ad5856 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -3310,6 +3310,7 @@ void DerivationGoal::checkOutputs(const std::map & outputs) struct Checks { + bool ignoreSelfRefs = false; std::experimental::optional maxSize, maxClosureSize; std::experimental::optional allowedReferences, allowedRequisites, disallowedReferences, disallowedRequisites; }; @@ -3345,35 +3346,6 @@ void DerivationGoal::checkOutputs(const std::map & outputs) return std::make_pair(pathsDone, closureSize); }; - auto checkRefs = [&](const std::experimental::optional & value, bool allowed, bool recursive) - { - if (!value) return; - - PathSet spec = parseReferenceSpecifiers(worker.store, *drv, *value); - - PathSet used = recursive ? getClosure(info.path).first : info.references; - - PathSet badPaths; - - for (auto & i : used) - if (allowed) { - if (spec.find(i) == spec.end()) - badPaths.insert(i); - } else { - if (spec.find(i) != spec.end()) - badPaths.insert(i); - } - - if (!badPaths.empty()) { - string badPathsStr; - for (auto & i : badPaths) { - badPathsStr += "\n "; - badPathsStr += i; - } - throw BuildError("output '%s' is not allowed to refer to the following paths:%s", info.path, badPathsStr); - } - }; - auto applyChecks = [&](const Checks & checks) { if (checks.maxSize && info.narSize > *checks.maxSize) @@ -3387,6 +3359,38 @@ void DerivationGoal::checkOutputs(const std::map & outputs) info.path, closureSize, *checks.maxClosureSize); } + auto checkRefs = [&](const std::experimental::optional & value, bool allowed, bool recursive) + { + if (!value) return; + + PathSet spec = parseReferenceSpecifiers(worker.store, *drv, *value); + + PathSet used = recursive ? getClosure(info.path).first : info.references; + + if (recursive && checks.ignoreSelfRefs) + used.erase(info.path); + + PathSet badPaths; + + for (auto & i : used) + if (allowed) { + if (!spec.count(i)) + badPaths.insert(i); + } else { + if (spec.count(i)) + badPaths.insert(i); + } + + if (!badPaths.empty()) { + string badPathsStr; + for (auto & i : badPaths) { + badPathsStr += "\n "; + badPathsStr += i; + } + throw BuildError("output '%s' is not allowed to refer to the following paths:%s", info.path, badPathsStr); + } + }; + checkRefs(checks.allowedReferences, true, false); checkRefs(checks.allowedRequisites, true, true); checkRefs(checks.disallowedReferences, false, false); @@ -3435,6 +3439,7 @@ void DerivationGoal::checkOutputs(const std::map & outputs) } else { // legacy non-structured-attributes case Checks checks; + checks.ignoreSelfRefs = true; checks.allowedReferences = parsedDrv->getStringsAttr("allowedReferences"); checks.allowedRequisites = parsedDrv->getStringsAttr("allowedRequisites"); checks.disallowedReferences = parsedDrv->getStringsAttr("disallowedReferences"); diff --git a/tests/check-refs.sh b/tests/check-refs.sh index 34ee22cfc..16bbabc40 100644 --- a/tests/check-refs.sh +++ b/tests/check-refs.sh @@ -1,5 +1,7 @@ source common.sh +clearStore + RESULT=$TEST_ROOT/result dep=$(nix-build -o $RESULT check-refs.nix -A dep) diff --git a/tests/check-reqs.nix b/tests/check-reqs.nix index 47b5b3d9c..41436cb48 100644 --- a/tests/check-reqs.nix +++ b/tests/check-reqs.nix @@ -33,7 +33,7 @@ rec { }; # When specifying all the requisites, the build succeeds. - test1 = makeTest 1 [ "out" dep1 dep2 deps ]; + test1 = makeTest 1 [ dep1 dep2 deps ]; # But missing anything it fails. test2 = makeTest 2 [ dep2 deps ]; diff --git a/tests/check-reqs.sh b/tests/check-reqs.sh index 77689215d..e9f65fc2a 100644 --- a/tests/check-reqs.sh +++ b/tests/check-reqs.sh @@ -1,5 +1,7 @@ source common.sh +clearStore + RESULT=$TEST_ROOT/result nix-build -o $RESULT check-reqs.nix -A test1