Repository navigation
Track consolidating NVX host and guest code in the nvx-rs crate #356
Description
Context
aci_edge_sandboxes combines two concerns:
- the ACI Edge Sandboxes contract: the MXC request model and its validation order, the wire error codes,
SandboxId, theBackendtrait, and the asynchronous and mock APIs; and - everything it takes to drive NVX: launching OpenVMM, the authenticated
NVXS/NVXCcontrol protocol, artifact discovery, process and control-endpoint primitives for Linux and Windows, network and filesystem lowering, bundled-release staging, and a fake OpenVMM for tests.
The same NVX mechanics exist a second time in Python, in control_session.py, sandbox_lifecycle.py, sandbox.py, and egress_policy.py under scripts/nvx_tools/. The guest side of the control protocol is written in C, in guest/common/. A change to the control protocol therefore touches Rust twice (the backend and the fake OpenVMM), Python, and C.
Goal
A new Rust crate, nvx-rs, owns all NVX-specific code and provides:
- a library,
nvx, thataci_edge_sandboxes, the crate's own binaries, and tests build on; - six static guest binaries that replace
guest/common/*.cunder their existing names; and - a host CLI,
nvx-rs, that becomes the backend of the runtime paths ofscripts/nvx.py.
Phases
Each phase is one pull request with its own sub-issue, and the phases merge in order.
| Phase | Issue | Scope | Depends on |
|---|---|---|---|
| 1 | #357 | Extract the NVX-specific code from aci_edge_sandboxes into nvx-rs, without behavior changes |
— |
| 2 | #358 | Replace the guest C programs with Rust binaries from nvx-rs |
Phase 1 |
| 3 | #359 | Make the nvx-rs CLI the backend of nvx.py for the managed sandbox lifecycle, the control session, egress-policy lowering, and artifact lookup |
Phase 1; merges after phase 2 |
| 4 | #638 | Make the nvx-rs CLI the backend of nvx.py run: its option checks, live shares, network options, and OpenVMM command line |
Phase 3 |
The shared image-backed runtime of #535 carries the rest of the consolidation inside nvx-rs: #620 moves the CLI's sandbox lifecycle and host::instance onto one store, supervisor, and NVXS session, and #622 gives them one launch planner.
Decisions
| Topic | Decision |
|---|---|
| Crate | Package nvx-rs in nvx-rs/, library crate nvx, CLI binary nvx-rs. It is a standalone crate with its own Cargo.lock, like aci_edge_sandboxes. A workspace at the repository root would interact with the nested openvmm/ workspace and widen the Docker build context of the guests |
| Toolchain | As for aci_edge_sandboxes: CI toolchain 1.93, MSRV 1.89, edition 2024, and the same lints. Guest builds pin an exact toolchain |
| Guest binaries | Six separate static binaries with the existing /sbin/nvx-* names, so guest scripts don't change |
nvx.py scope |
The code that Python duplicates today: the managed sandbox lifecycle (including the EROFS layer and scratch mode), the control session, egress-policy lowering, artifact lookup, and, in phase 4, the launch of nvx.py run. Benchmark and test-microvm orchestration stay in Python |
| Compatibility | No compatibility guarantees for consumers of aci_edge_sandboxes, such as MXC. Its README documents every breaking change |
| Porting | Faithful ports first: the same wire formats, limits, exit statuses, output formats, and setpriv exec chain. Redesigns are follow-ups |
Target layout
nvx-rs/
├── src/
│ ├── protocol/ NVXS records, NVXC frames, EXEC payloads, guest features, and nvx_map tokens;
│ │ no dependencies, shared by the host and the guest
│ ├── contract.rs control-contract versions and release-manifest compatibility
│ ├── net/ CIDR parsing and subtraction
│ ├── host/ feature `host` (default): artifacts, launch, network, filesystem, session,
│ │ process, platform, VM instances, the sandbox launch profile, and the CLI
│ ├── guest/ feature `guest` (Linux): the managed agent and the guest tools
│ ├── testing/ feature `testing`: the fake OpenVMM
│ └── bin/ nvx-rs, nvx-fake-openvmm, and the six guest binaries
├── build.rs bundled-release staging, and link arguments for the freestanding nvx-device-io
└── artifacts.json the NVX release that the `bundled` feature stages
aci_edge_sandboxes keeps the ACI contract: the facade, Backend, capabilities, the MXC model and its validation, error codes, SandboxId, the execution and stream plumbing, and the asynchronous and mock APIs. It also keeps a thin openvmm backend that translates requests into nvx calls and maps nvx errors to ACI error codes.
Validation
Each phase runs:
nvx.py verify;- the
nvx-rschecks:cargo fmt --check,cargo clippywith-D warnings(all targets and features, and the library without default features),cargo test,cargo docwith-D warnings, and the MSRV check; - the
check-aci-edge-sandboxes,check-quality, andvalidate-nvxactions; and - the affected hypervisor tests (
test-aci-edge-sandboxesandtest-microvmscenarios) on Linux/KVM. CI covers Linux/MSHV and Windows/WHP.
Risks
| Risk | Mitigation |
|---|---|
| The managed-agent port drifts in security-critical behavior (privilege drop, mounts, containment) | A line-by-line parity checklist, the ported tests, a loopback test against the host session, real-VM scenarios, and a security review |
| Larger guest images or slower boot | A size-optimized guest profile, a size and boot-time comparison against the C build, and the CI performance gate |
| Guest builds that aren't reproducible | An exact toolchain pin, --locked, path remapping, no build ID, one codegen unit, and a fresh target directory for each determinism build |
| A build path without the Rust toolchain (Docker, native builds, Copilot cloud sessions, self-hosted runners) | Install the pinned toolchain in each one. The Copilot agent firewall already allows rustup and crates.io |
nvx.py sandbox behavior changes when it moves to Rust |
Golden CLI tests derived from today's Python behavior, and the managed exec tests stay end to end |
Acceptance criteria
- Phase 1:
aci_edge_sandboxescontains no NVX mechanics beyond translating its requests intonvxcalls. - Phase 2: no C sources remain outside
openvmm/, and every guest image ships the Rust binaries at the existing paths. - Phase 3: Python duplicates no control-protocol, lifecycle, or egress logic, and releases ship
nvx-rs. - Phase 4:
nvx.py rungoes throughnvx-rs, and Python builds no OpenVMM command line for it. - CI, including the KVM, MSHV, and WHP workloads and the performance gate, passes after each phase.
Activity
nvx-rs: extract the NVX mechanics from aci_edge_sandboxes
nvx-rs: extract the NVX mechanics from aci_edge_sandboxes
nvx-rs: extract the NVX mechanics from aci_edge_sandboxes
nvx-rs: extract the NVX mechanics from aci_edge_sandboxes
nvx-rs: add the crate with its error type, hypervisors, and networks
esaurez commentedon Oct 20, 2026
Checklist status: #357, #358 (through #561) and #359 (through #594–#598) have merged, so the three phase items look done; please tick them if you agree. Two follow-ups stay open and aren't part of those phases: #581 (one shared
EXECandMAPSdecoder), which #623 finishes, and #601 (the direct-mode launch test), which #619 completes. #535 now tracks the shared image-backed runtime built onnvx-rs.esaurez commentedon Oct 23, 2026
#535 delivered the shared host and guest libraries. Moving NVX's own binaries and tools onto them, the rest of this consolidation, continues in #816.
ppenna commentedon Oct 27, 2026
All four phases have merged, and
devmeets every acceptance criterion, so I ticked the last two:nvx.py rundelegate tonvx-rs run(nvx-rs: make the nvx-rs CLI the backend of nvx.py run #638), and nvx.py: retire the run and sandbox commands in favor of nvx-rs #902 then removednvx.py runandnvx.py sandboxaltogether (nvx.py: retire the sandbox and run commands in favor of nvx-rs #725), sonvx-rsbuilds the OpenVMM command line of every runtime path. Only the orchestration ofbenchmarkandtest-microvmbuilds its own, which this issue keeps in Python.devruns of the merges of nvx-rs: extract the NVX mechanics from aci_edge_sandboxes #519 (phase 1, run), Ship nvx-rs in NVX releases #598 (phase 3, run), nvx-rs: make the nvx-rs CLI the backend of nvx.py run #704 (phase 4, run), and nvx.py: retire the run and sandbox commands in favor of nvx-rs #902 (run) passed. Those of Build the guest binaries from nvx-rs #561 (phase 2, run) and of Port egress policies to nvx-rs #594 after it (run) failed on Windows/WHP withUbuntu artifact manifest does not match initramfs-ubuntu.cpio.gz. Order Ubuntu converter inputs alike on every OS #599 fixed that by ordering the Ubuntu converter's inputs alike on every OS (run), and everydevrun from it through Ship nvx-rs in NVX releases #598 passed.#914 corrects the last descriptions that still present
nvx-rsas a backend ofnvx.py, or its sandbox profile and egress policy files asnvx.py's, and closes this issue when it merges. Moving NVX's own binaries and tools onto the shared host and guest libraries, the rest of this consolidation, continues in #816.nvx-rs: stop describing the CLI as a backend of nvx.py
nvx-rs: attribute the sandbox profile and egress policy files to nvx-rs