Skip to content

Build the guest binaries from nvx-rs - #561

Merged
Pedro Henrique Penna (ppenna) merged 6 commits into
devfrom
agents/fix-issue-358-build-switch
Oct 19, 2026
Merged

Pedro Henrique Penna (ppenna) merged 6 commits into
devfrom
agents/fix-issue-358-build-switch

Conversation

@ppenna

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

Copy link
Copy Markdown
Contributor

Closes #358 (PR 5 of 5).

#528, #531, #533, and #550 have merged, so the six commits here are the whole change. They are rebased onto dev at e67a06f40, which includes #583.

Summary

  • Replace native and Docker C compilation with the shared, pinned nvx.py build-guest-binaries routine from Port the small guest tools to Rust #528.
  • Build one checked set of nine static Rust executables in a digest-pinned Rust stage and install identical bytes in Alpine, Ubuntu, and Azure Linux at the existing /sbin/nvx-* paths, through a guest-only Docker base that the kernel targets do not inherit.
  • Bind source releases, package manifests, benchmark provenance, cache keys, setup, and SOURCE-MANIFEST.json to the complete Rust source/toolchain identity. The guest cache keys end with its path-aware digest, which nvx.py guest-binary-source-identity prints.
  • Delete the nine C implementations and their C-driven Python suites, port every case those suites checked to nvx-rs tests except the direct-mode launch cases that Test the managed agent's direct-mode launch without privileges #601 tracks, pin the protocol's wire constants literally in place of the C-source comparisons, reject future C/header/assembler sources outside openvmm/, and update the current documentation.
  • Make check-static-elf reject an executable stack (PT_GNU_STACK with PF_X), which the C device-I/O helper's -z noexecstack flag used to rule out; all nine Rust binaries pass it.
  • Cover the linked Rust runtime and crate closure (libc, nix, getrandom, bitflags, cfg-if, and memoffset) in THIRD_PARTY_NOTICES.md.

The issue originally named six programs, one of which, nvx-port-io, #574 has since retired. Every remaining compiled guest/common program switches together: the other five plus nvx-ingress, nvx-time, nvx-time-probe, and nvx-exit, nine in all.

Rebase onto the merged #550

The rebase adapted the stack to what landed underneath it:

  • Remove the unused nvx-port-io helper #574 retired nvx-port-io, so the build, Docker stage, manifests, notices, and documentation cover nine binaries.
  • The upstream builder runs one cargo build for every binary and has no nvx-rs/freestanding crate. The source identity covers nvx-rs/src, the crate manifest, lockfile, and build script, rust-toolchain.toml, and the two build modules, and the documentation no longer describes a separate freestanding link.
  • Prebuilt binaries are selected through upstream's GuestRustBuildConstants.BINARIES_VARIABLE (NVX_GUEST_BINARIES) rather than a second constant.
  • build-guest-binaries now upgrades an earlier build's output in place, so inspect_guest_binaries refuses an output that lacks an added executable or still holds the retired nvx-port-io; a new test covers both cases.
  • The guest cache keys keep dev's .dockerignore input and kernel patch identity alongside this PR's Rust inputs and v2 schemas, and validate-nvx keeps test_markdown_links.py.
  • THIRD_PARTY_NOTICES.md adds getrandom 0.4.3, which the guest feature links.
  • Where Port the time tools to Rust #550 rewrote text that this PR also edited, Port the time tools to Rust #550's version stays; the time tools' module docs no longer name the deleted C files.

Latest rebase and review follow-ups

  • The branch now sits on dev at e67a06f40: openvmm: answer guest UDP to host loopback from the gateway #583, which moves OpenVMM from c6d97c529 to 5ab8a8462 and extends the microVM tests, plus a performance-baseline update. The rebase applied without conflicts.
  • The protocol tests pin every wire value that the deleted C-source comparisons checked, including APP_STOP, APP_CANCEL, and APP_STOPPED, as nvx-rs: replace the guest C programs with Rust binaries #358 asks.
  • The Alpine, Ubuntu, and Azure Linux cache keys end with the path-aware Rust source digest that the package manifests record, so a module move that keeps every file's bytes still rebuilds the images.
  • A guest-only guest-base Docker stage carries the Rust sources and binaries, so the kernel, debug kernel, and Linux source targets no longer compile them.

Coverage of the deleted suites

