Repository navigation
nvx.py: retire the run and sandbox commands in favor of nvx-rs - #902
Open
Pedro Henrique Penna (ppenna) wants to merge 5 commits into
Open
Pedro Henrique Penna (ppenna) wants to merge 5 commits into
Pedro Henrique Penna (ppenna) wants to merge 5 commits into
Conversation
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
Missing setup-build provenance needs correction, and the breaking CLI migration with cross-platform runtime changes warrants final human review.
2 open issues
What changed in this PR
Moves NVX’s runtime interface entirely to nvx-rs, leaving builds, diagnostics, benchmarks, and test orchestration in Python.
Changes:
- Removes
nvx.py run,nvx.py sandbox, and Rust’s--progcompatibility option; simplifies usage output. - Moves CPU-profile guidance into Rust and adds catalog synchronization checks.
- Migrates scenarios, setup scripts, workflows, and documentation to direct
nvx-rsinvocation, with improved crash-exit waiting.
| File | Description |
|---|---|
scripts/test_time_abi.py |
Removes tests for retired Python guidance. |
scripts/test_microvm_tests.py |
Updates command expectations and tests thread-exit waiting. |
scripts/setup/setup-windows-whp.ps1 |
Builds and invokes nvx-rs directly. |
scripts/setup/setup-linux-mshv.sh |
Builds and invokes nvx-rs directly. |
scripts/nvx.py |
Removes runtime commands and their parsers. |
scripts/nvx_tools/time_abi.py |
Removes Python cold-boot guidance. |
scripts/nvx_tools/sandbox_proxy_tests.py |
Updates the documented CLI name. |
scripts/nvx_tools/sandbox_lifecycle_tests.py |
Uses Rust commands and waits for remaining threads. |
scripts/nvx_tools/release.py |
Adds the manual Cargo build hint. |
scripts/nvx_tools/nvx_rs.py |
Simplifies command construction and removes delegation helpers. |
scripts/nvx_tools/microvm_tests.py |
Runs affected scenarios through nvx-rs. |
scripts/nvx_tools/managed_exec_tests.py |
Invokes the Rust sandbox CLI. |
scripts/nvx_tools/adversarial_executor.py |
Updates runtime-related comments. |
README.md |
Updates quick starts and build instructions. |
nvx-rs/tests/openvmm_cpu_profiles.rs |
Adds catalog comparison with OpenVMM profiles. |
nvx-rs/tests/fixtures/run-help.txt |
Removes the fixed help-layout fixture. |
nvx-rs/tests/fake_openvmm.rs |
Updates comments to name the Rust CLI. |
nvx-rs/tests/cli/usage.rs |
Checks compact usage output. |
nvx-rs/tests/cli.rs |
Updates usage, guidance, and interruption tests. |
nvx-rs/src/testing/fake_openvmm.rs |
Updates fake-runtime documentation. |
nvx-rs/src/host/sandbox/options/tests.rs |
Updates a dry-run helper comment. |
nvx-rs/src/host/sandbox/options.rs |
Updates option-contract documentation. |
nvx-rs/src/host/sandbox/mod.rs |
Updates sandbox-profile documentation. |
nvx-rs/src/host/sandbox/layer.rs |
Updates layer documentation. |
nvx-rs/src/host/network/policy/mod.rs |
Updates policy-consumer documentation. |
nvx-rs/src/host/mod.rs |
Documents CLI ownership and CPUID usage. |
nvx-rs/src/host/cli/session.rs |
Updates control-session documentation. |
nvx-rs/src/host/cli/sandbox/tests.rs |
Adapts tests to the simplified parser signature. |
nvx-rs/src/host/cli/sandbox/mod.rs |
Simplifies sandbox usage and parser calls. |
nvx-rs/src/host/cli/run/specification.rs |
Adapts property tests to parser changes. |
nvx-rs/src/host/cli/run.rs |
Integrates native CPU guidance and compact usage. |
nvx-rs/src/host/cli/mod.rs |
Removes --prog and checks help completeness. |
nvx-rs/src/host/cli/egress.rs |
Simplifies parser and usage definitions. |
nvx-rs/src/host/cli/cpu_generations.json |
Adds the built-in CPU profile catalog. |
nvx-rs/src/host/cli/artifacts.rs |
Simplifies artifact-command usage and parsing. |
nvx-rs/src/host/cli/args.rs |
Replaces usage wrapping with one-line formatting. |
nvx-rs/src/host/artifacts.rs |
Updates guest and artifact documentation. |
nvx-rs/README.md |
Documents the standalone runtime CLI. |
doc/setup.md |
Explains obtaining the Rust executable. |
doc/run.md |
Migrates runtime examples to nvx-rs. |
doc/project-structure.md |
Updates component responsibilities. |
doc/guests/ubuntu-guest.md |
Updates guest command references. |
doc/guests/azurelinux-guest.md |
Updates the guest command reference. |
doc/distribution.md |
Clarifies executable installation and build requirements. |
doc/contribute.md |
Documents migrated scenarios and catalog checks. |
doc/ci.md |
Updates runtime handoff and validation documentation. |
doc/build.md |
Clarifies executable provenance wording. |
doc/adversarial-testing.md |
Updates target runtime instructions. |
aci_edge_sandboxes/src/openvmm/config.rs |
Updates the documented source of defaults. |
.github/workflows/run-nvx-microvm-tests.yml |
Invokes Rust directly in sandbox steps. |
.github/workflows/ci.yml |
Adds CPU catalog comparisons on both platforms. |
.github/skills/nvx-run/SKILL.md |
Updates build and runtime instructions. |
.github/skills/nvx-openvmm-promote/SKILL.md |
Adds CPU catalog synchronization guidance. |
.github/skills/nvx-host-connect/SKILL.md |
Updates artifact preparation and dry-run instructions. |
.github/skills/nvx-debug/SKILL.md |
Updates diagnostic command examples. |
.github/copilot-instructions.md |
Updates runtime and rebuild guidance. |
Review effort: Balanced
Pedro Henrique Penna (ppenna)
requested a review
from Enrique Saurez (esaurez)
October 25, 2026 16:03
nvx-rs run now prints the CPU-profile guidance itself after OpenVMM fails a cold boot on a host whose CPU no built-in CPU profile serves, instead of printing what nvx.py run passed it in the hidden --cold-boot-guidance option. Callers that run nvx-rs run directly, as they will once nvx.py run is retired, keep the guidance. nvx-rs identifies the host CPU with CPUID, as OpenVMM's cpu_profile crate does: the vendor string of leaf 0, the display family, model, and stepping of CPUID.1:EAX, with the model extended for Intel's families 6 and 15 and for AMD's family 15 alone, and the brand string of leaves 0x80000002 to 0x80000004 without its padding. A host without CPUID, which is not an x86-64 host, gets no guidance. The CPUs that the built-in profiles serve come from src/host/cli/cpu_generations.json, which nvx-rs embeds: a copy of the ID, the vendor, and the generation of each profile that OpenVMM pins. The guidance keeps its text: what --cpu-profile auto does on the CPU, the generations that the built-in profiles cover, and, on an Intel or AMD CPU, the fingerprint command of the OpenVMM that the run ran and the prefilled CPU profile request, whose fields it encodes as OpenVMM's fallback warning does. It still applies to auto, and to host on a CPU of a vendor that host profiles do not serve either, and still prints only after a failed cold boot, never after a dry run, a restore, a refused option, a usage error, or Ctrl-C. The nvx-rs job cannot check out the OpenVMM submodule, so the ignored test tests/openvmm_cpu_profiles.rs compares the copy with the profiles that the submodule pins, and each NVX CLI job runs it beside the comparison of OpenVMM's protocol vectors, as an OpenVMM pin promotion now does too. The host modules deny unsafe code, so the one CPUID call allows it locally, as the guest's time tools do: the intrinsic is still unsafe in the crate's minimum Rust version, 1.89. nvx.py run no longer reads the host CPU, nor looks OpenVMM up with nvx-rs artifacts, so its parser no longer keeps the values that decided on the guidance, nvx_rs.py drops the artifact lookup, and time_abi.py drops the guidance functions and the issue table that only they used; doctor and benchmark keep its CPU catalog and its profile requests. The Python tests of the guidance become Rust unit tests of the same cases, and a CLI test checks the guidance end to end on the host that runs it, whose CPU the host OS reports through /proc/cpuinfo or PROCESSOR_IDENTIFIER. The one-shot run tests, whose fake OpenVMM fails some cold boots, expect the guidance after those on a host whose CPU no built-in profile serves, such as the Xeon 6973P-C of some GitHub-hosted runners, and nothing after them elsewhere. Part of #725. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The test-microvm scenarios, the sandbox steps of the microVM test workflow, and the checks of the Linux/MSHV and Windows/WHP setup scripts now run their sandboxes and microVMs with nvx-rs itself, rather than through nvx.py sandbox and nvx.py run, so that the test suites no longer depend on the commands that #725 retires. nvx_rs.command_line gives the command line that nvx.py ran: the nvx-rs that nvx.py finds, NVX_RS first, or builds, with this checkout as its artifact root, or another root, which the sandbox-lifecycle acceptance names for the artifacts of another runtime identity. The public run scenarios, the shares of host paths with commas and the L3/L4 and IPv6 egress acceptances, run nvx-rs run with the options that they passed nvx.py run, and record nvx-rs run as the interface of their evidence. The managed-exec-config, sandbox-lifecycle, and sandbox-proxy-only acceptances run nvx-rs sandbox. The process tree of each command loses the Python interpreter that stood between the scenario and nvx-rs, and nothing else. The workflow's bash and PowerShell steps run the nvx-rs that each microVM job downloads into nvx-rs/target/release/, whose artifact root is then the checkout, and the test that derives the guest artifacts that each step reads recognizes those invocations. setup-linux-mshv.sh and setup-windows-whp.ps1 build nvx-rs with the pinned Cargo command that nvx.py runs, and the toolchain that each pins, and record the provenance of that executable, before they dry-run nvx-rs run, where nvx.py run built nvx-rs on demand and recorded its provenance, which packaging and the adversarial executor require. The sandbox-lifecycle acceptance, which kills OpenVMM as a crash would, now waits until the last thread of OpenVMM exits before its next transition, as nvx-rs tells that a process exited. It waited only until OpenVMM's command line vanished, which happens once the main thread is a zombie, while the other threads still exit and nvx-rs still counts the process as running: without the interpreter that nvx.py started first, exec reached that window and reported endpoint-closed rather than sandbox-exited on a Linux/MSHV host. Unit tests check the wait for each state that /proc reports and on a real child process. The unit tests of the scenarios expect the nvx-rs command lines, with the operation after --root ROOT, and substitute a stand-in path for nvx-rs where they compile no egress policy. The documents that describe the scenarios and the CI steps name nvx-rs sandbox and nvx-rs run. Part of #725. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The documentation, the README quick start, and the skills now run NVX's microVMs and sandboxes with nvx-rs itself, which #725 makes the only command-line interface that runs them, rather than with nvx.py run and nvx.py sandbox, which the next commit removes. The command-line reference gives nvx-rs a chapter of its own. It names the two ways that a checkout gets nvx-rs at nvx-rs/target/release/: the download of a release that was built from the checkout's nvx-rs sources, or the pinned Cargo command that nvx.py runs, which the reference gives instead of a new nvx.py command. The chapter describes the artifact root that nvx-rs uses without --root, the order in which the test-microvm scenarios find or build nvx-rs, and the provenance that binds a build to its sources. The run and sandbox sections move into that chapter under their former titles, so that links to #run and #sandbox still resolve, with nvx-rs synopses, the nvx-rs prefixes of their usage errors, and the note that nvx-rs, unlike argparse, takes no abbreviated option names. "Download and run" becomes "Releases", since running no longer goes through nvx.py. The quick start of the README builds nvx-rs with Cargo unless download installed it, so that a checkout of a development release still runs without Rust, and boots with nvx-rs run on each platform. The run guide; the setup, build, CI, distribution, guest, and project-structure documents; the nvx-run, nvx-debug, and nvx-host-connect skills; the repository instructions; and the nvx-rs README run nvx-rs run and nvx-rs sandbox in their examples and prose. The Rust doc comments that named nvx.py run or nvx.py sandbox as the command behind a behavior name nvx-rs run and nvx-rs sandbox. The command table of the reference keeps its run and sandbox rows, which now point at the nvx-rs sections, until the next commit removes the commands from nvx.py. Part of #725. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
nvx.py no longer fronts the runtime CLI. Its run and sandbox commands, which ran nvx-rs run and nvx-rs sandbox with nvx.py's name, standard streams, and exit status, are gone, and argparse refuses them as it refuses any unknown command. The documentation, the test-microvm scenarios, and the CI steps already run nvx-rs itself. nvx.py loses the parsers of both commands, their handlers, the argparse action that recorded their options for nvx-rs, and the constants that only those parsers used. nvx_rs.py loses what only they needed: the command line with --prog, the hand-over of SIGINT, SIGTERM, and SIGHUP to nvx-rs while it ran, the wait that outlasted a KeyboardInterrupt, and the mapping of nvx-rs's exit status to nvx.py's. Its queries, which compile the egress policies of the scenarios, take their command line from command_line, as the scenarios' runs do. nvx.py describes itself as building, testing, benchmarking, and packaging NVX, since it no longer runs microVMs. When download finds that a release ships no nvx-rs built from the checkout's sources, it now gives the Cargo command that builds one, since no nvx.py command builds it on demand any more; only the microVM tests still do. The tests of the delegation go with it: the recording of options in command-line order, abbreviations, the usage errors that argparse kept, the shared standard streams and statuses, and the signal handling. The query tests take their command lines from command_line, the test of an unstartable nvx-rs runs a query, and the test that nvx-rs run leaves OpenVMM a terminal to restore runs the nvx-rs that NVX_RS names. Two tests that read nvx.py's help now run that nvx-rs: one checks that the nvx-rs chapter of doc/usage.md documents every option of nvx-rs run and sandbox, as the test of nvx.py's commands checked those sections before, and the other that the help of nvx-rs run states the memory default that guests.py gives test-microvm for each guest. The usage test keeps the check of those defaults in doc/usage.md. The command table of doc/usage.md drops run and sandbox. doc/ci.md, doc/project-structure.md, the CI workflow, the nvx-rs README, and the docs and help of the nvx-rs CLI no longer say that nvx.py runs nvx-rs for those commands or passes it its name, and the notes on the Copilot setup say that the microVM tests build nvx-rs when they need it. The README's differences from nvx.py say that nvx-rs takes no abbreviated options, which argparse took, and drop the order in which nvx.py and nvx-rs checked a command line. Part of #725. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
nvx-rs no longer reproduces nvx.py's program name or argparse's layout
of usages, which it kept only so that nvx.py run and nvx.py sandbox
printed what they printed before they delegated to it. The previous
commit removed those commands, and nothing passes --prog any more.
The top-level parser drops --prog, which callers could set to any name
without square brackets or control characters, so every usage and error
names the program nvx-rs, as in `nvx-rs run: error[CODE]: ...`. A
command line that still passes --prog fails with status 2, as any
unknown option does.
Syntax drops the emulation of HelpFormatter._format_usage, which wrapped
each usage at its parts for 80 columns, and holds the text that follows
the parser's name instead: a usage is one line, `usage: nvx-rs COMMAND
ARGUMENTS`. The top-level, artifacts, and egress parsers, which take few
options, keep naming them, as in `usage: nvx-rs egress compile [-h]
PATH`, while run and sandbox, which take 29 and 35, name them
[OPTIONS], as in `usage: nvx-rs run [OPTIONS]` and `usage: nvx-rs
sandbox [{run,provision,start,exec,stop,deprovision}] [OPTIONS]`. Their
help still lists every option, with its value and description, after
the usage, and usage errors still exit with status 2 with their codes.
The tests that pinned argparse's layout go: the unit test of the
wrapping, the help of run that tests/fixtures/run-help.txt pinned byte
for byte, and the tests of --prog and of the usage that nvx.py sandbox
printed. A unit test checks that each parser's usage is one line and
that its help lists exactly the options that the parser takes, another
that the help of run states the memory default of each guest that
Guest::default_memory_mib applies, and the CLI tests check the usages of
usage errors and help, and that --prog is refused. The test that Ctrl-C
ends a help that fills a pipe now checks that the sandbox help, whose
usage takes one line, still overflows the pipe's page.
The nvx-rs README and the docs of the CLI describe the one-line usages,
and call run and sandbox ports of the former nvx.py commands. The tests
of nvx.py's reader of nvx-rs errors use the one-line usages, and drop
the program name with colons that only --prog could give.
Part of #725.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-725-validate-remote-server
branch
from
October 25, 2026 16:15
26ffcfc to
f53e154
Compare
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.

Closes #725.
nvx.pyno longer fronts the runtime CLI. Sandboxes and microVMs run withnvx-rsdirectly,
nvx.py runandnvx.py sandboxare gone, andnvx-rsno longer reproducesnvx.py's program name orargparse's usage layout.Decisions
nvx-rs: with Cargo. The docs give the pinned command(
cargo build --release --locked --features cli --manifest-path nvx-rs/Cargo.toml --target-dir nvx-rs/target), anddownloadstill installs thenvx-rsof a release builtfrom the checkout's sources. No new
nvx.pycommand was added.nvx-rs run. It identifies the CPU with CPUID, asOpenVMM does, and reads a copy of the CPUs that OpenVMM's built-in profiles serve. Both NVX
CLI jobs compare that copy with the submodule's profiles, as they compare the protocol
vectors.
doctorandbenchmarkkeep the Python catalog.nvx.py runandnvx.py sandboxare removed outright, without adeprecation period, so
argparserefuses them as unknown commands (status 2).usage: nvx-rs run [OPTIONS]andusage: nvx-rs sandbox [{run,provision,start,exec,stop,deprovision}] [OPTIONS]. The helpstill lists every option, and usage errors still exit with status 2 and their
argument-*codes.Commits
guidance from
nvx.py runintonvx-rs run, replacing the hidden--cold-boot-guidanceoption, and adds the catalog copy, its sync test, and the CI comparison step. The one-shot
run tests expect the guidance after a failed cold boot when the CPU is unserved.
test-microvmscenarios, the workflow's sandbox steps, and both setup scripts' checks nowrun
nvx-rs. The setup scripts also record the provenance of thenvx-rsthat they build,as
nvx.py rundid. The sandbox-lifecycle acceptance now waits for OpenVMM's last threadafter it kills OpenVMM; see the note below.
doc/usage.mdgets annvx-rschapter,and the README quick start,
doc/run.md, the other docs, and the skills runnvx-rs.argparse action, and signal hand-over. The real-
nvx-rstests now check the docs againstnvx-rs's own help.--prog, the80-column usage wrapping,
tests/fixtures/run-help.txt, and the tests that pinned them. Aunit test now checks that each help lists exactly the options its parser takes.
Behavior changes
nvx-rstakes no abbreviated options (--dryis unknown), whereargparseaccepted anyunambiguous prefix. The docs say so.
--progis gone. A caller that still passes it gets a usage error with status 2.nvx-rsbuilt from the checkout's sources,downloadnow printsthe Cargo command that builds one.
Note: race in the sandbox-lifecycle acceptance
Running
nvx-rs sandboxdirectly exposed a race in the sandbox-lifecycle acceptance on aLinux/MSHV host.
check_crashSIGKILLs OpenVMM and waited only until its/proc/PID/cmdlinewas empty. That happens as soon as the main thread is a zombie, while OpenVMM's other threads
are still exiting.
nvx-rscounts such a process as running, by design, so an immediateexecreportedendpoint-closedinstead ofsandbox-exited. The Python start-up ofnvx.py sandboxused to hide that window.kill_openvmmnow also waits until the recordedprocess has no thread left, as
nvx-rstells it, with unit tests.Validation
Remote bare-metal host:
prometheus30, Linux/MSHV on an Intel Xeon Silver 4114(Skylake-SP), Azure Linux 3.0. Tested at 26ffcfc, the head before the CI and review fixes,
with OpenVMM
2b681564and thev0.1.0-dev.1ff24c52991alinux-mshv package.nvx.py verifypassed.nvx.py download --hypervisor mshvprinted the new Cargo hint, andthe documented Cargo command built
nvx-rs.nvx-rs/target/release/nvx-rs run --hypervisor mshvon a pty printedNVX-GUEST-BOOT-OK: alpine, and/sbin/nvx-exit 0exited with status 0. No guidance wasprinted, since a built-in profile serves this CPU, and no OpenVMM was left running.
nvx.py test-microvm --backend mshvpassed every scenario that thisPR changes:
filesystem-comma-paths,l3-l4-egress-policy,l3-l4-egress-protocols,l3-l4-egress-port-ranges,ipv6-egress-policy,managed-exec-config,sandbox-lifecycle, andsandbox-proxy-only. The sandbox scenarios used the package'sUbuntu layer and a scratch template made the way
build-guest-artifactsmakes it. After thekill_openvmmfix,sandbox-lifecyclealso passed twice on its own.CPU-guidance tests, as did the
host::cliunit tests.cargo test --all-featurespassed except threeguest::tests, which fail the same wayon unchanged
origin/devon this host.nvx-rs runand the real-nvx-rsdocumentation tests, plustest_adversarial,test_hosts, and the Specula tests.Local Windows/WHP host (AMD EPYC 7763):
check, the PowerShell syntax check, and shellcheck and shfmt on
setup-linux-mshv.shpassed.no-default-features tests, rustdoc, MSRV 1.89, and the runtime adapter's protocol and host
configurations passed.
test_adversarial, andtest_hostspassed.test_setup_azureand the Specula tests need bash andfcntl, so they ran on the Linuxhost only.
Fixes after the first CI run and review:
which no built-in profile serves. They now expect the guidance there. With the host's own
profile removed from the catalog, so that the host counts as unserved, the full CLI suites
pass on Windows (50 tests) and on the Linux host (53).
nvx-rsprovenance. I ran theLinux snippet on
prometheus30and the Windows one locally; each record names theexecutable's SHA-256, the pinned toolchain, and the host target.