Introduce allowedRequisites feature

This commit is contained in:
Gergely Risko 2014-08-27 16:46:02 +02:00 committed by Eelco Dolstra
parent 3f0a4bf0e7
commit fd61069a42
6 changed files with 108 additions and 2 deletions

View file

@ -11,6 +11,20 @@
<para>TODO</para>
<itemizedlist>
<listitem><para>Derivations can specify the new special attribute
<varname>allowedRequisites</varname>, which has a similar meaning to
<varname>allowedReferences</varname>. But instead of only enforcing
to explicitly specify the immediate references, it requires the
derivation to specify all the dependencies recursively (hence the
name, requisites) that are used by the resulting output. This is
used in NixOS when rebuilding the stdenv on Linux to ensure that the
resulting stdenv doesn't have any surprising dependency, e.g. on
bootstrapTools.</para></listitem>
</itemizedlist>
</section>

View file

@ -1569,6 +1569,25 @@ allowedReferences = [];
</varlistentry>
<varlistentry><term><varname>allowedRequisites</varname></term>
<listitem><para>This attribute is similar to
<varname>allowedReferences</varname>, but it specifies the legal
requisites of the whole closure, so all the dependencies
recursively. For example,
<programlisting>
allowedReferences = [ foobar ];
</programlisting>
enforces that the output of a derivation cannot have any other
runtime dependency than <varname>foobar</varname>, and in addition
it enforces that <varname>foobar</varname> itself doesn't
introduce any other dependency itself. This is used in NixOS when
rebuilding the stdenv on Linux to ensure that the resulting stdenv
doesn't have any surprising dependency, e.g. on bootstrapTools.
</varlistentry>
<varlistentry><term><varname>exportReferencesGraph</varname></term>

View file

@ -2326,7 +2326,24 @@ void DerivationGoal::registerOutputs()
PathSet allowed = parseReferenceSpecifiers(drv, get(drv.env, "allowedReferences"));
foreach (PathSet::iterator, i, references)
if (allowed.find(*i) == allowed.end())
throw BuildError(format("output is not allowed to refer to path %1%") % *i);
throw BuildError(format("output (%1%) is not allowed to refer to path %2%") % actualPath % *i);
}
/* If the derivation specifies an `allowedRequisites'
attribute (containing a list of paths that the output may
refer to), check that all requisites are in that list. !!!
allowedRequisites should really be per-output. */
if (drv.env.find("allowedRequisites") != drv.env.end()) {
PathSet allowed = parseReferenceSpecifiers(drv, get(drv.env, "allowedRequisites"));
PathSet requisites;
/* Our requisites are the union of the closures of our references. */
foreach (PathSet::iterator, i, references)
/* Don't call computeFSClosure on ourselves. */
if (actualPath != *i)
computeFSClosure(worker.store, *i, requisites);
foreach (PathSet::iterator, i, requisites)
if (allowed.find(*i) == allowed.end())
throw BuildError(format("output (%1%) is not allowed to refer to requisite path %2%") % actualPath % *i);
}
worker.store.optimisePath(path); // FIXME: combine with scanForReferences()

43
tests/check-reqs.nix Normal file
View file

@ -0,0 +1,43 @@
with import ./config.nix;
rec {
dep1 = mkDerivation {
name = "check-reqs-dep1";
builder = builtins.toFile "builder.sh" "mkdir $out; touch $out/file1";
};
dep2 = mkDerivation {
name = "check-reqs-dep2";
builder = builtins.toFile "builder.sh" "mkdir $out; touch $out/file2";
};
deps = mkDerivation {
name = "check-reqs-deps";
dep1 = dep1;
dep2 = dep2;
builder = builtins.toFile "builder.sh" ''
mkdir $out
ln -s $dep1/file1 $out/file1
ln -s $dep2/file2 $out/file2
'';
};
makeTest = nr: allowreqs: mkDerivation {
name = "check-reqs-" + toString nr;
inherit deps;
builder = builtins.toFile "builder.sh" ''
mkdir $out
ln -s $deps $out/depdir1
'';
allowedRequisites = allowreqs;
};
# When specifying all the requisites, the build succeeds.
test1 = makeTest 1 [ dep1 dep2 deps ];
# But missing anything it fails.
test2 = makeTest 2 [ dep2 deps ];
test3 = makeTest 3 [ dep1 deps ];
test4 = makeTest 4 [ deps ];
test5 = makeTest 5 [];
}

12
tests/check-reqs.sh Normal file
View file

@ -0,0 +1,12 @@
source common.sh
RESULT=$TEST_ROOT/result
# test1 should succeed.
nix-build -o $RESULT check-reqs.nix -A test1
# test{2,3,4,5} should fail.
(! nix-build -o $RESULT check-reqs.nix -A test2)
(! nix-build -o $RESULT check-reqs.nix -A test3)
(! nix-build -o $RESULT check-reqs.nix -A test4)
(! nix-build -o $RESULT check-reqs.nix -A test5)

View file

@ -10,7 +10,8 @@ nix_tests = \
remote-store.sh export.sh export-graph.sh negative-caching.sh \
binary-patching.sh timeout.sh secure-drv-outputs.sh nix-channel.sh \
multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \
binary-cache.sh nix-profile.sh repair.sh dump-db.sh case-hack.sh
binary-cache.sh nix-profile.sh repair.sh dump-db.sh case-hack.sh \
check-reqs.sh
# parallel.sh
install-tests += $(foreach x, $(nix_tests), tests/$(x))