Skip to content

aci_edge_sandboxes: make the fake OpenVMM's printenv exit 1 for unset variables - #354

Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
devfrom
copilot/aci-edge-sandboxes-fix-printenv-exit-status
Oct 4, 2026
Merged

Pedro Henrique Penna (ppenna) merged 2 commits into
devfrom
copilot/aci-edge-sandboxes-fix-printenv-exit-status

Conversation

Copilot AI commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

The fake OpenVMM ended every script with status 0, so printenv NAME succeeded even when NAME was unset. In the guest it exits 1, and exec_environments_follow_the_mxc_schema expects Exited(1) on a real hypervisor. As a result, fake-backed tests could pass for an execution that fails on a real guest.

Fake (src/bin/aci-edge-sandboxes-fake-openvmm.rs)

  • A script now exits with the status of its last command, as sh does.
  • printenv NAME prints nothing and sets status 1 when NAME is unset. This covers both the script command and a printenv NAME program, because the program is converted to the same script command.
  • The doc comment at the top of the file describes both behaviors.

Test (tests/openvmm_fake.rs)

each_execution_has_its_own_environment no longer reads unset cases through output_of, which required success. It now asserts ExecOutcome::Exited(1) with empty stdout and stderr. New cases:

Execution Outcome stdout
printenv BAR; printenv FOO, only BAR=x set Exited(1) x\n
printenv FOO; printenv BAR, only BAR=x set Exited(0) x\n
/usr/bin/printenv FOO, unset Exited(1) empty

Not changed

read KEY still exits 0 when the key was never written. The issue doesn't cover it, but now that a script exits with its last command's status, this matters wherever read is the last command.

Copilot AI balanced review requested due to automatic review settings October 4, 2026 21:00

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.

Copilot wasn't able to review any files in this pull request. Check if the Files changed in this pull request are included in default exclusions.

Co-authored-by: ppenna <4939789+ppenna@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings October 4, 2026 21:04

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.

Copilot review overview

🟢 Approval recommended

The focused implementation satisfies the issue requirements with representative regression coverage.

Review effort: Balanced
Findings: None

Copilot AI changed the title [WIP] Fix fake OpenVMM exit status for unset variables in printenv aci_edge_sandboxes: make the fake OpenVMM's printenv exit 1 for unset variables Oct 4, 2026
@ppenna
Pedro Henrique Penna (ppenna) marked this pull request as ready for review October 4, 2026 21:19
@ppenna
Pedro Henrique Penna (ppenna) merged commit 27f771b into dev Oct 4, 2026
45 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the copilot/aci-edge-sandboxes-fix-printenv-exit-status branch October 4, 2026 23:27
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 12, 2026
Phase 1 of #356. Move the code in aci_edge_sandboxes that drives NVX
into a new standalone crate, nvx-rs, whose library is nvx, and rebuild
aci_edge_sandboxes on top of it. Behavior, wire formats, on-disk state,
error codes and messages, and test coverage stay the same; only Rust
paths, names, and build variables change.

nvx-rs has its own Cargo.lock outside the aci_edge_sandboxes workspace,
edition 2024, MSRV 1.89, the lints of aci_edge_sandboxes, and the
features host (default), bundled, testing, and serde:

- protocol/: the NVXS and NVXC codec, now public, documented, and
  dependency-free, split into outer records, application frames, EXEC
  and MAPS payloads, guest features, and kernel command-line tokens.
  The wire constants are unchanged. It gains the guest-side EXEC and
  MAPS decoders that the fake OpenVMM kept privately, so the fake now
  shares the codec with the host. Golden byte fixtures, computed with
  Python's struct module, therefore pin every record for both the
  encoders and the decoders, and tests compare the constants with the
  guest agent's source.
- contract.rs, net/cidr.rs, hypervisor.rs, and error.rs: the control
  contract, Cidr, Hypervisor with its serde form behind the serde
  feature, and nvx::Error with an ErrorKind of Unavailable, Unsupported,
  Exited, Io, Protocol, TimedOut, or Other, all outside the host
  feature. The hypervisor probe stays in nvx::host::platform.
- host/: artifact discovery; the Linux, Windows, and other platform
  primitives; process, which takes the OpenVMM path and the
  job-breakaway flag instead of OpenVmmConfig; the control session;
  launch, which builds OpenVMM's command line from a typed LaunchSpec
  and owns the kernel-parameter, timeout, and workload-identity rules;
  network and filesystem lowering behind nvx-owned input types that
  carry the names messages use; instance, which holds the launch and
  runtime records, the private-file, lock, and capability helpers,
  reconciliation, interrupted-launch recovery, start with its readiness,
  feature, and MAPS steps, the exec pump with generic sinks,
  cancellation, and deadlines, and graceful stop with a forced fallback;
  and report, which summarizes OpenVMM's outcome report.
