@@ -934,72 +934,82 @@ fn materialize_safe_required_file_symlinks(archive_dir: &Path) -> Result<()> {
934934 } ) ?;
935935
936936 for rel_path in REQUIRED_SITE_FILES {
937- let path = archive_dir. join ( rel_path) ;
938- let metadata = match std:: fs:: symlink_metadata ( & path) {
939- Ok ( metadata) => metadata,
940- Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: NotFound => continue ,
941- Err ( err) => {
942- return Err ( err) . with_context ( || {
943- format ! (
944- "Failed to inspect required site file {} before key mutation" ,
945- path. display( )
946- )
947- } ) ;
948- }
949- } ;
950- if !metadata. file_type ( ) . is_symlink ( ) {
951- continue ;
952- }
937+ materialize_safe_required_file_symlink ( archive_dir, & canonical_archive_dir, rel_path) ?;
938+ }
953939
954- let canonical_target = path. canonicalize ( ) . with_context ( || {
955- format ! (
956- "Failed to resolve symlinked required site file {} before key mutation" ,
957- path. display( )
958- )
959- } ) ?;
960- if !canonical_target. starts_with ( & canonical_archive_dir) {
961- bail ! (
962- "Refusing to materialize required site file symlink outside archive root: {}" ,
963- path. display( )
964- ) ;
965- }
940+ Ok ( ( ) )
941+ }
966942
967- let target_metadata = std:: fs:: metadata ( & canonical_target) . with_context ( || {
968- format ! (
969- "Failed to inspect symlink target {} before key mutation" ,
970- canonical_target. display( )
971- )
972- } ) ?;
973- if !target_metadata. file_type ( ) . is_file ( ) {
974- bail ! (
975- "Refusing to materialize required site file symlink that does not point to a regular file: {}" ,
976- path. display( )
977- ) ;
943+ fn materialize_safe_required_file_symlink (
944+ archive_dir : & Path ,
945+ canonical_archive_dir : & Path ,
946+ rel_path : & str ,
947+ ) -> Result < ( ) > {
948+ let path = archive_dir. join ( rel_path) ;
949+ let metadata = match std:: fs:: symlink_metadata ( & path) {
950+ Ok ( metadata) => metadata,
951+ Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: NotFound => return Ok ( ( ) ) ,
952+ Err ( err) => {
953+ return Err ( err) . with_context ( || {
954+ format ! (
955+ "Failed to inspect required site file {} before key mutation" ,
956+ path. display( )
957+ )
958+ } ) ;
978959 }
960+ } ;
961+ if !metadata. file_type ( ) . is_symlink ( ) {
962+ return Ok ( ( ) ) ;
963+ }
964+
965+ let canonical_target = path. canonicalize ( ) . with_context ( || {
966+ format ! (
967+ "Failed to resolve symlinked required site file {} before key mutation" ,
968+ path. display( )
969+ )
970+ } ) ?;
971+ if !canonical_target. starts_with ( canonical_archive_dir) {
972+ bail ! (
973+ "Refusing to materialize required site file symlink outside archive root: {}" ,
974+ path. display( )
975+ ) ;
976+ }
979977
980- let temp_path = unique_atomic_sidecar_path ( & path, "materialize" , "site-file" ) ;
981- std:: fs:: copy ( & canonical_target, & temp_path) . with_context ( || {
978+ let target_metadata = std:: fs:: metadata ( & canonical_target) . with_context ( || {
979+ format ! (
980+ "Failed to inspect symlink target {} before key mutation" ,
981+ canonical_target. display( )
982+ )
983+ } ) ?;
984+ if !target_metadata. file_type ( ) . is_file ( ) {
985+ bail ! (
986+ "Refusing to materialize required site file symlink that does not point to a regular file: {}" ,
987+ path. display( )
988+ ) ;
989+ }
990+
991+ let temp_path = unique_atomic_sidecar_path ( & path, "materialize" , "site-file" ) ;
992+ std:: fs:: copy ( & canonical_target, & temp_path) . with_context ( || {
993+ format ! (
994+ "Failed copying symlink target {} into staged required site file {}" ,
995+ canonical_target. display( ) ,
996+ temp_path. display( )
997+ )
998+ } ) ?;
999+ File :: open ( & temp_path)
1000+ . and_then ( |file| file. sync_all ( ) )
1001+ . with_context ( || {
9821002 format ! (
983- "Failed copying symlink target {} into staged required site file {}" ,
984- canonical_target. display( ) ,
1003+ "Failed syncing materialized required site file {}" ,
9851004 temp_path. display( )
9861005 )
9871006 } ) ?;
988- File :: open ( & temp_path)
989- . and_then ( |file| file. sync_all ( ) )
990- . with_context ( || {
991- format ! (
992- "Failed syncing materialized required site file {}" ,
993- temp_path. display( )
994- )
995- } ) ?;
996- replace_file_from_temp ( & temp_path, & path) . with_context ( || {
997- format ! (
998- "Failed materializing required site file symlink {} before key mutation" ,
999- path. display( )
1000- )
1001- } ) ?;
1002- }
1007+ replace_file_from_temp ( & temp_path, & path) . with_context ( || {
1008+ format ! (
1009+ "Failed materializing required site file symlink {} before key mutation" ,
1010+ path. display( )
1011+ )
1012+ } ) ?;
10031013
10041014 Ok ( ( ) )
10051015}
@@ -1886,34 +1896,40 @@ mod tests {
18861896
18871897 #[ test]
18881898 #[ cfg( unix) ]
1889- fn test_key_add_password_materializes_in_tree_symlinked_required_asset ( ) {
1899+ fn test_key_add_password_materializes_in_tree_symlinked_required_asset ( ) -> Result < ( ) > {
18901900 let ( _temp_dir, archive_dir) = setup_test_archive ( ) ;
1891- let site_dir = super :: super :: resolve_site_dir ( & archive_dir) . unwrap ( ) ;
1901+ let site_dir = super :: super :: resolve_site_dir ( & archive_dir) ? ;
18921902 replace_viewer_with_in_tree_symlink ( & site_dir) ;
18931903
1894- key_add_password ( & archive_dir, "test-password" , "new-password" ) . unwrap ( ) ;
1904+ key_add_password ( & archive_dir, "test-password" , "new-password" ) ? ;
18951905
1896- assert_eq ! ( verify_bundle( & archive_dir, false ) . unwrap( ) . status, "valid" ) ;
1897- let viewer_metadata = std:: fs:: symlink_metadata ( site_dir. join ( "viewer.js" ) ) . unwrap ( ) ;
1898- assert ! ( viewer_metadata. file_type( ) . is_file( ) ) ;
1899- assert ! ( !viewer_metadata. file_type( ) . is_symlink( ) ) ;
1906+ anyhow:: ensure!( verify_bundle( & archive_dir, false ) ?. status == "valid" ) ;
1907+ let viewer_metadata = std:: fs:: symlink_metadata ( site_dir. join ( "viewer.js" ) ) ?;
1908+ anyhow:: ensure!( viewer_metadata. file_type( ) . is_file( ) ) ;
1909+ anyhow:: ensure!( !viewer_metadata. file_type( ) . is_symlink( ) ) ;
1910+ Ok ( ( ) )
19001911 }
19011912
19021913 #[ test]
19031914 #[ cfg( unix) ]
1904- fn test_key_add_password_wrong_password_preserves_in_tree_symlinked_required_asset ( ) {
1915+ fn test_key_add_password_wrong_password_preserves_in_tree_symlinked_required_asset ( )
1916+ -> Result < ( ) > {
19051917 let ( _temp_dir, archive_dir) = setup_test_archive ( ) ;
1906- let site_dir = super :: super :: resolve_site_dir ( & archive_dir) . unwrap ( ) ;
1918+ let site_dir = super :: super :: resolve_site_dir ( & archive_dir) ? ;
19071919 replace_viewer_with_in_tree_symlink ( & site_dir) ;
19081920
1909- let err = key_add_password ( & archive_dir, "wrong-password" , "new-password" ) . unwrap_err ( ) ;
1921+ let err = match key_add_password ( & archive_dir, "wrong-password" , "new-password" ) {
1922+ Ok ( _) => bail ! ( "wrong password unexpectedly added a key slot" ) ,
1923+ Err ( err) => err,
1924+ } ;
19101925
1911- assert ! (
1926+ anyhow :: ensure !(
19121927 err. to_string( ) . contains( "Invalid password" ) ,
19131928 "unexpected error: {err:#}"
19141929 ) ;
1915- let viewer_metadata = std:: fs:: symlink_metadata ( site_dir. join ( "viewer.js" ) ) . unwrap ( ) ;
1916- assert ! ( viewer_metadata. file_type( ) . is_symlink( ) ) ;
1930+ let viewer_metadata = std:: fs:: symlink_metadata ( site_dir. join ( "viewer.js" ) ) ?;
1931+ anyhow:: ensure!( viewer_metadata. file_type( ) . is_symlink( ) ) ;
1932+ Ok ( ( ) )
19171933 }
19181934
19191935 #[ test]
0 commit comments