Skip to content

feat(image): ship a reference sandbox image, and publish it from CI - #1

Merged
Lutherwaves merged 1 commit into
mainfrom
feat/publish-sandbox-image
Aug 13, 2026
Merged

feat(image): ship a reference sandbox image, and publish it from CI#1
Lutherwaves merged 1 commit into
mainfrom
feat/publish-sandbox-image

Conversation

@Lutherwaves

Copy link
Copy Markdown
Member

openblox pulls an absent image on create, but never shipped one — so the default path didn't work until you'd authored a Dockerfile yourself. This adds that image and the CI to publish it.

The image

image/Dockerfileghcr.io/blox-eng/openblox-sandbox. Debian slim + python3, bash, nc, non-root sandbox user (uid 1000), writable /workspace. 121 MB.

Debian rather than Alpine deliberately: sandboxes run Python, musl has no manylinux wheels, so on Alpine every numpy/pandas install compiles from source inside the sandbox.

The contract, written down

openblox requires exactly three things of an image, and until now they were folklore that surfaced as a broken preview:

  • /bin/sh — openblox replaces the entrypoint with its own idle loop
  • a non-root USER — an integration test already asserts this
  • nc or python3 — the preview relay reaches an in-sandbox port over the exec channel, since the container has no network interface

Now stated in image/README.md, asserted at build time, and re-asserted against the pushed manifest.

CI

Event Behaviour
pull request build amd64, assert the contract, no push
push to main :edge, multi-arch
tag v* :X.Y.Z + :latest, multi-arch

The digest goes to the job summary — pin that, not a tag: a tag can be repointed by whoever controls the registry, and the image is the sandbox's entire userland.

The PR job exists so a broken Dockerfile is a red check rather than a missing image discovered on main.

Verification

Built locally and driven through the real openblox API on a gVisor host:

✓ create          ✓ non-root                ✓ detached process
✓ python3         ✓ /workspace round-trip   ✓ preview over the relay (230 bytes)
✓ bash

The preview now takes the nc fast path instead of the python3 fallback.

Also drops a stale "Not yet published" line from the README.

Follow-up (not in this PR)

Blox's own blox-sandbox image is still FROM daytonaio/sandbox. Rebasing it onto this image is what finally removes that dependency — and is why nc was missing in the first place.

openblox pulls an absent image on create, but never shipped one, so the
default path did not work until you had authored a Dockerfile yourself.

image/ is that default: python3, bash, nc and a non-root user on Debian
slim. The three things openblox actually requires of an image — a shell,
a non-root USER, and nc-or-python3 for the preview relay — are now stated
in one place and asserted at build time, rather than being folklore that
surfaced as a broken preview. Debian rather than Alpine because musl has
no manylinux wheels, so on Alpine every numpy install compiles from
source inside the sandbox.

CI publishes it to ghcr: a tag pushes that version plus :latest, main
pushes :edge, both multi-arch. A pull request builds and asserts the
contract without pushing, so a broken Dockerfile is a red check rather
than a missing image discovered on main. The digest lands in the job
summary, because a tag can be repointed by whoever controls the registry
and the image is the sandbox's entire userland.

Verified against a real gVisor host: create, python3, bash, non-root,
/workspace round-trip, a detached process, and a preview fetched over the
relay — which now takes the nc fast path rather than the python3 fallback.
@Lutherwaves
Lutherwaves merged commit 7c33b2f into main Aug 13, 2026
6 checks passed
@Lutherwaves
Lutherwaves deleted the feat/publish-sandbox-image branch August 13, 2026 09:55
Lutherwaves added a commit that referenced this pull request Aug 17, 2026
openblox pulls an absent image on create, but never shipped one, so the
default path did not work until you had authored a Dockerfile yourself.

image/ is that default: python3, bash, nc and a non-root user on Debian
slim. The three things openblox actually requires of an image — a shell,
a non-root USER, and nc-or-python3 for the preview relay — are now stated
in one place and asserted at build time, rather than being folklore that
surfaced as a broken preview. Debian rather than Alpine because musl has
no manylinux wheels, so on Alpine every numpy install compiles from
source inside the sandbox.

CI publishes it to ghcr: a tag pushes that version plus :latest, main
pushes :edge, both multi-arch. A pull request builds and asserts the
contract without pushing, so a broken Dockerfile is a red check rather
than a missing image discovered on main. The digest lands in the job
summary, because a tag can be repointed by whoever controls the registry
and the image is the sandbox's entire userland.

Verified against a real gVisor host: create, python3, bash, non-root,
/workspace round-trip, a detached process, and a preview fetched over the
relay — which now takes the nc fast path rather than the python3 fallback.
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.

1 participant