- testing/: the fake OpenVMM, moved onto nvx::protocol, with an
  nvx-fake-openvmm binary. It keeps the fixes of #354 and #355.
- build.rs and artifacts.json: bundled-release staging with
  links = "nvx", NVX_BUNDLE=skip, NVX_BUNDLE_DIR, NVX_BUNDLE_HYPERVISOR,
  and DEP_NVX_ARTIFACTS_DIR.

aci_edge_sandboxes keeps the ACI contract and an openvmm module reduced
to OpenVmmBackend, OpenVmmConfig, SandboxRecord, StateStore, the
conversions from MXC requests to nvx types, and the error mapping:
Unavailable becomes backend_unavailable, Unsupported policy_validation,
Exited not_started when an exec finds its VM gone, and everything else
backend_error. It depends on nvx-rs without default features and
re-exports it as aci_edge_sandboxes::nvx. The openvmm feature enables
nvx-rs/host, testing enables nvx-rs/testing, and bundled forwards to
nvx-rs/bundled. A minimal build.rs keeps links = "aci_edge_sandboxes",
so dependents still receive DEP_ACI_EDGE_SANDBOXES_ARTIFACTS_DIR, and a
thin aci-edge-sandboxes-fake-openvmm wrapper stays because
CARGO_BIN_EXE_* only names binaries of the same package.
aci_edge_sandboxes_model depends on nvx with only serde, re-exports
cidr and setup::Hypervisor at their paths, and converts nvx::Error into
its Error.

Sandbox state keeps format 3, because the export plan keeps its serde
form, and a new test loads a record that the previous crate wrote.
SetupConfig keeps its JSON. The integration tests changed only their
imports, and every unit test moved with its code. The relative
process.cwd message now points at nvx::guest_path. The README of
aci_edge_sandboxes documents the breaking changes: Artifacts,
Hypervisor, guest_path, and resolve_guest_path move to
aci_edge_sandboxes::nvx; Hypervisor's FromStr and from_env_or_default
fail with nvx::Error; vendoring the crate also vendors nvx-rs; and
ACI_EDGE_SANDBOXES_BUNDLE, _BUNDLE_DIR, and _BUNDLE_HYPERVISOR become
NVX_BUNDLE, NVX_BUNDLE_DIR, and NVX_BUNDLE_HYPERVISOR.

CI gains a check-nvx-rs action that takes the toolchain from
rust-toolchain.toml and runs rustfmt, Clippy for all targets and
features and for the library without default features, the tests, the
synthetic-release bundled test moved from check-aci-edge-sandboxes,
which now fails when a requested bundle was not staged, rustdoc with
-D warnings, the MSRV check, and the aarch64-apple-darwin check. A new
nvx-rs job runs it on Ubuntu and Windows and gates required-status-check
and the development release like aci-edge-sandboxes, and nvx-rs/ is an
input of the microVM test suites. The Copilot setup steps install every
crate's MSRV, and the repository instructions, project structure,
component map, CI, contribution, and usage guides describe the crate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 12, 2026
Phase 1 of #356. Move the code in aci_edge_sandboxes that drives NVX
into a new standalone crate, nvx-rs, whose library is nvx, and rebuild
aci_edge_sandboxes on top of it. Behavior, wire formats, on-disk state,
error codes and messages, and test coverage stay the same; only Rust
paths, names, and build variables change.

nvx-rs has its own Cargo.lock outside the aci_edge_sandboxes workspace,
edition 2024, MSRV 1.89, the lints of aci_edge_sandboxes, and the
features host (default), bundled, testing, and serde. Without default
features, it has no dependencies, not even for its build script. It
contains:

- protocol/: the NVXS and NVXC codec, now public, documented, and
  dependency-free, split into outer records, application frames, EXEC
  and MAPS payloads, guest features, and kernel command-line tokens.
  The wire constants are unchanged. It gains the guest-side EXEC and
  MAPS decoders that the fake OpenVMM kept privately, so the fake now
  shares the codec with the host. Golden byte fixtures, computed with
  Python's struct module, therefore pin every record for both the
  encoders and the decoders, and tests compare the constants with the
  guest agent's source. The decoders refuse everything that the guest
  agent refuses, such as more than 64 arguments, a relative program, or
  a mapping path with an empty, ".", or ".." component, and the MAPS
  encoder refuses such paths too; the host never produces them.
