feat(rest): images pull + list end-to-end (POL-32)#637
Open
G4614 wants to merge 4 commits into
Open
Conversation
Implements the OpenAPI image endpoints (POST /v1/images/pull, GET /v1/images) that have been spec'd but not wired. Server handlers delegate to the local image manager — the REST server is itself a local runtime behind HTTP, so the path that backs `boxlite pull` over loopback is the same one that now backs `boxlite --profile p1 pull` over the wire. Client side, `BoxliteRuntime::pull_image_remote` / `list_images_remote` return the in-process `ImageInfo` shape via the new wire DTOs in `rest::types`. Local callers keep `images()?.pull()` (which returns the heavier `ImageObject` the SDKs depend on) — we don't unify the two trait paths because `ImageObject` carries blob-store pointers that have no meaning over the wire. `boxlite pull` and `boxlite images` now branch on `is_rest()` and route accordingly. SDKs (Node, Python, C) keep their local-only shape — POL-32 is the CLI-side coverage; SDK exposure is follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8133eaf to
8493590
Compare
`pull_image` handler used `images.iter().find(|i| i.reference == req.reference)`
to look up the just-cached metadata. But `ImageManager::pull(ref)`
takes the *user's input* (e.g. `"alpine"`) while `ImageStore` keys the
cache index on the *resolved* reference yielded by `ReferenceIter`
(`docker.io/library/alpine:latest`, picked by registry-fallback in
`src/boxlite/src/images/store.rs:170-204`). Result: every unqualified
or partially-qualified pull (`alpine`, `alpine:latest`, `library/alpine`)
returned 500 InternalError "pull succeeded but image X did not appear
in the cache listing" — exactly the response when the lookup misses.
`ImageObject::reference()` still carries the user input (preserved for
backwards compat with the local `pull` CLI display), so we can't use
it as the join key either. The stable id is the manifest digest:
`ImageInfo::id` is `cached.manifest_digest`, and `ImageObject` already
has the same digest on `self.manifest.manifest_digest` — just not
exposed publicly.
Changes:
- `src/boxlite/src/images/object.rs`: add
`pub fn manifest_digest(&self) -> &str`, documenting why a caller
needs to correlate by digest rather than reference.
- `src/cli/src/commands/serve/handlers/images.rs`:
- Bind the `ImageObject` returned by `handle.pull()` instead of
discarding it.
- Find list entry by `i.id == pulled.manifest_digest()`.
- Surface the digest in the (now-unreachable-by-construction)
500 fallback message so an operator who somehow hits it has
something to grep.
Test gap (knowingly accepted): the existing `tests/rest_images.rs`
suite stubs the SERVER side from the CLI's POV, so it doesn't
exercise the actual `pull_image` handler. A handler-side test
needs a real `ImageManager` + registry scaffold (the existing
`serve` test module acknowledges "we can't construct a full
AppState without BoxliteRuntime" at mod.rs:1152). Leaving that
to a follow-up since the diff is mechanical and the bug is
unambiguous from the code.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
545639a to
c32c9ac
Compare
|
Gamnaam Song seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
REST/SDK runtime support image pull/list
Test plan
cargo nextest run -p boxlite-cli --test rest_images— 4 stub-driven tests:pull --profile p1 alpine:latestImage operations not supported over REST API, exit 1/v1/images/pullwith{"reference":"alpine:latest"}; stdoutPulled: alpine:latest+ID: sha256:...pull --profile p1 -q alpine:latestIMAGE_ID=$(...))images --profile p1/v1/images, renders table withdocker.io/library/alpinelatestpullagainst server422 image_pull_failedAdditional server-side coverage:
BOXLITE_DEPS_STUB=1 cargo test -p boxlite-cli serve::handlers::images::testsPOST /v1/images/pullresponse correlation matches the pulled manifest digest, not the user's raw reference (alpinevsdocker.io/library/alpine:latest)Two-side:
git checkout HEAD -- pull.rs images.rsreverts the CLI branching (server + REST client + tests preserved) →rest_images4/4 fail. Restore → 4/4 pass.i.reference == req_reference) makespulled_image_response_matches_by_manifest_digest_not_user_referencefail with500vs expected200. Restore digest matching (i.id == manifest_digest) → server handler tests pass.Known follow-ups
ImageObjectshape; REST exposure is a separate PR.GET /v1/images/{id}and the HEAD variant from OpenAPI aren't wired here; follow-up.