Repository navigation
nvx-rs: lower adapter plans into the plans of template captures - #884
Merged
Pedro Henrique Penna (ppenna) merged 1 commit intoOct 28, 2026
Merged
Pedro Henrique Penna (ppenna) merged 1 commit into
Pedro Henrique Penna (ppenna) merged 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The scoped, I/O-free lowering and supporting tests have no identified blocking issues.
No open issues 🎉
What changed in this PR
Adds pure adapter-plan lowering for platform template captures in nvx-rs, the first stage of #841’s capture-and-publication work. This PR prepares capture configuration without launching a VM or publishing a template.
Changes:
- Adds
TemplatePlanandTemplateResources, validating placeholder bindings, resources, network policies, and transaction paths. - Renders dormant devices, tenant-free kernel options, and generation-based snapshot arguments.
- Adds lowering and allowlist tests, verifies copied OpenVMM source excerpts, and documents the API.
| File | Description |
|---|---|
nvx-rs/tests/vectors/README.md |
Documents OpenVMM source excerpts and verification. |
nvx-rs/tests/vectors/openvmm/platform_command_line_token_is_invariant.rs |
Copies the platform token allowlist for tests. |
nvx-rs/tests/vectors/openvmm/microvm_control_tty_command_line.rs |
Copies the control TTY token constant. |
nvx-rs/tests/openvmm_vectors.rs |
Checks source excerpts against the submodule. |
nvx-rs/src/host/template/plan/tests.rs |
Tests lowering, argument rendering, allowlisting, and refusals. |
nvx-rs/src/host/template/plan.rs |
Implements capture plans and resource validation. |
nvx-rs/src/host/template/mod.rs |
Declares and re-exports the plan API. |
nvx-rs/src/host/sandbox/mod.rs |
Makes disk-path validation available within the crate. |
nvx-rs/src/host/mod.rs |
Documents template-plan lowering. |
nvx-rs/README.md |
Describes the new API and capture configuration. |
doc/ci.md |
Documents allowlist excerpt checks in CI. |
.github/workflows/ci.yml |
Updates comments describing existing comparison checks. |
Review effort: Balanced
Enrique Saurez (esaurez)
force-pushed
the
esaurez/839-pr2-template-store-20261024
branch
from
October 24, 2026 22:20
401015b to
8718d50
Compare
Enrique Saurez (esaurez)
changed the base branch from
esaurez/839-pr2-template-store-20261024
to
esaurez/839-pr3-leases-20261024
October 24, 2026 22:30
Enrique Saurez (esaurez)
force-pushed
the
esaurez/841-pr1-template-lowering-20261024
branch
from
October 24, 2026 22:30
39ac01d to
79d580b
Compare
Enrique Saurez (esaurez)
force-pushed
the
esaurez/841-pr1-template-lowering-20261024
branch
from
October 24, 2026 23:04
79d580b to
7f55573
Compare
Enrique Saurez (esaurez)
changed the base branch from
esaurez/839-pr3-leases-20261024
to
esaurez/839-pr4-supervisor-seam-20261024
October 25, 2026 00:59
Enrique Saurez (esaurez)
force-pushed
the
esaurez/841-pr1-template-lowering-20261024
branch
from
October 25, 2026 00:59
7f55573 to
290a45b
Compare
This was referenced Oct 25, 2026
Enrique Saurez (esaurez)
force-pushed
the
esaurez/839-pr4-supervisor-seam-20261024
branch
2 times, most recently
from
October 27, 2026 04:39
b7ac52f to
061e368
Compare
Enrique Saurez (esaurez)
force-pushed
the
esaurez/839-pr4-supervisor-seam-20261024
branch
from
October 27, 2026 15:18
061e368 to
d0789ce
Compare
Enrique Saurez (esaurez)
force-pushed
the
esaurez/841-pr1-template-lowering-20261024
branch
from
October 27, 2026 16:23
290a45b to
0468d07
Compare
Enrique Saurez (esaurez)
force-pushed
the
esaurez/839-pr4-supervisor-seam-20261024
branch
from
October 27, 2026 17:55
d0789ce to
a101e05
Compare
This was referenced Oct 27, 2026
A template is a capture of a microVM that consumed only its invariant configuration, for clones that each bind their own image, upper, and export when they are restored. Before a store captures one, the host needs the exact VM and options of that capture: OpenVMM refuses a platform-tier capture whose kernel command line holds a token outside its platform allowlist, and a template must hold no tenant data. Add nvx::host::template::TemplatePlan, which lowers an adapter's SandboxPlan without I/O into: - the placeholder distro, bound through its DistroBinding, whose length is the capacity of every clone's image, at an absolute path that OpenVMM's block device options hold whole, and that it attaches as a raw image, over a dormant scratch device, a sparse file in the capture's transaction directory; - the dormant filesystem slot, and no NIC or one fixed NIC under the template's policy, which may allow neither ingress nor host-loopback access both ways, since OpenVMM publishes the guest's listeners through them as live host attachments, which no snapshot holds; - TemplateResources: every processor online at boot, and RAM with a --memory-capacity, in blocks of 128 MiB; - the kernel command line nvx_sandbox=1, the one token that the host adds to those that OpenVMM writes itself; - the capture's options: --snapshot-tier platform, a --snapshot-destination in the transaction directory, under the name of a generation's snapshot in the template store, and --snapshot-block-identity generation with the capture's StorageGeneration, the bound-block storage generation, so that the capture hashes no block device. The tests check each token of a template's command line with OpenVMM's own allowlist, compiled from verbatim excerpts of its source in tests/vectors/openvmm/, which the ignored test of tests/openvmm_vectors.rs compares with the OpenVMM submodule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 32eea669-a52c-4a53-87fa-521c498537e5
Base automatically changed from
esaurez/839-pr4-supervisor-seam-20261024
to
dev
October 27, 2026 19:41
Enrique Saurez (esaurez)
changed the base branch from
dev
to
esaurez/840-pr2-template-mode-20261024
October 27, 2026 19:45
Enrique Saurez (esaurez)
force-pushed
the
esaurez/841-pr1-template-lowering-20261024
branch
from
October 27, 2026 19:46
0468d07 to
77e1660
Compare
Base automatically changed from
esaurez/840-pr2-template-mode-20261024
to
dev
October 27, 2026 21:16
This was referenced Oct 27, 2026
Pedro Henrique Penna (ppenna)
deleted the
esaurez/841-pr1-template-lowering-20261024
branch
October 28, 2026 00:27
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.

