Skip to content

fix(sandbox): let from_registry name the guest OS - #3154

Merged
r33drichards merged 1 commit into
mainfrom
fix-from-registry-ostype
Aug 13, 2026
Merged

fix(sandbox): let from_registry name the guest OS#3154
r33drichards merged 1 commit into
mainfrom
fix-from-registry-ostype

Conversation

@r33drichards

Copy link
Copy Markdown
Collaborator

Image.from_registry() hardcoded os_type="linux" and took no parameter to override it:

def from_registry(cls, ref: str) -> Image:
    return cls(os_type="linux", distro="registry", version="latest", kind=None, _registry=ref)

from_file, the adjacent constructor building the same object from a different source, takes os_type and kind as keyword arguments. Same class, two constructors, inconsistent surface.

os_type is what selects UEFI — on the local QEMU runtime and in the Fleet transport alike. So a Windows containerDisk pulled from any registry was handed BIOS and could not boot, and the only way out was reaching past the constructor:

dataclasses.replace(Image.from_registry(ref), os_type='windows', kind='vm')

This is the firmware failure fixed for Fleet in #3125 arriving through a different door. It surfaced while publishing a Windows containerDisk to a registry and booting it back, which is a documented workflow.

The default stays "linux", so existing callers are unaffected.

Tests

tests/test_from_registry_ostype.py — the default is preserved, a Windows disk can declare itself, the registry ref survives, os_type passes through verbatim, and the constructor offers the same knobs as from_file. Plus the end the bug was actually felt at: a Windows registry image must not come out of _template_request() with null firmware.

Seven of the eight fail without the source change.

Also in here: a test that has been red on main since #3133

#3133 made Sandbox._create pass ephemeral= to runtime.start(). The fake Runtime in test_cloud.py does not accept it, so test_cloud_local_creation_never_routes_to_fleet has been failing on main ever since — it fails the call, before it can fail its assertion. Confirmed pre-existing by stashing only this PR's source change and re-running.

It went unnoticed because cua-sandbox is not in the ci-test-python package matrix. That matrix is core, agent, computer, computer-server, mcp-server, som, cua-auto — the cua-sandbox suite never runs on pull requests, so nothing here is covered by CI, including the tests in this PR.

That is worth addressing separately and is not a one-line change: the suite currently has other failures and at least one test that hangs, so adding it to the matrix wholesale would land red. Flagging rather than bundling.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

🤖 Generated with Claude Code

from_registry hardcoded os_type="linux" with no way to override it, while
from_file — the adjacent constructor building the same object from a different
source — takes os_type and kind as keyword arguments.

os_type is what selects UEFI, on the local QEMU runtime and in the Fleet
transport alike. A Windows containerDisk pulled from a registry was therefore
handed BIOS and could not boot, and the only escape was reaching past the
constructor with dataclasses.replace(). That is the firmware failure fixed for
Fleet in #3125 arriving through a different door.

The default stays "linux", so existing callers are unaffected.

Also repairs a test double in test_cloud.py: #3133 made Sandbox._create pass
ephemeral= to runtime.start(), and the fake Runtime there does not accept it, so
that test has been failing on main since it merged. It went unnoticed because
cua-sandbox is not in the ci-test-python package matrix and its suite never runs
on pull requests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@r33drichards
r33drichards merged commit 1927960 into main Aug 13, 2026
16 checks passed
@r33drichards
r33drichards deleted the fix-from-registry-ostype branch August 13, 2026 21:18
r33drichards added a commit that referenced this pull request Aug 13, 2026
…vice (#3156)

cua-sandbox 0.3.3 gives from_registry the os_type and kind keywords that
from_file already had (#3154), so the dataclasses.replace() reach-around is
gone from the snippet and the frozen-dataclass explanation with it. The version
floor moves to 0.3.3, which is also the first release with the pull-secret fix
that lets Fleet boot an image from a registry outside its own allowlist.

Also corrects the retry advice, which was wrong. It said a fresh sandbox name
avoids the 403 on update template. Four boots of the same image say otherwise:

    same name after a failed boot   -> 403 update template
    fresh name (e2e-fleet-cd-1)     -> 403 update template
    fresh name (e2e-fleet-cd-2)     -> READY in 187 s
    fresh name (mc-ghcr-fleet2)     -> READY in 157 s

Two fresh names disagreeing rules out the name as the cause. What holds is the
policy — both branches of the gateway rule are guarded by
input.method != "PATCH", so any update is refused — and that the failure is
intermittent. The page now says retry, rather than prescribing a fix that does
not reliably work.

Re-tested end to end against the released package in a clean venv, using the
page's snippets verbatim: from_registry(..., os_type="windows", kind="vm")
builds correctly on 0.3.3, and the local boot of
ghcr.io/trycua/minecraft-agent:1.20.1 reached READY in 248 s with
sb.exposed_ports returning {3000: 56457}.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants