diff --git a/baseten/sandbox/_fs.py b/baseten/sandbox/_fs.py index bd95f90..50a4994 100644 --- a/baseten/sandbox/_fs.py +++ b/baseten/sandbox/_fs.py @@ -1048,7 +1048,8 @@ def _copy_command(source: str, destination: str) -> str: quoted = [ "'" + value.replace("'", "'\\''") + "'" for value in (source, destination) ] - return f"cp -r {quoted[0]} {quoted[1]}" + # End option parsing so relative paths beginning with - remain operands. + return f"cp -r -- {quoted[0]} {quoted[1]}" def _watch_path(path: str, recursive: bool | None) -> str: diff --git a/tests/sandbox/test_copy_paths.py b/tests/sandbox/test_copy_paths.py new file mode 100644 index 0000000..029ef2b --- /dev/null +++ b/tests/sandbox/test_copy_paths.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +import subprocess +from pathlib import Path + +import httpx +import pytest + +from tests.sandbox.test_fs import _body, _Fake, _ok, _process + + +@pytest.mark.parametrize("asynchronous", [False, True]) +@pytest.mark.parametrize( + ("source", "destination"), + [("-source", "copy"), ("source", "-destination"), ("-source", "-destination")], +) +@pytest.mark.asyncio +async def test_copy_preserves_paths_starting_with_dash( + tmp_path: Path, source: str, destination: str, asynchronous: bool +) -> None: + (tmp_path / source).write_text("file contents") + + def handle(request: httpx.Request) -> httpx.Response: + if request.method == "POST": + # Execute the SDK's actual command against local fixture files. + result = subprocess.run( + _body(request)["command"], + shell=True, + check=False, + cwd=tmp_path, + capture_output=True, + text=True, + timeout=5, + ) + return _ok( + _process( + status="completed" if result.returncode == 0 else "failed", + exitCode=result.returncode, + stderr=result.stderr, + ) + ) + return _ok(_process()) + + fake = _Fake(handle) + if asynchronous: + await fake.async_sandbox().fs.copy(source=source, destination=destination) + else: + fake.sandbox().fs.copy(source=source, destination=destination) + assert (tmp_path / destination).read_text() == "file contents" diff --git a/tests/sandbox/test_fs.py b/tests/sandbox/test_fs.py index a7e6d7c..1fb83b4 100644 --- a/tests/sandbox/test_fs.py +++ b/tests/sandbox/test_fs.py @@ -646,7 +646,9 @@ def handle(request: httpx.Request) -> httpx.Response: fake = _Fake(handle) fake.sandbox().fs.copy(source="/tmp/it's", destination="/tmp/b c") - assert _body(fake.requests[0])["command"] == "cp -r '/tmp/it'\\''s' '/tmp/b c'" + assert ( + _body(fake.requests[0])["command"] == "cp -r -- '/tmp/it'\\''s' '/tmp/b c'" + ) assert _path(fake.requests[1]) == "/process/7" @pytest.mark.parametrize(