- contract.rs, net/cidr.rs, hypervisor.rs, and error.rs: the control
  contract, Cidr, Hypervisor with its serde form behind the serde
  feature, and nvx::Error with an ErrorKind of Unavailable, Unsupported,
  Exited, Io, Protocol, TimedOut, or Other, all outside the host
  feature. The hypervisor probe stays in nvx::host::platform.
- host/: artifact discovery; the Linux, Windows, and other platform
  primitives; process, which takes the OpenVMM path and the
  job-breakaway flag instead of OpenVmmConfig; the control session;
  launch, which builds OpenVMM's command line from a typed LaunchSpec
  and owns the kernel-parameter, timeout, and workload-identity rules;
  network and filesystem lowering behind nvx-owned input types that
  carry the names messages use; instance, which holds the launch and
  runtime records, the private-file, lock, and capability helpers,
  reconciliation, interrupted-launch recovery, start with its readiness,
  feature, and MAPS steps, the exec pump with generic sinks,
  cancellation, and deadlines, and graceful stop with a forced fallback;
  and report, which summarizes OpenVMM's outcome report.
- testing/: the fake OpenVMM, moved onto nvx::protocol, with an
  nvx-fake-openvmm binary. It keeps the fixes of #354 and #355.
- build.rs and artifacts.json: bundled-release staging with
  links = "nvx", NVX_BUNDLE=skip, NVX_BUNDLE_DIR, NVX_BUNDLE_HYPERVISOR,
  and DEP_NVX_ARTIFACTS_DIR.

aci_edge_sandboxes keeps the ACI contract and an openvmm module reduced
to OpenVmmBackend, OpenVmmConfig, SandboxRecord, StateStore, the
conversions from MXC requests to nvx types, and the error mapping:
Unavailable becomes backend_unavailable, Unsupported policy_validation,
Exited not_started when an exec finds its VM gone, and everything else
backend_error. It depends on nvx-rs without default features and
re-exports it as aci_edge_sandboxes::nvx. The openvmm feature enables
nvx-rs/host, testing enables nvx-rs/testing, and bundled forwards to
nvx-rs/bundled. A minimal build.rs keeps links = "aci_edge_sandboxes",
so dependents still receive DEP_ACI_EDGE_SANDBOXES_ARTIFACTS_DIR, and a
thin aci-edge-sandboxes-fake-openvmm wrapper stays because
CARGO_BIN_EXE_* only names binaries of the same package.
aci_edge_sandboxes_model depends on nvx with only serde, re-exports
cidr and setup::Hypervisor at their paths, and converts nvx::Error into
its Error.

Sandbox state keeps format 3, because the export plan keeps its serde
form, and a new test loads a record that the previous crate wrote.
SetupConfig keeps its JSON. The integration tests changed only their
imports, and every unit test moved with its code. The relative
process.cwd message now points at nvx::guest_path. The README of
aci_edge_sandboxes documents the breaking changes: Artifacts,
Hypervisor, guest_path, and resolve_guest_path move to
aci_edge_sandboxes::nvx; Hypervisor's FromStr and from_env_or_default
fail with nvx::Error; vendoring the crate also vendors nvx-rs; and
ACI_EDGE_SANDBOXES_BUNDLE, _BUNDLE_DIR, and _BUNDLE_HYPERVISOR become
NVX_BUNDLE, NVX_BUNDLE_DIR, and NVX_BUNDLE_HYPERVISOR.

CI gains a check-nvx-rs action that takes the toolchain from
rust-toolchain.toml and runs rustfmt, Clippy for all targets and
features and for the library without default features, the tests, the
synthetic-release bundled test moved from check-aci-edge-sandboxes,
which now fails when a requested bundle was not staged, rustdoc with
-D warnings, the MSRV check, and the aarch64-apple-darwin check. A new
nvx-rs job runs it on Ubuntu and Windows and gates required-status-check
and the development release like aci-edge-sandboxes, and nvx-rs/ is an
input of the microVM test suites. The Copilot setup steps install every
crate's MSRV, and the repository instructions, project structure,
component map, CI, contribution, and usage guides describe the crate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 12, 2026
Phase 1 of #356. Move the code in aci_edge_sandboxes that drives NVX
into a new standalone crate, nvx-rs, whose library is nvx, and rebuild
aci_edge_sandboxes on top of it. Behavior, wire formats, on-disk state,
error codes and messages, and test coverage stay the same; only Rust
paths, names, and build variables change.

