···25 export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
26 export NIX_STATE_DIR=$TEST_ROOT/var/nix
27 export NIX_STORE_DIR=$TEST_ROOT/store
28+29+ # cargo tests run in parallel by default, which would then run into
30+ # https://github.com/NixOS/nix/issues/2706 unless the store is initialised first
31+ nix-store --init
32 '';
33 postCheck = ''
34 cargo fmt --check
+9-3
pkgs/test/nixpkgs-check-by-name/src/eval.rs
···30 // Write the list of packages we need to check into a temporary JSON file.
31 // This can then get read by the Nix evaluation.
32 let attrs_file = NamedTempFile::new().context("Failed to create a temporary file")?;
00000033 serde_json::to_writer(&attrs_file, &nixpkgs.package_names).context(format!(
34 "Failed to serialise the package names to the temporary path {}",
35- attrs_file.path().display()
36 ))?;
3738 // With restrict-eval, only paths in NIX_PATH can be accessed, so we explicitly specify the
···57 // Pass the path to the attrs_file as an argument and add it to the NIX_PATH so it can be
58 // accessed in restrict-eval mode
59 .args(["--arg", "attrsPath"])
60- .arg(attrs_file.path())
61 .arg("-I")
62- .arg(attrs_file.path())
63 // Same for the nixpkgs to test
64 .args(["--arg", "nixpkgsPath"])
65 .arg(&nixpkgs.path)
···30 // Write the list of packages we need to check into a temporary JSON file.
31 // This can then get read by the Nix evaluation.
32 let attrs_file = NamedTempFile::new().context("Failed to create a temporary file")?;
33+ // We need to canonicalise this path because if it's a symlink (which can be the case on
34+ // Darwin), Nix would need to read both the symlink and the target path, therefore need 2
35+ // NIX_PATH entries for restrict-eval. But if we resolve the symlinks then only one predictable
36+ // entry is needed.
37+ let attrs_file_path = attrs_file.path().canonicalize()?;
38+39 serde_json::to_writer(&attrs_file, &nixpkgs.package_names).context(format!(
40 "Failed to serialise the package names to the temporary path {}",
41+ attrs_file_path.display()
42 ))?;
4344 // With restrict-eval, only paths in NIX_PATH can be accessed, so we explicitly specify the
···63 // Pass the path to the attrs_file as an argument and add it to the NIX_PATH so it can be
64 // accessed in restrict-eval mode
65 .args(["--arg", "attrsPath"])
66+ .arg(&attrs_file_path)
67 .arg("-I")
68+ .arg(&attrs_file_path)
69 // Same for the nixpkgs to test
70 .args(["--arg", "nixpkgsPath"])
71 .arg(&nixpkgs.path)
···140 Ok(())
141 }
142143+ /// Tests symlinked temporary directories.
144+ /// This is needed because on darwin, `/tmp` is a symlink to `/private/tmp`, and Nix's
145+ /// restrict-eval doesn't also allow access to the canonical path when you allow the
146+ /// non-canonical one.
147+ ///
148+ /// The error if we didn't do this would look like this:
149+ /// error: access to canonical path '/private/var/folders/[...]/.tmpFbcNO0' is forbidden in restricted mode
150+ #[test]
151+ fn test_symlinked_tmpdir() -> anyhow::Result<()> {
152+ // Create a directory with two entries:
153+ // - actual (dir)
154+ // - symlinked -> actual (symlink)
155+ let temp_root = tempdir()?;
156+ fs::create_dir(temp_root.path().join("actual"))?;
157+ std::os::unix::fs::symlink("actual", temp_root.path().join("symlinked"))?;
158+ let tmpdir = temp_root.path().join("symlinked");
159+160+ // Then set TMPDIR to the symlinked directory
161+ // Make sure to persist the old value so we can undo this later
162+ let old_tmpdir = env::var("TMPDIR").ok();
163+ env::set_var("TMPDIR", &tmpdir);
164+165+ // Then run a simple test with this symlinked temporary directory
166+ // This should be successful
167+ test_nixpkgs("symlinked_tmpdir", Path::new("tests/success"), "")?;
168+169+ // Undo the env variable change
170+ if let Some(old) = old_tmpdir {
171+ env::set_var("TMPDIR", old);
172+ } else {
173+ env::remove_var("TMPDIR");
174+ }
175+176+ Ok(())
177+ }
178+179 fn test_nixpkgs(name: &str, path: &Path, expected_errors: &str) -> anyhow::Result<()> {
180 let extra_nix_path = Path::new("tests/mock-nixpkgs.nix");
181