77#include " nix/util/users.hh"
88#include " nix/util/util.hh"
99#include " nix/util/hash.hh"
10+ #include " nix/util/json-utils.hh"
1011#include " nix/store/ssh.hh"
1112#include " nix/util/deleter.hh"
1213
@@ -291,7 +292,8 @@ void Fetch::fetch(
291292
292293 const auto obj = objUrls[0 ];
293294 try {
294- std::string sha256 = obj.at (" oid" ); // oid is also the sha256
295+ // Use the committed pointer's oid/size for integrity, not server's claim
296+ std::string sha256 = pointer->oid ;
295297 std::string ourl = obj.at (" actions" ).at (" download" ).at (" href" );
296298 auto authHeader = [&]() -> std::optional<std::string> {
297299 const auto & download = obj.at (" actions" ).at (" download" );
@@ -303,7 +305,20 @@ void Fetch::fetch(
303305 return std::nullopt ;
304306 return std::string (*authIt);
305307 }();
306- const uint64_t size = obj.at (" size" );
308+ const uint64_t size = pointer->size ;
309+
310+ auto objOid = getString (valueAt (getObject (obj), " oid" ));
311+ auto objSize = getUnsigned (valueAt (getObject (obj), " size" ));
312+ if (objOid != pointer->oid || objSize != pointer->size ) {
313+ throw Error (
314+ " LFS server returned mismatched oid/size for '%s' (got oid=%s size=%d, expected oid=%s size=%d)" ,
315+ pointerFilePath,
316+ objOid,
317+ objSize,
318+ pointer->oid ,
319+ pointer->size );
320+ }
321+
307322 sizeCallback (size);
308323 downloadToSink (ourl, authHeader, sink, sha256, size);
309324
0 commit comments