Skip to content

sandbox: bind GPT disks, plan adapter launches, and stage registered images - #813

Merged
Enrique Saurez (esaurez) merged 4 commits into
devfrom
esaurez/a4-adapter-gpt-staging-20261023
Oct 23, 2026
Merged

Enrique Saurez (esaurez) merged 4 commits into
devfrom
esaurez/a4-adapter-gpt-staging-20261023

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

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_sandboxes gains a staging contract that keeps reading, pulling, and hashing images out of provision and start.

What changed

GPT distro bindings (nvx-rs).

  • DistroFormat::Gpt and SandboxLayer::gpt name a GPT disk by the disk GUID that the guest checks. A DistroBinding records its layer's format beside the identity, and check refuses a binding of another format before it compares identities. The binding's serde form gains only the gpt format, so its version stays 1.
  • SandboxPlan and SandboxLaunch plan a GPT binding as RootImage::gpt, so PreparedLaunch prepares 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 no SandboxSettings and 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's nvx_* tokens, followed by the root's boot tokens.
  • It refuses the root's 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_export refuses an export plan; the adapter renders its shares with ExportPlan::openvmm_arguments. sandbox: deliver managed live shares as a host mapping table #794's managed share delivery is unchanged for the sandbox profile.
  • The persisted plan keeps version 3: an adapter's plan has "settings": null, and every plan that an earlier build wrote still reads. SandboxPlan::settings returns an Option.

aci_edge_sandboxes: provision only registered images.

  • Registration is the one step that reads, pulls, or hashes an image. It stages a read-only raw copy, which RegisteredImage::path names 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.
  • Provision takes only registered images: by ID, by the registered path, refusing one whose file changed since its registration, or by the reference. It never pulls, copies, or hashes. unregister_image also removes the staged copy.
  • AgentBackend::register_reference registers a registry image, pulling it once, and ImageRegistration names exactly one of path and reference. A backend that does not honor references refuses one before the library sees it.
  • Diagnostics::content_verification is removed, so no setup makes a start hash anything; verify_image stays the explicit diagnostic.
  • The opt-in agent_guest tests, 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 only verify_image checks, references refused without the runtime bundle's image tool, and, given a registry image, a reference pulled once, staged, booted, and removed.

Behavior changes

  • The sandbox ABI moves to 2. A client of ABI 1 always sends contentVerification, which the setup now refuses, and an image registration has a new form. A build with agent-bundled refuses a bundle of ABI 1, so it needs a bundle released at or after this change, or ACI_EDGE_SANDBOXES_AGENT_BUNDLE_URL or _DIR.
  • A path or reference that is not registered no longer provisions; register it first, or name it as the setup's default image, which a backend registers when it opens.

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 dev at a83bb88e, 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, and scripts/test_nvx_tools.py AgentBundlingTests.
  • In nvx-rs, with NVX_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-features and cargo test --locked --lib --no-default-features; cargo doc --locked --no-deps --all-features with RUSTDOCFLAGS=-D warnings; cargo +1.89 check --locked --all-targets --all-features; on Linux also the artifact bundling test, the aarch64-apple-darwin check, and the guest binaries' check, build, and test.
  • aci_edge_sandboxes: the steps of check-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.
  • Each commit builds and lints cleanly on Windows, and passes the tests of the code that it changes.
  • python scripts/check_markdown_links.py.
  • Real VMs: left to CI. This change leaves the CLI's EROFS plans as they were (its golden tests are unchanged), and the opt-in agent_guest tests need an agent library of sandbox ABI 2, which is built and validated separately.

Enrique Saurez and others added 4 commits October 23, 2026 10:42
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
Copilot AI balanced review requested due to automatic review settings October 23, 2026 18:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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

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