Repository navigation
Port the managed agent to Rust - #531
Draft
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Draft
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Pedro Henrique Penna (ppenna) wants to merge 4 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Data-record failures no longer preserve the C agent’s diagnostic stages and status details.
1 open finding
What changed in this PR
Ports the managed guest agent to Rust while preserving the existing protocol, execution, containment, mapping, and diagnostic contracts. Guest images continue using the C agent until a later build-switch PR.
Changes:
- Adds byte-oriented guest protocol decoding and managed-agent session handling.
- Implements execution, cgroup containment, mappings, launch helpers, and loopback tests.
- Adds static musl guest binaries, ELF validation, CI coverage, and documentation.
| File | Description |
|---|---|
.github/actions/check-nvx-rs/action.yml |
Builds and validates musl guest binaries. |
doc/ci.md |
Documents guest-binary CI checks. |
doc/contribute.md |
Updates Rust validation guidance. |
doc/project-structure.md |
Documents guest modules and binaries. |
doc/usage.md |
Documents check-static-elf. |
nvx-rs/Cargo.toml |
Defines guest feature, binaries, and profile. |
nvx-rs/README.md |
Documents guest binaries and agent architecture. |
nvx-rs/src/lib.rs |
Exposes Linux guest modules. |
nvx-rs/src/bin/nvx-console-pending.rs |
Adds console-pending entry point. |
nvx-rs/src/bin/nvx-device-io.rs |
Adds freestanding device benchmark entry point. |
nvx-rs/src/bin/nvx-exit.rs |
Adds freestanding VM-exit entry point. |
nvx-rs/src/bin/nvx-managed-agent.rs |
Adds managed-agent entry point. |
nvx-rs/src/bin/nvx-mmio-write.rs |
Adds MMIO writer entry point. |
nvx-rs/src/bin/nvx-port-io.rs |
Adds port-I/O entry point. |
nvx-rs/src/bin/nvx-reseed.rs |
Adds reseed entry point. |
nvx-rs/src/guest/agent/cgroup.rs |
Implements workload cgroup containment. |
nvx-rs/src/guest/agent/diagnostics.rs |
Implements agent diagnostics and descriptor I/O. |
nvx-rs/src/guest/agent/dispatch.rs |
Dispatches control requests. |
nvx-rs/src/guest/agent/exec.rs |
Supervises workload execution and output. |
nvx-rs/src/guest/agent/exec_config.rs |
Encodes sealed helper configuration. |
nvx-rs/src/guest/agent/helper.rs |
Applies helper environment and working directory. |
nvx-rs/src/guest/agent/launch.rs |
Implements fork and launch preparation. |
nvx-rs/src/guest/agent/loopback.rs |
Tests real host-to-agent control flow. |
nvx-rs/src/guest/agent/mappings.rs |
Applies announced host mappings. |
nvx-rs/src/guest/agent/mod.rs |
Defines managed-agent modes and lifecycle. |
nvx-rs/src/guest/agent/seam.rs |
Provides production and test system seams. |
nvx-rs/src/guest/agent/session.rs |
Implements guest protocol sequencing and credit. |
nvx-rs/src/guest/agent/tty.rs |
Opens and configures the control TTY. |
nvx-rs/src/guest/console_pending.rs |
Ports pending-console inspection. |
nvx-rs/src/guest/freestanding/args.rs |
Parses kernel-provided arguments. |
nvx-rs/src/guest/freestanding/device_io.rs |
Ports the freestanding I/O benchmark. |
nvx-rs/src/guest/freestanding/exit.rs |
Ports the freestanding exit utility. |
nvx-rs/src/guest/freestanding/hosted.rs |
Provides hosted test entry points. |
nvx-rs/src/guest/freestanding/mem.rs |
Supplies freestanding memory routines. |
nvx-rs/src/guest/freestanding/mod.rs |
Organizes freestanding components. |
nvx-rs/src/guest/freestanding/start.rs |
Supplies _start and panic handling. |
nvx-rs/src/guest/freestanding/syscall.rs |
Wraps raw x86-64 syscalls. |
nvx-rs/src/guest/mmio_write.rs |
Ports MMIO writing. |
nvx-rs/src/guest/mod.rs |
Organizes guest programs. |
nvx-rs/src/guest/parse.rs |
Reimplements C-compatible numeric parsing. |
nvx-rs/src/guest/port_io.rs |
Ports port and generation-ID operations. |
nvx-rs/src/guest/reseed.rs |
Ports entropy reseeding. |
nvx-rs/src/guest/sys.rs |
Preserves shared C runtime behavior. |
nvx-rs/src/protocol/boot.rs |
Parses nvx_maps=COUNT. |
nvx-rs/src/protocol/exec.rs |
Adds byte-oriented guest EXEC decoding. |
nvx-rs/src/protocol/features.rs |
Defines direct and sandbox feature masks. |
nvx-rs/src/protocol/maps.rs |
Adds byte-oriented guest MAPS decoding. |
nvx-rs/src/protocol/mod.rs |
Exports new guest protocol APIs. |
nvx-rs/src/protocol/outer.rs |
Adds guest attach, ACK, and CREDIT records. |
nvx-rs/src/protocol/tests.rs |
Tests guest protocol parity and boundaries. |
nvx-rs/tests/guest_tools.rs |
Exercises built guest binaries. |
scripts/nvx.py |
Adds the static-ELF command. |
scripts/nvx_tools/elf.py |
Implements ELF linkage inspection. |
scripts/test_nvx_tools.py |
Tests CI coverage and ELF validation. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 13, 2026 19:49
9f13734 to
7548a55
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 14, 2026 19:23
7548a55 to
5378207
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 14, 2026 19:37
5378207 to
54f904a
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 14, 2026 19:46
54f904a to
f4f6b80
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 14, 2026 19:56
f4f6b80 to
8d0a02c
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 14, 2026 20:13
8d0a02c to
0ed5ad7
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 15, 2026 04:03
03fff78 to
ad98df0
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 15, 2026 04:24
ad98df0 to
c46d300
Compare
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 15, 2026 17:07
c46d300 to
99b6bfb
Compare
Pedro Henrique Penna (ppenna)
changed the base branch from
dev
to
agents/fix-issue-358-validate-changes-ci
October 15, 2026 17:38
Base automatically changed from
agents/fix-issue-358-validate-changes-ci
to
dev
October 15, 2026 18:06
Pedro Henrique Penna (ppenna)
marked this pull request as draft
October 15, 2026 18:17
Add the guest attachment, acknowledgement, and credit records and window payloads. Parse the current nvx_maps count contract and expose the feature sets announced by each agent mode. Keep byte-oriented EXEC and MAPS decoders for the Linux guest beside the existing UTF-8 host decoders, including the C guest's 4096-byte cwd bound. Pin the new records and parser with golden and round-trip tests. Part of #358. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Port the managed agent as a static Rust guest binary while preserving its control session, execution, cgroup, host-mapping, sealed configuration, helper, and diagnostic contracts. Follow the guest programs' conventions. The agent and its execution helper fail with the shared CommandError and exit with the new shared ExitStatus::AgentFailure, 125. Errors are nix's Errno, whose descriptions the diagnostics print, and the safe nvx::guest::sys wrappers make the system calls through nix. Only the forked child, the raw wait-status decoding, which keeps real-time signals, and the duplication of the inherited descriptor reach libc, through nix's re-export. The standard library parses the decimal identities and descriptor, and no resource is dropped by hand. Prepare argv, envp, physical-PWD storage, and descriptor actions before fork. The child allocates nothing and terminates through exec or _exit. The helper builds the workload's environment in memory and passes it to execve, so no process changes its own environment and the binary needs no unsafe entry point. Keep the privileged seam for production wrappers and failure-injecting tests, and cover the complete path with the host-to-agent loopback. Part of #358. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exercise the managed agent helper as a real process, including exact and layered environments, cwd handling, malformed configuration, the internal descriptor lifetime, and command-line failures. The tests can use either the Cargo test binary or the prebuilt guest-profile binary. Part of #358. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add nvx-managed-agent to the Rust guest-binary inventory. The existing nvx.py build-guest-binaries and test-guest-binaries commands now build its static musl executable in the same fresh, reproducible Cargo build as the other guest programs, check its ELF form, include its digest in the manifest, and run its prebuilt helper integration tests. An output whose manifest validates the previous six-binary inventory upgrades in place; unrelated inventories, files, symlinks, and digest mismatches are still refused. The command documentation now counts seven binaries. Part of #358. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/fix-issue-358-managed-agent
branch
from
October 15, 2026 18:32
99b6bfb to
61d24f1
Compare
Pedro Henrique Penna (ppenna)
requested a review
from Enrique Saurez (esaurez)
October 15, 2026 19:43
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.


