about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--configure.ac1
-rw-r--r--doc/manual/command-ref/nix-channel.xml4
-rw-r--r--doc/manual/expressions/advanced-attributes.xml73
-rw-r--r--doc/manual/expressions/language-values.xml9
-rw-r--r--perl/lib/Nix/Manifest.pm7
-rw-r--r--release.nix4
-rw-r--r--scripts/download-from-binary-cache.pl.in4
-rwxr-xr-xscripts/nix-build.in13
-rwxr-xr-xscripts/nix-push.in2
-rw-r--r--src/libexpr/eval.cc3
-rw-r--r--src/libexpr/lexer.l2
-rw-r--r--src/libexpr/parser.y4
-rw-r--r--src/libstore/build.cc55
-rw-r--r--src/nix-store/nix-store.cc12
-rw-r--r--tests/binary-cache.sh16
-rw-r--r--tests/local.mk2
-rw-r--r--tests/pass-as-file.sh17
-rw-r--r--tests/remote-builds.nix1
19 files changed, 168 insertions, 63 deletions
diff --git a/Makefile b/Makefile
index 08e4012f99b2..d8d4a7cc5768 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ makefiles = \
 
 GLOBAL_CXXFLAGS += -std=c++0x -g -Wall
 
-include Makefile.config
+-include Makefile.config
 
 OPTIMIZE = 1
 
diff --git a/configure.ac b/configure.ac
index be77975bd3ab..756b2f22729c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,7 @@ AC_CHECK_HEADERS([sys/mount.h], [], [],
 # include <sys/param.h>
 # endif
 ])
+AC_CHECK_HEADERS([sys/syscall.h])
 
 
 # Check for lutimes, optionally used for changing the mtime of
diff --git a/doc/manual/command-ref/nix-channel.xml b/doc/manual/command-ref/nix-channel.xml
index 531b41fc0902..a6f4a27203ac 100644
--- a/doc/manual/command-ref/nix-channel.xml
+++ b/doc/manual/command-ref/nix-channel.xml
@@ -129,7 +129,7 @@ $ nix-instantiate --eval -E '(import &lt;nixpkgs> {}).lib.nixpkgsVersion'
 
 <variablelist>
 
-  <varlistentry><term><filename>/nix/var/nix/profiles/<replaceable>username</replaceable>/channels</filename></term>
+  <varlistentry><term><filename>/nix/var/nix/profiles/per-user/<replaceable>username</replaceable>/channels</filename></term>
 
     <listitem><para><command>nix-channel</command> uses a
     <command>nix-env</command> profile to keep track of previous
@@ -144,7 +144,7 @@ $ nix-instantiate --eval -E '(import &lt;nixpkgs> {}).lib.nixpkgsVersion'
   <varlistentry><term><filename>~/.nix-defexpr/channels</filename></term>
 
     <listitem><para>This is a symlink to
-    <filename>/nix/var/nix/profiles/<replaceable>username</replaceable>/channels</filename>. It
+    <filename>/nix/var/nix/profiles/per-user/<replaceable>username</replaceable>/channels</filename>. It
     ensures that <command>nix-env</command> can find your channels. In
     a multi-user installation, you may also have
     <filename>~/.nix-defexpr/channels_root</filename>, which links to