An audit compared each of the 85 cases in the deleted Python suites (test_guest_ingress.py, test_guest_time.py, test_managed_agent.py, and the C-backed classes of test_nvx_tools.py) with the nvx-rs tests. The ingress and nvx-exit cases were already covered; the latest push ports the rest into the commit that deletes the suites:

  • The guest agent's own EXEC decoder refuses every request that the C agent refused: repeated, nameless, or NUL-containing environment entries; unknown and launch-helper flags; flags that contradict their fields; empty, relative, NUL-containing, or 4,097-byte working directories; truncation; and trailing bytes. Its MAPS decoder refuses the four payloads that only the host decoder's table covered.
  • A configurable dispatch harness pins the agent's replies. While the exec cgroup cannot be verified empty, every EXEC gets containment-failed. The host-mapping sequence answers mappings-incomplete, READY, mapping-failed, and invalid-request as the C agent did, with the exact mount calls. Failed environment exports refuse the launch without spawning.
  • nvx-time's kernel-log watcher, boot-log, timer-list, cpuinfo, exhaustive-check, packet, arithmetic, state-file, and status expectations are pinned exactly, as are its SCHED_IDLE policies on the musl build.
  • The direct-mode launch cases (working-directory refusals, a setgroups failure, the checked-directory race, end-to-end PWD, and the sandbox agent's exit after STOP) need an unprivileged test hook in spawn.rs, which Test the managed agent's direct-mode launch without privileges #601 tracks.

GuestRustBuildConstants again lists the guest source inventory, relative to a checkout's root, and guest_binary_source_files reads it from there.

Acceptance criteria

Criterion Evidence
No C sources remain outside openvmm/. git ls-files reports zero .c, .h, .S, or .s files outside the submodule, and BuildConstantsTests.test_no_c_or_assembler_sources_remain_outside_openvmm enforces it.
Alpine, Ubuntu, and Azure Linux ship the Rust programs at the existing paths. Scope is nine by the decision above. At 9a901738b, the Docker build installed one digest-checked set from the pinned builder; all three package manifests record the same source digest and the same nine binary digests, and none lists nvx-port-io.
verify-guest-determinism passes. At cc31fe2e0, the ubuntu-determinism Docker target rebuilt both attempts from fresh Cargo targets and passed. The exact-head CI run rebuilt this head's Ubuntu artifacts without a cache hit and passed it again.
The affected runtime coverage passes. At 9a901738b, each of prometheus32 (KVM), prometheus30 (MSHV), and prometheus28 (WHP) passed 25 microVM scenario runs across Alpine, Ubuntu, and Azure Linux, including time-ABI conformance with the exhaustive check, snapshot and restore, managed exec and lifecycle, sandbox lifecycle, and ingress, plus all 18 test-aci-edge-sandboxes cases.
Compare initramfs sizes and boot p50 with C. Measured at cc31fe2e0, before the rebase; see below.
CI matrix and performance gate pass. Exact-head run 39140770842 passed the complete KVM, MSHV, and WHP matrix and the performance regression gate. Run 38975065637 also passed at f1b84285c, before the coverage follow-ups.
The agent port has had a security review. Two independent security reviews of the agent port found no regressions against the C; two low-severity soundness gaps in the new system layer were fixed in #531.

Size comparison

Measured at cc31fe2e0, with ten binaries before the rebase, and not re-measured since. Fresh Docker artifacts use the same guest inputs. Positive compressed deltas are under 0.9%; every unpacked initramfs is 228,352 bytes smaller.

Guest C compressed Rust compressed Delta C unpacked Rust unpacked Delta
Alpine 7,904,783 7,975,132 +70,349 (+0.890%) 19,434,496 19,206,144 -228,352 (-1.175%)
Ubuntu 38,466,969 38,533,410 +66,441 (+0.173%) 100,246,016 100,017,664 -228,352 (-0.228%)
Azure Linux 42,695,564 42,762,395 +66,831 (+0.157%) 110,819,328 110,590,976 -228,352 (-0.206%)

Cold boot

Measured at cc31fe2e0, before the rebase, and not re-measured since. prometheus32 used one exact kernel and OpenVMM binary, zero warmups, and 20 retained runs per build. Runs were interleaved in pairs with the first build alternating.

Build p50 Range
C (dev 2735f2ace) 284.402 ms 276.288–292.125 ms
Rust (cc31fe2e0) 283.482 ms 276.239–295.151 ms
Delta -0.920 ms (-0.323%) Rust faster

For context, #550 measured nvx-time's own baremetal phase p50s (µs elapsed):

Backend Phase C Final Rust Delta
KVM boot 6,084 6,351 +267
KVM restore 7,353.5 8,163 +809.5
MSHV boot 1,947 2,295 +348
MSHV restore 1,620 1,489 -131

Boot is about 0.3 ms slower; restore is mixed.

Validation

The hardware rows are from 9a901738b, before the latest rebase (OpenVMM 5ab8a8462) and the review follow-ups. Those follow-ups touch only Rust tests and a module comment, the guest cache keys and the command that prints their Rust identity, the Docker stage layout, the static-ELF check, the build constants' source inventory, and documentation; the exact-head CI run covers the current head on KVM, MSHV, and WHP. At 9a901738b, every host built OpenVMM from the pinned c6d97c529, and prometheus32 built all guests with Docker from a fresh BuildKit cache; the other hosts checked the copied artifacts by SHA-256.

Environment Evidence
Windows At 12f87520a: Ruff, Linux and Windows Pyright, 1111 validate-nvx tests (32 expected skips) including the Markdown link tests, the link checker, 70 adversarial tests (6 expected skips), and host-profile tests; nvx-rs Clippy with all features and its tests.
WSL Ubuntu (no hypervisor) At 12f87520a: nvx-rs formatting, Clippy in both feature modes, 396 all-feature and 115 default tests, documentation, and the 1.89 MSRV and macOS checks; aci_edge_sandboxes formatting, Clippy in both feature modes, 157 all-feature and 85 default tests, documentation, the 1.89 MSRV and macOS checks, and agent bundling; check-guest-binaries (317 tests), a fresh build-guest-binaries whose nine binaries pass the executable-stack check, and 34 test-guest-binaries tests; 1111 validate-nvx tests (17 expected skips), 70 adversarial tests, and host-profile tests.
prometheus32 / Linux KVM / baremetal Docker builds of every guest target, 25 microVM scenario runs, and the ACI suite.
prometheus30 / Linux MSHV / baremetal 25 microVM scenario runs and the ACI suite. Both Rust crates' formatting, Clippy, tests (157 for aci_edge_sandboxes), documentation, and 1.89 MSRV checks; nvx-rs bundling; check-guest-binaries, build-guest-binaries, and test-guest-binaries; 1011 validate-nvx tests and Specula. Two fresh native guest-binary builds were byte-identical; their bytes differ from the Docker builder's, with the same source digest, so the guests' identical bytes come from the one Docker builder.
prometheus28 / Windows WHP / baremetal 25 microVM scenario runs and the ACI suite.
GitHub Actions Exact-head run 39140770842 passed, including the Linux and Windows nvx-rs and aci_edge_sandboxes jobs and the KVM, MSHV, and WHP matrix. Run 38975065637 passed at f1b84285c, where every kernel and guest Docker target rebuilt without a cache hit, the Ubuntu determinism target passed, and the debug-kernel build no longer reached the Rust stage.

The previous head's validation, including the Docker Desktop byte comparison, WSL checks, and device-I/O smoke, is in this description's edit history.

Merge order

#528, #531, #533, and #550 have merged; this PR completes the stack.

Copilot AI balanced review requested due to automatic review settings October 15, 2026 08:15

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 privileged runtime and packaging migration needs human review and exact-head CI confirmation, with a cross-platform provenance issue still unresolved.

1 open finding
What changed in this PR

Completes the guest-build migration for #358, using nvx-rs binaries across Alpine, Ubuntu, and Azure Linux while preserving existing executable paths.

Changes:

  • Integrates pinned Rust guest builds and static-executable validation.
  • Extends artifact provenance, release metadata, caches, and setup for Rust inputs.
  • Replaces C implementations and updates tests and documentation.
File Description
THIRD_PARTY_NOTICES.md Adds Rust runtime and dependency notices.
SOURCE-MANIFEST.json Records Rust toolchain and guest sources.
scripts/​test_tool_versions.py Checks musl target setup.
scripts/​setup/​setup-linux-runner.sh Explicitly selects the target toolchain.
scripts/​setup/​setup-linux-mshv.sh Installs and verifies the musl target.
scripts/​nvx.py Exposes guest-build, test, and ELF commands.
scripts/​nvx_tools/​ubuntu.py Includes Rust customization inputs.
scripts/​nvx_tools/​release.py Validates Rust source metadata.
scripts/​nvx_tools/​elf.py Checks static ELF linkage.
scripts/​nvx_tools/​ci.py Tracks Rust guest build dependencies.
scripts/​nvx_tools/​build.py Installs Rust binaries and records provenance.
scripts/​nvx_tools/​benchmark.py Records Rust device-I/O provenance.
scripts/​nvx_tools/​azurelinux.py Includes Rust build inputs.
scripts/​nvx_tools/​archive.py Excludes generated source-archive content.
README.md Describes shared Rust guest binaries.
nvx-rs/​src/​protocol/​outer.rs Adds guest records and flow-control codecs.
nvx-rs/​src/​protocol/​mod.rs Exports shared guest protocol APIs.
nvx-rs/​src/​protocol/​maps.rs Adds byte-oriented guest mapping decoding.
nvx-rs/​src/​protocol/​features.rs Defines agent feature sets.
nvx-rs/​src/​protocol/​boot.rs Parses mapping-count boot parameters.
nvx-rs/​src/​net/​cidr.rs Documents existing internals.
nvx-rs/​src/​lib.rs Exposes the Linux guest module.
nvx-rs/​src/​host/​session.rs Documents existing session internals.
nvx-rs/​src/​host/​process.rs Documents existing process internals.
nvx-rs/​src/​host/​platform/​windows.rs Documents existing Windows primitives.
nvx-rs/​src/​host/​platform/​mod.rs Documents platform modules.
nvx-rs/​src/​host/​platform/​linux.rs Documents existing Linux primitives.
nvx-rs/​src/​host/​instance.rs Documents existing instance internals.
nvx-rs/​src/​host/​filesystem.rs Documents existing filesystem internals.
nvx-rs/​src/​host/​artifacts.rs Documents existing artifact helpers.
nvx-rs/​src/​guest/​time/​mod.rs Adds time-tool dispatch.
nvx-rs/​src/​guest/​time/​events.rs Formats bounded time-ABI events.
nvx-rs/​src/​guest/​time_probe/​mod.rs Adds diagnostic command dispatch.
nvx-rs/​src/​guest/​time_probe/​format.rs Preserves libc numeric formatting.
nvx-rs/​src/​guest/​sys/​x86.rs Wraps x86 instructions.
nvx-rs/​src/​guest/​sys/​terminal.rs Wraps terminal configuration and draining.
nvx-rs/​src/​guest/​sys/​stdio.rs Wraps libc formatting and scanning.
nvx-rs/​src/​guest/​sys/​scheduler.rs Wraps affinity and scheduling operations.
nvx-rs/​src/​guest/​sys/​port.rs Provides time and shutdown port access.
nvx-rs/​src/​guest/​sys/​poll.rs Wraps descriptor polling.
nvx-rs/​src/​guest/​sys/​msr.rs Provides owned MSR-device access.
nvx-rs/​src/​guest/​sys/​mapping.rs Owns mappings and device writes.
nvx-rs/​src/​guest/​sys/​kernel.rs Wraps kernel-log and auxiliary-vector queries.
nvx-rs/​src/​guest/​sys/​ioctl.rs Wraps console and entropy ioctls.
nvx-rs/​src/​guest/​sys/​filesystem.rs Wraps filesystem and mount operations.
nvx-rs/​src/​guest/​sys/​errno.rs Provides typed errno and libc diagnostics.
nvx-rs/​src/​guest/​parse.rs Preserves libc integer parsing.
nvx-rs/​src/​guest/​mod.rs Organizes guest tools and unsafe boundary.
nvx-rs/​src/​guest/​ingress/​test_mode.rs Processes ingress snapshot fixtures.
nvx-rs/​src/​guest/​ingress/​mod.rs Adds ingress entry and protocol definitions.
nvx-rs/​src/​guest/​ingress/​encode.rs Encodes bounded listener announcements.
nvx-rs/​src/​guest/​agent/​tty.rs Handles agent terminal setup.
nvx-rs/​src/​guest/​agent/​diagnostics.rs Provides agent diagnostics and I/O helpers.
nvx-rs/​src/​error.rs Documents existing error fields.
nvx-rs/​src/​bin/​nvx-time.rs Adds time-tool entry point.
nvx-rs/​src/​bin/​nvx-time-probe.rs Adds time-probe entry point.
nvx-rs/​src/​bin/​nvx-reseed.rs Adds reseed entry point.
nvx-rs/​src/​bin/​nvx-port-io.rs Adds port-I/O entry point.
nvx-rs/​src/​bin/​nvx-mmio-write.rs Adds MMIO-write entry point.
nvx-rs/​src/​bin/​nvx-managed-agent.rs Initializes the managed agent.
nvx-rs/​src/​bin/​nvx-ingress.rs Adds ingress entry point.
nvx-rs/​src/​bin/​nvx-exit.rs Selects freestanding or hosted exit runtime.
nvx-rs/​src/​bin/​nvx-device-io.rs Selects device-I/O runtime.
nvx-rs/​src/​bin/​nvx-console-pending.rs Adds console-query entry point.
nvx-rs/​freestanding/​src/​runtime/​syscall.rs Implements raw Linux syscall boundary.
nvx-rs/​freestanding/​src/​runtime/​mod.rs Organizes freestanding runtime modules.
nvx-rs/​freestanding/​src/​runtime/​hosted.rs Provides hosted execution adapters.
nvx-rs/​freestanding/​src/​runtime/​entry.rs Provides freestanding startup and buffers.
nvx-rs/​freestanding/​src/​runtime/​args.rs Wraps initial-stack arguments.
nvx-rs/​freestanding/​src/​lib.rs Defines the no-std runtime crate.
nvx-rs/​freestanding/​src/​exit.rs Implements VM exit-code handling.
nvx-rs/​freestanding/​Cargo.toml Configures the freestanding crate.
nvx-rs/​Cargo.toml Adds guest binaries, dependencies, and profile.
nvx-rs/​Cargo.lock Locks guest dependencies.
nvx-rs/​build.rs Documents existing bundle-build internals.
guest/​common/​nvx-reseed.c Removes the C reseed implementation.
guest/​common/​nvx-mmio-write.c Removes the C MMIO implementation.
guest/​common/​nvx-exit.c Removes the C exit implementation.
guest/​common/​nvx-console-pending.c Removes the C console implementation.
doc/​usage.md Documents new CLI commands.
doc/​setup.md Documents Rust guest prerequisites.
doc/​project-structure.md Describes the Rust guest layout.
doc/​guests/​ubuntu-guest.md Documents Rust binary installation.
doc/​guests/​azurelinux-guest.md Documents Rust binaries and provenance.
doc/​contribute.md Updates guest testing guidance.
doc/​ci.md Describes Rust checks and cache inputs.
doc/​build.md Documents Rust builds and packaging.
doc/​benchmarks.md Documents Rust benchmark provenance.
.github/​workflows/​copilot-setup-steps.yml Triggers setup validation on Rust changes.
.github/​copilot-instructions.md Updates setup documentation.
.github/​actions/​validate-nvx/​action.yml Replaces retired C-driven test suites.
.github/​actions/​check-nvx-rs/​action.yml Adds workspace and musl validation.
.github/​actions/​build-guest-artifacts/​action.yml Updates guest cache identities.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/nvx_tools/build.py
Copilot AI balanced review requested due to automatic review settings October 15, 2026 08:31
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from 4185f68 to b5ff179 Compare October 15, 2026 08:31

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 privileged runtime migration needs human review, resolution of cross-platform provenance hashing, and confirmation of exact-head CI and performance gates.

2 open findings

🧠 Review effort: Balanced

Comment thread scripts/nvx_tools/ubuntu.py
Copilot AI balanced review requested due to automatic review settings October 15, 2026 08:41
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from b5ff179 to e24b046 Compare October 15, 2026 08:41

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 privileged runtime migration needs human sign-off and exact-head CI confirmation, with a benchmark-provenance issue still unresolved.

1 open finding
2 resolved since last review

🧠 Review effort: Balanced

Comment thread scripts/nvx_tools/benchmark.py Outdated
Copilot AI balanced review requested due to automatic review settings October 15, 2026 08:54
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from e24b046 to cc31fe2 Compare October 15, 2026 08:54

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 privileged guest-runtime migration needs final human review and confirmation of exact-head platform and performance gates.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

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 cross-distribution switch of privileged guest binaries and release provenance needs final human compatibility and validation sign-off.

1 open issue

Review effort: Balanced

Comment thread nvx-rs/src/protocol/tests.rs
Copilot AI balanced review requested due to automatic review settings October 16, 2026 21:22
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from 9a90173 to 196c29f Compare October 16, 2026 21:22

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 cross-platform executable switch needs human confirmation of exact-head validation, and the guest-cache identity issue remains unresolved.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread .github/actions/build-guest-artifacts/action.yml
Copilot AI balanced review requested due to automatic review settings October 16, 2026 21:45
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from 196c29f to 4acf331 Compare October 16, 2026 21:45

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 production runtime switch across three distributions warrants human approval, and the Docker kernel-build dependency remains unresolved.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread docker/Dockerfile Outdated
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from 4acf331 to f1b8428 Compare October 16, 2026 22:19

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

Switching all nine shipped guest binaries and their release provenance warrants final human review with completed current-head cross-platform validation.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Replace native C helper compilation with the shared Rust guest-binary
builder introduced by #528. Build one checked set of all nine
executables per initramfs, install it at the established /sbin/nvx-*
paths, and record the aggregate source and individual binary digests.

Remove the obsolete C compiler flags, helper inventories, and build
functions. Keep C test-only flags local until the C-driven suites are
deleted later in this stack. Because the device-I/O helper's
-z noexecstack flag goes with them, make check-static-elf reject an
executable stack.

Part of #358.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Build one checked set of Rust guest executables in the digest-pinned Rust
1.95.0 image and reuse its exact bytes in Alpine, Ubuntu, and Azure
Linux through a guest-only base, so the kernel and Linux source targets
never compile them. Keep the toolchain available only for Ubuntu's two
fresh determinism attempts, and remove the guest C compilers from the
base.

Bind reusable binary sets to normalized Rust-source, toolchain, target,
profile, and executable digests, and refuse the output of an earlier
build that a rebuild would upgrade in place. Record all nine helpers in
the Azure Linux package manifest.

Part of #358.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover the nvx-rs guest inputs in every image identity, package the crate
without its target directory, and declare the exact Rust toolchain and
musl target in SOURCE-MANIFEST.json. Verify those pins and inputs from
nvx.py verify and release packaging.

Make device-I/O benchmark provenance validate the shared Rust source
digest, and bind the Azure Linux cache input to the newly tracked files.
The build constants list the guest inputs once, relative to a checkout's
root, and every source digest reads them from there.

Part of #358.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Hash the complete nvx-rs tree except target, the exact toolchain pin, and
the shared build modules into every guest cache, and advance the guest
cache schemas. Because hashFiles hashes contents only, also append the
path-aware Rust source digest that the guest package manifests record,
which the new guest-binary-source-identity command prints, so a module
move that keeps every file's bytes still rebuilds the images. Treat
nvx-rs changes as OpenVMM VMM-test inputs so they rebuild and boot the
affected images.

Keep Copilot setup and both Linux setup paths on the pinned musl target,
and revalidate Copilot setup for every nvx-rs change.

Part of #358.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 18, 2026 15:07
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from f1b8428 to eaabc08 Compare October 18, 2026 15:07

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 cross-distribution guest migration warrants human review, and the new dispatch tests retain a child-reaping race.

1 open issue

Review effort: Balanced

Comment thread nvx-rs/src/guest/managed_agent/dispatch.rs
Remove the nine remaining guest C implementations and the C-compiled
Python suites, and drop the deleted modules from both CLI validation
legs.

Port the cases that the nvx-rs tests did not pin yet: the refusals of
the guest agent's own EXEC and MAPS decoders; its containment, mapping,
and environment-failure replies through dispatch; and nvx-time's
watcher, boot-log, timer-list, cpuinfo, exhaustive, packet, arithmetic,
state, status, and scheduling-policy expectations. The nvx-rs unit,
guest-binary, loopback, and real-VM tests now cover the suites'
behavior, except the direct-mode launch cases, which need an
unprivileged test hook that #601 tracks.

Add a repository regression that rejects C, header, or assembler sources
outside the OpenVMM submodule.

Part of #358.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document the one pinned build shared by native builds, Docker, and CI,
the nine binaries shipped by every guest, their provenance, cache inputs,
test ownership, and release source. Now that the Rust definitions are
authoritative, replace the obsolete source comparisons with literal wire
values and remove C-era wording.

Extend the third-party notices for the Rust standard libraries,
compiler_builtins and its compiler-rt-derived routines, libc, nix,
getrandom, and their linked transitive crates, and musl's complete
guest-binary scope.

Closes #358.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 18, 2026 15:30
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/fix-issue-358-build-switch branch from eaabc08 to 12f8752 Compare October 18, 2026 15:30

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

Switching every shipped guest executable, including the privileged agent, and changing release provenance warrants final human review despite the reported passing CI.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) merged commit cea040d into dev Oct 19, 2026
34 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/fix-issue-358-build-switch branch October 19, 2026 10:52
Jay (jay23606) pushed a commit to jay23606/nvx that referenced this pull request Oct 19, 2026
converter_input_sha256() hashes an inventory of the files that
customize the Ubuntu guest, in the order that sorted() gives their Path
objects. That order depends on the OS: PosixPath compares path
components with case, and WindowsPath without it. The Linux hosts that
build the Ubuntu artifacts record this digest in their manifests and
derive the EROFS filesystem UUID from it, and `nvx.py package`
recomputes it on the packaging host, Windows included, and requires
the manifests to match.