nvx-rs has its own Cargo.lock outside the aci_edge_sandboxes workspace,
edition 2024, MSRV 1.89, the lints of aci_edge_sandboxes, and the
features host (default), bundled, testing, and serde. Without default
features, it has no dependencies, not even for its build script. It
contains:

- protocol/: the NVXS and NVXC codec, now public, documented, and
  dependency-free, split into outer records, application frames, EXEC
  and MAPS payloads, guest features, and kernel command-line tokens.
  The wire constants are unchanged. It gains the guest-side EXEC and
  MAPS decoders that the fake OpenVMM kept privately, so the fake now
  shares the codec with the host. Golden byte fixtures, computed with
  Python's struct module, therefore pin every record for both the
  encoders and the decoders, and tests compare the constants with the
  guest agent's source. The decoders refuse everything that the guest
  agent refuses, such as more than 64 arguments, a relative program, or
  a mapping path with an empty, ".", or ".." component, and the MAPS
  encoder refuses such paths too; the host never produces them.
- contract.rs, net/cidr.rs, hypervisor.rs, and error.rs: the control
  contract, Cidr, Hypervisor with its serde form behind the serde
  feature, and nvx::Error with an ErrorKind of Unavailable, Unsupported,
  Exited, Io, Protocol, TimedOut, or Other, all outside the host
  feature. The hypervisor probe stays in nvx::host::platform.
- host/: artifact discovery; the Linux, Windows, and other platform
  primitives; process, which takes the OpenVMM path and the
  job-breakaway flag instead of OpenVmmConfig; the control session;
  launch, which builds OpenVMM's command line from a typed LaunchSpec
  and owns the kernel-parameter, timeout, and workload-identity rules;
  network and filesystem lowering behind nvx-owned input types that
  carry the names messages use; instance, which holds the launch and
  runtime records, the private-file, lock, and capability helpers,
  reconciliation, interrupted-launch recovery, start with its readiness,
  feature, and MAPS steps, the exec pump with generic sinks,
  cancellation, and deadlines, and graceful stop with a forced fallback;
  and report, which summarizes OpenVMM's outcome report.
- testing/: the fake OpenVMM, moved onto nvx::protocol, with an
  nvx-fake-openvmm binary. It keeps the fixes of #354 and #355.
- build.rs and artifacts.json: bundled-release staging with
  links = "nvx", NVX_BUNDLE=skip, NVX_BUNDLE_DIR, NVX_BUNDLE_HYPERVISOR,
  and DEP_NVX_ARTIFACTS_DIR.

aci_edge_sandboxes keeps the ACI contract and an openvmm module reduced
to OpenVmmBackend, OpenVmmConfig, SandboxRecord, StateStore, the
conversions from MXC requests to nvx types, and the error mapping:
Unavailable becomes backend_unavailable, Unsupported policy_validation,
Exited not_started when an exec finds its VM gone, and everything else
backend_error. It depends on nvx-rs without default features and
re-exports it as aci_edge_sandboxes::nvx. The openvmm feature enables
nvx-rs/host, testing enables nvx-rs/testing, and bundled forwards to
nvx-rs/bundled. A minimal build.rs keeps links = "aci_edge_sandboxes",
so dependents still receive DEP_ACI_EDGE_SANDBOXES_ARTIFACTS_DIR, and a
thin aci-edge-sandboxes-fake-openvmm wrapper stays because
CARGO_BIN_EXE_* only names binaries of the same package.
aci_edge_sandboxes_model depends on nvx with only serde, re-exports
cidr, setup::Hypervisor, and spec::is_valid_hostname and
is_valid_guest_network, which move to nvx::net, at their paths, and
converts nvx::Error into its Error.

The public host API checks its own inputs instead of relying on
aci_edge_sandboxes. LaunchSpec::check, which every command line
applies, refuses a zero memory size, a root workload identity, a
hostname or guest network of the wrong form, and reserved kernel
parameters. Instance::start, exec, and stop refuse zero or overlong
timeouts before they compute a deadline, and network lowering refuses a
policy that allows ingress, which the portable profile cannot express,
instead of denying it silently. aci_edge_sandboxes applies the same
rules first, so its behavior is unchanged.

