6565 retry_async ,
6666)
6767from ....sandbox .util .tar_utils import UnsafeTarMemberError , validate_tar_bytes
68+ from ....sandbox .workspace_paths import coerce_posix_path , posix_path_as_path , sandbox_path_str
6869
6970DEFAULT_BLAXEL_WORKSPACE_ROOT = "/workspace"
7071logger = logging .getLogger (__name__ )
@@ -319,7 +320,7 @@ async def start(self) -> None:
319320 # Ensure workspace root exists before BaseSandboxSession.start() materializes
320321 # the manifest. Blaxel base images run as root and do not ship a pre-created
321322 # workspace directory.
322- root = self .state .manifest .root
323+ root = sandbox_path_str ( self .state .manifest .root )
323324 try :
324325 await self ._sandbox .process .exec (
325326 {
@@ -368,7 +369,7 @@ async def mkdir(
368369 if path == Path ("/" ):
369370 return
370371 try :
371- await self ._sandbox .fs .mkdir (str (path ))
372+ await self ._sandbox .fs .mkdir (sandbox_path_str (path ))
372373 except Exception as e :
373374 raise WorkspaceArchiveWriteError (
374375 path = path ,
@@ -377,14 +378,14 @@ async def mkdir(
377378 ) from e
378379
379380 async def read (self , path : Path | str , * , user : str | User | None = None ) -> io .IOBase :
380- path = Path ( path )
381+ error_path = posix_path_as_path ( coerce_posix_path ( path ) )
381382 if user is not None :
382383 workspace_path = await self ._check_read_with_exec (path , user = user )
383384 else :
384385 workspace_path = await self ._validate_path_access (path )
385386
386387 try :
387- data : Any = await self ._sandbox .fs .read_binary (str (workspace_path ))
388+ data : Any = await self ._sandbox .fs .read_binary (sandbox_path_str (workspace_path ))
388389 if isinstance (data , str ):
389390 data = data .encode ("utf-8" )
390391 return io .BytesIO (bytes (data ))
@@ -397,8 +398,8 @@ async def read(self, path: Path | str, *, user: str | User | None = None) -> io.
397398 status = first_arg .get ("status" )
398399 error_str = str (e ).lower ()
399400 if status == 404 or "not found" in error_str or "no such file" in error_str :
400- raise WorkspaceReadNotFoundError (path = path , cause = e ) from e
401- raise WorkspaceArchiveReadError (path = path , cause = e ) from e
401+ raise WorkspaceReadNotFoundError (path = error_path , cause = e ) from e
402+ raise WorkspaceArchiveReadError (path = error_path , cause = e ) from e
402403
403404 async def write (
404405 self ,
@@ -407,19 +408,19 @@ async def write(
407408 * ,
408409 user : str | User | None = None ,
409410 ) -> None :
410- path = Path ( path )
411+ error_path = posix_path_as_path ( coerce_posix_path ( path ) )
411412 if user is not None :
412413 await self ._check_write_with_exec (path , user = user )
413414
414415 payload = data .read ()
415416 if isinstance (payload , str ):
416417 payload = payload .encode ("utf-8" )
417418 if not isinstance (payload , bytes | bytearray ):
418- raise WorkspaceWriteTypeError (path = path , actual_type = type (payload ).__name__ )
419+ raise WorkspaceWriteTypeError (path = error_path , actual_type = type (payload ).__name__ )
419420
420421 workspace_path = await self ._validate_path_access (path , for_write = True )
421422 try :
422- await self ._sandbox .fs .write_binary (str (workspace_path ), bytes (payload ))
423+ await self ._sandbox .fs .write_binary (sandbox_path_str (workspace_path ), bytes (payload ))
423424 except Exception as e :
424425 raise WorkspaceArchiveWriteError (path = workspace_path , cause = e ) from e
425426
@@ -525,11 +526,11 @@ def _tar_exclude_args(self) -> list[str]:
525526 )
526527 )
527528 async def persist_workspace (self ) -> io .IOBase :
528- root = Path ( self .state . manifest . root )
529+ root = self ._workspace_root_path ( )
529530 tar_path = f"/tmp/bl-persist-{ self .state .session_id .hex } .tar"
530531 excludes = " " .join (self ._tar_exclude_args ())
531532 tar_cmd = (
532- f"tar { excludes } -C { shlex .quote (str ( root ))} -cf { shlex .quote (tar_path )} ."
533+ f"tar { excludes } -C { shlex .quote (root . as_posix ( ))} -cf { shlex .quote (tar_path )} ."
533534 ).strip ()
534535
535536 unmounted_mounts : list [tuple [Mount , Path ]] = []
@@ -596,7 +597,7 @@ async def persist_workspace(self) -> io.IOBase:
596597 return io .BytesIO (raw )
597598
598599 async def hydrate_workspace (self , data : io .IOBase ) -> None :
599- root = self .state . manifest . root
600+ root = self ._workspace_root_path ()
600601 tar_path = f"/tmp/bl-hydrate-{ self .state .session_id .hex } .tar"
601602 payload = data .read ()
602603 if isinstance (payload , str ):
@@ -608,7 +609,7 @@ async def hydrate_workspace(self, data: io.IOBase) -> None:
608609 validate_tar_bytes (bytes (payload ))
609610 except UnsafeTarMemberError as e :
610611 raise WorkspaceArchiveWriteError (
611- path = Path ( root ) ,
612+ path = root ,
612613 context = {
613614 "reason" : "unsafe_or_invalid_tar" ,
614615 "member" : e .member ,
@@ -623,12 +624,12 @@ async def hydrate_workspace(self, data: io.IOBase) -> None:
623624 result = await self ._exec_internal (
624625 "sh" ,
625626 "-c" ,
626- f"tar -C { shlex .quote (root )} -xf { shlex .quote (tar_path )} " ,
627+ f"tar -C { shlex .quote (root . as_posix () )} -xf { shlex .quote (tar_path )} " ,
627628 timeout = self .state .timeouts .workspace_tar_s ,
628629 )
629630 if result .exit_code != 0 :
630631 raise WorkspaceArchiveWriteError (
631- path = Path ( root ) ,
632+ path = root ,
632633 context = {
633634 "reason" : "tar_extract_failed" ,
634635 "output" : result .stderr .decode ("utf-8" , errors = "replace" ),
@@ -637,7 +638,7 @@ async def hydrate_workspace(self, data: io.IOBase) -> None:
637638 except WorkspaceArchiveWriteError :
638639 raise
639640 except Exception as e :
640- raise WorkspaceArchiveWriteError (path = Path ( root ) , cause = e ) from e
641+ raise WorkspaceArchiveWriteError (path = root , cause = e ) from e
641642 finally :
642643 try :
643644 await self ._exec_internal (
0 commit comments