diff --git a/doc/manual/expressions/advanced-attributes.xml b/doc/manual/expressions/advanced-attributes.xml
index d476d613e462..83ad6eefc8b1 100644
--- a/doc/manual/expressions/advanced-attributes.xml
+++ b/doc/manual/expressions/advanced-attributes.xml
@@ -90,6 +90,33 @@ derivation {
   </varlistentry>
 
 
+  <varlistentry><term><varname>impureEnvVars</varname></term>
+
+    <listitem><para>This attribute allows you to specify a list of
+    environment variables that should be passed from the environment
+    of the calling user to the builder.  Usually, the environment is
+    cleared completely when the builder is executed, but with this
+    attribute you can allow specific environment variables to be
+    passed unmodified.  For example, <function>fetchurl</function> in
+    Nixpkgs has the line
+
+<programlisting>
+impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
+</programlisting>
+
+    to make it use the proxy server configuration specified by the
+    user in the environment variables <envar>http_proxy</envar> and
+    friends.</para>
+
+    <para>This attribute is only allowed in <link
+    linkend="fixed-output-drvs">fixed-output derivations</link>, where
+    impurities such as these are okay since (the hash of) the output
+    is known in advance.  It is ignored for all other
+    derivations.</para></listitem>
+
+  </varlistentry>
+
+
   <varlistentry xml:id="fixed-output-drvs">
     <term><varname>outputHash</varname></term>
     <term><varname>outputHashAlgo</varname></term>
@@ -215,29 +242,29 @@ stdenv.mkDerivation {
   </varlistentry>
 
 
-  <varlistentry><term><varname>impureEnvVars</varname></term>
-
-    <listitem><para>This attribute allows you to specify a list of
-    environment variables that should be passed from the environment
-    of the calling user to the builder.  Usually, the environment is
-    cleared completely when the builder is executed, but with this
-    attribute you can allow specific environment variables to be
-    passed unmodified.  For example, <function>fetchurl</function> in
-    Nixpkgs has the line
-
-<programlisting>
-impureEnvVars = [ "http_proxy" "https_proxy" <replaceable>...</replaceable> ];
-</programlisting>
-
-    to make it use the proxy server configuration specified by the
-    user in the environment variables <envar>http_proxy</envar> and
-    friends.</para>
-
-    <para>This attribute is only allowed in <link
-    linkend="fixed-output-drvs">fixed-output derivations</link>, where
-    impurities such as these are okay since (the hash of) the output
-    is known in advance.  It is ignored for all other
-    derivations.</para></listitem>
+  <varlistentry><term><varname>passAsFile</varname></term>
+
+    <listitem><para>A list of names of attributes that should be
+    passed via files rather than environment variables.  For example,
+    if you have
+
+    <programlisting>
+passAsFile = ["big"];
+big = "a very long string";
+    </programlisting>
+
+    then when the builder runs, the environment variable
+    <envar>bigPath</envar> will contain the absolute path to a
+    temporary file containing <literal>a very long
+    string</literal>. That is, for any attribute
+    <replaceable>x</replaceable> listed in
+    <varname>passAsFile</varname>, Nix will pass an environment
+    variable <envar><replaceable>x</replaceable>Path</envar> holding
+    the path of the file containing the value of attribute
+    <replaceable>x</replaceable>. This is useful when you need to pass
+    large strings to a builder, since most operating systems impose a
+    limit on the size of the environment (typically, a few hundred
+    kilobyte).</para></listitem>
 
   </varlistentry>
 
diff --git a/doc/manual/expressions/language-values.xml b/doc/manual/expressions/language-values.xml
index c3514e58f0de..0bf6632d6e3a 100644
--- a/doc/manual/expressions/language-values.xml
+++ b/doc/manual/expressions/language-values.xml
@@ -155,7 +155,14 @@ stdenv.mkDerivation {
   expression that contained it.  For instance, if a Nix expression in
   <filename>/foo/bar/bla.nix</filename> refers to
   <filename>../xyzzy/fnord.nix</filename>, the absolute path is
-  <filename>/foo/xyzzy/fnord.nix</filename>.</para></listitem>
+  <filename>/foo/xyzzy/fnord.nix</filename>.</para>
+
+  <para>If the first component of a path is a <literal>~</literal>,
+  it is interpreted as if the rest of the path were relative to the
+  user's home directory. e.g. <filename>~/foo</filename> would be
+  equivalent to <filename>/home/edolstra/foo</filename> for a user
+  whose home directory is <filename>/home/edolstra</filename>.
+  </para></listitem>
 
   <listitem><para><emphasis>Booleans</emphasis> with values
   <literal>true</literal> and
diff --git a/perl/lib/Nix/Manifest.pm b/perl/lib/Nix/Manifest.pm
index b82c82fb253c..93c9c261ddc9 100644
--- a/perl/lib/Nix/Manifest.pm
+++ b/perl/lib/Nix/Manifest.pm
@@ -377,7 +377,6 @@ EOF
 }
 
 
-
 # Delete all old manifests downloaded from a given URL.
 sub deleteOldManifests {
     my ($url, $curUrlFile) = @_;
@@ -399,14 +398,14 @@ sub deleteOldManifests {
 # signatures. It contains the store path, the SHA-256 hash of the
 # contents of the path, and the references.
 sub fingerprintPath {
-    my ($storePath, $narHash, $references) = @_;
+    my ($storePath, $narHash, $narSize, $references) = @_;
     die if substr($storePath, 0, length($Nix::Config::storeDir)) ne $Nix::Config::storeDir;
     die if substr($narHash, 0, 7) ne "sha256:";
     die if length($narHash) != 59;
     foreach my $ref (@{$references}) {
         die if substr($ref, 0, length($Nix::Config::storeDir)) ne $Nix::Config::storeDir;
     }
-    return "1;" . $storePath . ";" . $narHash . ";" . join(",", @{$references});
+    return "1;" . $storePath . ";" . $narHash . ";" . $narSize . ";" . join(",", @{$references});
 }
 
 
@@ -464,7 +463,7 @@ sub parseNARInfo {
         }
 
         my $fingerprint = fingerprintPath(
-            $storePath, $narHash,
+            $storePath, $narHash, $narSize,
             [ map { "$Nix::Config::storeDir/$_" } @refs ]);
 
         if (!checkSignature($publicKey, decode_base64($sig64), $fingerprint)) {
diff --git a/release.nix b/release.nix
index ff164ce57208..c5f700d8e776 100644
--- a/release.nix
+++ b/release.nix
@@ -183,6 +183,10 @@ let
       };
 
 
+    rpm_fedora18i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora18i386) [];
+    rpm_fedora18x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora18x86_64) [];
+    rpm_fedora19i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora19i386) [];
+    rpm_fedora19x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora19x86_64) [];
     rpm_fedora20i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora20i386) [];
     rpm_fedora20x86_64 = makeRPM_x86_64 (diskImageFunsFun: diskImageFunsFun.fedora20x86_64) [];
     rpm_fedora21i386 = makeRPM_i686 (diskImageFuns: diskImageFuns.fedora21i386) [ "libsodium-devel" ];
