Repository navigation
sandbox: bind GPT disks, plan adapter launches, and stage registered images - #813
Merged
Enrique Saurez (esaurez) merged 4 commits intoOct 23, 2026
Merged
Conversation
A distro binding named only EROFS layers, so a caller whose distro image is a GPT disk could not bind it, check it, or prepare a launch of it, and had to keep checks of its own beside NVX's. `DistroFormat::Gpt` names a GPT disk, and `SandboxLayer::gpt` names one by the disk GUID that the guest checks. A binding records its layer's format beside the identity, and `check` refuses a binding of another format, before it compares the identity. `SandboxPlan` and `SandboxLaunch` plan a GPT binding as `RootImage::gpt`, so `PreparedLaunch` prepares it as it prepares an EROFS layer. The binding's serde form gains only the `gpt` format, so its version stays 1. Part of #622. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3b1602-3998-4aa1-b32b-9598ac7f7ffd
A plan always rendered NVX's sandbox profile: the workload identity for the VMM, and `nvx_sandbox=1` with the entrypoint, hostname, and arguments for the guest, and it refused every `nvx_*` token of the caller. An adapter that boots its own guest, which chooses the identity and program of its workloads and attaches its shares itself, could not use the plan, nor the prepared launch and checked handoff built on it. `SandboxPlan::adapter` plans the same root without launch settings or an export plan. Its arguments name the block devices and any network alone, and its kernel command line is the adapter's own, which may hold `nvx_*` tokens, followed by the root's boot tokens. It refuses the root's tokens and `virtfs_*` tokens, which OpenVMM appends for shares, and checks the result against the 1024-byte budget and the guest's parser. An adapter's plan refuses an export plan. The persisted form keeps version 3: an adapter's plan has `null` settings, and every plan that an earlier build wrote still reads. Part of #622. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3b1602-3998-4aa1-b32b-9598ac7f7ffd
`Diagnostics::content_verification` made every start hash the image and the runtime files again. A start should cost about the guest's boot time, and a caller that doubts an image has `verify_image`, which hashes it on request, so no setup makes a start hash anything. The setup no longer accepts `contentVerification`, so the sandbox ABI moves to 2: a client of ABI 1 always sends the field, which a library of ABI 2 refuses. The agent tests now start a sandbox of a trusted digest that its image does not have, which only `verify_image` finds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3b1602-3998-4aa1-b32b-9598ac7f7ffd
A library pulled a reference the first time a sandbox used it, so a provision could download and convert a whole image, and its sandboxes attached the registered file itself, which the file's owner could still change. Registration is now the one step that reads, pulls, or hashes an image, and it stages the image: sandboxes attach the library's own read-only raw copy, which `RegisteredImage::path` names, so a later change to the registered file reaches no sandbox. The copy keeps the image's ID, the SHA-256 of the registered file, even where it drops a fixed VHD's footer. Provision takes only registered images, by ID, by the path that was registered, or by the reference, and refuses a path whose file changed since its registration. `register_reference` registers a registry image, pulling it once, and an `ImageRegistration` names either a path or a reference; a backend that honors no references refuses one before the library sees it. The setup's default image is still registered when a backend opens, and `unregister_image` also removes the staged copy. The agent tests cover the staged copy and its ID, a change to the registered file, which provision by path refuses while sandboxes keep booting the copy, a change to the copy, which fails closed until the image is registered again, the copy's removal, and references: a runtime without the image tool registers none, and a registered reference is pulled once, staged, booted by its reference and its ID, and removed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: bd3b1602-3998-4aa1-b32b-9598ac7f7ffd
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
The ABI-breaking staging contract needs validation against a compatible external agent library on real hypervisors before final human approval.
No open issues 🎉
What changed in this PR
This PR advances #622 by extending NVX’s shared launch planning to GPT disks and adapter-owned guests, and defining an ABI 2 image-staging contract for aci_edge_sandboxes.
Changes:
- Add GPT distro bindings and format-aware launch preparation.
- Add adapter plans without sandbox workload settings or managed exports, while validating root boot tokens and command-line limits.
- Add reference registration and staged-image contracts, remove start-time content verification, and expand opt-in integration tests.
| File | Description |
|---|---|
nvx-rs/src/host/sandbox/prepared/tests.rs |
Test GPT preparation and adapter workload-identity omission. |
nvx-rs/src/host/sandbox/prepared.rs |
Document adapter workload identity ownership. |
nvx-rs/src/host/sandbox/plan/tests.rs |
Test adapter rendering, validation, and persistence. |
nvx-rs/src/host/sandbox/plan/form.rs |
Support persisted adapter plans with null settings. |
nvx-rs/src/host/sandbox/plan.rs |
Add adapter planning and GPT binding conversion. |
nvx-rs/src/host/sandbox/mod.rs |
Make sandbox launches respect distro format. |
nvx-rs/src/host/sandbox/layer.rs |
Add GPT layers and format accessors. |
nvx-rs/src/host/sandbox/distro/tests.rs |
Test GPT bindings and cross-format rejection. |
nvx-rs/src/host/sandbox/distro.rs |
Record and check GPT binding formats. |
nvx-rs/README.md |
Document GPT bindings and adapter plans. |
aci_edge_sandboxes/tests/agent_guest.rs |
Extend opt-in staging and registration contract tests. |
aci_edge_sandboxes/src/agent/mod.rs |
Add validated, capability-gated reference registration. |
aci_edge_sandboxes/README.md |
Document registration-only provisioning and staged copies. |
aci_edge_sandboxes/model/src/wire.rs |
Bump sandbox ABI to 2 and extend image registration. |
aci_edge_sandboxes/model/src/spec.rs |
Share image validation and document registration requirements. |
aci_edge_sandboxes/model/src/setup.rs |
Remove content verification and clarify reference handling. |
aci_edge_sandboxes/model/src/image.rs |
Clarify original-image IDs and staged-file metadata. |
aci_edge_sandboxes/model/src/capabilities.rs |
Document reference registration capability. |
aci_edge_sandboxes/examples/agent_lifecycle.rs |
Update diagnostics construction. |
Review effort: Balanced
Enrique Saurez (esaurez)
marked this pull request as ready for review
October 23, 2026 18:08
Enrique Saurez (esaurez)
deleted the
esaurez/a4-adapter-gpt-staging-20261023
branch
October 23, 2026 18:36
This was referenced Oct 23, 2026
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.
An adapter that boots its own guest from a GPT disk can now use NVX's typed launch plan, distro binding, and checked handoff, and
aci_edge_sandboxesgains a staging contract that keeps reading, pulling, and hashing images out of provision and start.What changed
GPT distro bindings (
nvx-rs).DistroFormat::GptandSandboxLayer::gptname a GPT disk by the disk GUID that the guest checks. ADistroBindingrecords its layer's format beside the identity, andcheckrefuses a binding of another format before it compares identities. The binding's serde form gains only thegptformat, so its version stays 1.SandboxPlanandSandboxLaunchplan a GPT binding asRootImage::gpt, soPreparedLaunchprepares a GPT disk as it prepares an EROFS layer.Plans of an adapter's own guest (
nvx-rs).SandboxPlan::adapter(distro, upper)plans the same root, block devices, and network for an adapter whose guest chooses the identity and program of its workloads and attaches its shares itself: it holds noSandboxSettingsand no export plan. Its OpenVMM arguments name no--microvm-workload-identity, and its kernel command line is the adapter's own, which may carry the adapter'snvx_*tokens, followed by the root's boot tokens.nvx_layer=,nvx_scratch=,nvx_overlay_upper=),virtfs_*tokens, a NUL, a command line beyond the 1024-byte budget, and one whose root tokens the guest's parser refuses.with_exportrefuses an export plan; the adapter renders its shares withExportPlan::openvmm_arguments. sandbox: deliver managed live shares as a host mapping table #794's managed share delivery is unchanged for the sandbox profile."settings": null, and every plan that an earlier build wrote still reads.SandboxPlan::settingsreturns anOption.aci_edge_sandboxes: provision only registered images.RegisteredImage::pathnames and sandboxes attach, so a later change to the registered file reaches no sandbox. The copy of a fixed VHD drops the footer and keeps the image's ID, the SHA-256 of the registered file.unregister_imagealso removes the staged copy.AgentBackend::register_referenceregisters a registry image, pulling it once, andImageRegistrationnames exactly one ofpathandreference. A backend that does not honor references refuses one before the library sees it.Diagnostics::content_verificationis removed, so no setup makes a start hash anything;verify_imagestays the explicit diagnostic.agent_guesttests, which run against a separately built agent library, define the contract: the staged copy, its ID and raw content, changes to the registered file and to the copy, the copy's removal, trusted digests that onlyverify_imagechecks, references refused without the runtime bundle's image tool, and, given a registry image, a reference pulled once, staged, booted, and removed.Behavior changes
contentVerification, which the setup now refuses, and an image registration has a new form. A build withagent-bundledrefuses a bundle of ABI 1, so it needs a bundle released at or after this change, orACI_EDGE_SANDBOXES_AGENT_BUNDLE_URLor_DIR.The CLI's GPT integration (#818) and the test adapter's end-to-end adoption (#822) follow in #816; until then the runtime adapter keeps
SandboxPlan::new.Part of #622
Validation
At this head, on
devata83bb88e, on Windows 11 and on Linux, in a container with Rust 1.95.0 and 1.89, as a non-root user:python scripts/nvx.py verify, andscripts/test_nvx_tools.py AgentBundlingTests.nvx-rs, withNVX_BUNDLE=skip:cargo fmt --all --check;cargo clippy --locked --all-targets --all-features -- -D warnings;cargo clippy --locked --lib --no-default-features -- -D warnings;cargo test --locked --all-features;cargo test --locked;cargo build --locked --lib --no-default-featuresandcargo test --locked --lib --no-default-features;cargo doc --locked --no-deps --all-featureswithRUSTDOCFLAGS=-D warnings;cargo +1.89 check --locked --all-targets --all-features; on Linux also the artifact bundling test, theaarch64-apple-darwincheck, and the guest binaries' check, build, and test.aci_edge_sandboxes: the steps ofcheck-aci-edge-sandboxes: fmt, both clippy configurations, both test configurations,nvx.py test-agent-bundling, docs, and MSRV; the macOS check on Linux.tests/runtime-adapter: the protocol-only and host-only configurations on both, and the guest-only (musl) configuration on Linux.python scripts/check_markdown_links.py.agent_guesttests need an agent library of sandbox ABI 2, which is built and validated separately.