@@ -1408,6 +1408,19 @@ fn validate_sandbox_source_path(workspace_root: &str, path: &str) -> Result<Stri
14081408 Ok ( cleaned)
14091409}
14101410
1411+ /// Build the remote probe that prints the workspace root, then the resolved
1412+ /// path if it exists. Uses only POSIX `[` and bare `realpath`, because busybox
1413+ /// `realpath` has no `-e` and treats `--` as a file name.
1414+ fn resolve_probe_command ( sandbox_path : & str ) -> String {
1415+ let operand = if sandbox_path. starts_with ( '/' ) {
1416+ sandbox_path. to_string ( )
1417+ } else {
1418+ format ! ( "./{sandbox_path}" )
1419+ } ;
1420+ let path = shell_escape ( & operand) ;
1421+ format ! ( "pwd -P && if [ -e {path} ]; then realpath {path}; fi" )
1422+ }
1423+
14111424/// Discover the workspace root and resolve every symlink in `sandbox_path` in
14121425/// one SSH probe, then refuse the result if it lands outside the workspace.
14131426///
@@ -1422,10 +1435,7 @@ async fn resolve_sandbox_source_path(
14221435 session : & SshSessionConfig ,
14231436 sandbox_path : & str ,
14241437) -> Result < String > {
1425- let resolve_cmd = format ! (
1426- "pwd -P && realpath -e -- {path}" ,
1427- path = shell_escape( sandbox_path)
1428- ) ;
1438+ let resolve_cmd = resolve_probe_command ( sandbox_path) ;
14291439 let output = ssh_run_capture_stdout ( session, & resolve_cmd)
14301440 . await
14311441 . wrap_err_with ( || format ! ( "failed to resolve sandbox source path '{sandbox_path}'" ) ) ?;
@@ -3080,6 +3090,30 @@ mod tests {
30803090 assert_eq ! ( lexical_clean_absolute_path( "./a" ) , None ) ;
30813091 }
30823092
3093+ #[ test]
3094+ #[ cfg( unix) ]
3095+ fn resolve_probe_command_is_posix_and_resolves_symlinks ( ) {
3096+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
3097+ let root = dir. path ( ) . canonicalize ( ) . unwrap ( ) ;
3098+ fs:: write ( root. join ( "-f" ) , "x" ) . unwrap ( ) ;
3099+ std:: os:: unix:: fs:: symlink ( root. join ( "-f" ) , root. join ( "link" ) ) . unwrap ( ) ;
3100+ let run = |path : & str | {
3101+ let output = Command :: new ( "sh" )
3102+ . arg ( "-c" )
3103+ . arg ( resolve_probe_command ( path) )
3104+ . current_dir ( & root)
3105+ . output ( )
3106+ . unwrap ( ) ;
3107+ assert ! ( output. status. success( ) ) ;
3108+ String :: from_utf8 ( output. stdout ) . unwrap ( )
3109+ } ;
3110+ let cwd = format ! ( "{}\n " , root. display( ) ) ;
3111+ assert ! ( !resolve_probe_command( "a" ) . contains( " -e --" ) ) ;
3112+ assert_eq ! ( run( "link" ) , format!( "{cwd}{}/-f\n " , root. display( ) ) ) ;
3113+ assert_eq ! ( run( "-f" ) , format!( "{cwd}{}/-f\n " , root. display( ) ) ) ;
3114+ assert_eq ! ( run( "missing" ) , cwd) ;
3115+ }
3116+
30833117 #[ test]
30843118 fn validate_sandbox_source_path_accepts_workspace_paths ( ) {
30853119 let workspace_root = "/workspace/project" ;
0 commit comments