Skip to content

nvx-rs: download releases, and fetch one for a checkout that has none - #934

Merged
Pedro Henrique Penna (ppenna) merged 7 commits into
devfrom
agents/nvx-py-usage-inquiry
Oct 27, 2026
Merged

Pedro Henrique Penna (ppenna) merged 7 commits into
devfrom
agents/nvx-py-usage-inquiry

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Folds nvx.py download into the nvx-rs CLI, so that the quick start needs no Python: clone the repository, build nvx-rs with Cargo, and run it. When nvx-rs run, sandbox run, or sandbox start finds no artifacts in a checkout, it first downloads the release that CI built from the checkout.

What changed

  • nvx-rs download (download.rs) installs the development release of the checkout, as nvx.py download did. It walks up to 20 first-parent commits, reads each commit's VERSION, and takes the first release v<VERSION>-dev.<commit[..12]> that publishes the package of the host's platform (--hypervisor, --repository). It checks the package's member names and SHA256SUMS, then installs OpenVMM into openvmm/target/release/, and the guest artifacts that SOURCE-MANIFEST.json declares, with their provenance, into build/: all of them or none. Each file is staged beside its destination, the files it replaces are set aside, and a failure puts them back. It never touches nvx-rs itself.
  • No new crates. The command drives the host's git, curl, and tar, as the bundled feature's build script already does; on Windows, the curl.exe and tar.exe of System32. The curl configuration, and so GH_TOKEN or GITHUB_TOKEN, goes through stdin, never the command line. nvx-rs follows redirects itself and sends the token to the API's origin only; a token that GitHub refuses falls back to anonymous access.
  • Automatic download. run, sandbox run, and sandbox start download the release when an artifact that they need is missing, the root is a Git checkout with its SOURCE-MANIFEST.json, and none of the files that a release installs exist. When some exist, which may be local builds, they install nothing and warn instead, so a release never mixes with built artifacts. A lock in build/ makes concurrent commands download once. Every command also waits for a download's installation before it checks the checkout, and keeps downloads out until it has launched OpenVMM. A download that sees one of those files appear, even while it puts its files in place, rolls back and warns. NVX_AUTO_DOWNLOAD=0 turns it off; run-nvx-microvm-tests.yml sets it, so that CI only ever runs the artifacts that it built.
  • Python. nvx.py download, its release code in release.py, and its tests go.
  • Docs. The README's quick start is now clone, build, and run. doc/usage.md and nvx-rs/README.md document nvx-rs download and the automatic download, and the docs, skills, and messages that pointed to nvx.py download now point to nvx-rs download.
  • Review fixes (second through seventh commits).
    • Commands share the download lock from their decision until they have launched OpenVMM. sandbox run takes it before it reads its distro layer, and sandbox start keeps it until its VM is ready. So a command never sees part of an installation, and no download replaces the files it reads.
    • sandbox provision shares the lock while it reads its layer and records the sandbox. sandbox exec, stop, and deprovision share it while they read the runtime identity of a recorded launch. None of these downloads anything, or needs an artifact root that it did not need before.
    • With NVX_AUTO_DOWNLOAD=0, commands take no lock.
    • A fresh installation links each file into place with fs::hard_link, so a file that a local build publishes at the last moment cancels the installation instead of being replaced.
    • The rollback keeps any file that a build has rewritten or replaced since the installation put it in place, which it detects by the file's SHA256SUMS digest.
    • A replacing installation refuses a directory where the release has a file.
    • run and sandbox run download nothing for options that they refuse. run builds its share arguments once the artifacts are in place.
    • Ctrl-C ends a command's wait for a download, and the command with it.
    • Each fix has a regression test that fails without it, except the last one, whose case needs a real download.

Notes for reviewers

  • An automatic download reports on standard error, so that the >> COMMAND line of run stays alone on standard output.
  • A restore (run --restore-snapshot) needs only OpenVMM, and an OpenVMM that NVX_OPENVMM names is the caller's to provide.
  • download refuses the root of an extracted release package; it only installs into checkouts.
  • There are no new error codes: release problems are unavailable, and an NVX_AUTO_DOWNLOAD other than empty, 0, or 1 is unsupported.
  • The CLI scenario tests never reach the network: their roots have no .git, and the download scenarios use a .git that git rejects. The unit tests run the real tar, and the real curl against loopback servers, to check that the token does not follow a cross-origin redirect.