diff --git a/scripts/download-from-binary-cache.pl.in b/scripts/download-from-binary-cache.pl.in
index 4655f9ac9a0e..bb63eafca522 100644
--- a/scripts/download-from-binary-cache.pl.in
+++ b/scripts/download-from-binary-cache.pl.in
@@ -54,6 +54,10 @@ sub isTrue {
     return $x eq "true" || $x eq "1";
 }
 
+# FIXME: this should be cache URLs required to have valid signatures,
+# or "*" to require signatures on all binary caches.
+# FIXME: should binary caches using a key in
+# ‘binary-cache-public-keys’ be trusted by default?
 my $requireSignedBinaryCaches = ($Nix::Config::config{"signed-binary-caches"} // "0") ne "0";
 
 my $curlConnectTimeout = int(
diff --git a/scripts/nix-build.in b/scripts/nix-build.in
index 7e1f28870309..19de6feb6080 100755
--- a/scripts/nix-build.in
+++ b/scripts/nix-build.in
@@ -30,6 +30,7 @@ my $myName = $runEnv ? "nix-shell" : "nix-build";
 
 my $inShebang = 0;
 my $script;
+my @savedArgs;
 
 my $tmpDir = mkTempDir($myName);
 
@@ -43,13 +44,14 @@ $SIG{'INT'} = sub { exit 1 };
 # Heuristic to see if we're invoked as a shebang script, namely, if we
 # have a single argument, it's the name of an executable file, and it
 # starts with "#!".
-if ($runEnv && scalar @ARGV == 1) {
+if ($runEnv && $ARGV[0] !~ /nix-shell/) {
     $script = $ARGV[0];
     if (-f $script && -x $script) {
         open SCRIPT, "<$script" or die "$0: cannot open ‘$script’: $!\n";
         my $first = <SCRIPT>;
         if ($first =~ /^\#\!/) {
             $inShebang = 1;
+            @savedArgs = @ARGV; shift @savedArgs;
             @ARGV = ();
             while (<SCRIPT>) {
                 chomp;
@@ -193,7 +195,12 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
         # or (undocumented) argv[0] does not contain "perl". Exploit
         # the latter by doing "exec -a".
         my $execArgs = $interpreter =~ /perl/ ? "-a PERL" : "";
-        $envCommand = "exec $execArgs $interpreter $script";
+        sub shellEscape {
+            my $s = $_;
+            $s =~ s/'/'\\''/g;
+            return "'" . $s . "'";
+        }
+        $envCommand = "exec $execArgs $interpreter $script ${\(join ' ', (map shellEscape, @savedArgs))}";
     }
 
     elsif (substr($arg, 0, 1) eq "-") {
@@ -231,7 +238,7 @@ foreach my $expr (@exprs) {
         # If we're in a #! script, interpret filenames relative to the
         # script.
         $expr = dirname(Cwd::abs_path($script)) . "/" . $expr
-            if $inShebang && $expr !~ /^\//;
+            if $inShebang && !$packages && $expr !~ /^\//;
 
         # !!! would prefer the perl 5.8.0 pipe open feature here.
         my $pid = open(DRVPATHS, "-|") || exec "$Nix::Config::binDir/nix-instantiate", "--add-root", $drvLink, "--indirect", @instArgs, $expr;
diff --git a/scripts/nix-push.in b/scripts/nix-push.in
index a060ea128fd1..d5d3bc1e7e79 100755
--- a/scripts/nix-push.in
+++ b/scripts/nix-push.in
@@ -257,7 +257,7 @@ for (my $n = 0; $n < scalar @storePaths2; $n++) {
         chomp $s;
         my ($keyName, $secretKey) = split ":", $s;
         die "invalid secret key file ‘$secretKeyFile’\n" unless defined $keyName && defined $secretKey;
-        my $fingerprint = fingerprintPath($storePath, $narHash, $refs);
+        my $fingerprint = fingerprintPath($storePath, $narHash, $narSize, $refs);
         my $sig = encode_base64(signString(decode_base64($secretKey), $fingerprint), "");
         $info .= "Sig: $keyName:$sig\n";
     }
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 298f6a3a60e3..95b56e84d89a 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1174,7 +1174,8 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
     else if (firstType == tPath) {
         if (!context.empty())
             throwEvalError("a string that refers to a store path cannot be appended to a path, at %1%", pos);
-        mkPath(v, s.str().c_str());
+        auto path = canonPath(s.str());
+        mkPath(v, path.c_str());
     } else
         mkString(v, s.str(), context);
 }
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 82520ee7a59a..7051909008d1 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -80,6 +80,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
 ID          [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
 INT         [0-9]+
 PATH        [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+
+HPATH       \~(\/[a-zA-Z0-9\.\_\-\+]+)+
 SPATH       \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
 URI         [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
 
@@ -159,6 +160,7 @@ or          { return OR_KW; }
 <IND_STRING>.    return yytext[0]; /* just in case: shouldn't be reached */
 
 {PATH}      { yylval->path = strdup(yytext); return PATH; }
+{HPATH}     { yylval->path = strdup(yytext); return HPATH; }
 {SPATH}     { yylval->path = strdup(yytext); return SPATH; }
 {URI}       { yylval->uri = strdup(yytext); return URI; }
 
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 7d877cd67862..d70d29be8ba7 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -268,7 +268,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
 %token <id> ID ATTRPATH
 %token <e> STR IND_STR
 %token <n> INT
-%token <path> PATH SPATH
+%token <path> PATH HPATH SPATH
 %token <uri> URI
 %token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
 %token DOLLAR_CURLY /* == ${ */
@@ -286,7 +286,6 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
 %left '*' '/'
 %right CONCAT
 %nonassoc '?'
-%nonassoc '~'
 %nonassoc NEGATE
 
 %%
@@ -376,6 +375,7 @@ expr_simple
       $$ = stripIndentation(CUR_POS, data->symbols, *$2);
   }
   | PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
+  | HPATH { $$ = new ExprPath(getEnv("HOME", "") + string{$1 + 1}); }
   | SPATH {
       string path($1 + 1, strlen($1) - 2);
       $$ = new ExprApp(CUR_POS,
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 259324734fd1..e64bd3fef587 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -38,6 +38,9 @@
 #if HAVE_SYS_MOUNT_H
 #include <sys/mount.h>
 #endif
+#if HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
 #if HAVE_SCHED_H
 #include <sched.h>
 #endif
@@ -48,7 +51,7 @@
 #include <linux/fs.h>
 #endif
 
-#define CHROOT_ENABLED HAVE_CHROOT && HAVE_UNSHARE && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE) && defined(CLONE_NEWNS)
+#define CHROOT_ENABLED HAVE_CHROOT && HAVE_UNSHARE && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_PRIVATE) && defined(CLONE_NEWNS) && defined(SYS_pivot_root)
 
 /* chroot-like behavior from Apple's sandbox */
 #if __APPLE__
@@ -1643,14 +1646,26 @@ void DerivationGoal::startBuilder()
     /* The maximum number of cores to utilize for parallel building. */
     env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
 
-    /* Add all bindings specified in the derivation. */
-    foreach (StringPairs::iterator, i, drv.env)
-        env[i->first] = i->second;
-
     /* Create a temporary directory where the build will take
        place. */
     tmpDir = createTempDir("", "nix-build-" + storePathToName(drvPath), false, false, 0700);
 
+    /* Add all bindings specified in the derivation via the
+       environments, except those listed in the passAsFile
+       attribute. Those are passed as file names pointing to
+       temporary files containing the contents. */
+    StringSet passAsFile = tokenizeString<StringSet>(get(drv.env, "passAsFile"));
+    int fileNr = 0;
+    for (auto & i : drv.env) {
+        if (passAsFile.find(i.first) == passAsFile.end()) {
+            env[i.first] = i.second;
+        } else {
+            Path p = tmpDir + "/.attr-" + int2String(fileNr++);
+            writeFile(p, i.second);
+            env[i.first + "Path"] = p;
+        }
+    }
+
     /* For convenience, set an environment pointing to the top build
        directory. */
     env["NIX_BUILD_TOP"] = tmpDir;
@@ -2059,6 +2074,11 @@ void DerivationGoal::runChild()
                     throw SysError(format("unable to make filesystem ‘%1%’ private") % fs);
             }
 
+            /* Bind-mount chroot directory to itself, to treat it as a
+               different filesystem from /, as needed for pivot_root. */
+            if (mount(chrootRootDir.c_str(), chrootRootDir.c_str(), 0, MS_BIND, 0) == -1)
+                throw SysError(format("unable to bind mount ‘%1%’") % chrootRootDir);
+
             /* Set up a nearly empty /dev, unless the user asked to
                bind-mount the host /dev. */
             if (dirsInChroot.find("/dev") == dirsInChroot.end()) {
@@ -2130,13 +2150,26 @@ void DerivationGoal::runChild()
                 chmod_(chrootRootDir + "/dev/pts/ptmx", 0666);
             }
 
-            /* Do the chroot().  Below we do a chdir() to the
-               temporary build directory to make sure the current
-               directory is in the chroot.  (Actually the order
-               doesn't matter, since due to the bind mount tmpDir and
-               tmpRootDit/tmpDir are the same directories.) */
-            if (chroot(chrootRootDir.c_str()) == -1)
+            /* Do the chroot(). */
+            if (chdir(chrootRootDir.c_str()) == -1)
+                throw SysError(format("cannot change directory to ‘%1%’") % chrootRootDir);
+
+            if (mkdir("real-root", 0) == -1)
+                throw SysError("cannot create real-root directory");
+
+#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
+            if (pivot_root(".", "real-root") == -1)
+                throw SysError(format("cannot pivot old root directory onto ‘%1%’") % (chrootRootDir + "/real-root"));
+#undef pivot_root
+
+            if (chroot(".") == -1)
                 throw SysError(format("cannot change root directory to ‘%1%’") % chrootRootDir);
+
+            if (umount2("real-root", MNT_DETACH) == -1)
+                throw SysError("cannot unmount real root filesystem");
+
+            if (rmdir("real-root") == -1)
+                throw SysError("cannot remove real-root directory");
         }
 #endif
 
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index c16adf049628..7ce5f63c2d2f 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -1015,8 +1015,11 @@ static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
     foreach (Strings::iterator, i, opFlags)
         throw UsageError(format("unknown flag ‘%1%’") % *i);
 
-    if (opArgs.size() != 1) throw UsageError("one argument expected");
-    string keyName = opArgs.front();
+    if (opArgs.size() != 3) throw UsageError("three arguments expected");
+    auto i = opArgs.begin();
+    string keyName = *i++;
+    string secretKeyFile = *i++;
+    string publicKeyFile = *i++;
 
 #if HAVE_SODIUM
     sodium_init();
@@ -1026,8 +1029,9 @@ static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs)
     if (crypto_sign_keypair(pk, sk) != 0)
         throw Error("key generation failed");
 
-    std::cout << keyName << ":" << base64Encode(string((char *) pk, crypto_sign_PUBLICKEYBYTES)) << std::endl;
-    std::cout << keyName << ":" << base64Encode(string((char *) sk, crypto_sign_SECRETKEYBYTES)) << std::endl;
+    writeFile(publicKeyFile, keyName + ":" + base64Encode(string((char *) pk, crypto_sign_PUBLICKEYBYTES)));
+    umask(0077);
+    writeFile(secretKeyFile, keyName + ":" + base64Encode(string((char *) sk, crypto_sign_SECRETKEYBYTES)));
 #else
     throw Error("Nix was not compiled with libsodium, required for signed binary cache support");
 #endif
diff --git a/tests/binary-cache.sh b/tests/binary-cache.sh
index 753c2c466e6d..c72d2defa5d0 100644
--- a/tests/binary-cache.sh
+++ b/tests/binary-cache.sh
@@ -94,18 +94,16 @@ if [ -n "$HAVE_SODIUM" ]; then
 # Create a signed binary cache.
 clearCache
 
-declare -a res=($(nix-store --generate-binary-cache-key test.nixos.org-1))
-publicKey="${res[0]}"
-secretKey="${res[1]}"
-echo "$secretKey" > $TEST_ROOT/secret-key
+declare -a res=($(nix-store --generate-binary-cache-key test.nixos.org-1 $TEST_ROOT/sk1 $TEST_ROOT/pk1 ))
+publicKey="$(cat $TEST_ROOT/pk1)"
 
-res=($(nix-store --generate-binary-cache-key test.nixos.org-1))
-badKey="${res[0]}"
+res=($(nix-store --generate-binary-cache-key test.nixos.org-1 $TEST_ROOT/sk2 $TEST_ROOT/pk2))
+badKey="$(cat $TEST_ROOT/pk2)"
 
-res=($(nix-store --generate-binary-cache-key foo.nixos.org-1))
-otherKey="${res[0]}"
+res=($(nix-store --generate-binary-cache-key foo.nixos.org-1 $TEST_ROOT/sk3 $TEST_ROOT/pk3))
+otherKey="$(cat $TEST_ROOT/pk3)"
 
-nix-push --dest $cacheDir --key-file $TEST_ROOT/secret-key $outPath
+nix-push --dest $cacheDir --key-file $TEST_ROOT/sk1 $outPath
 
 
 # Downloading should fail if we don't provide a key.
diff --git a/tests/local.mk b/tests/local.mk
index 69a227495d94..7a24fadcb8b9 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -11,7 +11,7 @@ nix_tests = \
   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 \
-  check-reqs.sh
+  check-reqs.sh pass-as-file.sh
   # parallel.sh
 
 install-tests += $(foreach x, $(nix_tests), tests/$(x))
diff --git a/tests/pass-as-file.sh b/tests/pass-as-file.sh
new file mode 100644
index 000000000000..3dfe10baa235
--- /dev/null
+++ b/tests/pass-as-file.sh
@@ -0,0 +1,17 @@
+source common.sh
+
+clearStore
+
+outPath=$(nix-build --no-out-link -E "
+with import ./config.nix;
+
+mkDerivation {
+  name = \"pass-as-file\";
+  passAsFile = [ \"foo\" ];
+  foo = [ \"xyzzy\" ];
+  builder = builtins.toFile \"builder.sh\" ''
+    [ \"\$(cat \$fooPath)\" = xyzzy ]
+    touch \$out
+  '';
+}
+")
diff --git a/tests/remote-builds.nix b/tests/remote-builds.nix
index 0f16026a428a..34276e7d6981 100644
--- a/tests/remote-builds.nix
+++ b/tests/remote-builds.nix
@@ -14,6 +14,7 @@ let
     { services.openssh.enable = true;
       virtualisation.writableStore = true;
       nix.package = nix;
+      nix.useChroot = true;
     };
 
   # Trivial Nix expression to build remotely.