@@ -291,12 +291,13 @@ mod proof_tests {
291291
292292#[ cfg( test) ]
293293mod tests {
294+ use crate :: diff:: IgnoreConflictsResolver ;
294295 use crate :: git:: types:: DiffOperation ;
295296 #[ cfg( feature = "rocksdb_storage" ) ]
296297 use crate :: git:: versioned_store:: RocksDBVersionedKvStore ;
297298 use crate :: git:: versioned_store:: {
298- FileVersionedKvStore , GitVersionedKvStore , HistoricalAccess , HistoricalCommitAccess ,
299- InMemoryVersionedKvStore , ThreadSafeGitVersionedKvStore ,
299+ FileVersionedKvStore , GitNamespacedKvStore , GitVersionedKvStore , HistoricalAccess ,
300+ HistoricalCommitAccess , InMemoryVersionedKvStore , ThreadSafeGitVersionedKvStore ,
300301 } ;
301302 use crate :: tree:: Tree ;
302303 use tempfile:: TempDir ;
@@ -341,6 +342,67 @@ mod tests {
341342 assert ! ( store. is_ok( ) ) ;
342343 }
343344
345+ #[ test]
346+ fn namespaced_merge_rejects_invalid_committed_hash_mapping_entry ( ) {
347+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
348+ gix:: init ( temp_dir. path ( ) ) . unwrap ( ) ;
349+ let dataset_dir = temp_dir. path ( ) . join ( "dataset" ) ;
350+ std:: fs:: create_dir_all ( & dataset_dir) . unwrap ( ) ;
351+ let _cwd = CwdGuard :: set ( & dataset_dir) ;
352+
353+ std:: process:: Command :: new ( "git" )
354+ . args ( [ "config" , "user.name" , "ProllyTree Test" ] )
355+ . current_dir ( temp_dir. path ( ) )
356+ . output ( )
357+ . expect ( "git config user.name" ) ;
358+ std:: process:: Command :: new ( "git" )
359+ . args ( [ "config" , "user.email" , "prollytree@example.test" ] )
360+ . current_dir ( temp_dir. path ( ) )
361+ . output ( )
362+ . expect ( "git config user.email" ) ;
363+
364+ let mut store = GitNamespacedKvStore :: < 32 > :: init ( & dataset_dir) . unwrap ( ) ;
365+ store
366+ . namespace ( "personal" )
367+ . insert ( b"base" . to_vec ( ) , b"base-value" . to_vec ( ) )
368+ . unwrap ( ) ;
369+ store. commit ( "base" ) . unwrap ( ) ;
370+
371+ store. create_branch ( "feature" ) . unwrap ( ) ;
372+ store
373+ . namespace ( "personal" )
374+ . insert ( b"feature" . to_vec ( ) , b"feature-value" . to_vec ( ) )
375+ . unwrap ( ) ;
376+ store. commit ( "feature data" ) . unwrap ( ) ;
377+
378+ let mapping_path = dataset_dir. join ( "prolly_hash_mappings" ) ;
379+ let mut mappings = std:: fs:: read_to_string ( & mapping_path) . unwrap ( ) ;
380+ mappings. push_str ( "not-hex:also-not-a-git-object\n " ) ;
381+ std:: fs:: write ( & mapping_path, mappings) . unwrap ( ) ;
382+
383+ let add = std:: process:: Command :: new ( "git" )
384+ . args ( [ "add" , "dataset/prolly_hash_mappings" ] )
385+ . current_dir ( temp_dir. path ( ) )
386+ . output ( )
387+ . expect ( "git add" ) ;
388+ assert ! ( add. status. success( ) , "git add failed: {add:?}" ) ;
389+ let commit = std:: process:: Command :: new ( "git" )
390+ . args ( [ "commit" , "-m" , "corrupt feature mappings" ] )
391+ . current_dir ( temp_dir. path ( ) )
392+ . output ( )
393+ . expect ( "git commit" ) ;
394+ assert ! ( commit. status. success( ) , "git commit failed: {commit:?}" ) ;
395+
396+ store. checkout ( "main" ) . unwrap ( ) ;
397+ let err = store
398+ . merge ( "feature" , & IgnoreConflictsResolver )
399+ . expect_err ( "invalid committed mapping entries must fail merge" ) ;
400+ assert ! (
401+ err. to_string( ) . contains( "Invalid prolly hash" ) ,
402+ "unexpected error: {err}"
403+ ) ;
404+ }
405+
344406 #[ test]
345407 fn test_basic_kv_operations ( ) {
346408 let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
0 commit comments