Validation

  • Windows, rebased on dev: the check-nvx-rs steps (rustfmt, Clippy with -D warnings for every feature set, the tests, rustdoc with -D warnings, the MSRV check with Rust 1.89, the aarch64-apple-darwin check, and the runtime adapter's configurations). In the full run, the CLI scenario lifecycle::refusals_of_lifecycle_operations once missed its 0.5 s window for a fake OpenVMM that exits at start, and passed on its rerun; that window opens after the launch, which this change does not touch.
  • Windows, rebased on dev: check-quality's Ruff, Pyright for Linux and Windows, and link check, and validate-nvx's unit tests (1,345), test_adversarial.py, test_hosts.py, and nvx.py help commands. The only failures are five test_setup_azure.py tests that run the Linux setup scripts with bash, which is WSL's on this host; this change touches neither.
  • Linux (WSL Ubuntu): Clippy with -D warnings for all targets, and the CLI download and interrupt scenarios, at the head.
  • End to end, against the published releases: on Windows, run --dry-run in a fresh checkout downloaded and installed the release of its HEAD (142 MiB), with matching provenance digests; a partial checkout got the warning; download replaced a partial checkout; and two concurrent runs downloaded once. In a Linux clone with a local commit, run fell back to the parent's release and installed OpenVMM with mode 0755, and NVX_AUTO_DOWNLOAD=0 disabled the download.
  • Left to CI: the hypervisor suites and real boots.

The quick start needed Python only to install a development release
with nvx.py download. nvx-rs download now does it. It walks up to 20
first-parent commits of the checkout, reads each commit's VERSION, and
looks for the development release v{VERSION}-dev.{commit[..12]} that
holds the package of the host's platform. It checks the package's
SHA256SUMS, then installs OpenVMM, the guest artifacts that
SOURCE-MANIFEST.json declares, and their provenance as one transaction:
it stages each file beside its destination, sets aside each file that it
replaces, and puts them all back if any step fails.

So that the crate takes no new dependency, the command drives the
host's git, curl and tar, which the bundled feature's build script
already uses; on Windows, it runs those of System32. It hands curl its
configuration, and so the token of GH_TOKEN or GITHUB_TOKEN, on stdin.
It follows redirects itself, sends the token to the API's origin only,
and retries without the token when GitHub refuses it.

nvx-rs run, sandbox run and sandbox start download the release when a
Git checkout misses an artifact that they need and holds none of the
files that a release installs. When it holds some of them, which may be
local builds, they install nothing and warn instead, so that no release
mixes with built artifacts; a download that sees such a file appear
while it runs cancels, puts everything back and warns too. A lock in
build/ makes concurrent commands download once. NVX_AUTO_DOWNLOAD=0
turns this off, and the microVM test workflow sets it so that CI runs
only the artifacts that it built.

nvx.py download goes, with its release code and tests, and the
README's quick start is now: clone, build nvx-rs, and run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 20:08

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.

🟡 Changes recommended

Unresolved installation races can overwrite locally built artifacts or expose incomplete artifacts to concurrent launches.

2 open issues
What changed in this PR

Moves release downloading from Python into nvx-rs, enabling a clone–build–run quick start without Python and automatic artifact preparation for empty checkouts.

Changes:

  • Adds release discovery, authenticated downloads, archive verification, and staged installation with rollback.
  • Integrates automatic downloads into VM and sandbox launches, adds tests, and disables automatic downloads in microVM CI.
  • Removes the Python download command and updates documentation, diagnostics, and contributor guidance.
File Description
tests/​runtime-adapter/​src/​runtime.rs Updates the download command in module documentation.
tests/​runtime-adapter/​README.md Updates artifact preparation instructions.
scripts/​publish_development_release.py Clarifies packaged executable roles in a docstring.
scripts/​nvx.py Removes the Python download command and options.
scripts/​nvx_tools/​release.py Removes Python release download and installation logic.
scripts/​nvx_tools/​nvx_rs.py Updates executable discovery documentation and missing-Cargo guidance.
README.md Replaces the quick start with Cargo build and automatic download.
nvx-rs/​tests/​cli/​usage.rs Tests download argument errors and help.
nvx-rs/​tests/​cli/​harness.rs Clears download-related environment variables.
nvx-rs/​tests/​cli/​download.rs Adds network-free download CLI scenarios.
nvx-rs/​tests/​cli.rs Registers download scenarios and updates expected messages.
nvx-rs/​src/​host/​mod.rs Documents the CLI’s download capability.
nvx-rs/​src/​host/​cli/​sandbox/​mod.rs Prepares missing artifacts before sandbox runs.
nvx-rs/​src/​host/​cli/​sandbox/​lifecycle.rs Prepares artifacts before managed sandbox starts.
nvx-rs/​src/​host/​cli/​run.rs Integrates automatic downloads into VM runs.
nvx-rs/​src/​host/​cli/​mod.rs Registers the download command and environment help.
nvx-rs/​src/​host/​cli/​download/​tests.rs Tests release selection, download eligibility, staging, and locking.
nvx-rs/​src/​host/​cli/​download/​install/​tests.rs Tests installation layouts, rollback, and conflicts.
nvx-rs/​src/​host/​cli/​download/​install.rs Implements staged artifact installation and rollback.
nvx-rs/​src/​host/​cli/​download/​github/​tests.rs Tests HTTP requests, credentials, redirects, and errors.
nvx-rs/​src/​host/​cli/​download/​github.rs Implements GitHub release access through curl.
nvx-rs/​src/​host/​cli/​download/​git.rs Reads checkout history and per-commit versions.
nvx-rs/​src/​host/​cli/​download/​archive/​tests.rs Tests archive paths, extraction, and checksums.
nvx-rs/​src/​host/​cli/​download/​archive.rs Validates and extracts release packages.
nvx-rs/​src/​host/​cli/​download.rs Coordinates explicit and automatic release downloads.
nvx-rs/​src/​host/​artifacts/​tests.rs Updates the expected missing-provenance guidance.
nvx-rs/​src/​host/​artifacts/​mod.rs Exposes the build-directory constant and updates documentation.
nvx-rs/​src/​host/​artifacts/​identity.rs Points recovery guidance to nvx-rs download.
nvx-rs/​src/​host/​artifacts/​dir.rs Updates artifact layout and provenance documentation.
nvx-rs/​README.md Documents download behavior and checkout preparation.
nvx-rs/​Cargo.toml Updates the CLI feature comment; dependencies are unchanged.
doc/​usage.md Moves download reference documentation to the Rust CLI.
doc/​setup.md Revises build and download prerequisites.
doc/​run.md Updates first-run preparation and provenance guidance.
doc/​project-structure.md Updates CLI and release-module descriptions.
doc/​guests/​ubuntu-guest.md Names the Rust download command.
doc/​guests/​azurelinux-guest.md Names the Rust download command.
doc/​distribution.md Documents installation without replacing nvx-rs.
doc/​ci.md Documents CI download controls and package roles.
doc/​adversarial-testing.md Removes obsolete executable-installation guidance.
.github/​workflows/​run-nvx-microvm-tests.yml Disables automatic release downloads during microVM tests.
.github/​skills/​nvx-run/​SKILL.md Updates build and artifact preparation guidance.
.github/​skills/​nvx-host-connect/​SKILL.md Updates platform-specific preparation commands.
.github/​skills/​nvx-debug/​SKILL.md Updates missing-artifact guidance.
.github/​copilot-instructions.md Explains automatic downloads and source-change validation.
.github/​actions/​package-release/​action.yml Updates a packaging comment without changing action behavior.

Review effort: Balanced

Comment thread nvx-rs/src/host/cli/download.rs Outdated
Comment thread nvx-rs/src/host/cli/download/install.rs Outdated
Copilot AI balanced review requested due to automatic review settings October 27, 2026 20:32
Review found two races in the automatic download.

A command that runs the artifacts of a checkout decided whether to
download without the download lock, so it could read the checkout in
the middle of another download's installation. It then warned of a
kernel that the download had yet to install, and failed, or ran
artifacts whose provenance the download had yet to install, which a
managed start reads. The command now decides under the lock, taken
shared: commands that decide do not wait for each other, while a
download, which takes the lock exclusively, waits for them, and they
for it. A command creates no lock file in a checkout into which nothing
downloaded: it decides without one there, and decides again under the
lock if the file appeared meanwhile, as a download creates it before it
installs anything. A root that is no Git checkout takes no lock, as
before. A wait is reported once it outlasts a retry interval, which a
decision takes far less than, so that a download does not mistake a
command that decides for another download.

An installation of Mode::Fresh checked that each destination was free
and then renamed the package's file there, so a file that a local build
published in between was replaced, with nothing to restore. It now
links the file into place, which fails where a file exists: such a file
cancels the installation as one that appeared earlier does. The staged
names of the linked files go once every file is in place.

Regression tests pause a download between installation steps while a
command waits for it, and publish a kernel between the check and the
installation; each fails without its fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

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.

🟡 Changes recommended

Artifact locking and rollback races can mix runtime files or delete concurrent build outputs, and incomplete validation allows invalid commands to trigger installation.

3 open issues
2 resolved since last review

Review effort: Balanced

Comment thread nvx-rs/src/host/cli/download.rs Outdated
Comment thread nvx-rs/src/host/cli/download/install.rs Outdated
Comment thread nvx-rs/src/host/cli/run.rs Outdated
Copilot AI balanced review requested due to automatic review settings October 27, 2026 20:39

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

Cross-platform installation, rollback, credential handling, and concurrent artifact access warrant final human review before approval.

3 open issues

Review effort: Balanced

…' files

The second review found three more gaps.

A command released the download lock as soon as it decided, before it
read the artifacts and their provenance. An explicit download could
still replace them during those reads, failing the command on a missing
artifact, or having sandbox start record a runtime identity that did
not match the artifacts that it launched. download::ensure now returns
a Hold, which keeps the lock until the command has launched OpenVMM:
run and sandbox run drop it once OpenVMM has started, and sandbox start
once its VM is ready, by which time OpenVMM has read the artifacts. A
command therefore creates the lock file, and build/, where it may, as a
download does, instead of deciding without the lock in a checkout that
has no lock file. Where it may not, as in a read-only checkout, it
decides without the lock. With NVX_AUTO_DOWNLOAD at 0 it takes no lock,
so CI's commands, which run the artifacts that CI built, create
nothing. A download that waits reports that it waits for another nvx-rs
command, since that may be a command that launches.

The rollback of a fresh installation removed every file that it had
put in place, including one that a local build had since rewritten in
place, as shutil.copy2 does, or replaced, before a later file of the
build cancelled the installation. It now removes only the files that
still hold the package's content, by the digest that the package's
SHA256SUMS lists, which plan now reads.

run downloaded before it checked its share and network options, so a
command with options that it refuses downloaded a release, or failed
offline with the download's error. It now checks those options first
and downloads only if they pass. It still reports a missing artifact
before them, as the validation tests pin.

A scenario test has sandbox start keep a download out until its VM,
whose readiness the fake OpenVMM delays, is ready. Other tests pin the
rollback around a rewritten and a replaced kernel, a run that downloads
nothing for options that it refuses, and a package whose SHA256SUMS
does not list a file that it installs. The tests of the start, the
rollback, and the run fail without their fixes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 21:03

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.

🟡 Changes recommended

Sandbox validation can follow download side effects, and lifecycle operations can read provenance during an incomplete installation.

2 open issues
3 resolved since last review

Review effort: Balanced

Comment thread nvx-rs/src/host/cli/sandbox/lifecycle.rs
Comment thread nvx-rs/src/host/cli/sandbox/mod.rs Outdated
…ties

The third review found two more gaps.

sandbox exec, stop, and deprovision read the runtime identity that the
artifacts' provenance names, to find the sandbox's VM, without the
download lock. A download that replaced the provenance meanwhile, even
one of the same release, could fail a stop on missing provenance
instead of shutting the VM down. These operations now hold the lock
shared while they find the VM, as download::hold takes it: in a Git
checkout that may download, after any download that holds the lock, and
without downloading anything. A start already holds the lock from its
own decision at that point.

sandbox run reached the download before it checked its command line, so
a run with nvx_sandbox=0, or with a command line over the budget,
downloaded a release or failed on the network. It now renders the
shares and the kernel command line of its plan first, and downloads only
if they pass. It still reports a missing artifact before them.

One scenario test has a stop wait for a download that holds the lock.
Another has sandbox run, like run, download nothing for options that it
refuses. Both fail without their fixes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 21:17

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.

Comment thread nvx-rs/src/host/cli/download/install.rs
Comment thread nvx-rs/src/host/cli/sandbox/lifecycle.rs
Comment thread nvx-rs/src/host/cli/sandbox/mod.rs Outdated
The fourth review found three more gaps.

A replacing installation moved whatever stood at the path of a release
file aside, directories included, and its cleanup then deleted such a
directory with everything in it. A directory there now fails the
installation, which restores the checkout, and the cleanup no longer
removes a directory that is not empty.

sandbox exec, stop, and deprovision took the download lock before they
knew whether the sandbox had recorded a launch, the only case that
needs the artifacts. A deprovision of a sandbox that never started
therefore failed where nvx-rs could find no artifact root, which it did
not before. These operations now take the lock only to read the
runtime identity of a recorded launch.

sandbox run read its distro layer, which may be the release's own
ubuntu-distro.erofs, before it took the lock. A download that replaced
the layer meanwhile failed the run at the check of the layer's binding.
A one-shot run now takes the shared lock before it reads the layer, and
decides whether to download under that lock with
download::ensure_under, which drops it before taking the lock
exclusively to download. A failure to take the lock is reported where
the run decides, after its options are checked, as before.

Each fix has a test that fails without it: a replacement over a
directory, a deprovision from an nvx-rs outside any root, and a run
that waits for a download that replaces the packaged layer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 21:36

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.

Comment thread nvx-rs/src/host/cli/run.rs Outdated
Comment thread nvx-rs/src/host/cli/sandbox/mod.rs Outdated
…ision

The fifth review found two more gaps.

run built its share and network arguments before the download, so that
it would download nothing for options that it refuses, and then
launched with those arguments. But a share's kind depends on what its
host path holds, so a release file that the download installed was
taken for a directory and shared as one. run now only checks those
options before the download, and builds their arguments where it always
did, once the artifacts are in place. A command whose options it
refuses also reads the artifacts under the download lock, without
downloading.

sandbox provision read its distro layer, which may be the release's,
and the layer's manifest without the lock, so a download that replaced
them meanwhile could fail a valid provision. A provision now holds the
lock while it reads the layer and records the sandbox, wherever it can
take the lock: it runs no artifact, so it still needs no artifact root.

One scenario test has a provision wait for a download that replaces the
packaged layer, then starts the sandbox on the layer that it recorded.
Another provisions and deprovisions a sandbox from an nvx-rs outside
any root. Each fails without its fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 21:51

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 installer and launch-locking changes need human review, and the confirmed provision cancellation bug remains unresolved.

1 open issue
2 resolved since last review

Review effort: Balanced

Comment thread nvx-rs/src/host/cli/sandbox/mod.rs Outdated
The sixth review found a gap in sandbox provision. It holds the
download lock where it can take it, and goes on without the lock
otherwise. It also went on when Ctrl-C ended its wait for a download
that held the lock, so it created the sandbox while it exited as
interrupted. A provision now ends as interrupted at once. So does a
one-shot run, which used to read the layer before it reported the
interruption.

A Unix test interrupts a provision that waits for a download, and
checks that it exits with status 130 and records no sandbox. The test
fails without the fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 27, 2026 22:05

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

Cross-platform installation rollback, credential handling, and lifecycle synchronization warrant human review, with real-boot validation still deferred to CI.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) merged commit 0612719 into dev Oct 27, 2026
47 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/nvx-py-usage-inquiry branch October 27, 2026 22:41
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