On dev, no two of those files sort differently with and without case,
so every OS computes the same digest, and the bug is latent. microsoft#561
exposes it by adding the nvx-rs guest binary sources to the inputs,
among them nvx-rs/Cargo.toml, nvx-rs/Cargo.lock, and nvx-rs/build.rs.
Windows then sorts build.rs before the Cargo files and Linux after
them, so Windows computes another digest than the one that the
Linux-built manifests record, and `nvx.py package` fails with "Ubuntu
artifact manifest does not match initramfs-ubuntu.cpio.gz".
Pull-request runs never package releases, so microsoft#561 passes its checks,
but the windows-whp platform job packages every development release on
dev pushes, and the first one after microsoft#561 would fail.

The inventory now takes the files in the order of their POSIX paths
relative to the repository, component by component and with case. That
is the order that Linux has always used, so Linux digests do not
change, and existing artifacts and manifests stay valid; Windows now
computes the same digests. The callers' own order no longer matters.
The Alpine and Azure Linux input digests already sort by POSIX path
strings, which compare alike everywhere.

A test feeds the files in both orders and checks the inventory's order,
Cargo.toml before build.rs and src/cli/args.rs before src/cli.rs, as
Linux sorts them; it fails on Windows without the fix.

Merge this before or together with microsoft#561 so that no development release
runs with the OS-dependent order. The microsoft#359 stack carries the same
commit until this lands; rebasing it onto dev then drops the duplicate.

