Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package nix for openSUSE:Factory checked in 
at 2026-10-14 18:35:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nix (Old)
 and      /work/SRC/openSUSE:Factory/.nix.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nix"

Wed Oct 14 18:35:27 2026 rev:23 rq:1384673 version:2.35.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/nix/nix.changes  2026-08-14 22:07:27.519048271 
+0200
+++ /work/SRC/openSUSE:Factory/.nix.new.3698736/nix.changes     2026-10-14 
18:36:09.356480799 +0200
@@ -1,0 +2,90 @@
+Tue Oct 13 15:31:33 UTC 2026 - Marcus Rueckert <[email protected]>
+
+- Update to version 2.35.3:
+  - 10d9e06fe Fix sandbox breakpoint escape
+  - 4cfab486f Merge remote-tracking branch
+    'nix-ghsa-hf6w-2rg9-v84g/fix-installer-2.35' into
+    mitigations-2.35
+  - 224b720f2 Merge remote-tracking branch
+    'nix-ghsa-jwvx-xq5j-gc56/restrict-repair-flag-to-trusted-users-2.35'
+    into mitigations-2.35
+  - cd9020f77 Merge remote-tracking branch
+    'nix-ghsa-92x5-h528-wrmw/reject-build-users-group-2.35' into
+    mitigations-2.35
+  - 3755b3b73 Merge remote-tracking branch
+    'nix-ghsa-25vp-6h23-hj3g/fix-gen-list-overflows-2.35' into
+    mitigations-2.35
+  - 7e675b31a [Backport 2.35-maintenance] libstore: treat `\r\n` as
+    a single line terminator in build logs (#16599)
+  - c4807b4a1 libstore: treat `\r\n` as a single line terminator in
+    build logs
+  - 623bbfd94 installer: Fix store object ownership in multi-user
+    installs
+  - a3ec144fa [Backport 2.35-maintenance] installer: Fix store
+    mtime in binary tarballs (#16559)
+  - b07ef7c01 installer: Fix store mtime in binary tarballs
+  - f4dd3bda8 tests/installer: Refactor to support custom checks
+    and mirror nix-installer repo
+  - 1a202f9dc tests/installer: Set -u in the tests
+  - 56f147d2e [Backport 2.35-maintenance] gc-closure.sh: avoid
+    SIGPIPE from head (#16557)
+  - c0cb11d58 gc-closure.sh: avoid SIGPIPE from head
+  - 355240b45 libstore: Unpack to temporary location in
+    LocalStore::addToStore
+  - 2252caebf libstore/daemon: Disallow unprivileged repair in
+    AddMultipleToStore/AddToStoreNar/AddToStore
+  - 48d8bc136 Record gid in getPeerInfo when using LOCAL_PEERCRED
+  - 83f4ac399 Merge pull request #16511 from
+    NixOS/backport-16229-to-2.35-maintenance
+  - 0df979fe0 Fix ignored nodiscard results
+  - 1ad4a52d3 Merge pull request #16489 from
+    NixOS/backport-16487-to-2.35-maintenance
+  - 528e705b8 nix flake prefetch-inputs: skip relative path inputs
+  - d7c4344e4 libexpr: Tighten allocBytes with overload that does
+    unsigned overflow detection
+  - 88c2bcc16 Merge pull request #16464 from
+    NixOS/backport-16067-to-2.35-maintenance
+  - a5a93f8e8 libstore: detect Rosetta via runtime file instead of
+    spawning arch
+  - a40dd52cf Merge pull request #16419 from
+    NixOS/backport-16418-to-2.35-maintenance
+  - beed3dd4a fix(packaging): do not add boost fiber patch if
+    duplicate
+  - e69fa58ed Merge pull request #16410 from
+    NixOS/backport-16407-to-2.35-maintenance
+  - 413162760 libexpr-c: allow null primop docs
+  - 8e94a93ec Merge pull request #16405 from
+    NixOS/backport-16403-to-2.35-maintenance
+  - c39e300db Convert stdenv.isLinux to stdenv.hostPlatform.isLinux
+  - 0b726cab9 Merge pull request #16402 from
+    NixOS/backport-16397-to-2.35-maintenance
+  - 878674493 Merge pull request #16401 from
+    NixOS/backport-16391-to-2.35-maintenance
+  - 81dca68c7 libfetchers/git: render submodules as empty dirs in
+    workdir accessor
+  - 9c5d36a0c libfetchers/git: use HEAD as default ref for detached
+    local repos
+  - 553bac087 Merge pull request #16379 from
+    NixOS/backport-16373-to-2.35-maintenance
+  - d6f5cef6c nix flake prefetch-inputs: fix inputs being randomly
+    skipped
+  - 8eb4cf95c Merge pull request #16351 from
+    NixOS/backport-16190-to-2.35-maintenance
+  - b8abc0832 Populate the srcToStore cache when we have a fetcher
+    cache hit
+  - cf5200adb Merge pull request #16350 from
+    NixOS/backport-16295-to-2.35-maintenance
+  - de3a27708 Improve 'sandbox-fallback' diagnostics, disallow
+    fallback with relocated store
+  - c138b869a Merge pull request #16331 from
+    JamieMagee/backport-16325-to-2.35-maintenance
+  - 4284b5768 Validate padding after skipped NAR contents
+  - 939898e5f Merge pull request #16319 from
+    NixOS/backport-fix-16317
+  - 76c15a273 libstore: Merge, don't clobber, colliding `inputDrvs`
+    hashes modulo
+  - b87548075 Merge pull request #16304 from
+    NixOS/backport-16303-to-2.35-maintenance
+  - 1e4f38765 rl-2.35.md: correct meson option to disable mimalloc
+
+-------------------------------------------------------------------

Old:
----
  nix-2.35.2.tar.gz

New:
----
  nix-2.35.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ nix.spec ++++++
--- /var/tmp/diff_new_pack.CCUDB4/_old  2026-10-14 18:36:10.414525346 +0200
+++ /var/tmp/diff_new_pack.CCUDB4/_new  2026-10-14 18:36:10.415525388 +0200
@@ -26,7 +26,7 @@
 %bcond_with docs
 
 Name:           nix
-Version:        2.35.2
+Version:        2.35.3
 Release:        0
 Summary:        The purely functional package manager
 License:        LGPL-2.1-only

++++++ nix-2.35.2.tar.gz -> nix-2.35.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/.version new/nix-2.35.3/.version
--- old/nix-2.35.2/.version     2026-08-12 23:09:18.000000000 +0200
+++ new/nix-2.35.3/.version     2026-10-13 13:32:25.000000000 +0200
@@ -1 +1 @@
-2.35.2
+2.35.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.35.2/doc/manual/source/release-notes/rl-2.35.md 
new/nix-2.35.3/doc/manual/source/release-notes/rl-2.35.md
--- old/nix-2.35.2/doc/manual/source/release-notes/rl-2.35.md   2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/doc/manual/source/release-notes/rl-2.35.md   2026-10-13 
13:32:25.000000000 +0200
@@ -61,7 +61,7 @@
 
   The `nix` binary now links [mimalloc](https://github.com/microsoft/mimalloc) 
by default, replacing glibc's malloc for all non-GC allocations.
   This yields a **5–12% wall-clock improvement** on evaluation workloads, 
ranging from `nix-instantiate hello` to `nix-env -qa` and full NixOS 
configurations.
-  The allocator can be disabled at build time with `-Dmimalloc=disabled`.
+  The allocator can be disabled at build time with `-Dnix:mimalloc=disabled`.
 
 - The `revCount` attribute of the Git fetchers is now lazily computed and 
passed-through as-is when explicitly specified 
[#15772](https://github.com/NixOS/nix/pull/15772) 
[#14596](https://github.com/NixOS/nix/pull/14596)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/packaging/binary-tarball.nix 
new/nix-2.35.3/packaging/binary-tarball.nix
--- old/nix-2.35.2/packaging/binary-tarball.nix 2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/packaging/binary-tarball.nix 2026-10-13 13:32:25.000000000 
+0200
@@ -79,10 +79,11 @@
   fn=$out/$dir.tar.xz
   mkdir -p $out/nix-support
   echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products
+  # Store mtime is 1 second into the epoch.
   tar cf - \
     --sort=name \
     --owner=0 --group=0 --mode=u+rw,uga+r \
-    --mtime='1970-01-01' \
+    --mtime='@1' \
     --absolute-names \
     --hard-dereference \
     --transform "s,$TMPDIR/install,$dir/install," \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/packaging/dependencies.nix 
new/nix-2.35.3/packaging/dependencies.nix
--- old/nix-2.35.2/packaging/dependencies.nix   2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/packaging/dependencies.nix   2026-10-13 13:32:25.000000000 
+0200
@@ -98,9 +98,14 @@
         "--with-iostreams"
         "--with-url"
       ];
-      patches = [
-        
./patches/0001-Fix-uncaught_exceptions-not-accounting-for-forced_un.patch
-      ];
+      patches = lib.optional (
+        lib.versionAtLeast pkgs.boost.version "1.88"
+        && lib.versionOlder pkgs.boost.version "1.92"
+        # may already be done in nixpkgs: 
https://github.com/NixOS/nixpkgs/pull/546405
+        && !lib.any (patch: lib.hasInfix 
"5883212311535a0046031d74d1568ae173c1e35b" (baseNameOf patch)) (
+          pkgs.boost.patches or [ ]
+        )
+      ) 
./patches/0001-Fix-uncaught_exceptions-not-accounting-for-forced_un.patch;
       enableIcu = false;
     }).overrideAttrs
       (old: {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/packaging/everything.nix 
new/nix-2.35.3/packaging/everything.nix
--- old/nix-2.35.2/packaging/everything.nix     2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/packaging/everything.nix     2026-10-13 13:32:25.000000000 
+0200
@@ -161,7 +161,7 @@
       ln -sT ${nix-manual} $doc
       ln -sT ${nix-manual.man} $man
     ''
-    + lib.optionalString stdenv.isLinux ''
+    + lib.optionalString stdenv.hostPlatform.isLinux ''
       lndir ${nix-nswrapper} $out
     '';
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/packaging/rust-installer/tarball.nix 
new/nix-2.35.3/packaging/rust-installer/tarball.nix
--- old/nix-2.35.2/packaging/rust-installer/tarball.nix 2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/packaging/rust-installer/tarball.nix 2026-10-13 
13:32:25.000000000 +0200
@@ -36,10 +36,11 @@
 
     cp ${installerClosureInfo}/registration $TMPDIR/reginfo
 
+    # Store mtime is 1 second into the epoch.
     tar cf - \
       --sort=name \
       --owner=0 --group=0 --mode=u+rw,uga+r \
-      --mtime='1970-01-01' \
+      --mtime='@1' \
       --absolute-names \
       --hard-dereference \
       --transform "s,$TMPDIR/reginfo,$dir/.reginfo," \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/scripts/install-multi-user.sh 
new/nix-2.35.3/scripts/install-multi-user.sh
--- old/nix-2.35.2/scripts/install-multi-user.sh        2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/scripts/install-multi-user.sh        2026-10-13 
13:32:25.000000000 +0200
@@ -864,6 +864,9 @@
                   cp -RP --preserve=ownership,timestamps ./store/* 
"$NIX_ROOT/store/"
         fi
 
+        _sudo "to chown the $NIX_ROOT/store contents" \
+              chown -hR 0:0 "$NIX_ROOT"/store/*
+
         _sudo "to make the new store non-writable at $NIX_ROOT/store" \
               chmod -R ugo-w "$NIX_ROOT/store/"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/scripts/install-nix-from-tarball.sh 
new/nix-2.35.3/scripts/install-nix-from-tarball.sh
--- old/nix-2.35.2/scripts/install-nix-from-tarball.sh  2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/scripts/install-nix-from-tarball.sh  2026-10-13 
13:32:25.000000000 +0200
@@ -187,6 +187,10 @@
         mv "$i_tmp" "$dest/store/$i"
         chmod -w "$dest/store/$i"
     fi
+    # BusyBox tar is bad at preserving mtime because it doesn't seem to do the 
correct
+    # thing of doing a final fixup pass for fixing parent directory 
permissions and doesn't
+    # handle symlinks at all. So we can set the correct mtime here.
+    find "$dest/store/$i" -depth -exec touch -hmd "@1" {} +
 done
 echo "" >&2
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libcmd/unix/unix-socket-server.cc 
new/nix-2.35.3/src/libcmd/unix/unix-socket-server.cc
--- old/nix-2.35.2/src/libcmd/unix/unix-socket-server.cc        2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libcmd/unix/unix-socket-server.cc        2026-10-13 
13:32:25.000000000 +0200
@@ -49,8 +49,10 @@
 
     xucred cred;
     socklen_t credLen = sizeof(cred);
-    if (getsockopt(remote, SOL_LOCAL, LOCAL_PEERCRED, &cred, &credLen) == 0)
+    if (getsockopt(remote, SOL_LOCAL, LOCAL_PEERCRED, &cred, &credLen) == 0) {
         peer.uid = cred.cr_uid;
+        peer.gid = cred.cr_gid;
+    }
 
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libexpr/attr-set.cc 
new/nix-2.35.3/src/libexpr/attr-set.cc
--- old/nix-2.35.2/src/libexpr/attr-set.cc      2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libexpr/attr-set.cc      2026-10-13 13:32:25.000000000 
+0200
@@ -18,7 +18,7 @@
         throw Error("attribute set of size %d is too big", capacity);
     stats.nrAttrsets++;
     stats.nrAttrsInAttrsets += capacity;
-    return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) 
Bindings();
+    return new (allocBytes<Attr, sizeof(Bindings)>(capacity)) Bindings();
 }
 
 Value & BindingsBuilder::alloc(Symbol name, PosIdx pos)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libexpr/eval.cc 
new/nix-2.35.3/src/libexpr/eval.cc
--- old/nix-2.35.2/src/libexpr/eval.cc  2026-08-12 23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libexpr/eval.cc  2026-10-13 13:32:25.000000000 +0200
@@ -87,9 +87,7 @@
 
 StringData & StringData::alloc(EvalMemory & mem, size_t size)
 {
-    void * t = mem.allocBytes(sizeof(StringData) + size + 1);
-    if (!t)
-        throw std::bad_alloc();
+    void * t = mem.allocBytes<char, sizeof(StringData) + 1>(size);
     auto res = new (t) StringData(size);
     return *res;
 }
@@ -898,7 +896,7 @@
     if (context.empty())
         return nullptr;
 
-    auto ctx = new (mem.allocBytes(sizeof(Context) + context.size() * 
sizeof(value_type))) Context(context.size());
+    auto ctx = new (mem.allocBytes<value_type, 
sizeof(Context)>(context.size())) Context(context.size());
     std::ranges::transform(
         context, ctx->elems, [&](const NixStringContextElem & elt) { return 
&StringData::make(mem, elt.to_string()); });
     return ctx;
@@ -954,7 +952,7 @@
 
 ListBuilder::ListBuilder(EvalMemory & mem, size_t size)
     : size(size)
-    , elems(size <= 2 ? inlineElems : (Value **) mem.allocBytes(size * 
sizeof(Value *)))
+    , elems(size <= 2 ? inlineElems : (Value **) mem.allocBytes<Value *>(size))
 {
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.35.2/src/libexpr/include/nix/expr/eval-inline.hh 
new/nix-2.35.3/src/libexpr/include/nix/expr/eval-inline.hh
--- old/nix-2.35.2/src/libexpr/include/nix/expr/eval-inline.hh  2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libexpr/include/nix/expr/eval-inline.hh  2026-10-13 
13:32:25.000000000 +0200
@@ -26,6 +26,21 @@
     return p;
 }
 
+template<typename T, std::size_t N>
+[[gnu::always_inline]]
+inline void * EvalMemory::allocBytes(size_t count)
+{
+    size_t res = 0;
+
+    if (__builtin_mul_overflow(count, sizeof(T), &res)) [[unlikely]]
+        throw std::bad_alloc();
+
+    if (__builtin_add_overflow(res, N, &res)) [[unlikely]]
+        throw std::bad_alloc();
+
+    return allocBytes(res);
+}
+
 [[gnu::always_inline]]
 Value * EvalMemory::allocValue()
 {
@@ -85,7 +100,7 @@
         env = (Env *) p;
     } else
 #endif
-        env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
+        env = (Env *) allocBytes<Value *, sizeof(Env)>(size);
 
     /* We assume that env->values has been cleared by the allocator; 
maybeThunk() and lookupVar fromWith expect this. */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libexpr/include/nix/expr/eval.hh 
new/nix-2.35.3/src/libexpr/include/nix/expr/eval.hh
--- old/nix-2.35.2/src/libexpr/include/nix/expr/eval.hh 2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libexpr/include/nix/expr/eval.hh 2026-10-13 
13:32:25.000000000 +0200
@@ -325,6 +325,14 @@
     EvalMemory & operator=(EvalMemory &&) = delete;
 
     inline void * allocBytes(size_t n);
+
+    /**
+     * Allocates @p count * sizeof(T) + N contiguous bytes.
+     * @throws bad_alloc if the computation would overflow.
+     */
+    template<typename T, std::size_t N = 0>
+    inline void * allocBytes(size_t count);
+
     inline Value * allocValue();
     inline Env & allocEnv(size_t size);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libexpr-c/nix_api_value.cc 
new/nix-2.35.3/src/libexpr-c/nix_api_value.cc
--- old/nix-2.35.2/src/libexpr-c/nix_api_value.cc       2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libexpr-c/nix_api_value.cc       2026-10-13 
13:32:25.000000000 +0200
@@ -156,7 +156,7 @@
                     .name = name,
                     .args = {},
                     .arity = (size_t) arity,
-                    .doc = doc,
+                    .doc = doc ? std::optional<std::string>{doc} : 
std::nullopt,
                     .impl = std::bind(nix_c_primop_wrapper, fun, user_data, 
arity, _1, _2, _3, _4)};
         if (args)
             for (size_t i = 0; args[i]; i++)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libexpr-tests/nix_api_expr.cc 
new/nix-2.35.3/src/libexpr-tests/nix_api_expr.cc
--- old/nix-2.35.2/src/libexpr-tests/nix_api_expr.cc    2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libexpr-tests/nix_api_expr.cc    2026-10-13 
13:32:25.000000000 +0200
@@ -244,6 +244,16 @@
     nix_init_int(context, ret, i * i);
 }
 
+TEST_F(nix_api_expr_test, nix_alloc_primop_without_doc)
+{
+    PrimOp * primop = nix_alloc_primop(ctx, primop_square, 1, "undocumented", 
nullptr, nullptr, nullptr);
+    assert_ctx_ok();
+    ASSERT_NE(nullptr, primop);
+
+    nix_gc_decref(ctx, primop);
+    assert_ctx_ok();
+}
+
 TEST_F(nix_api_expr_test, nix_expr_primop)
 {
     PrimOp * primop = nix_alloc_primop(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libexpr-tests/primops.cc 
new/nix-2.35.3/src/libexpr-tests/primops.cc
--- old/nix-2.35.2/src/libexpr-tests/primops.cc 2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libexpr-tests/primops.cc 2026-10-13 13:32:25.000000000 
+0200
@@ -1005,4 +1005,18 @@
     auto v = eval("builtins.genericClosure { startSet = []; }");
     ASSERT_THAT(v, IsListOfSize(0));
 }
+
+TEST_F(PrimOpTest, genListOverflow)
+{
+    // Test multiplication overflow detection. Shifting out the upper bits 
would
+    // leave us with a zero size - that should be caught.
+    if (sizeof(void *) == 8) {
+        // (1 << 61) * 8
+        ASSERT_THROW({ eval("builtins.genList (x: x) 2305843009213693952"); }, 
std::bad_alloc);
+    } else if (sizeof(void *) == 4) {
+        // (1 << 30) * 4
+        ASSERT_THROW({ eval("builtins.genList (x: x) 1073741824"); }, 
std::bad_alloc);
+    }
+}
+
 } /* namespace nix */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libfetchers/fetch-to-store.cc 
new/nix-2.35.3/src/libfetchers/fetch-to-store.cc
--- old/nix-2.35.2/src/libfetchers/fetch-to-store.cc    2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libfetchers/fetch-to-store.cc    2026-10-13 
13:32:25.000000000 +0200
@@ -82,6 +82,7 @@
                     path,
                     store.printStorePath(storePath),
                     hash.to_string(HashFormat::SRI, true));
+                settings.srcToStore->cache.insert_or_assign(srcToStoreKey, 
std::make_tuple(storePath, hash, mode));
                 return {storePath, hash};
             }
             debug("source path '%s' not in store", path);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libfetchers/git-utils.cc 
new/nix-2.35.3/src/libfetchers/git-utils.cc
--- old/nix-2.35.2/src/libfetchers/git-utils.cc 2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libfetchers/git-utils.cc 2026-10-13 13:32:25.000000000 
+0200
@@ -23,6 +23,7 @@
 #include <git2/describe.h>
 #include <git2/errors.h>
 #include <git2/global.h>
+#include <git2/index.h>
 #include <git2/indexer.h>
 #include <git2/object.h>
 #include <git2/odb.h>
@@ -117,6 +118,7 @@
 typedef std::unique_ptr<git_odb, Deleter<git_odb_free>> ObjectDb;
 typedef std::unique_ptr<git_packbuilder, Deleter<git_packbuilder_free>> 
PackBuilder;
 typedef std::unique_ptr<git_indexer, Deleter<git_indexer_free>> Indexer;
+typedef std::unique_ptr<git_index, Deleter<git_index_free>> Index;
 
 static Hash toHash(const git_oid & oid)
 {
@@ -572,10 +574,27 @@
         if (git_status_foreach_ext(*this, &options, &statusCallbackTrampoline, 
&statusCallback))
             throw GitError("getting working directory status");
 
-        /* Get submodule info. */
+        /* Gitlinks in the index are the submodules; .gitmodules only
+           supplies their URLs. */
+        std::map<CanonPath, Submodule> configured;
         auto modulesFile = path / ".gitmodules";
         if (pathExists(modulesFile))
-            info.submodules = parseSubmodules(modulesFile);
+            for (auto & submodule : parseSubmodules(modulesFile))
+                configured.emplace(submodule.path, submodule);
+
+        Index index;
+        if (git_repository_index(Setter(index), *this))
+            throw GitError("opening index of Git repository %s", 
PathFmt(path));
+        for (size_t n = 0, count = git_index_entrycount(index.get()); n < 
count; ++n) {
+            auto entry = git_index_get_byindex(index.get(), n);
+            if (entry->mode != GIT_FILEMODE_COMMIT || 
git_index_entry_stage(entry) != 0)
+                continue;
+            CanonPath entryPath(entry->path);
+            if (auto it = configured.find(entryPath); it != configured.end())
+                info.submodules.push_back(std::move(it->second));
+            else
+                info.submodules.push_back(Submodule{.path = entryPath});
+        }
 
         return info;
     }
@@ -968,7 +987,7 @@
 
             auto path2 = *parent;
             path2.push(entryName);
-            lookupCache.emplace(path2, std::move(copy)).first->second.get();
+            lookupCache.emplace(path2, std::move(copy));
         }
 
         return res;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libfetchers/git.cc 