Stacked on #932; this PR retargets when its parent merges.
Chain: #932 → this PR → #887 → #933, on
dev; #879, #881, #885, #886, and #877 have merged.Part of #841 (PR 1 of 3: template lowering).
What and why
A template is a capture of a microVM at OpenVMM's platform tier, after the VM consumed only its invariant configuration, for clones that each bind their own image, upper, and export when they are restored. Before a store can capture one, the host needs the exact VM and options of that capture, and they must meet OpenVMM's rules for the platform tier: a kernel command line of allowlisted tokens only, no tenant data, and nothing that a snapshot cannot hold.
nvx::host::template::TemplatePlan::newlowers an adapter'sSandboxPlan(SandboxPlan::adapter) into that plan, without I/O:distro, bound through itsDistroBinding: the plan's image must be the format and identity that the binding names, and the length that the binding records is the capacity of every clone's image (image_capacity()). Its path must be absolute, since OpenVMM would resolve a relative one against the directory in which it runs; it may hold no comma or semicolon, which OpenVMM's block device options would split; and its name may not end in.vhd,.vhdx,.vmgs, or.iso, which OpenVMM would not attach as a raw image, as a sandbox's validation andPreparedLaunchcheck them.SCRATCH_NAME(scratch.raw) in the capture's transaction directory, a sparse file whose length (scratch_length()) and block sizes the device takes, and which the template does not keep.TemplateResources: 1, 2, 4, or 8 processors, all online at boot (B = C), and RAM with--memory-capacity, both in blocks of 128 MiB (MEMORY_BLOCK_SIZE). The capacity is always rendered: without it, a capture records no memory expansion, andTemplateManifest::readrefuses it.nvx_sandbox=1(kernel_command_line()), which the caller passes as--cmdlinealone, in place of the adapter plan's, which names the root's image identity. OpenVMM writes the other tokens itself, each on its platform allowlist: the console, reboot, and panic settings,nr_cpus=,nvx_snapshot_tier=platform, the virtio devices and the control tty, and the NIC's addresses.--snapshot-tier platform,--snapshot-destinationatSNAPSHOT_NAME(snapshot, the name by which a generation of the template store names its snapshot) in the transaction directory, and--snapshot-block-identity generationwith the capture'sStorageGenerationas--snapshot-generation-id, so that the capture hashes no block device. The template keeps no storage generation: OpenVMM unbinds itsdistro, and its scratch is fresh.openvmm_arguments()renders the devices by path, asSandboxPlan::openvmm_argumentsdoes, thencapture_arguments(), which a caller that renders the devices' arguments itself can take alone.The bound-block storage generation is #881's
StorageGeneration, rendered with itsDisplay; this PR adds no type of its own for it, and derives it from none of the other namespaces of a template's generations.Outside
nvx-rs/src/host/template/plan.rsand its tests, the change declares and re-exports the module, makessandbox::reject_disk_pathandsandbox::reject_container_pathcrate-visible, extends the OpenVMM vector test, and updates the docs.Decisions to review
nvx_config=0xd0010000,65536is on OpenVMM's allowlist, but nothing in NVX defines or reads it, so a template does not pass it. Passing it later changes one constant.--snapshot-destination, OpenVMM opens each block device itself, without following a link at its path (O_NOFOLLOW;FILE_FLAG_OPEN_REPARSE_POINT), and on Windows without sharing write access. APreparedLaunch's/proc/self/fd/Npaths, and on Windows its inherited scratch claim, therefore don't serve a capture at this OpenVMM revision, and the docs here name no such composition. PR 2 therefore hands OpenVMM the paths of the files that it checked, and holds no writable handle on them when OpenVMM starts.Tests
nr_cpus=,nvx_snapshot_tier=,virtnet_ip=,virtnet_gw=), are checked with OpenVMM's own allowlist function, compiled from verbatim excerpts of its source innvx-rs/tests/vectors/openvmm/. The ignored test oftests/openvmm_vectors.rs, which the NVX CLI jobs run, checks that the excerpts are whole lines of the submodule's files.Validation
No VM is needed for this change: everything below ran without one, at this head, with the OpenVMM submodule at e68871cc.
Rebase: this head is rebased onto #932's f28fdca, whose base, with #886 and #877 now merged, retires
aci_edge_sandboxesand pins OpenVMM e68871cc. The excerpts of OpenVMM's allowlist are still whole lines of e68871cc's files, and the vectors' copies are unchanged, so the only port is thattests/vectors/README.mdnow records e68871cc.nvx-rs, withNVX_BUNDLE=skip:cargo fmt --all --check;cargo clippy --locked --all-targets --all-features -- -D warnings;cargo clippy --locked --lib -- -D warnings, also with--no-default-features;cargo clippy --locked --all-targets --no-default-features --features <feature> -- -D warningsforhost,cli,testing,serde, andbundled;cargo test --locked --all-features;cargo test --locked;cargo build --locked --lib --no-default-featuresandcargo test --locked --lib --no-default-features, also with--features host;RUSTDOCFLAGS="-D warnings" cargo doc --locked --no-deps --all-features;cargo +1.89 check --locked --all-targets --all-features; andcargo test --locked --test host_modules. From the root, the ignoredcargo test --locked --manifest-path nvx-rs/Cargo.toml --no-default-features --test openvmm_vectors -- --ignored. Then the commands ofcheck-nvx-rsfortests/runtime-adapter, protocol-only and host-only, andpython scripts/check_markdown_links.py.--features guest,cargo check --locked --all-targets --all-features --target aarch64-apple-darwin,python3 scripts/nvx.py check-guest-binaries, and the runtime adapter's static musl guest configuration.maxcpus=line fails it (checked by editing a copy, then restoring it).workflow_dispatchrun of CI at tests: capture templates in VMs through the runtime adapter #933's head, which holds this PR, passed: every job that a dispatch runs, among them the microVM, platform, and OpenVMM tests on KVM, MSHV, and WHP.Left to CI: the full matrix, once this PR targets
dev; a stacked PR runs none.