Refs microsoft#561.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 19, 2026
As the #359 discussion decided, nvx-rs sandbox start now negotiates
the guest's control features, with a required set of its own rather
than GuestFeatures::REQUIRED, which describes the direct agent of
nvx::host::instance. This is the one intended change from nvx.py
sandbox start, which does not ask.

GuestFeatures::LAYERED_SANDBOX holds exactly what the CLI's launches
use: EXEC_ENVIRONMENT (bit 4), because exec sends a working directory
and an environment in an extended EXEC. It holds no CANCEL (bit 0):
the CLI never sends APP_CANCEL, since, as nvx.py did, Ctrl-C ends an
exec by closing the session, and the guest agent ends the workload
when OpenVMM resets the session that it ran for. It holds no
WORKLOAD_ACCOUNT (bit 2), which no sandbox launch requests and the
layered root does not perform (#566). The NVX guest agents, the Rust
agent of #561 and the C agent before it, advertise bits 0, 2, and 4 in
sandbox mode.

After its PING, start sends FEATURES. An agent that predates the
request refuses it as an unsupported operation and so provides none.
If the guest lacks a required feature, start ends OpenVMM and removes
the runtime files, as a failed start does, and fails with

  error: the guest image lacks control features that layered
  sandboxes need (per-execution environments); use an NVX release or
  build that includes them

which names the missing features with GuestFeatures::missing, as the
reject_guest of nvx::host::instance does.

Tests cover the required set, the features responses of current,
older, and misbehaving agents, and, with the golden scenarios that
follow, a start against guests that lack the feature or predate the
request.

Part of #359.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 19, 2026
As the #359 discussion decided, nvx-rs sandbox start now negotiates
the guest's control features, with a required set of its own rather
than GuestFeatures::REQUIRED, which describes the direct agent of
nvx::host::instance. This is the one intended change from nvx.py
sandbox start, which does not ask.

GuestFeatures::LAYERED_SANDBOX holds exactly what the CLI's launches
use: EXEC_ENVIRONMENT (bit 4), because exec sends a working directory
and an environment in an extended EXEC. It holds no CANCEL (bit 0):
the CLI never sends APP_CANCEL, since, as nvx.py did, Ctrl-C ends an
exec by closing the session, and the guest agent ends the workload
when OpenVMM resets the session that it ran for. It holds no
WORKLOAD_ACCOUNT (bit 2), which no sandbox launch requests and the
layered root does not perform (#566). The NVX guest agents, the Rust
agent of #561 and the C agent before it, advertise bits 0, 2, and 4 in
sandbox mode.

After its PING, start sends FEATURES. An agent that predates the
request refuses it as an unsupported operation and so provides none.
If the guest lacks a required feature, start ends OpenVMM and removes
the runtime files, as a failed start does, and fails with

  error: the guest image lacks control features that layered
  sandboxes need (per-execution environments); use an NVX release or
  build that includes them

which names the missing features with GuestFeatures::missing, as the
reject_guest of nvx::host::instance does.

Tests cover the required set, the features responses of current,
older, and misbehaving agents, and, with the golden scenarios that
follow, a start against guests that lack the feature or predate the
request.

Part of #359.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 19, 2026
As the #359 discussion decided, nvx-rs sandbox start now negotiates
the guest's control features, with a required set of its own rather
than GuestFeatures::REQUIRED, which describes the direct agent of
nvx::host::instance. This is the one intended change from nvx.py
sandbox start, which does not ask.

GuestFeatures::LAYERED_SANDBOX holds exactly what the CLI's launches
use: EXEC_ENVIRONMENT (bit 4), because exec sends a working directory
and an environment in an extended EXEC. It holds no CANCEL (bit 0):
the CLI never sends APP_CANCEL, since, as nvx.py did, Ctrl-C ends an
exec by closing the session, and the guest agent ends the workload
when OpenVMM resets the session that it ran for. It holds no
WORKLOAD_ACCOUNT (bit 2), which no sandbox launch requests and the
layered root does not perform (#566). The NVX guest agents, the Rust
agent of #561 and the C agent before it, advertise bits 0, 2, and 4 in
sandbox mode.

After its PING, start sends FEATURES. An agent that predates the
request refuses it as an unsupported operation and so provides none.
If the guest lacks a required feature, start ends OpenVMM and removes
the runtime files, as a failed start does, and fails with

  error: the guest image lacks control features that layered
  sandboxes need (per-execution environments); use an NVX release or
  build that includes them

which names the missing features with GuestFeatures::missing, as the
reject_guest of nvx::host::instance does.

Tests cover the required set, the features responses of current,
older, and misbehaving agents, and, with the golden scenarios that
follow, a start against guests that lack the feature or predate the
request.

Part of #359.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 19, 2026
Packages now ship bin/nvx-rs[.exe], which statically links the Rust
standard library, the crates of the nvx-rs cli feature, and a C
runtime, so THIRD_PARTY_NOTICES.md, which every package ships, must
cover them, as it has covered the Rust guest binaries since #561.

The crate rows follow `cargo tree --locked --features cli -e normal`
in nvx-rs for both release targets, x86_64-unknown-linux-musl and
x86_64-pc-windows-msvc: 26 crates, with the licenses that
`cargo metadata` reports.

- The rows of the crates that the guest binaries already link, the
  Rust standard library, compiler_builtins, libc, nix, getrandom,
  bitflags, cfg-if, and memoffset, now name bin/nvx-rs too.
- New rows cover serde, serde_core, serde_json and its itoa, memchr,
  and zmij, sha2 and its RustCrypto dependencies, and windows-sys and
  windows-link on Windows. serde_derive and the proc-macro2, quote,
  syn, and unicode-ident crates that it runs on are marked as build
  time only, not linked.
- The musl row now includes the bin/nvx-rs of the linux-kvm and
  linux-mshv packages, under the musl terms that it already
  documents.
- A new LLVM libunwind row covers the unwinder that the Rust musl
  target links into the guest binaries and the Linux nvx-rs, under
  Apache-2.0 WITH LLVM-exception, which lifts the attribution
  conditions for compiled code.
- A new Microsoft C runtime row covers the static CRT of
  bin/nvx-rs.exe, under the Visual Studio redistribution terms.

doc/distribution.md says the same in its licensing section. A test
parses nvx-rs/Cargo.lock, requires each of its crates to be classified
as shipped or not, and checks that every shipped crate has a row with
its exact version that names bin/nvx-rs, and that the runtime rows name
it too.

Part of #359.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 19, 2026
Packages now ship bin/nvx-rs[.exe], which statically links the Rust
standard library, the crates of the nvx-rs cli feature, and a C
runtime, so THIRD_PARTY_NOTICES.md, which every package ships, must
cover them, as it has covered the Rust guest binaries since #561.

The crate rows follow `cargo tree --locked --features cli -e normal`
in nvx-rs for both release targets, x86_64-unknown-linux-musl and
x86_64-pc-windows-msvc: 26 crates, with the licenses that
`cargo metadata` reports.

- The rows of the crates that the guest binaries already link, the
  Rust standard library, compiler_builtins, libc, nix, getrandom,
  bitflags, cfg-if, and memoffset, now name bin/nvx-rs too.
- New rows cover serde, serde_core, serde_json and its itoa, memchr,
  and zmij, sha2 and its RustCrypto dependencies, and windows-sys and
  windows-link on Windows. serde_derive and the proc-macro2, quote,
  syn, and unicode-ident crates that it runs on are marked as build
  time only, not linked.
- The musl row now includes the bin/nvx-rs of the linux-kvm and
  linux-mshv packages, under the musl terms that it already
  documents.
- A new LLVM libunwind row covers the unwinder that the Rust musl
  target links into the guest binaries and the Linux nvx-rs, under
  Apache-2.0 WITH LLVM-exception, which lifts the attribution
  conditions for compiled code.
- A new Microsoft C runtime row covers the static CRT of
  bin/nvx-rs.exe, under the Visual Studio redistribution terms.

doc/distribution.md says the same in its licensing section. A test
parses nvx-rs/Cargo.lock, requires each of its crates to be classified
as shipped or not, and checks that every shipped crate has a row with
its exact version that names bin/nvx-rs, and that the runtime rows name
it too.

Part of #359.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

nvx-rs: replace the guest C programs with Rust binaries

2 participants