Summary
window, current feature masks, and the
nvx_maps=COUNTparserUTF-8 host API
nvx-managed-agentto a static Rust binary, including its session,dispatch, execution, containment, mapping, helper, launch, TTY, and
diagnostic behavior
nvx::guest::sysAPIs, with OwnedFd-backed RAII resourcesControlSessionthrough acredit-accounting broker shim to the real agent and exec engine
nvx.pywith the other Rust guest binariesPart of #358 (PR 2 of 5). Builds on #528, which has merged into
dev.The guests still ship
guest/common/nvx-managed-agent.c. PR 5 will switch theguest builds and remove the C programs and their old test harnesses.
PR #528 conventions
nvx::guest::sysuse nix 0.31.3 for descriptors, pipes, poll, termios,mounts, memfds and seals, identities, signals, kill, and wait operations
where nix preserves the syscall contract. Focused libc and architecture FFI
remain only in
sys.RAII-owned. Explicit consuming close/unmap paths retain C cleanup errors;
Drop handles paths where C ignored cleanup. Raw descriptor integers never
leave
sys.environment, process, and protocol failures use typed results and enums
internally.
function is documented under the crate-wide
clippy::missing_docs_in_private_itemslint.strtoullboundary. Helper environments usea safe ownership-transferring
putenvwrapper, retaining the C contract.GuestRustBuildConstants.HOSTED_BINARIESincludesnvx-managed-agent, sonvx.py build-guest-binariesandtest-guest-binariesbuild, inspect,manifest, and test it. A manifest-validated Port the small guest tools to Rust #528 six-binary output upgrades
in place; unrelated inventories, files, symlinks, and digest mismatches are
still refused.
Unsafe-count methodology is the number of
unsafe {blocks andunsafe fndefinitions in PR 2's agent, protocol, binary, and added system wrappers.
Before the rework: 79 blocks / 2 functions, all outside
sys. After: 33 / 2,all inside
sys, and 0 / 0 outside it. The completeguest::syslayer,including #528, now has 48 / 2.
Fork boundary and parity
The safe fork entry point receives owned C strings, owned descriptors, and
precomputed descriptor actions. It constructs the complete argv, envp,
physical-PWD storage, and pointer vectors before
fork. The child allocatesnothing, performs no Rust cleanup, runs only direct async-signal-safe
Linux/musl operations, and terminates through
execve,execv, or_exit.workload GID and UID, enter the cwd, regain root, join
nvx-exec, then runsetprivwith--reuid,--regid,--clear-groups,--no-new-privs, and all three capability-clearing options.nvx_maps=COUNTtoken from 1through 4096. Retired
nvx_map=tokens remain ignored.Dedicated guest decoders retain the C agent's 4096-byte cwd bound.
preallocated physical-PWD slot after the child enters the directory under
workload credentials. Failures remain
cwd-failedwith the original errno.documented musl
strerrorwording.Security review
The earlier independent review of the original port found no vulnerabilities.
Its one non-security cwd/PWD parity finding was fixed before this rework.
The post-refactor self-review found no regression:
setprivchain are unchangedclose-on-exec; only the sealed helper configuration deliberately survives
exec, and the helper closes it
O_NOFOLLOW|O_CREAT|O_EXCL|O_CLOEXECMS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV, plusMS_RDONLYwhen requested;the hostfs parent remains root:root mode 0700
explicit error path and best-effort RAII restoration
pids.current, orphan reaping, andcontainment-failure latching are unchanged; raw wait-status decoding keeps
every Linux real-time signal as a terminal workload outcome
or indexing; no untrusted-input path can panic
PID-1-style reaping tests run in isolated test-harness subprocesses, so their
intentional
waitpid(-1)behavior cannot collect children owned by parallelhost tests.
Validation
Windows
python scripts\nvx.py verifycheck-nvx-rs: workspace fmt, both Clippy modes, default andall-feature tests, synthetic bundle, rustdoc with warnings denied, Rust 1.89
MSRV, aarch64-apple-darwin, and musl dev/guest-profile Clippy
check-aci-edge-sandboxesWSL Linux
check-nvx-rscommands and complete dependent ACIcrate checks
nvx.py build-guest-binariesbuilds are byte-identical; all 22prebuilt-binary tests pass
inventory, then passes all prebuilt tests
8425dbbfea5d10453b586bda140233066ec2bebd05673aeaf65437f411c4f2dcDifferential
On both prometheus32 and prometheus30:
match all 3,600 deterministic cases: 1,200 EXEC, 1,200 MAPS, and 1,200
nvx_mapscommand lines2,433 bytes, SHA-256
8a90e0da18f2f64729edc009220bfaf3787cd11fafc5130ecde873697fe45576;canonicalization removes random request IDs, pipe chunk boundaries, and the
output-limit case's permitted bounded zero-prefix length
In VM
Fresh final-head binaries were overlaid into copies of the current Alpine and
Ubuntu initramfses on prometheus32 (KVM/baremetal) and prometheus30
(MSHV/baremetal).
managed-exec-config,sandbox-lifecycle,sandbox-blocks, andscratch-snapshotmanaged-lifecycleandfilesystem-sharesd57f7582c7857337d93ce77d37f21099aaedaf16fe3ad8e7d61ebc61d9a799c0ada79dc0a747d903d8ef6da675863458fa38e2b0bcf6b10101f6c90e00f25509test-aci-edge-sandboxes: 18/18 passpublication on this host and fails identically with the untouched baseline
initramfs. The agent-relevant tests and the prior 17-test suite pass.
The final Rust agent is a static PIE: 459,232 bytes on prometheus32 and
459,296 bytes on prometheus30, about 35.4% smaller than the 711,400-byte C
agent.
Both hosts' original initramfs files were restored byte-for-byte after every
run. Scratch/state directories were removed, validation worktrees and
submodules are clean, and no OpenVMM process remains.
A second independent review of the reworked agent found no regressions against the C implementation and identified two internal API soundness gaps in the new system layer, which are now fixed.