From d518eb94eee9d88e7a4aad37b8cd0065f394a79d Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Mon, 11 Sep 2023 15:44:44 +0200 Subject: [PATCH 1/2] tests.nixpkgs-check-by-name: Fix for symlinked tempdirs On Darwin, /tmp is sometimes a symlink to /private/tmp, which couldn't be handled before: error: access to canonical path '/private/var/folders/xp/9_ry6h9x6l9gh_g32qspz0_40000gp/T/.tmpFbcNO0' is forbidden in restricted mode This both fixes that and adds a test to make sure it can't happen again --- pkgs/test/nixpkgs-check-by-name/src/eval.rs | 12 +++++-- pkgs/test/nixpkgs-check-by-name/src/main.rs | 36 +++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/pkgs/test/nixpkgs-check-by-name/src/eval.rs b/pkgs/test/nixpkgs-check-by-name/src/eval.rs index d084642ffe7e..17e22495b22a 100644 --- a/pkgs/test/nixpkgs-check-by-name/src/eval.rs +++ b/pkgs/test/nixpkgs-check-by-name/src/eval.rs @@ -30,9 +30,15 @@ pub fn check_values( // Write the list of packages we need to check into a temporary JSON file. // This can then get read by the Nix evaluation. let attrs_file = NamedTempFile::new().context("Failed to create a temporary file")?; + // We need to canonicalise this path because if it's a symlink (which can be the case on + // Darwin), Nix would need to read both the symlink and the target path, therefore need 2 + // NIX_PATH entries for restrict-eval. But if we resolve the symlinks then only one predictable + // entry is needed. + let attrs_file_path = attrs_file.path().canonicalize()?; + serde_json::to_writer(&attrs_file, &nixpkgs.package_names).context(format!( "Failed to serialise the package names to the temporary path {}", - attrs_file.path().display() + attrs_file_path.display() ))?; // With restrict-eval, only paths in NIX_PATH can be accessed, so we explicitly specify the @@ -57,9 +63,9 @@ pub fn check_values( // Pass the path to the attrs_file as an argument and add it to the NIX_PATH so it can be // accessed in restrict-eval mode .args(["--arg", "attrsPath"]) - .arg(attrs_file.path()) + .arg(&attrs_file_path) .arg("-I") - .arg(attrs_file.path()) + .arg(&attrs_file_path) // Same for the nixpkgs to test .args(["--arg", "nixpkgsPath"]) .arg(&nixpkgs.path) diff --git a/pkgs/test/nixpkgs-check-by-name/src/main.rs b/pkgs/test/nixpkgs-check-by-name/src/main.rs index db22e524553b..751b5dbd0240 100644 --- a/pkgs/test/nixpkgs-check-by-name/src/main.rs +++ b/pkgs/test/nixpkgs-check-by-name/src/main.rs @@ -140,6 +140,42 @@ mod tests { Ok(()) } + /// Tests symlinked temporary directories. + /// This is needed because on darwin, `/tmp` is a symlink to `/private/tmp`, and Nix's + /// restrict-eval doesn't also allow access to the canonical path when you allow the + /// non-canonical one. + /// + /// The error if we didn't do this would look like this: + /// error: access to canonical path '/private/var/folders/[...]/.tmpFbcNO0' is forbidden in restricted mode + #[test] + fn test_symlinked_tmpdir() -> anyhow::Result<()> { + // Create a directory with two entries: + // - actual (dir) + // - symlinked -> actual (symlink) + let temp_root = tempdir()?; + fs::create_dir(temp_root.path().join("actual"))?; + std::os::unix::fs::symlink("actual", temp_root.path().join("symlinked"))?; + let tmpdir = temp_root.path().join("symlinked"); + + // Then set TMPDIR to the symlinked directory + // Make sure to persist the old value so we can undo this later + let old_tmpdir = env::var("TMPDIR").ok(); + env::set_var("TMPDIR", &tmpdir); + + // Then run a simple test with this symlinked temporary directory + // This should be successful + test_nixpkgs("symlinked_tmpdir", Path::new("tests/success"), "")?; + + // Undo the env variable change + if let Some(old) = old_tmpdir { + env::set_var("TMPDIR", old); + } else { + env::remove_var("TMPDIR"); + } + + Ok(()) + } + fn test_nixpkgs(name: &str, path: &Path, expected_errors: &str) -> anyhow::Result<()> { let extra_nix_path = Path::new("tests/mock-nixpkgs.nix"); From 9c9a7e00829169a68ee9ec0c6e5d2071ae1285b5 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Tue, 12 Sep 2023 01:06:37 +0200 Subject: [PATCH 2/2] tests.nixpkgs-check-by-name: Fix with parallel tests We seem to have enough tests to run into this now: error: creating symlink from '/private/tmp/nix-build-nixpkgs-check-by-name.drv-0/source/test-tmp/var/nix/gcroots/profiles' to '/private/tmp/nix-build-nixpkgs-check-by-name.drv-0/source/test-tmp/var/nix/profiles': File exists --- pkgs/test/nixpkgs-check-by-name/default.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/test/nixpkgs-check-by-name/default.nix b/pkgs/test/nixpkgs-check-by-name/default.nix index a997fc8612c8..cb8a672bc990 100644 --- a/pkgs/test/nixpkgs-check-by-name/default.nix +++ b/pkgs/test/nixpkgs-check-by-name/default.nix @@ -25,6 +25,10 @@ let export NIX_LOG_DIR=$TEST_ROOT/var/log/nix export NIX_STATE_DIR=$TEST_ROOT/var/nix export NIX_STORE_DIR=$TEST_ROOT/store + + # cargo tests run in parallel by default, which would then run into + # https://github.com/NixOS/nix/issues/2706 unless the store is initialised first + nix-store --init ''; postCheck = '' cargo fmt --check