Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package nix for openSUSE:Factory checked in at 2025-06-26 11:36:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nix (Old) and /work/SRC/openSUSE:Factory/.nix.new.7067 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nix" Thu Jun 26 11:36:56 2025 rev:3 rq:1288353 version:2.29.1 Changes: -------- --- /work/SRC/openSUSE:Factory/nix/nix.changes 2025-06-23 15:03:00.880130436 +0200 +++ /work/SRC/openSUSE:Factory/.nix.new.7067/nix.changes 2025-06-26 11:38:22.507424895 +0200 @@ -1,0 +2,13 @@ +Tue Jun 24 15:44:37 UTC 2025 - Marcus Rueckert <mrueck...@suse.de> + +- Update to 2.29.1: (boo#1245319) + Fixes: + - CVE-2025-46415 + - CVE-2025-52991 + - CVE-2025-52992 + - CVE-2025-52993 + + For the details see: + https://discourse.nixos.org/t/security-advisory-privilege-escalations-in-nix-lix-and-guix/66017 + +------------------------------------------------------------------- Old: ---- nix-2.29.0.tar.gz New: ---- nix-2.29.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nix.spec ++++++ --- /var/tmp/diff_new_pack.ktW1bp/_old 2025-06-26 11:38:23.339459350 +0200 +++ /var/tmp/diff_new_pack.ktW1bp/_new 2025-06-26 11:38:23.343459516 +0200 @@ -27,7 +27,7 @@ %endif Name: nix -Version: 2.29.0 +Version: 2.29.1 Release: 0 Summary: The purely functional package manager License: LGPL-2.1-only ++++++ nix-2.29.0.tar.gz -> nix-2.29.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/.version new/nix-2.29.1/.version --- old/nix-2.29.0/.version 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/.version 2025-06-24 16:05:12.000000000 +0200 @@ -1 +1 @@ -2.29.0 +2.29.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libflake/flake.cc new/nix-2.29.1/src/libflake/flake.cc --- old/nix-2.29.0/src/libflake/flake.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libflake/flake.cc 2025-06-24 16:05:12.000000000 +0200 @@ -570,7 +570,7 @@ /* Get the input flake, resolve 'path:./...' flakerefs relative to the parent flake. */ - auto getInputFlake = [&](const FlakeRef & ref) + auto getInputFlake = [&](const FlakeRef & ref, const fetchers::UseRegistries useRegistries) { if (auto resolvedPath = resolveRelativePath()) { return readFlake(state, ref, ref, ref, *resolvedPath, inputAttrPath); @@ -578,7 +578,7 @@ return getFlake( state, ref, - useRegistriesInputs, + useRegistries, inputAttrPath); } }; @@ -660,7 +660,7 @@ } if (mustRefetch) { - auto inputFlake = getInputFlake(oldLock->lockedRef); + auto inputFlake = getInputFlake(oldLock->lockedRef, useRegistriesInputs); nodePaths.emplace(childNode, inputFlake.path.parent()); computeLocks(inputFlake.inputs, childNode, inputAttrPath, oldLock, followsPrefix, inputFlake.path, false); @@ -685,10 +685,11 @@ nuked the next time we update the lock file. That is, overrides are sticky unless you use --no-write-lock-file. */ - auto ref = (input2.ref && explicitCliOverrides.contains(inputAttrPath)) ? *input2.ref : *input.ref; + auto inputIsOverride = explicitCliOverrides.contains(inputAttrPath); + auto ref = (input2.ref && inputIsOverride) ? *input2.ref : *input.ref; if (input.isFlake) { - auto inputFlake = getInputFlake(*input.ref); + auto inputFlake = getInputFlake(*input.ref, inputIsOverride ? fetchers::UseRegistries::All : useRegistriesInputs); auto childNode = make_ref<LockedNode>( inputFlake.lockedRef, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libstore/derivation-options.cc new/nix-2.29.1/src/libstore/derivation-options.cc --- old/nix-2.29.0/src/libstore/derivation-options.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libstore/derivation-options.cc 2025-06-24 16:05:12.000000000 +0200 @@ -211,8 +211,13 @@ auto e = optionalValueAt(parsed->structuredAttrs, "exportReferencesGraph"); if (!e || !e->is_object()) return ret; - for (auto & [key, storePathsJson] : getObject(*e)) { - ret.insert_or_assign(key, storePathsJson); + for (auto & [key, value] : getObject(*e)) { + if (value.is_array()) + ret.insert_or_assign(key, value); + else if (value.is_string()) + ret.insert_or_assign(key, StringSet{value}); + else + throw Error("'exportReferencesGraph' value is not an array or a string"); } } else { auto s = getOr(env, "exportReferencesGraph", ""); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libstore/http-binary-cache-store.cc new/nix-2.29.1/src/libstore/http-binary-cache-store.cc --- old/nix-2.29.0/src/libstore/http-binary-cache-store.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libstore/http-binary-cache-store.cc 2025-06-24 16:05:12.000000000 +0200 @@ -176,13 +176,13 @@ void getFile(const std::string & path, Callback<std::optional<std::string>> callback) noexcept override { + auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback)); + try { checkEnabled(); auto request(makeRequest(path)); - auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback)); - getFileTransfer()->enqueueFileTransfer(request, {[callbackPtr, this](std::future<FileTransferResult> result) { try { @@ -198,7 +198,7 @@ }}); } catch (...) { - callback.rethrow(); + callbackPtr->rethrow(); return; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libstore/local-store.cc new/nix-2.29.1/src/libstore/local-store.cc --- old/nix-2.29.0/src/libstore/local-store.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libstore/local-store.cc 2025-06-24 16:05:12.000000000 +0200 @@ -247,7 +247,7 @@ else if (curSchema == 0) { /* new store */ curSchema = nixSchemaVersion; openDB(*state, true); - writeFile(schemaPath, fmt("%1%", curSchema), 0666, true); + writeFile(schemaPath, fmt("%1%", curSchema), 0666, FsSync::Yes); } else if (curSchema < nixSchemaVersion) { @@ -298,7 +298,7 @@ txn.commit(); } - writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true); + writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, FsSync::Yes); lockFile(globalLock.get(), ltRead, true); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libstore/misc.cc new/nix-2.29.1/src/libstore/misc.cc --- old/nix-2.29.0/src/libstore/misc.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libstore/misc.cc 2025-06-24 16:05:12.000000000 +0200 @@ -225,6 +225,8 @@ auto parsedDrv = StructuredAttrs::tryParse(drv->env); DerivationOptions drvOptions; try { + // FIXME: this is a lot of work just to get the value + // of `allowSubstitutes`. drvOptions = DerivationOptions::fromStructuredAttrs( drv->env, parsedDrv ? &*parsedDrv : nullptr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libstore/unix/build/derivation-builder.cc new/nix-2.29.1/src/libstore/unix/build/derivation-builder.cc --- old/nix-2.29.0/src/libstore/unix/build/derivation-builder.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libstore/unix/build/derivation-builder.cc 2025-06-24 16:05:12.000000000 +0200 @@ -130,6 +130,11 @@ Path topTmpDir; /** + * The file descriptor of the temporary directory. + */ + AutoCloseFD tmpDirFd; + + /** * The path of the temporary directory in the sandbox. */ Path tmpDirInSandbox; @@ -325,10 +330,25 @@ /** * Make a file owned by the builder. + * + * SAFETY: this function is prone to TOCTOU as it receives a path and not a descriptor. + * It's only safe to call in a child of a directory only visible to the owner. */ void chownToBuilder(const Path & path); /** + * Make a file owned by the builder addressed by its file descriptor. + */ + void chownToBuilder(int fd, const Path & path); + + /** + * Create a file in `tmpDir` owned by the builder. + */ + void writeBuilderFile( + const std::string & name, + std::string_view contents); + + /** * Run the builder's process. */ void runChild(); @@ -895,7 +915,14 @@ } else { tmpDir = topTmpDir; } - chownToBuilder(tmpDir); + + /* The TOCTOU between the previous mkdir call and this open call is unavoidable due to + POSIX semantics.*/ + tmpDirFd = AutoCloseFD{open(tmpDir.c_str(), O_RDONLY | O_NOFOLLOW | O_DIRECTORY)}; + if (!tmpDirFd) + throw SysError("failed to open the build temporary directory descriptor '%1%'", tmpDir); + + chownToBuilder(tmpDirFd.get(), tmpDir); for (auto & [outputName, status] : initialOutputs) { /* Set scratch path we'll actually use during the build. @@ -1469,9 +1496,7 @@ } else { auto hash = hashString(HashAlgorithm::SHA256, i.first); std::string fn = ".attr-" + hash.to_string(HashFormat::Nix32, false); - Path p = tmpDir + "/" + fn; - writeFile(p, rewriteStrings(i.second, inputRewrites)); - chownToBuilder(p); + writeBuilderFile(fn, rewriteStrings(i.second, inputRewrites)); env[i.first + "Path"] = tmpDirInSandbox + "/" + fn; } } @@ -1580,11 +1605,9 @@ auto jsonSh = StructuredAttrs::writeShell(json); - writeFile(tmpDir + "/.attrs.sh", rewriteStrings(jsonSh, inputRewrites)); - chownToBuilder(tmpDir + "/.attrs.sh"); + writeBuilderFile(".attrs.sh", rewriteStrings(jsonSh, inputRewrites)); env["NIX_ATTRS_SH_FILE"] = tmpDirInSandbox + "/.attrs.sh"; - writeFile(tmpDir + "/.attrs.json", rewriteStrings(json.dump(), inputRewrites)); - chownToBuilder(tmpDir + "/.attrs.json"); + writeBuilderFile(".attrs.json", rewriteStrings(json.dump(), inputRewrites)); env["NIX_ATTRS_JSON_FILE"] = tmpDirInSandbox + "/.attrs.json"; } } @@ -1838,6 +1861,24 @@ #endif } +void DerivationBuilderImpl::chownToBuilder(int fd, const Path & path) +{ + if (!buildUser) return; + if (fchown(fd, buildUser->getUID(), buildUser->getGID()) == -1) + throw SysError("cannot change ownership of file '%1%'", path); +} + +void DerivationBuilderImpl::writeBuilderFile( + const std::string & name, + std::string_view contents) +{ + auto path = std::filesystem::path(tmpDir) / name; + AutoCloseFD fd{openat(tmpDirFd.get(), name.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC | O_EXCL | O_NOFOLLOW, 0666)}; + if (!fd) + throw SysError("creating file %s", path); + writeFile(fd, path, contents); + chownToBuilder(fd.get(), path); +} void DerivationBuilderImpl::runChild() { @@ -3043,6 +3084,15 @@ void DerivationBuilderImpl::deleteTmpDir(bool force) { if (topTmpDir != "") { + /* As an extra precaution, even in the event of `deletePath` failing to + * clean up, the `tmpDir` will be chowned as if we were to move + * it inside the Nix store. + * + * This hardens against an attack which smuggles a file descriptor + * to make use of the temporary directory. + */ + chmod(topTmpDir.c_str(), 0000); + /* Don't keep temporary directories for builtins because they might have privileged stuff (like a copy of netrc). */ if (settings.keepFailed && !force && !drv.isBuiltin()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libutil/file-content-address.cc new/nix-2.29.1/src/libutil/file-content-address.cc --- old/nix-2.29.0/src/libutil/file-content-address.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libutil/file-content-address.cc 2025-06-24 16:05:12.000000000 +0200 @@ -93,7 +93,7 @@ { switch (method) { case FileSerialisationMethod::Flat: - writeFile(path, source, 0666, startFsync); + writeFile(path, source, 0666, startFsync ? FsSync::Yes : FsSync::No); break; case FileSerialisationMethod::NixArchive: restorePath(path, source, startFsync); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libutil/file-system.cc new/nix-2.29.1/src/libutil/file-system.cc --- old/nix-2.29.0/src/libutil/file-system.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libutil/file-system.cc 2025-06-24 16:05:12.000000000 +0200 @@ -303,7 +303,7 @@ } -void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync) +void writeFile(const Path & path, std::string_view s, mode_t mode, FsSync sync) { AutoCloseFD fd = toDescriptor(open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT // TODO @@ -313,22 +313,29 @@ , mode)); if (!fd) throw SysError("opening file '%1%'", path); + + writeFile(fd, path, s, mode, sync); + + /* Close explicitly to propagate the exceptions. */ + fd.close(); +} + +void writeFile(AutoCloseFD & fd, const Path & origPath, std::string_view s, mode_t mode, FsSync sync) +{ + assert(fd); try { writeFull(fd.get(), s); + + if (sync == FsSync::Yes) + fd.fsync(); + } catch (Error & e) { - e.addTrace({}, "writing file '%1%'", path); + e.addTrace({}, "writing file '%1%'", origPath); throw; } - if (sync) - fd.fsync(); - // Explicitly close to make sure exceptions are propagated. - fd.close(); - if (sync) - syncParent(path); } - -void writeFile(const Path & path, Source & source, mode_t mode, bool sync) +void writeFile(const Path & path, Source & source, mode_t mode, FsSync sync) { AutoCloseFD fd = toDescriptor(open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT // TODO @@ -352,11 +359,11 @@ e.addTrace({}, "writing file '%1%'", path); throw; } - if (sync) + if (sync == FsSync::Yes) fd.fsync(); // Explicitly close to make sure exceptions are propagated. fd.close(); - if (sync) + if (sync == FsSync::Yes) syncParent(path); } @@ -419,7 +426,8 @@ #ifndef _WIN32 checkInterrupt(); - std::string name(baseNameOf(path.native())); + std::string name(path.filename()); + assert(name != "." && name != ".." && !name.empty()); struct stat st; if (fstatat(parentfd, name.c_str(), &st, @@ -460,7 +468,7 @@ throw SysError("chmod %1%", path); } - int fd = openat(parentfd, path.c_str(), O_RDONLY); + int fd = openat(parentfd, name.c_str(), O_RDONLY | O_DIRECTORY | O_NOFOLLOW); if (fd == -1) throw SysError("opening directory %1%", path); AutoCloseDir dir(fdopendir(fd)); @@ -472,7 +480,7 @@ checkInterrupt(); std::string childName = dirent->d_name; if (childName == "." || childName == "..") continue; - _deletePath(dirfd(dir.get()), path + "/" + childName, bytesFreed); + _deletePath(dirfd(dir.get()), path / childName, bytesFreed); } if (errno) throw SysError("reading directory %1%", path); } @@ -490,14 +498,13 @@ static void _deletePath(const std::filesystem::path & path, uint64_t & bytesFreed) { - Path dir = dirOf(path.string()); - if (dir == "") - dir = "/"; + assert(path.is_absolute()); + assert(path.parent_path() != path); - AutoCloseFD dirfd = toDescriptor(open(dir.c_str(), O_RDONLY)); + AutoCloseFD dirfd = toDescriptor(open(path.parent_path().string().c_str(), O_RDONLY)); if (!dirfd) { if (errno == ENOENT) return; - throw SysError("opening directory '%1%'", path); + throw SysError("opening directory %s", path.parent_path()); } _deletePath(dirfd.get(), path, bytesFreed); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libutil/include/nix/util/file-system.hh new/nix-2.29.1/src/libutil/include/nix/util/file-system.hh --- old/nix-2.29.0/src/libutil/include/nix/util/file-system.hh 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libutil/include/nix/util/file-system.hh 2025-06-24 16:05:12.000000000 +0200 @@ -175,21 +175,27 @@ std::string readFile(const std::filesystem::path & path); void readFile(const Path & path, Sink & sink, bool memory_map = true); +enum struct FsSync { Yes, No }; + /** * Write a string to a file. */ -void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false); -static inline void writeFile(const std::filesystem::path & path, std::string_view s, mode_t mode = 0666, bool sync = false) +void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No); + +static inline void writeFile(const std::filesystem::path & path, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No) { return writeFile(path.string(), s, mode, sync); } -void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false); -static inline void writeFile(const std::filesystem::path & path, Source & source, mode_t mode = 0666, bool sync = false) +void writeFile(const Path & path, Source & source, mode_t mode = 0666, FsSync sync = FsSync::No); + +static inline void writeFile(const std::filesystem::path & path, Source & source, mode_t mode = 0666, FsSync sync = FsSync::No) { return writeFile(path.string(), source, mode, sync); } +void writeFile(AutoCloseFD & fd, const Path & origPath, std::string_view s, mode_t mode = 0666, FsSync sync = FsSync::No); + /** * Flush a path's parent directory to disk. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/src/libutil/memory-source-accessor.cc new/nix-2.29.1/src/libutil/memory-source-accessor.cc --- old/nix-2.29.0/src/libutil/memory-source-accessor.cc 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/src/libutil/memory-source-accessor.cc 2025-06-24 16:05:12.000000000 +0200 @@ -187,6 +187,10 @@ ref<SourceAccessor> makeEmptySourceAccessor() { static auto empty = make_ref<MemorySourceAccessor>().cast<SourceAccessor>(); + /* Don't forget to clear the display prefix, as the default constructed + SourceAccessor has the «unknown» prefix. Since this accessor is supposed + to mimic an empty root directory the prefix needs to be empty. */ + empty->setPathDisplay(""); return empty; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/tests/functional/flakes/flakes.sh new/nix-2.29.1/tests/functional/flakes/flakes.sh --- old/nix-2.29.0/tests/functional/flakes/flakes.sh 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/tests/functional/flakes/flakes.sh 2025-06-24 16:05:12.000000000 +0200 @@ -160,7 +160,7 @@ nix build -o "$TEST_ROOT/result" "$flake2Dir#bar" --commit-lock-file [[ -e "$flake2Dir/flake.lock" ]] [[ -z $(git -C "$flake2Dir" diff main || echo failed) ]] -[[ $(jq --indent 0 . < "$flake2Dir/flake.lock") =~ ^'{"nodes":{"flake1":{"locked":{"lastModified":'.*',"narHash":"sha256-'.*'","ref":"refs/heads/master","rev":"'.*'","revCount":2,"type":"git","url":"file:///'.*'"},"original":{"id":"flake1","type":"indirect"}},"root":{"inputs":{"flake1":"flake1"}}},"root":"root","version":7}'$ ]] +[[ $(jq --indent 0 --compact-output . < "$flake2Dir/flake.lock") =~ ^'{"nodes":{"flake1":{"locked":{"lastModified":'.*',"narHash":"sha256-'.*'","ref":"refs/heads/master","rev":"'.*'","revCount":2,"type":"git","url":"file:///'.*'"},"original":{"id":"flake1","type":"indirect"}},"root":{"inputs":{"flake1":"flake1"}}},"root":"root","version":7}'$ ]] # Rerunning the build should not change the lockfile. nix build -o "$TEST_ROOT/result" "$flake2Dir#bar" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/tests/functional/flakes/relative-paths.sh new/nix-2.29.1/tests/functional/flakes/relative-paths.sh --- old/nix-2.29.0/tests/functional/flakes/relative-paths.sh 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/tests/functional/flakes/relative-paths.sh 2025-06-24 16:05:12.000000000 +0200 @@ -69,7 +69,7 @@ git -C "$rootFlake" add sub2/flake.lock [[ $(nix eval "$subflake2#y") = 15 ]] -[[ $(jq --indent 0 . < "$subflake2/flake.lock") =~ ^'{"nodes":{"root":{"inputs":{"root":"root_2","sub1":"sub1"}},"root_2":{"inputs":{"sub0":"sub0"},"locked":{"path":"..","type":"path"},"original":{"path":"..","type":"path"},"parent":[]},"root_3":{"inputs":{"sub0":"sub0_2"},"locked":{"path":"../","type":"path"},"original":{"path":"../","type":"path"},"parent":["sub1"]},"sub0":{"locked":{"path":"sub0","type":"path"},"original":{"path":"sub0","type":"path"},"parent":["root"]},"sub0_2":{"locked":{"path":"sub0","type":"path"},"original":{"path":"sub0","type":"path"},"parent":["sub1","root"]},"sub1":{"inputs":{"root":"root_3"},"locked":{"path":"../sub1","type":"path"},"original":{"path":"../sub1","type":"path"},"parent":[]}},"root":"root","version":7}'$ ]] +[[ $(jq --indent 0 --compact-output . < "$subflake2/flake.lock") =~ ^'{"nodes":{"root":{"inputs":{"root":"root_2","sub1":"sub1"}},"root_2":{"inputs":{"sub0":"sub0"},"locked":{"path":"..","type":"path"},"original":{"path":"..","type":"path"},"parent":[]},"root_3":{"inputs":{"sub0":"sub0_2"},"locked":{"path":"../","type":"path"},"original":{"path":"../","type":"path"},"parent":["sub1"]},"sub0":{"locked":{"path":"sub0","type":"path"},"original":{"path":"sub0","type":"path"},"parent":["root"]},"sub0_2":{"locked":{"path":"sub0","type":"path"},"original":{"path":"sub0","type":"path"},"parent":["sub1","root"]},"sub1":{"inputs":{"root":"root_3"},"locked":{"path":"../sub1","type":"path"},"original":{"path":"../sub1","type":"path"},"parent":[]}},"root":"root","version":7}'$ ]] # Make sure there are no content locks for relative path flakes. (! grep "$TEST_ROOT" "$subflake2/flake.lock") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/tests/functional/pure-eval.sh new/nix-2.29.1/tests/functional/pure-eval.sh --- old/nix-2.29.0/tests/functional/pure-eval.sh 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/tests/functional/pure-eval.sh 2025-06-24 16:05:12.000000000 +0200 @@ -34,3 +34,15 @@ (! nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ "." = "bla"; }') (! nix eval --expr '~/foo') + +expectStderr 0 nix eval --expr "/some/absolute/path" \ + | grepQuiet "/some/absolute/path" + +expectStderr 0 nix eval --expr "/some/absolute/path" --impure \ + | grepQuiet "/some/absolute/path" + +expectStderr 0 nix eval --expr "some/relative/path" \ + | grepQuiet "$PWD/some/relative/path" + +expectStderr 0 nix eval --expr "some/relative/path" --impure \ + | grepQuiet "$PWD/some/relative/path" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/tests/functional/repl.sh new/nix-2.29.1/tests/functional/repl.sh --- old/nix-2.29.0/tests/functional/repl.sh 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/tests/functional/repl.sh 2025-06-24 16:05:12.000000000 +0200 @@ -163,7 +163,8 @@ # - Re-eval it # - Check that the result has changed mkfifo repl_fifo -nix repl ./flake --experimental-features 'flakes' < repl_fifo > repl_output 2>&1 & +touch repl_output +nix repl ./flake --experimental-features 'flakes' < repl_fifo >> repl_output 2>&1 & repl_pid=$! exec 3>repl_fifo # Open fifo for writing echo "changingThing" >&3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nix-2.29.0/tests/functional/structured-attrs-shell.nix new/nix-2.29.1/tests/functional/structured-attrs-shell.nix --- old/nix-2.29.0/tests/functional/structured-attrs-shell.nix 2025-05-19 16:46:37.000000000 +0200 +++ new/nix-2.29.1/tests/functional/structured-attrs-shell.nix 2025-06-24 16:05:12.000000000 +0200 @@ -21,7 +21,7 @@ "b" "c" ]; - exportReferencesGraph.refs = [ dep ]; + exportReferencesGraph.refs = dep; buildCommand = '' touch ''${outputs[out]}; touch ''${outputs[dev]} '';