Repository navigation
feat(images): read image documents with no tarball, and pull them by name - #113
Conversation
…name A DockerImageArtifact's tar_gz_object_url is now optional. One with no tar.gz names a registry reference in image_name, which a sandbox pulls instead. - load_problem(): an image loads from its tar.gz, or, with none, by pulling an image_name that spells out its registry (names_registry). Anything else is refused up front, by the VM loader and by preflight on every provider. - VmSandbox.load_docker_images loads tarballs exactly as before (same script, same check) and pulls the rest through pull_images, the docker login + pull that create_container already ran, now shared. - The E2B and Sail overrides keep widening a restrictive policy for signed tarball downloads only; a pull goes through the policy as it is. - put_tar refuses an empty tar_gz_object_url; load() refuses an image with none. - Preflight's file:// check no longer misreads a missing tar.gz, and an agent the store can't read is left to the default-agent report instead of raising. Nothing writes a tarball-less document yet: readers ship first. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…loadable too Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A container path (Modal's gateway and agents, the local provider's agents) runs an image by name whatever it holds, and Modal's container gateway swaps out service-db images the image store doesn't hold, so an image with no tar.gz is refused only on a gateway VM, an agent VM, or a VM provider's infra. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…er pulls when one fails Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Cancelling an exec doesn't stop its command on the VM, and the Scale and Sail sandboxes leave a cancelled exec's connection or readers open, so the other pulls run to their end instead of being cancelled. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Hot-path verification on beta_scale (head The task deploys a registry gateway env (nine MCP servers plus the gateway and service-db, all from tarballs), loads its universe, and deploys a tarball-backed agent. An
The failed-pull row was run at |
| f"echo {shlex.quote(auth.password)} | docker login " | ||
| f"--username {shlex.quote(auth.username)} --password-stdin {shlex.quote(auth.registry)}" | ||
| ) | ||
| pulls = await asyncio.gather(*(_pull(self, image_name) for image_name in image_names), return_exceptions=True) |
There was a problem hiding this comment.
If one image pull fails quickly while another stalls, pull_images waits for the stalled pull before reporting the failure. exec_script sets no time limit on docker pull, so the deployment can remain stuck. Bound each pull while preserving cleanup of remote commands.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/providers/sandbox_providers/sandbox.py
Line: 319
Comment:
**Failed deployment stays open**
If one image pull fails quickly while another stalls, `pull_images` waits for the stalled pull before reporting the failure. `exec_script` sets no time limit on `docker pull`, so the deployment can remain stuck. Bound each pull while preserving cleanup of remote commands.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Agreed. In 5fea87d the first failure cancels the other pulls again, so a stalled one can't hold it back; a test pins it with pulls that never finish. A per-pull remote timeout isn't portable: the local provider runs docker pull on a macOS host, which has no timeout. A stalled pull with nothing failing still hangs a deploy, as the existing tarball curl and create_container pull already do.
There was a problem hiding this comment.
That addresses the reported failure mode. Cancelling pending pull tasks on the first exception prevents a stalled concurrent pull from delaying failure propagation, while awaiting the cancelled tasks preserves cleanup of the local asyncio work.
I agree that a shell-level per-pull timeout would not be portable here, and an all-pulls-stalled case is consistent with the existing unbounded docker pull and tarball-download behavior rather than a regression introduced by this change. No further change is needed for this finding.
…can't hold the failure back Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
What
A
DockerImageArtifactno longer needs an image tarball. One with notar_gz_object_urlnames a registry reference inimage_name, and a sandbox pulls it.This PR makes core read such documents and pull them on VM sandboxes. Nothing writes one yet. Released readers can't parse a tarball-less document (the field was a required
str), so the hub, worker and modal-proxy have to run this release before any producer ships.How
DockerImageArtifact.load_problem()says why no sandbox can get an image, orNonewhen one can. An image with a tar.gz is loaded from it. One with none is pulled byimage_name, which must spell out its registry (names_registry:ghcr.io/x/y,host:5000/x,localhost/x). A bareimg:v1would silently resolve on Docker Hub, so it's refused.VmSandbox.load_docker_imagesrefuses an unloadable image before anything runs. It loads tarballs exactly as before: the same script and the samedocker imagescheck, now pinned byte for byte by a test. It pulls the rest throughpull_images. That's thedocker login(for each registry the image store holds credentials for) plusdocker pullwith the amd64 fallback thatcreate_containeralready ran.create_containernow calls the same method, with the same commands.load_docker_imagesto_load_tarballs. They still widen a restrictive egress policy for signed tarball downloads only. A pull goes through the policy as it is, so a restrictive policy must allow the registry itself. Registry pulls also fetch layers from hosts that vary by registry, so allowlisting the registry host alone wouldn't be enough.load_problem()where a VM loads the image: a gateway deploy off Modal's container gateway, an agent on a provider that puts it on a VM (not local or Modal), and a VM provider's infra. Container paths run an image by name whether or not it has a tar.gz, and Modal's container gateway swaps out service-db images the image store doesn't hold. Itsfile://check no longer misreads a missing tar.gz, and an agent document the store can't read is left to the default-agent report rather than raising.put_tarrefuses an emptytar_gz_object_url(it used to pass).load()refuses an image with no tar.gz.put_tarkeeps itstar_gz_s3_url=/build_context_s3_url=keywords.Modal container mode and the local provider's containers already used
image_namealone, so they're unchanged.Compatibility
null.load_docker_images,create_container): this needs thebump-versionrelease, the bot pin, and the hg4 prod-universe smoke after rollout.Testing
load_problemandnames_registrycases;docker_image_artifact_test,server_env_local_testandmulti_env_local_testall passed (5).repo@sha256:…)🤖 Generated with Claude Code
The PR appears safe to merge based on the reviewed changes and resolved findings.
Fix with agent prompt
Summary
Docker image documents can now point to a registry without carrying a tarball, and VM sandboxes can pull those images by name. Bundle preflight checks whether each provider can load the images it needs.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR A[Image artifact] --> B{Has tarball?} B -->|Yes| C[Load tarball on VM] B -->|No| D{Names a registry?} D -->|Yes| E[Log in if needed and pull] D -->|No| F[Refuse VM load]Reviews (6) · Last reviewed commit: "fix(images): cancel the other pulls when..." · Reviewed by Greptile