Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions libs/python/cua-sandbox/cua_sandbox/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,26 @@ def android(cls, version: str = "14", kind: str = "vm") -> Image:
return cls(os_type="android", distro="android", version=version, kind=kind)

@classmethod
def from_registry(cls, ref: str) -> Image:
"""Create an image from a registry reference. kind is resolved after pull."""
return cls(os_type="linux", distro="registry", version="latest", kind=None, _registry=ref)
def from_registry(
cls,
ref: str,
*,
os_type: str = "linux",
kind: Optional[str] = None,
) -> Image:
"""Create an image from a registry reference.

os_type selects the firmware: Windows guest disks are built UEFI-only,
so a Windows containerDisk pulled from a registry must say so or it is
handed BIOS and will not boot. kind is resolved after pull when omitted.
"""
return cls(
os_type=os_type,
distro="registry",
version="latest",
kind=kind,
_registry=ref,
)

@classmethod
def from_file(
Expand Down
4 changes: 3 additions & 1 deletion libs/python/cua-sandbox/tests/test_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ async def test_cloud_local_creation_never_routes_to_fleet(monkeypatch):
calls = []

class Runtime:
async def start(self, image, name):
# Sandbox._create tells the runtime whether the sandbox is ephemeral;
# a double that omits it fails the call rather than the assertion.
async def start(self, image, name, *, ephemeral=True):
calls.append(("start", image, name))
return RuntimeInfo(host="127.0.0.1", api_port=8000, name=name, environment="linux")

Expand Down
60 changes: 60 additions & 0 deletions libs/python/cua-sandbox/tests/test_from_registry_ostype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""A registry image must be able to say it is Windows.

os_type selects the firmware: Windows guest disks are built UEFI-only, and both
the local QEMU runtime and the Fleet transport read os_type to decide. With
from_registry hardcoding "linux", a Windows containerDisk pulled from any
registry was handed BIOS and could not boot — the same failure fixed for Fleet
in #3125, through a different door. The only escape was reaching past the
constructor with dataclasses.replace().
"""

import inspect

import pytest
from cua_sandbox import Image

REF = "ghcr.io/trycua/minecraft-workspace:1.20.1"


def test_defaults_to_linux_so_existing_callers_are_unaffected():
image = Image.from_registry(REF)
assert image.os_type == "linux"
assert image.kind is None


def test_a_windows_container_disk_can_say_so():
image = Image.from_registry(REF, os_type="windows", kind="vm")
assert image.os_type == "windows"
assert image.kind == "vm"


def test_the_registry_reference_survives():
"""Naming the OS must not disturb what gets pulled."""
plain = Image.from_registry(REF)
windows = Image.from_registry(REF, os_type="windows", kind="vm")
assert plain._registry == REF
assert windows._registry == REF


def test_it_offers_the_same_knobs_as_from_file():
"""The two constructors build the same object from different sources; a
caller should not have to know which one lets them name the guest OS."""
from_file = set(inspect.signature(Image.from_file).parameters)
from_registry = set(inspect.signature(Image.from_registry).parameters)
missing = {"os_type", "kind"} - from_registry
assert not missing, f"from_registry lacks knobs from_file has: {sorted(missing)}"
assert "os_type" in from_file # guards the premise, not the fix


@pytest.mark.parametrize("os_type", ["windows", "linux", "macos"])
def test_os_type_is_passed_through_verbatim(os_type):
assert Image.from_registry(REF, os_type=os_type).os_type == os_type


def test_windows_registry_image_gets_uefi_on_fleet():
"""The end the bug was actually felt at: firmware selection."""
from cua_sandbox.transport.fleet_cloud import FleetCloudTransport

image = Image.from_registry(REF, os_type="windows", kind="vm")
template = FleetCloudTransport(image=image, name="demo")._template_request().spec.vm_template
assert template.firmware is not None, "a Windows containerDisk must not be handed BIOS"
Loading