Sandbox state keeps format 3, because the export plan keeps its serde
form, and a new test loads a record that the previous crate wrote.
SetupConfig keeps its JSON. The integration tests changed only their
imports, and every unit test moved with its code. The relative
process.cwd message now points at nvx::guest_path. The README of
aci_edge_sandboxes documents the breaking changes: Artifacts,
Hypervisor, guest_path, and resolve_guest_path move to
aci_edge_sandboxes::nvx; Hypervisor's FromStr and from_env_or_default
fail with nvx::Error; vendoring the crate also vendors nvx-rs; and
ACI_EDGE_SANDBOXES_BUNDLE, _BUNDLE_DIR, and _BUNDLE_HYPERVISOR become
NVX_BUNDLE, NVX_BUNDLE_DIR, and NVX_BUNDLE_HYPERVISOR.

CI gains a check-nvx-rs action that takes the toolchain from
rust-toolchain.toml and runs rustfmt, Clippy for all targets and
features and for the library without default features, the tests, the
synthetic-release bundled test moved from check-aci-edge-sandboxes,
which now fails when a requested bundle was not staged, rustdoc with
-D warnings, the MSRV check, and the aarch64-apple-darwin check. A new
nvx-rs job runs it on Ubuntu and Windows and gates required-status-check
and the development release like aci-edge-sandboxes, and nvx-rs/ is an
input of the microVM test suites. The Copilot setup steps install every
crate's MSRV, and the repository instructions, project structure,
component map, CI, contribution, and usage guides describe the crate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 12, 2026
Phase 1 of #356. Move the code in aci_edge_sandboxes that drives NVX
into a new standalone crate, nvx-rs, whose library is nvx, and rebuild
aci_edge_sandboxes on top of it. Behavior, wire formats, on-disk state,
error codes and messages, and test coverage stay the same; only Rust
paths, names, and build variables change.

nvx-rs has its own Cargo.lock outside the aci_edge_sandboxes workspace,
edition 2024, MSRV 1.89, the lints of aci_edge_sandboxes, and the
features host (default), bundled, testing, and serde. Without default
features, it has no dependencies, not even for its build script. It
contains:

- protocol/: the NVXS and NVXC codec, now public, documented, and
  dependency-free, split into outer records, application frames, EXEC
  and MAPS payloads, guest features, and kernel command-line tokens.
  The wire constants are unchanged. It gains the guest-side EXEC and
  MAPS decoders that the fake OpenVMM kept privately, so the fake now
  shares the codec with the host. Golden byte fixtures, computed with
  Python's struct module, therefore pin every record for both the
  encoders and the decoders, and tests compare the constants with the
  guest agent's source. The decoders refuse everything that the guest
  agent refuses, such as more than 64 arguments, a relative program, or
  a mapping path with an empty, ".", or ".." component, and the MAPS
  encoder refuses such paths too; the host never produces them.
- contract.rs, net/cidr.rs, hypervisor.rs, and error.rs: the control
  contract, Cidr, Hypervisor with its serde form behind the serde
  feature, and nvx::Error with an ErrorKind of Unavailable, Unsupported,
  Exited, Io, Protocol, TimedOut, or Other, all outside the host
  feature. The hypervisor probe stays in nvx::host::platform.
- host/: artifact discovery; the Linux, Windows, and other platform
  primitives; process, which takes the OpenVMM path and the
  job-breakaway flag instead of OpenVmmConfig; the control session;
  launch, which builds OpenVMM's command line from a typed LaunchSpec
  and owns the kernel-parameter, timeout, and workload-identity rules;
  network and filesystem lowering behind nvx-owned input types that
  carry the names messages use; instance, which holds the launch and
  runtime records, the private-file, lock, and capability helpers,
  reconciliation, interrupted-launch recovery, start with its readiness,
  feature, and MAPS steps, the exec pump with generic sinks,
  cancellation, and deadlines, and graceful stop with a forced fallback;
  and report, which summarizes OpenVMM's outcome report.
- testing/: the fake OpenVMM, moved onto nvx::protocol, with an
  nvx-fake-openvmm binary. It keeps the fixes of #354 and #355.
- build.rs and artifacts.json: bundled-release staging with
  links = "nvx", NVX_BUNDLE=skip, NVX_BUNDLE_DIR, NVX_BUNDLE_HYPERVISOR,
  and DEP_NVX_ARTIFACTS_DIR.

