fix(runtime): tear the sandbox down when staging is cancelled

CancelledError is not an Exception, so a run cancelled during the extra-file
upload or unpack left a created-but-uncached sandbox running.
This commit is contained in:
Ahmed Allam
2026-09-17 18:45:00 +00:00
parent fdf8747407
commit a4f39e1b53
2 changed files with 42 additions and 1 deletions

View File

@@ -334,7 +334,7 @@ async def create_or_reuse(
report("Placing workspace files")
try:
await stage_extra_files(session, extra_file_archive)
except Exception:
except BaseException:
await _discard_session(client, session)
raise

View File

@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import io
import tarfile
from dataclasses import dataclass
@@ -479,6 +480,46 @@ async def test_a_failed_unpack_tears_the_session_down(monkeypatch: pytest.Monkey
assert scan_id not in session_manager._SESSION_CACHE
@pytest.mark.asyncio
async def test_a_cancelled_unpack_tears_the_session_down(monkeypatch: pytest.MonkeyPatch) -> None:
"""A run cancelled mid-staging must not leave the sandbox running."""
class _HangingSession(_Session):
async def exec(self, *argv: str, timeout: float | None = None) -> _ExecResult:
del argv, timeout
await asyncio.Event().wait()
raise AssertionError("unreachable")
fake_session = _HangingSession()
fake_client = _Client()
async def _backend(**_kwargs: Any) -> tuple[Any, Any]:
return fake_client, fake_session
scan_id = "unpack-cancelled"
backend_name = f"test-{scan_id}"
_use_backend(monkeypatch, backend_name, _backend, supports_bind_mounts=True)
try:
task = asyncio.create_task(
session_manager.create_or_reuse(
scan_id,
image="img",
local_sources=[],
extra_files=[{"workspace_path": "/workspace/notes.md", "content": b"x"}],
)
)
while not fake_session.writes:
await asyncio.sleep(0)
task.cancel()
with pytest.raises(asyncio.CancelledError):
await task
finally:
_forget_backend(backend_name)
assert fake_client.deleted == [fake_session]
assert scan_id not in session_manager._SESSION_CACHE
def test_only_bind_mount_capable_backends_are_registered_as_such() -> None:
assert backend_supports_bind_mounts("docker")
assert not backend_supports_bind_mounts("e2b")