From 509f91a4b1e8357f702cae987b41798f619ead01 Mon Sep 17 00:00:00 2001 From: Markus Ziller Date: Wed, 17 Dec 2025 10:33:34 +0100 Subject: [PATCH 1/2] Add test for serialization behaviour --- src/manifest.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/manifest.rs b/src/manifest.rs index 6141a40d..31670718 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -1349,6 +1349,46 @@ mod tests { assert!(serialized.contains("[package]")); assert!(serialized.contains("test")); } + + #[test] + fn packages_manifest_serialization_is_consistent_regardless_of_empty_dependencies_section() { + // A manifest with an empty [dependencies] section should serialize + // identically to a manifest without a [dependencies] section. + // This is important for reproducible package hashes. + + let toml_with_empty_deps = r#" + edition = "0.12" + + [package] + type = "lib" + name = "test" + version = "1.0.0" + + [dependencies] + "#; + + let toml_without_deps = r#" + edition = "0.12" + + [package] + type = "lib" + name = "test" + version = "1.0.0" + "#; + + let manifest_with = PackagesManifest::from_str(toml_with_empty_deps).expect("should parse"); + let manifest_without = PackagesManifest::from_str(toml_without_deps).expect("should parse"); + + let serialized_with: String = manifest_with.try_into().expect("should serialize"); + let serialized_without: String = manifest_without.try_into().expect("should serialize"); + + assert_eq!( + serialized_with, serialized_without, + "Serialization must be consistent for reproducible package hashes.\n\ + With [dependencies]:\n{}\n\nWithout [dependencies]:\n{}", + serialized_with, serialized_without + ); + } } // ===== WorkspaceManifest Tests ===== From f00f4ad43c48adedc8e8fc45749d9a1673f104e7 Mon Sep 17 00:00:00 2001 From: Markus Ziller Date: Wed, 17 Dec 2025 10:37:57 +0100 Subject: [PATCH 2/2] Expand test to hashing --- src/manifest.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/manifest.rs b/src/manifest.rs index 31670718..ec9698e0 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -1355,6 +1355,7 @@ mod tests { // A manifest with an empty [dependencies] section should serialize // identically to a manifest without a [dependencies] section. // This is important for reproducible package hashes. + use crate::lock::DigestAlgorithm; let toml_with_empty_deps = r#" edition = "0.12" @@ -1382,11 +1383,16 @@ mod tests { let serialized_with: String = manifest_with.try_into().expect("should serialize"); let serialized_without: String = manifest_without.try_into().expect("should serialize"); + let hash_with = DigestAlgorithm::SHA256.digest(serialized_with.as_bytes()); + let hash_without = DigestAlgorithm::SHA256.digest(serialized_without.as_bytes()); + assert_eq!( - serialized_with, serialized_without, - "Serialization must be consistent for reproducible package hashes.\n\ + hash_with, hash_without, + "Package hashes must be identical for reproducible builds.\n\ + Hash with [dependencies]: {}\n\ + Hash without [dependencies]: {}\n\n\ With [dependencies]:\n{}\n\nWithout [dependencies]:\n{}", - serialized_with, serialized_without + hash_with, hash_without, serialized_with, serialized_without ); } }