aci_edge_sandboxes keeps the ACI contract and an openvmm module reduced
to OpenVmmBackend, OpenVmmConfig, SandboxRecord, StateStore, the
conversions from MXC requests to nvx types, and the error mapping:
Unavailable becomes backend_unavailable, Unsupported policy_validation,
Exited not_started when an exec finds its VM gone, and everything else
backend_error. It depends on nvx-rs without default features and
re-exports it as aci_edge_sandboxes::nvx. The openvmm feature enables
nvx-rs/host, testing enables nvx-rs/testing, and bundled forwards to
nvx-rs/bundled. A minimal build.rs keeps links = "aci_edge_sandboxes",
so dependents still receive DEP_ACI_EDGE_SANDBOXES_ARTIFACTS_DIR, and a
thin aci-edge-sandboxes-fake-openvmm wrapper stays because
CARGO_BIN_EXE_* only names binaries of the same package.
aci_edge_sandboxes_model depends on nvx with only serde, re-exports
cidr, setup::Hypervisor, and spec::is_valid_hostname and
is_valid_guest_network, which move to nvx::net, at their paths, and
converts nvx::Error into its Error.

The public host API checks its own inputs instead of relying on
aci_edge_sandboxes. LaunchSpec::check, which every command line
applies, refuses a zero memory size, a root workload identity, a
hostname or guest network of the wrong form, and reserved kernel
parameters. Instance::start, exec, and stop refuse zero or overlong
timeouts before they compute a deadline. Start also holds OpenVMM's
command line to the limit of a Windows process command line on every
host, without the reserve that provisioning keeps. Network lowering
refuses a policy that allows ingress, which the portable profile cannot
express, instead of denying it silently. aci_edge_sandboxes applies the
same rules first, so its behavior is unchanged, except that a start
whose configured paths grew past that reserve since provision now fails
with policy_validation on every host.

Sandbox state keeps format 3, because the export plan keeps its serde
form, and a new test loads a record that the previous crate wrote.
SetupConfig keeps its JSON. The integration tests changed only their
imports, and every unit test moved with its code. The relative
process.cwd message now points at nvx::guest_path. The README of
aci_edge_sandboxes documents the breaking changes: Artifacts,
Hypervisor, guest_path, and resolve_guest_path move to
aci_edge_sandboxes::nvx; Hypervisor's FromStr and from_env_or_default
fail with nvx::Error; vendoring the crate also vendors nvx-rs; and
ACI_EDGE_SANDBOXES_BUNDLE, _BUNDLE_DIR, and _BUNDLE_HYPERVISOR become
NVX_BUNDLE, NVX_BUNDLE_DIR, and NVX_BUNDLE_HYPERVISOR.

CI gains a check-nvx-rs action that takes the toolchain from
rust-toolchain.toml and runs rustfmt, Clippy for all targets and
features and for the library without default features, the tests, the
synthetic-release bundled test moved from check-aci-edge-sandboxes,
which now fails when a requested bundle was not staged, rustdoc with
-D warnings, the MSRV check, and the aarch64-apple-darwin check. A new
nvx-rs job runs it on Ubuntu and Windows and gates required-status-check
and the development release like aci-edge-sandboxes, and nvx-rs/ is an
input of the microVM test suites. The Copilot setup steps install every
crate's MSRV, and the repository instructions, project structure,
component map, CI, contribution, and usage guides describe the crate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna) added a commit that referenced this pull request Oct 13, 2026
Part of #357. Move the fake OpenVMM from the
aci-edge-sandboxes-fake-openvmm binary to nvx::testing::fake_openvmm,
behind the new testing feature. The fake is the test double that serves
the control console and runs scripted workloads without a VM. nvx-rs
ships it as the nvx-fake-openvmm binary. aci_edge_sandboxes keeps its
binary, because its tests need it under that name, as a wrapper that
calls nvx::testing::fake_openvmm::main.

The fake drops its private copy of the codec and speaks nvx::protocol.
It decodes EXEC and MAPS requests with the guest agent's decoders,
whose golden byte fixtures pin the wire format independently. It keeps
the fixes of #354 and #355, and prefixes its diagnostics with the name
of the executable that runs it.

New integration tests drive an Instance end to end against
nvx-fake-openvmm. They cover start, workloads and their outcomes,
cancellation, refused guests, failed launches, timeouts, and oversized
command lines.

The testing feature of aci_edge_sandboxes enables nvx-rs/testing, and
aci_edge_sandboxes no longer depends on getrandom directly.

git show -C shows the fake as a copy of
aci_edge_sandboxes/src/bin/aci-edge-sandboxes-fake-openvmm.rs.

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.

aci_edge_sandboxes: fake OpenVMM exits 0 when printenv names an unset variable

3 participants