new/nix-2.35.3/src/libfetchers/git.cc
--- old/nix-2.35.2/src/libfetchers/git.cc       2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libfetchers/git.cc       2026-10-13 13:32:25.000000000 
+0200
@@ -767,7 +767,10 @@
     {
         auto head = std::visit(
             overloaded{
-                [&](const std::filesystem::path & path) { return 
GitRepo::openRepo(path, {})->getWorkdirRef(); },
+                [&](const std::filesystem::path & path) -> 
std::optional<std::string> {
+                    /* A detached HEAD is still resolvable by libgit2. */
+                    return GitRepo::openRepo(path, 
{})->getWorkdirRef().value_or("HEAD");
+                },
                 [&](const ParsedURL & url) { return readHeadCached(settings, 
url.to_string(), shallow); }},
             repoInfo.location);
         if (!head) {
@@ -989,10 +992,9 @@
     {
         auto repoPath = repoInfo.getPath().value();
 
-        if (getSubmodulesAttr(input))
-            /* Create mountpoints for the submodules. */
-            for (auto & submodule : repoInfo.workdirInfo.submodules)
-                repoInfo.workdirInfo.files.insert(submodule.path);
+        /* Create mountpoints for the submodules. */
+        for (auto & submodule : repoInfo.workdirInfo.submodules)
+            repoInfo.workdirInfo.files.insert(submodule.path);
 
         auto repo = GitRepo::openRepo(repoPath, {});
 
@@ -1002,12 +1004,19 @@
             repo->getAccessor(repoInfo.workdirInfo, {.exportIgnore = 
exportIgnore}, makeNotAllowedError(repoPath));
 
         /* If the repo has submodules, return a mounted input accessor
-           consisting of the accessor for the top-level repo and the
-           accessors for the submodule workdirs. */
-        if (getSubmodulesAttr(input) && 
!repoInfo.workdirInfo.submodules.empty()) {
+           consisting of the accessor for the top-level repo and, per
+           submodule, either its workdir accessor or an empty directory
+           where getAccessorFromCommit() would produce one (submodules
+           disabled, or a gitlink without a .gitmodules entry). */
+        if (!repoInfo.workdirInfo.submodules.empty()) {
             std::map<CanonPath, nix::ref<SourceAccessor>> mounts;
 
             for (auto & submodule : repoInfo.workdirInfo.submodules) {
+                if (!getSubmodulesAttr(input) || submodule.url.empty()) {
+                    mounts.insert_or_assign(submodule.path, 
makeEmptySourceAccessor());
+                    continue;
+                }
+
                 auto submodulePath = repoPath / submodule.path.rel();
                 fetchers::Attrs attrs;
                 attrs.insert_or_assign("type", "git");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libstore/build/build-log.cc 
new/nix-2.35.3/src/libstore/build/build-log.cc
--- old/nix-2.35.2/src/libstore/build/build-log.cc      2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libstore/build/build-log.cc      2026-10-13 
13:32:25.000000000 +0200
@@ -10,9 +10,16 @@
 
 void BuildLog::operator()(std::string_view data)
 {
-    for (auto c : data)
+    for (auto c : data) {
+        /* Only let a '\r' reset the column if it isn't followed by '\n', so
+           "\r\n" acts as a line terminator; defer a char to handle split 
chunks. */
+        if (pendingCR) {
+            pendingCR = false;
+            if (c != '\n')
+                currentLogLinePos = 0;
+        }
         if (c == '\r')
-            currentLogLinePos = 0;
+            pendingCR = true;
         else if (c == '\n')
             flushLine();
         else {
@@ -20,6 +27,7 @@
                 currentLogLine.resize(currentLogLinePos + 1);
             currentLogLine[currentLogLinePos++] = c;
         }
+    }
 }
 
 void BuildLog::flush()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libstore/daemon.cc 
new/nix-2.35.3/src/libstore/daemon.cc
--- old/nix-2.35.2/src/libstore/daemon.cc       2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libstore/daemon.cc       2026-10-13 13:32:25.000000000 
+0200
@@ -410,6 +410,10 @@
             bool repairBool;
             conn.from >> repairBool;
             auto repair = RepairFlag{repairBool};
+            /* Repairing is not atomic, so disallowed for "untrusted"
+               clients. */
+            if (repair && !trusted)
+                throw Error("you are not privileged to repair paths");
 
             logger->startWork();
             auto pathInfo = [&]() {
@@ -491,6 +495,10 @@
     case WorkerProto::Op::AddMultipleToStore: {
         bool repair, dontCheckSigs;
         conn.from >> repair >> dontCheckSigs;
+        /* Repairing is not atomic, so disallowed for "untrusted"
+           clients. */
+        if (repair && !trusted)
+            throw Error("you are not privileged to repair store paths");
         if (!trusted && dontCheckSigs)
             dontCheckSigs = false;
 
@@ -923,6 +931,10 @@
         info.sigs = WorkerProto::Serialise<std::set<Signature>>::read(*store, 
rconn);
         info.ca = ContentAddress::parseOpt(readString(conn.from));
         conn.from >> repair >> dontCheckSigs;
+        /* Repairing is not atomic, so disallowed for "untrusted"
+           clients. */
+        if (repair && !trusted)
+            throw Error("you are not privileged to repair store paths");
         if (!trusted && dontCheckSigs)
             dontCheckSigs = false;
         if (!trusted)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.35.2/src/libstore/darwin/build/darwin-derivation-builder.cc 
new/nix-2.35.3/src/libstore/darwin/build/darwin-derivation-builder.cc
--- old/nix-2.35.2/src/libstore/darwin/build/darwin-derivation-builder.cc       
2026-08-12 23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libstore/darwin/build/darwin-derivation-builder.cc       
2026-10-13 13:32:25.000000000 +0200
@@ -109,11 +109,6 @@
         const size_t breakpoint = sandboxProfile.length() + (1 << 14);
         for (auto & i : pathsInChroot) {
 
-            if (sandboxProfile.length() >= breakpoint) {
-                debug("Sandbox break: %d %d", sandboxProfile.length(), 
breakpoint);
-                sandboxProfile += ")\n(allow file-read* file-write* 
process-exec\n";
-            }
-
             if (i.first != i.second.source)
                 throw Error(
                     "can't map %1% to %2%: mismatched impure paths not 
supported on Darwin",
@@ -127,6 +122,16 @@
                     continue;
                 throw SysError("getting attributes of required path '%s", 
path);
             }
+
+            /* Only open a new allow form once we know this path will actually
+             * contribute a selector. Opening it before resolving the path
+             * leaves an unqualified (allow ...) form behind when an optional
+             * path is missing, and an unqualified allow form render the 
sandbox useless. */
+            if (sandboxProfile.length() >= breakpoint) {
+                debug("Sandbox break: %d %d", sandboxProfile.length(), 
breakpoint);
+                sandboxProfile += ")\n(allow file-read* file-write* 
process-exec\n";
+            }
+
             if (S_ISDIR(optSt->st_mode))
                 sandboxProfile += fmt("\t(subpath \"%s\")\n", path);
             else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libstore/derivations.cc 
new/nix-2.35.3/src/libstore/derivations.cc
--- old/nix-2.35.2/src/libstore/derivations.cc  2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libstore/derivations.cc  2026-10-13 13:32:25.000000000 
+0200
@@ -945,7 +945,8 @@
                     [&](const DrvHashModulo::DeferredDrv &) { return true; },
                     // Regular non-CA derivation, replace derivation
                     [&](const DrvHashModulo::DrvHash & drvHash) {
-                        
inputs2.insert_or_assign(drvHash.to_string(HashFormat::Base16, false), node);
+                        inputs2[drvHash.to_string(HashFormat::Base16, 
false)].value.insert(
+                            node.value.begin(), node.value.end());
                         return false;
                     },
                     // CA derivation's output hashes
@@ -955,11 +956,7 @@
                             const auto h = get(outputHashes, outputName);
                             if (!h)
                                 throw Error("no hash for output '%s' of 
derivation '%s'", outputName, drv.name);
-                            inputs2.insert_or_assign(
-                                h->to_string(HashFormat::Base16, false),
-                                DerivedPathMap<StringSet>::ChildNode{
-                                    .value = {"out"},
-                                });
+                            inputs2[h->to_string(HashFormat::Base16, 
false)].value.insert("out");
                         }
                         return false;
                     },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libstore/globals.cc 
new/nix-2.35.3/src/libstore/globals.cc
--- old/nix-2.35.2/src/libstore/globals.cc      2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libstore/globals.cc      2026-10-13 13:32:25.000000000 
+0200
@@ -4,6 +4,7 @@
 #include "nix/util/config-global.hh"
 #include "nix/util/current-process.hh"
 #include "nix/util/executable-path.hh"
+#include "nix/util/file-system.hh"
 #include "nix/util/args.hh"
 #include "nix/util/abstract-setting-to-json.hh"
 #include "nix/util/compute-levels.hh"
@@ -254,11 +255,11 @@
     // machines. Note that we can’t force processes from executing
     // x86_64 in aarch64 environments or vice versa since they can
     // always exec with their own binary preferences.
+    //
+    // The runtime file exists iff Rosetta 2 is installed; checking it avoids
+    // spawning a subprocess during static initialization of `settings`.
     if (std::string{NIX_LOCAL_SYSTEM} == "aarch64-darwin"
-        && runProgram(
-               RunOptions{.program = "arch", .args = {"-arch", "x86_64", 
"/usr/bin/true"}, .mergeStderrToStdout = true})
-                   .first
-               == 0)
+        && pathExists("/Library/Apple/usr/libexec/oah/libRosettaRuntime"))
         extraPlatforms.insert("x86_64-darwin");
 #endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.35.2/src/libstore/include/nix/store/build/build-log.hh 
new/nix-2.35.3/src/libstore/include/nix/store/build/build-log.hh
--- old/nix-2.35.2/src/libstore/include/nix/store/build/build-log.hh    
2026-08-12 23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libstore/include/nix/store/build/build-log.hh    
2026-10-13 13:32:25.000000000 +0200
@@ -31,6 +31,8 @@
     std::string currentLogLine;
     size_t currentLogLinePos = 0; // to handle carriage return
 
+    bool pendingCR = false; // defer '\r' so "\r\n" is treated as a line 
terminator
+
     void flushLine();
 
 public:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libstore/local-store.cc 
new/nix-2.35.3/src/libstore/local-store.cc
--- old/nix-2.35.2/src/libstore/local-store.cc  2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libstore/local-store.cc  2026-10-13 13:32:25.000000000 
+0200
@@ -1065,8 +1065,12 @@
 
             /* The path may have been created by another process in the 
meantime, so check again. */
             if (repair || !isValidPathUncached(info.path)) {
-
-                deletePath(realPath);
+                /* We'll restore to a temporary location accessible only to us 
first, confirm that
+                   the narHash/narSize/ca match after restoration and only 
then move the path into
+                   the expected location. */
+                auto [tempDir, tempDirFd] = createTempDirInStore();
+                AutoDelete delTempDir(tempDir);
+                std::filesystem::path tempPath = tempDir / "x";
 
                 /* While restoring the path from the NAR, compute the hash
                    of the NAR. */
@@ -1074,7 +1078,7 @@
 
                 TeeSource wrapperSource{source, hashSink};
 
-                restorePath(realPath, wrapperSource, 
config->getLocalSettings().fsyncStorePaths);
+                restorePath(tempPath, wrapperSource, 
config->getLocalSettings().fsyncStorePaths);
 
                 auto hashResult = hashSink.finish();
 
@@ -1095,7 +1099,7 @@
                 if (info.ca) {
                     auto & specified = *info.ca;
                     auto actualHash = ({
-                        SourcePath sourcePath = 
requireStoreObjectAccessor(info.path, /*requireValidPath=*/false);
+                        SourcePath sourcePath = 
{makeFSSourceAccessor(tempPath)};
                         Hash h{HashAlgorithm::SHA256}; // throwaway def to 
appease C++
                         auto fim = specified.method.getFileIngestionMethod();
                         switch (fim) {
@@ -1127,6 +1131,19 @@
                     }
                 }
 
+                /* Now that the content address / signed NAR contents is 
checked, we can move the path into place.
+                   TODO: We should use atomic exchange (RENAME_EXCHANGE and 
renamex_np with RENAME_SWAP) if possible. */
+
+                /* Delete the path for good measure even if not repairing. */
+                deletePath(realPath);
+
+                /* Move the temporary path we restored above. */
+                moveFile(tempPath, realPath);
+
+                /* Clean up the staging directory. */
+                delTempDir.deletePath();
+                tempDirFd.close();
+
                 autoGC();
 
                 canonicalisePathMetaData(realPath, 
{NIX_WHEN_SUPPORT_ACLS(config->getLocalSettings().ignoredAcls)});
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libstore/s3-binary-cache-store.cc 
new/nix-2.35.3/src/libstore/s3-binary-cache-store.cc
--- old/nix-2.35.2/src/libstore/s3-binary-cache-store.cc        2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libstore/s3-binary-cache-store.cc        2026-10-13 
13:32:25.000000000 +0200
@@ -376,7 +376,7 @@
         req.uri = VerbatimURL(url);
         req.method = HttpMethod::Delete;
 
-        fileTransfer->enqueueFileTransfer(req).get();
+        (void) fileTransfer->enqueueFileTransfer(req).get();
     } catch (...) {
         ignoreExceptionInDestructor();
     }
@@ -409,7 +409,7 @@
     req.data = {payload};
     req.mimeType = "text/xml";
 
-    fileTransfer->enqueueFileTransfer(req).get();
+    (void) fileTransfer->enqueueFileTransfer(req).get();
 
     debug("S3 multipart upload completed: %d parts uploaded for '%s'", 
partEtags.size(), key);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/nix-2.35.2/src/libstore/unix/build/derivation-builder.cc 
new/nix-2.35.3/src/libstore/unix/build/derivation-builder.cc
--- old/nix-2.35.2/src/libstore/unix/build/derivation-builder.cc        
2026-08-12 23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/libstore/unix/build/derivation-builder.cc        
2026-10-13 13:32:25.000000000 +0200
@@ -1777,7 +1777,9 @@
             useSandbox = params.drv.type().isSandboxed() && 
!params.drvOptions.noChroot;
     }
 
-    if (store.storeDir != store.config->realStoreDir.get()) {
+    const bool isRelocatedStore = store.storeDir != 
store.config->realStoreDir.get();
+
+    if (isRelocatedStore) {
 #if defined(__linux__) || defined(__FreeBSD__)
         useSandbox = true;
 #else
@@ -1790,10 +1792,19 @@
         if (!localSettings.sandboxFallback)
             throw Error(
                 "this system does not support the kernel namespaces that are 
required for sandboxing; use '--no-sandbox' to disable sandboxing");
-        debug("auto-disabling sandboxing because the prerequisite namespaces 
are not available");
+
+        if (isRelocatedStore)
+            throw Error(
+                "this system does not support the kernel namespaces that are 
required for sandboxing, which is required for building in a diverted store");
+
+        static std::atomic<bool> warned = false;
+        warnOnce(
+            warned,
+            "auto-disabling sandboxing because the prerequisite namespaces are 
not available and '%1%' is enabled; use '--no-sandbox' or specify 'sandbox = 
false' setting to silence this warning",
+            localSettings.sandboxFallback.name);
+
         useSandbox = false;
     }
-
 #endif
 
     if (!useSandbox && params.drvOptions.useUidRange(params.drv))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/libutil/archive.cc 
new/nix-2.35.3/src/libutil/archive.cc
--- old/nix-2.35.2/src/libutil/archive.cc       2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/src/libutil/archive.cc       2026-10-13 13:32:25.000000000 
+0200
@@ -1,10 +1,11 @@
+#include <algorithm>
 #include <cerrno>
+#include <limits>
 #include <map>
 
 #include <strings.h> // for strcasecmp
 
 #include "nix/util/archive.hh"
-#include "nix/util/alignment.hh"
 #include "nix/util/config-global.hh"
 #include "nix/util/source-accessor.hh"
 #include "nix/util/source-path.hh"
@@ -151,7 +152,7 @@
     sink.preallocateContents(size);
 
     if (sink.skipContents) {
-        uint64_t left = alignUp(size, 8);
+        uint64_t left = size;
         /* Source::skip takes a size_t, which might be narrower on 32 bit 
systems, so
            be careful around truncations. */
         while (left) {
@@ -159,11 +160,10 @@
             source.skip(toSkip);
             left -= toSkip;
         }
-        return;
+    } else {
+        source.drainInto(sink, size);
     }
 
-    source.drainInto(sink, size);
-
     readPadding(size, source);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/src/nix/flake-prefetch-inputs.cc 
new/nix-2.35.3/src/nix/flake-prefetch-inputs.cc
--- old/nix-2.35.2/src/nix/flake-prefetch-inputs.cc     2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/src/nix/flake-prefetch-inputs.cc     2026-10-13 
13:32:25.000000000 +0200
@@ -42,7 +42,9 @@
             if (!state_.lock()->done.insert(&node).second)
                 return;
 
-            if (auto lockedNode = dynamic_cast<const LockedNode *>(&node)) {
+            // Relative path inputs are part of their parent's source tree.
+            if (auto lockedNode = dynamic_cast<const LockedNode *>(&node);
+                lockedNode && !lockedNode->lockedRef.input.isRelative()) {
                 try {
                     Activity act(*logger, lvlInfo, actUnknown, fmt("fetching 
'%s'", lockedNode->lockedRef));
                     auto accessor = 
lockedNode->lockedRef.input.getAccessor(fetchSettings, *store).first;
@@ -56,11 +58,11 @@
 
             for (auto & [inputName, input] : node.inputs) {
                 if (auto inputNode = std::get_if<0>(&input))
-                    pool.enqueue(std::bind(visit, **inputNode));
+                    pool.enqueue([&visit, inputNode(*inputNode)] { 
visit(*inputNode); });
             }
         };
 
-        pool.enqueue(std::bind(visit, *flake.lockFile.root));
+        pool.enqueue([&] { visit(*flake.lockFile.root); });
 
         pool.process();
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/tests/functional/fetchGit.sh 
new/nix-2.35.3/tests/functional/fetchGit.sh
--- old/nix-2.35.2/tests/functional/fetchGit.sh 2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/tests/functional/fetchGit.sh 2026-10-13 13:32:25.000000000 
+0200
@@ -211,6 +211,9 @@
 git -C "$TEST_ROOT"/minimal fetch "$repo" "$rev2"
 git -C "$TEST_ROOT"/minimal checkout "$rev2"
 [[ $(nix eval --impure --raw --expr "(builtins.fetchGit { url = 
$TEST_ROOT/minimal; }).rev") = "$rev2" ]]
+# Detached HEAD must not fall back to a guessed 'master' ref.
+expectStderr 0 nix eval --raw --expr "(builtins.fetchGit { url = 
$TEST_ROOT/minimal; rev = \"$rev2\"; }).outPath" \
+    | grepQuietInverse "could not read HEAD ref"
 
 # Explicit ref = "HEAD" should work, and produce the same outPath as without 
ref
 path7=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = 
\"file://$repo\"; ref = \"HEAD\"; }).outPath")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/tests/functional/fetchGitSubmodules.sh 
new/nix-2.35.3/tests/functional/fetchGitSubmodules.sh
--- old/nix-2.35.2/tests/functional/fetchGitSubmodules.sh       2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/tests/functional/fetchGitSubmodules.sh       2026-10-13 
13:32:25.000000000 +0200
@@ -36,7 +36,21 @@
 
 rev=$(git -C "$rootRepo" rev-parse HEAD)
 
+# A clean workdir must yield the same tree as fetching its HEAD rev: the
+# submodule is an empty directory, whether or not it is checked out.
+r0=$(nix eval --impure --raw --expr "(builtins.fetchGit { url = 
\"file://$rootRepo\"; }).outPath")
+[[ -d $r0/sub ]]
+[[ -z "$(ls -A "$r0/sub")" ]]
+# Both paths share a fingerprint, so compare narHashes with separate caches.
+hashWorkdir=$(XDG_CACHE_HOME=$TEST_ROOT/cache-workdir nix eval --impure --raw 
--expr "(builtins.fetchGit { url = \"file://$rootRepo\"; }).narHash")
+hashRev=$(XDG_CACHE_HOME=$TEST_ROOT/cache-rev nix eval --raw --expr 
"(builtins.fetchGit { url = \"file://$rootRepo\"; rev = \"$rev\"; }).narHash")
+[[ $hashWorkdir == "$hashRev" ]]
+# The non-local (clone-to-cache) code path must agree as well.
+hashHttp=$(_NIX_FORCE_HTTP=1 XDG_CACHE_HOME=$TEST_ROOT/cache-http nix eval 
--raw --expr "(builtins.fetchGit { url = \"file://$rootRepo\"; rev = \"$rev\"; 
}).narHash")
+[[ $hashWorkdir == "$hashHttp" ]]
+
 r1=$(nix eval --raw --expr "(builtins.fetchGit { url = \"file://$rootRepo\"; 
rev = \"$rev\"; }).outPath")
+[[ $r0 == "$r1" ]]
 r2=$(nix eval --raw --expr "(builtins.fetchGit { url = \"file://$rootRepo\"; 
rev = \"$rev\"; submodules = false; }).outPath")
 r3=$(nix eval --raw --expr "(builtins.fetchGit { url = \"file://$rootRepo\"; 
rev = \"$rev\"; submodules = true; }).outPath")
 
@@ -226,3 +240,28 @@
 
 }
 test_submodule_nested
+
+
+# A gitlink without a .gitmodules entry is still a submodule (#15423): it must
+# render the same (empty directory) from the workdir and by rev.
+test_gitlink_without_gitmodules() {
+  local repo=$TEST_ROOT/nogitmodules
+  createGitRepo "$repo"
+  git -C "$repo" submodule add "$subRepo" sub
+  git -C "$repo" commit -m "Add submodule"
+  git -C "$repo" rm .gitmodules
+  git -C "$repo" commit -m "Remove .gitmodules"
+  local rev
+  rev=$(git -C "$repo" rev-parse HEAD)
+
+  for submodules in true false; do
+    local hashWorkdir hashRev outWorkdir
+    hashWorkdir=$(XDG_CACHE_HOME=$TEST_ROOT/ngm-workdir-$submodules nix eval 
--impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; submodules 
= $submodules; }).narHash")
+    hashRev=$(XDG_CACHE_HOME=$TEST_ROOT/ngm-rev-$submodules nix eval --raw 
--expr "(builtins.fetchGit { url = \"file://$repo\"; rev = \"$rev\"; submodules 
= $submodules; }).narHash")
+    [[ $hashWorkdir == "$hashRev" ]]
+    outWorkdir=$(XDG_CACHE_HOME=$TEST_ROOT/ngm-workdir-$submodules nix eval 
--impure --raw --expr "(builtins.fetchGit { url = \"file://$repo\"; submodules 
= $submodules; }).outPath")
+    [[ -d $outWorkdir/sub ]]
+    [[ -z "$(ls -A "$outWorkdir/sub")" ]]
+  done
+}
+test_gitlink_without_gitmodules
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/tests/functional/flakes/relative-paths.sh 
new/nix-2.35.3/tests/functional/flakes/relative-paths.sh
--- old/nix-2.35.2/tests/functional/flakes/relative-paths.sh    2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/tests/functional/flakes/relative-paths.sh    2026-10-13 
13:32:25.000000000 +0200
@@ -68,6 +68,9 @@
 git -C "$rootFlake" add sub2/flake.lock
 [[ $(nix eval "$subflake2#y") = 15 ]]
 
+# Relative path inputs must not make prefetch-inputs fail.
+nix flake prefetch-inputs "$subflake2"
+
 [[ $(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.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/tests/functional/gc-closure.sh 
new/nix-2.35.3/tests/functional/gc-closure.sh
--- old/nix-2.35.2/tests/functional/gc-closure.sh       2026-08-12 
23:09:18.000000000 +0200
+++ new/nix-2.35.3/tests/functional/gc-closure.sh       2026-10-13 
13:32:25.000000000 +0200
@@ -12,7 +12,7 @@
     input0=$(realpath "$TEST_ROOT/gc-root")
     input1=$(nix build -f dependencies2.nix input1_drv --no-link 
--print-out-paths)
     input2=$(nix build -f dependencies2.nix input2_drv --no-link 
--print-out-paths)
-    input2_out=$(printf "%s" "$input2" | head -n1)
+    input2_out=$(head -n1 <<< "$input2")
     input2_out2=$(printf "%s" "$input2" | tail -n1)
     top=$(nix build -f dependencies2.nix --no-link --print-out-paths)
     something_else=$(nix store add-path ./dependencies2.nix)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/nix-2.35.2/tests/installer/default.nix 
new/nix-2.35.3/tests/installer/default.nix
--- old/nix-2.35.2/tests/installer/default.nix  2026-08-12 23:09:18.000000000 
+0200
+++ new/nix-2.35.3/tests/installer/default.nix  2026-10-13 13:32:25.000000000 
+0200
@@ -4,10 +4,31 @@
 }:
 
 let
+  commonCheck = ''
+    export NIX_CONFIG="substituters = "
 
-  installScripts = {
+    nix-env --version
+
+    nix --extra-experimental-features nix-command store info
+    nix-store --verify --check-contents
+    nix store verify --all --extra-experimental-features nix-command --no-trust
+
+    nix-channel --add file://$HOME/channel myChannel
+    nix-channel --update
+    [[ $(nix-instantiate --eval --expr 'builtins.readFile 
<myChannel/someFile>') = '"someContent"' ]]
+
+    bad_mtime=$( find /nix/store/ -mindepth 1 ! -path /nix/store/.links \
+                 -exec sh -c '[ "$(stat -c %Y "{}")" -ne 1 ]' \; -print -quit )
+    if [ -n "$bad_mtime" ]; then
+      echo "bad filesystem object mtime after install:"
+      stat "$bad_mtime"
+      exit 1
+    fi
+  '';
+
+  installCases = {
     install-default = {
-      script = ''
+      install = ''
         tar -xf ./nix.tar.xz
         mv ./nix-* nix
         ./nix/install --no-channel-add
@@ -15,7 +36,7 @@
     };
 
     install-both-profile-links = {
-      script = ''
+      install = ''
         tar -xf ./nix.tar.xz
         mv ./nix-* nix
         ln -s $HOME/.local/state/nix/profiles/a-profile $HOME/.nix-profile
@@ -26,7 +47,7 @@
     };
 
     install-force-no-daemon = {
-      script = ''
+      install = ''
         tar -xf ./nix.tar.xz
         mv ./nix-* nix
         ./nix/install --no-daemon --no-channel-add
@@ -34,11 +55,26 @@
     };
 
     install-force-daemon = {
-      script = ''
+      install = ''
         tar -xf ./nix.tar.xz
         mv ./nix-* nix
         ./nix/install --daemon --no-channel-add
       '';
+
+      check = ''
+        [ "$(stat -c '%a %U:%G' /nix/store)" = "1775 root:nixbld" ] || {
+          echo "/nix/store is not 1775 root:nixbld:"
+          stat /nix/store
+          exit 1
+        }
+
+        bad_ownership=$(find /nix/store/ -mindepth 1 ! \( -user root -group 
root \) -print -quit)
+        if [ -n "$bad_ownership" ]; then
+          echo "bad store object ownership in the store after install:"
+          stat "$bad_ownership"
+          exit 1
+        fi
+      '';
     };
   };
 
@@ -136,13 +172,13 @@
       postBoot = disableSELinux;
       extraQemuOpts = "-cpu Westmere-v2";
     };
-
   };
 
   makeTest =
     imageName: testName:
     let
       image = images.${imageName};
+      test = installCases.${testName};
     in
     with nixpkgsFor.${image.system}.native;
     runCommand "installer-test-${imageName}-${testName}"
@@ -153,11 +189,13 @@
         ];
         image = image.image;
         postBoot = image.postBoot or "";
-        installScript = installScripts.${testName}.script;
+        installScript = test.install;
+        checkScript = commonCheck + (test.check or "");
         binaryTarball = binaryTarballs.${image.system};
       }
       ''
         shopt -s nullglob
+        set -eu
 
         echo "Unpacking Vagrant box $image..."
         tar xvf $image
@@ -207,7 +245,7 @@
 
         if [[ -n $postBoot ]]; then
           echo "Running post-boot commands..."
-          $ssh "set -ex; $postBoot"
+          $ssh "set -eux; $postBoot"
         fi
 
         echo "Copying installer..."
@@ -223,30 +261,14 @@
 
         echo "Testing Nix installation..."
         $ssh <<EOF
-          set -ex
-
           # FIXME: get rid of this; ideally ssh should just work.
           source ~/.bash_profile || true
           source ~/.bash_login || true
           source ~/.profile || true
           source /etc/bashrc || true
 
-          nix-env --version
-          nix --extra-experimental-features nix-command store info
-
-          out=\$(nix-build --no-substitute -E 'derivation { name = "foo"; 
system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > 
\$out"]; }')
-          [[ \$(cat \$out) = foobar ]]
-
-          if pgrep nix-daemon; then
-            MAYBESUDO="sudo"
-          else
-            MAYBESUDO=""
-          fi
-
-
-          $MAYBESUDO \$(which nix-channel) --add file://\$HOME/channel 
myChannel
-          $MAYBESUDO \$(which nix-channel) --update
-          [[ \$(nix-instantiate --eval --expr 'builtins.readFile 
<myChannel/someFile>') = '"someContent"' ]]
+          set -eux
+          $checkScript
         EOF
 
         echo "Done!"
@@ -256,5 +278,5 @@
 in
 
 builtins.mapAttrs (imageName: image: {
-  ${image.system} = builtins.mapAttrs (testName: test: makeTest imageName 
testName) installScripts;
+  ${image.system} = builtins.mapAttrs (testName: test: makeTest imageName 
testName) installCases;
 }) images

Reply via email to