Skip to content

host: hand prepared cold launches to external callers - #1349

Closed
Enrique Saurez (esaurez) wants to merge 42 commits into
feature/nvx-refactorfrom
esaurez/slim-2.2.1-sl2.8b-20261107
Closed

Enrique Saurez (esaurez) wants to merge 42 commits into
feature/nvx-refactorfrom
esaurez/slim-2.2.1-sl2.8b-20261107

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Part of #1076.

Add SL2.8b's Prepared::into_command() and owning host::vm::VmmCommand so an external caller can launch the exact command that cold preparation checked. Move the already-opened log, inherited resources, arguments, capability and output names without reopening, cloning handles, rerendering or rediscovering runtime inputs. InheritedHandle owns Unix OwnedFd / Windows OwnedHandle, with move-only standard ownership conversions and safe borrowed views.

Capture the program, working directory and breakaway policy during preparation. Preserve the parent's creation, rollback, renderer and native preflight behavior. No restore, process registry, Sandbox, producer configuration or native pin changes.

Add a Cargo-compiled external-launch public-API consumer. It resolves all three artifact paths against the caller's directory before preparation, uses the existing low-level launch primitive without a sandbox store, boots Alpine, checks a real shell response, and requires the VMM's actual exit status 0 as well as a successful guest outcome and complete teardown.

Review corrections reuse the existing status-bearing Launched::wait_timeout as a public host API, with its coupled Unix helpers and Windows imports/private waiter available without cli. This minimal API extension was explicitly approved; spawn, allowlisting and process-identity behavior remain unchanged. Regenerate both platform API snapshots.

Stacked on #1342 at 7c4156ad in preserved native stack 1343, above #1334. The normal input merge retains both original owned commits and current parent corrections. Official whole-layer measurement including these fixes: 268 core lines, 5 counted files, 10 raw paths. The compiled example counts as production; docs/tests/generated snapshots are disclosed separately. The original 160-line estimate is exceeded, but the 320-line stop and 5-counted-file project limit are respected.

Tests

Keep four focused ownership tests for moved vectors/resources, the same opened log after path replacement, captured launch inputs and platform-owned conversions. Adapt the original opened-resource test to owning inherited storage without weakening its lifetime assertions.

Add a focused public-API regression in the existing checked_handoff integration test. Its real fixture checks zero-timeout while the VMM is running, actual statuses 0 and 17, and repeated retained status reads on Linux and Windows; reuse the existing fixture cleanup guard. No existing assertions or deadlines are removed or weakened.

Validation

  • Review-fix inputs: Windows host-only exit-status regression plus 9 applicable Rust checks passed; Linux 13 passed, including the same regression, warnings-denied all-target/all-feature and host-only Clippy, whole all-feature/default tests, rustfmt, warnings-denied rustdoc, MSRV 1.89, host adapter tests, host-only release example builds, macOS check, and public API generation/check. Current test layout and diff whitespace passed.
  • Independent native Opus 5.5/max/long read-only review of corrected ae25aa40: CLEAN. Its coupled Unix/non-Unix cfg and reaped-child lifetime documentation follow-up was also independently reviewed CLEAN and passed focused Windows/Linux host Clippy/status tests and Windows host rustdoc. The prior clean 5c89457e review is separate evidence, not approval of the correction.
  • Actually cold-launched the newly compiled corrected example with all three artifact paths relative to the caller's directory on WHP and MSHV. Both obtained the Alpine boot marker and real shell response, actual VMM/launcher status 0, successful outcome and all teardown steps. Compiler-capable phases ended before the guest runs and fresh resource/growth guards passed.
  • The previously qualified 5c89457e had fresh 17 Windows / 18 Linux host checks, current source-f4b2ccee CLIs/examples, CLI units (3), whole adversarial tests (84), host tests (4) and help checks (8) per platform. Those release-CLI results are explicitly prior-head evidence, not rebuilt correction-head CLI results. Its Linux copied-executable ETXTBSY recovery and other initial failures remain recorded.
  • Reuse only proven identical non-host/protocol/guest/scripts/quality inputs from qualified 2a4a7379, including the full 1,818-unit corpus and guest input 4050fa15. Current review-fix host/API/example tests and actual relative-path cold runs above are fresh.
  • Additional WASI host-only check remains blocked by the existing unchanged template/clone/launch.rs:366 use of Inherited::new, which exists only on Unix/Windows. After restoring the missing pinned WASI standard target, this precise pre-existing failure was preserved; no unrelated template/allowlist fix or WASI pass is claimed.

Native 14dc4116, kernel and Alpine payload identities are unchanged and hash/provenance-validated. Native reuse is bounded artifact-level source/origin/ABI/hash/sidecar evidence; its historical compiler/full recipe is unavailable and not reconstructed. KVM and unchanged full producer distro/performance matrices were not replayed. This remains a Draft; no CI result is claimed or manually queried/triggered.

Enrique Saurez and others added 30 commits November 5, 2026 21:36
Add caller-owned VM directories, fixed output names and redacted control
capabilities without creating launch outputs or persisting credentials.
Require current-user ownership and mode 0700 on Linux, or a protected
owner-only DACL on Windows, without changing existing directories.

Use the crate's Result and report a non-private directory as ErrorKind::Io.
Normalize trailing separators and dot components before no-follow checks
so a final symbolic link is refused, while preserving parent components.
Keep the existing store privacy policies unchanged.

Compare Windows ACL snapshots using the same canonical SDDL SID
spellings as the descriptor serializer, including well-known aliases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d334d041-d2f2-47db-be92-5564ff14f2d7
Add VmConfig in the new host::config: a VM's processors, its memory in
MiB, its root, blockless or layered, the View that its workload has of
it, the export plan of the host paths that it exports, and where its
boot console's output goes, to a listener or nowhere; the console's
device exists either way. A layered root names its image and format, an
optional bound of a GPT disk's first partition, its overlay mode, and a
scratch upper with its journal policy or a RAM upper whose cap is 1 to
90 percent of the VM's memory, 50 by default.

VmConfig::check checks the whole value without reading the host, and
returns the first refusal as an Error of kind Unsupported, whose message
names what it refuses; an export's refusal keeps the error of
ExportPlan::check as its source. It reuses activation's journal, overlay
and machine-ID vocabulary, the record's hostname rule, which becomes
activation::is_hostname for both, and ExportPlan::check with the guest
targets that the root reserves.

Add activation::View, the hostname and machine ID that a VM's workload
sees, beside WorkloadView, which the record keeps for now.

The public API snapshots list the new items.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 869204bf-28f8-408e-bcab-e4353944ef69
Copilot-Session: 2d81c32c-865b-42d0-8f3e-6881809e0157
The fixture already freezes socket tables and waits for stubbed server output.
Observe a failed condition twice instead of spawning 101 awk or grep processes
over immutable input. Keep all 13 cases, the 10-second subprocess timeout and
production polling unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2d81c32c-865b-42d0-8f3e-6881809e0157
…pper

The boot tokens of a layered root gain four optional settings, after the
image's and the upper's: nvx_overlay_mode, trusted-lowers or
untrusted-lowers; nvx_scratch_journal, allowed or forbidden;
nvx_first_partition_bound, a GPT disk's bound in bytes; and
nvx_ram_upper_percent, a RAM upper's cap from 1 to 90 percent of the
VM's memory. RootLayout names each as an Option that renders no token
when it is None, so that the guest keeps its default. RootLayout::parse
reads them strictly: each once, with a value in its decimal or named
form, only beside an image, and the journal policy only with a scratch
upper, the cap with a RAM upper, and the bound with a GPT image. The
shared fixture records the new cases, which nvx-rs and the shell init
both replay.

guest::root's Upper::Tmpfs takes the cap, mounts the tmpfs with size=N%
when it has one, and refuses a cap outside 1 to 90 percent before
anything changes, since the kernel reads 0 as no cap. NVX's shell init
reads the four tokens with the parser's rules and messages, mounts a
capped RAM upper with size=N%, and refuses, before it mounts anything,
untrusted lowers and a forbidden journal, which it cannot assemble, as
it refuses a GPT image.

The sandbox plan names none of the settings, so its command lines stay
as they were, and an adapter's plan refuses a setting that its command
line names, since it reads the root's tokens back. A clone's activation
assembles its tmpfs without a cap, since its record names none, and the
runtime adapter's worker hands the cap of its boot tokens to its root.

BOOT_CONTRACT_VERSION stays 5, since nothing deployed renders the new
tokens. The public API snapshots list the new items.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
The executor-close fixture kills its surviving Windows child, whose stderr
still names a file in its temporary directory. Wait for the process object
to signal before cleaning up that directory, using the existing bounded
Windows wait helper and the fixture's existing cleanup deadline.

Keep the workload timeout, the measured close bound, and every existing
test assertion unchanged. A child that does not exit now fails explicitly
instead of racing the temporary-directory cleanup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Wait for the real fixture to publish its boot readiness and for its
descendant to publish its PID before starting the existing half-second
workload timeout. Keep that startup wait bounded and clean up the contained
processes if readiness fails.

Accept the runner's raw TimeoutError and its RuntimeError wrapper only with
the expected half-second workload-timeout message. Require a live, positive
descendant PID before the workload and retain the check that it has exited
after the timeout. Production code, measured deadlines, and skips do not
change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Apply the repository formatter's quoting and wrapping to the approved
fixture correction. Its parsed Python syntax tree is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Add net::Ipv4Cidr, a static guest address checked when it is built: an
IPv4 address with a /1 to /30 prefix that is not its network's own,
broadcast, or gateway address, as OpenVMM accepts it. It displays and
parses as ADDRESS/PREFIX, and with the serde feature it serializes as
that text. is_valid_guest_network and guest_gateway read addresses
through it, with the same rules.

VmConfig gains its network, a NetworkConfig of the policy that OpenVMM
enforces and the NIC's address, which a cold boot without one takes from
DEFAULT_GUEST_NETWORK, and a restore from the snapshot; and its boot, a
Boot of the caller's own kernel command-line tokens, which only a cold
boot takes. NicConfig names the NIC that a VM settled on.
DEFAULT_GUEST_NETWORK moves here from host::launch, which re-exports it.
VmConfig::check adds no refusal: the policy and the tokens are checked
where they are lowered.

The configuration tests' fixture gains the two fields.

The public API snapshots list the new items.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ab593c71-7f27-4207-8ff3-829d9a283b4c
Read the root settings before the init refuses GPT images, so an invalid
unsigned bound has the same numeric diagnostic in either token order.
Keep GPT unsupported and pin the existing image-first overflow fixture's
shell diagnostic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Reconcile configuration and root-token inputs without additional implementation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c390c333-e511-4ec5-a133-8352cb86d485
Join the unchanged pure SL2.4a2 inputs with the source-equivalent published
SL2.3b squash so that the candidate retains the actual feature ancestry.
The input tree is byte-identical; this adds no owned implementation.
Technical boundary: ENG-24a2-INPUT-ANCESTRY-8ED-SAME-TREE.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c390c333-e511-4ec5-a133-8352cb86d485
…pper

The boot tokens of a layered root gain four optional settings, after the
image's and the upper's: nvx_overlay_mode, trusted-lowers or
untrusted-lowers; nvx_scratch_journal, allowed or forbidden;
nvx_first_partition_bound, a GPT disk's bound in bytes; and
nvx_ram_upper_percent, a RAM upper's cap from 1 to 90 percent of the
VM's memory. RootLayout names each as an Option that renders no token
when it is None, so that the guest keeps its default. RootLayout::parse
reads them strictly: each once, with a value in its decimal or named
form, only beside an image, and the journal policy only with a scratch
upper, the cap with a RAM upper, and the bound with a GPT image. The
shared fixture records the new cases, which nvx-rs and the shell init
both replay.

guest::root's Upper::Tmpfs takes the cap, mounts the tmpfs with size=N%
when it has one, and refuses a cap outside 1 to 90 percent before
anything changes, since the kernel reads 0 as no cap. NVX's shell init
reads the four tokens with the parser's rules and messages, mounts a
capped RAM upper with size=N%, and refuses, before it mounts anything,
untrusted lowers and a forbidden journal, which it cannot assemble, as
it refuses a GPT image.

The sandbox plan names none of the settings, so its command lines stay
as they were, and an adapter's plan refuses a setting that its command
line names, since it reads the root's tokens back. A clone's activation
assembles its tmpfs without a cap, since its record names none, and the
runtime adapter's worker hands the cap of its boot tokens to its root.

BOOT_CONTRACT_VERSION stays 5, since nothing deployed renders the new
tokens. The public API snapshots list the new items.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
The executor-close fixture kills its surviving Windows child, whose stderr
still names a file in its temporary directory. Wait for the process object
to signal before cleaning up that directory, using the existing bounded
Windows wait helper and the fixture's existing cleanup deadline.

Keep the workload timeout, the measured close bound, and every existing
test assertion unchanged. A child that does not exit now fails explicitly
instead of racing the temporary-directory cleanup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Wait for the real fixture to publish its boot readiness and for its
descendant to publish its PID before starting the existing half-second
workload timeout. Keep that startup wait bounded and clean up the contained
processes if readiness fails.

Accept the runner's raw TimeoutError and its RuntimeError wrapper only with
the expected half-second workload-timeout message. Require a live, positive
descendant PID before the workload and retain the check that it has exited
after the timeout. Production code, measured deadlines, and skips do not
change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Apply the repository formatter's quoting and wrapping to the approved
fixture correction. Its parsed Python syntax tree is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Read the root settings before the init refuses GPT images, so an invalid
unsigned bound has the same numeric diagnostic in either token order.
Keep GPT unsupported and pin the existing image-first overflow fixture's
shell diagnostic.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4e354d65-494d-4fa9-ae9b-4f2e86c3c0f8
Join the unchanged declared input history with the actual current SL2.4a1
source. Both parents have the same input tree; this adds no implementation.
The original two owned commits remain outside the input anchor.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c390c333-e511-4ec5-a133-8352cb86d485
Compose root settings, a byte-preserving view, the export's mapping count
and the unchanged caller command line in one pure cold-boot renderer.
Parse the new view tokens strictly without changing legacy consumers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c390c333-e511-4ec5-a133-8352cb86d485
Document the byte-preserving view codec and pure kernel command-line
renderer alongside the other module contracts. Clarify that caller text
is appended unchanged rather than checked for token collisions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c390c333-e511-4ec5-a133-8352cb86d485
Check caller boot tokens with the existing kernel and init readers while leaving other guest tokens caller-owned. Expose the exact export mapping table and map codec, retaining the protocol-root re-exports, and move the kernel command-line budget into configuration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0aa8163c-8d27-4d54-be61-d9b23c1bc15c
Document the reserved boot-token names, unchanged caller-owned tokens, pure mapping table, public map codec and configuration command-line budget so the crate specification matches the configuration checks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0aa8163c-8d27-4d54-be61-d9b23c1bc15c
Derive whole cold-boot arguments from Runtime and VmConfig, borrowing only the caller-chosen output names. Retain the console device and configured NIC, lower block devices by path, and check the complete Windows command-line limit on every host.

Move the portable counting helpers to config while retaining the legacy launch paths and shared argument assembly. Add the reserved configuration-only check and document status-bearing guest power-off behavior.

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

Copilot-Session: 76d8c9ca-6594-44b1-bc7b-810b64e7fe51
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 76d8c9ca-6594-44b1-bc7b-810b64e7fe51
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Reuse the pure disk-path validator for layered image and scratch arguments before either configuration preflight or whole rendering returns. Move the shared guard into config and retain its sandbox re-export, preserving diagnostics and host module layering.

Add a regression for disk delimiters and bracket balance through both entry points, including valid literal paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 76d8c9ca-6594-44b1-bc7b-810b64e7fe51
Create an inspectable cold launch with its owned log, capability, outputs, arguments, and opened resources without starting a process. Refuse restores and missing boot data, preserve existing outputs, remove only newly created output on failure, and check the complete portable command-line limit. Keep the whole-configuration renderer internal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Enrique Saurez and others added 4 commits November 7, 2026 00:19
Pure local producer foundation: retain the recorded SL2.7/native14dc ancestry and carry only the genuine d1 representability correction after owned8707 readers END.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Carry genuine producer-only d1 input above the recorded pure foundation. Preserve all own cold-create code, API, rollback tests, metadata, and history; current qualification is now required for this effective tuple.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Reject Linux listener-option delimiters and socket names of 108 bytes or more before creating any cold-launch output. Cover both console configurations, Unicode byte boundaries, real valid socket binds, and preservation of caller inputs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 98b02bc4-2d86-490f-8241-2234ccd39feb
Preserve the owned external-command handoff while incorporating the corrected cold-launch renderer and pre-output endpoint checks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4820e3a0-adc3-4382-8ccc-ae8b30d282d0
@esaurez Enrique Saurez (esaurez) added tests-modified Changes existing tests, test data, or test wiring feat-nvx-refactor labels Nov 7, 2026
@github-actions

github-actions Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 47 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests.

Test code

Change What Before After
modified helper fn accepted_assembly in guest::clone::activation::apply::tests nvx-rs/src/guest/clone/activation/apply/tests.rs:627 nvx-rs/src/guest/clone/activation/apply/tests.rs:627
modified helper fn layout in protocol::root::tests nvx-rs/src/protocol/root/tests.rs:21 nvx-rs/src/protocol/root/tests.rs:33
modified helper fn recorded_layout in protocol::root::tests nvx-rs/src/protocol/root/tests.rs:30 nvx-rs/src/protocol/root/tests.rs:50
modified helper def SandboxRootTokenAgentTests._read in scripts/test_nvx_tools.py scripts/test_nvx_tools.py:19408 scripts/test_nvx_tools.py:19408
modified helper fn layout in guest_session (tests) tests/runtime-adapter/tests/guest_session.rs:1635 tests/runtime-adapter/tests/guest_session.rs:1635
modified test fn assembly_inputs_are_taken_exactly_from_the_record in guest::clone::activation::apply::tests nvx-rs/src/guest/clone/activation/apply/tests.rs:916 nvx-rs/src/guest/clone/activation/apply/tests.rs:918
modified test fn new_upper_and_work_directories_have_mode_0755_whatever_the_umask in guest::root::tests nvx-rs/src/guest/root/tests.rs:912 nvx-rs/src/guest/root/tests.rs:917
modified test fn a_fresh_upper_s_directories_must_be_missing_or_empty in guest::root::tests nvx-rs/src/guest/root/tests.rs:958 nvx-rs/src/guest/root/tests.rs:963
modified test fn a_runtime_directory_where_a_file_system_is_mounted_is_refused in guest::root::tests nvx-rs/src/guest/root/tests.rs:1169 nvx-rs/src/guest/root/tests.rs:1174
modified test fn both_overlay_modes_assemble_on_both_uppers_with_their_own_option_sets in guest::root::tests nvx-rs/src/guest/root/tests.rs:1587 nvx-rs/src/guest/root/tests.rs:1592
modified test fn a_tmpfs_upper_needs_no_scratch_device in guest::root::tests nvx-rs/src/guest/root/tests.rs:1676 nvx-rs/src/guest/root/tests.rs:1698
modified test fn a_refused_option_set_fails_without_a_fallback in guest::root::tests nvx-rs/src/guest/root/tests.rs:1698 nvx-rs/src/guest/root/tests.rs:1758
modified test fn an_overlay_that_the_kernel_mounts_without_its_mode_in_effect_is_refused_and_unmounted in guest::root::tests nvx-rs/src/guest/root/tests.rs:1752 nvx-rs/src/guest/root/tests.rs:1812
modified test fn options_that_the_kernel_does_not_show_have_their_defaults in guest::root::tests nvx-rs/src/guest/root/tests.rs:1809 nvx-rs/src/guest/root/tests.rs:1869
modified test fn effective_options_that_cannot_be_read_fail_the_assembly in guest::root::tests nvx-rs/src/guest/root/tests.rs:1868 nvx-rs/src/guest/root/tests.rs:1928
modified test fn overlay_options_that_a_mount_cannot_pass_are_refused_before_any_mount in guest::root::tests nvx-rs/src/guest/root/tests.rs:1927 nvx-rs/src/guest/root/tests.rs:1987
modified test fn up_to_195_layers_fit_in_the_overlay_s_options_below_run_nvx in guest::root::tests nvx-rs/src/guest/root/tests.rs:1978 nvx-rs/src/guest/root/tests.rs:2038
modified test fn a_tmpfs_upper_is_unmounted_last_and_every_failure_reported in guest::root::tests nvx-rs/src/guest/root/tests.rs:2165 nvx-rs/src/guest/root/tests.rs:2225
modified test fn a_scratch_s_file_system_is_synced_right_before_its_unmount in guest::root::tests nvx-rs/src/guest/root/tests.rs:2210 nvx-rs/src/guest/root/tests.rs:2270
modified test fn a_gpt_disk_that_differs_from_the_expected_identities_is_refused_before_any_mount in guest::root::tests nvx-rs/src/guest/root/tests.rs:2278 nvx-rs/src/guest/root/tests.rs:2338
modified test fn a_gpt_disk_without_a_layer_is_refused_before_any_mount in guest::root::tests nvx-rs/src/guest/root/tests.rs:2365 nvx-rs/src/guest/root/tests.rs:2425
modified test fn a_layer_that_is_not_ext4_or_whose_journal_needs_a_recovery_is_refused_before_any_mount in guest::root::tests nvx-rs/src/guest/root/tests.rs:2393 nvx-rs/src/guest/root/tests.rs:2453
modified test fn a_missing_partition_fails_at_once_before_any_mount in guest::root::tests nvx-rs/src/guest/root/tests.rs:2470 nvx-rs/src/guest/root/tests.rs:2530
modified test fn the_first_partition_is_returned_as_opaque_bytes_within_its_bound in guest::root::tests nvx-rs/src/guest/root/tests.rs:2735 nvx-rs/src/guest/root/tests.rs:2795
modified test fn a_teardown_unmounts_the_layers_top_first_and_reports_every_failure in guest::root::tests nvx-rs/src/guest/root/tests.rs:2800 nvx-rs/src/guest/root/tests.rs:2860
modified test fn a_layer_that_a_failed_unmount_left_keeps_the_runtime_directory_occupied in guest::root::tests nvx-rs/src/guest/root/tests.rs:2866 nvx-rs/src/guest/root/tests.rs:2926
modified test fn process_command_lines_are_measured_as_windows_quotes_them in host::launch::tests (moved) nvx-rs/src/host/launch/tests.rs:118 nvx-rs/src/host/config/tests.rs:1302
modified test fn every_format_and_upper_plans_and_renders in host::sandbox::plan::tests nvx-rs/src/host/sandbox/plan/tests.rs:136 nvx-rs/src/host/sandbox/plan/tests.rs:136
modified test fn adapter_plans_render_their_root_and_devices_alone in host::sandbox::plan::tests nvx-rs/src/host/sandbox/plan/tests.rs:1362 nvx-rs/src/host/sandbox/plan/tests.rs:1367
modified test fn launch_contract_builds_agent_command_line in host::sandbox::tests nvx-rs/src/host/sandbox/tests.rs:142 nvx-rs/src/host/sandbox/tests.rs:142
modified test fn openvmms_platform_allowlist_admits_its_tokens_and_refuses_tenant_data in host::template::plan::tests nvx-rs/src/host/template/plan/tests.rs:525 nvx-rs/src/host/template/plan/tests.rs:525
modified test fn wire_values_keep_their_literals in protocol::root::tests nvx-rs/src/protocol/root/tests.rs:45 nvx-rs/src/protocol/root/tests.rs:89
modified test fn every_layout_renders_its_tokens_and_reads_them_back in protocol::root::tests nvx-rs/src/protocol/root/tests.rs:67 nvx-rs/src/protocol/root/tests.rs:128
modified test fn every_reader_parses_the_recorded_command_lines_alike in protocol::root::tests nvx-rs/src/protocol/root/tests.rs:144 nvx-rs/src/protocol/root/tests.rs:277
modified test fn parsing_reports_bytes_that_are_not_text in protocol::root::tests nvx-rs/src/protocol/root/tests.rs:188 nvx-rs/src/protocol/root/tests.rs:348
modified test fn the_boot_contract_version_names_these_tokens in protocol::root::tests nvx-rs/src/protocol/root/tests.rs:231 nvx-rs/src/protocol/root/tests.rs:427
modified test def AdversarialOracleTests.test_contained_guest_runner_timeout_kills_descendants in scripts/test_adversarial.py scripts/test_adversarial.py:853 scripts/test_adversarial.py:857
modified test def ExecutorCloseTests.test_close_is_bounded_when_a_surviving_child_holds_executor_stdout in scripts/test_adversarial.py scripts/test_adversarial.py:3162 scripts/test_adversarial.py:3215
modified test def SandboxRootTokenAgentTests.test_agent_reads_the_boot_tokens_as_nvx_rs_reads_them in scripts/test_nvx_tools.py scripts/test_nvx_tools.py:19434 scripts/test_nvx_tools.py:19435
modified test def SandboxRootTokenAgentTests.test_agent_explains_the_roots_that_it_cannot_assemble in scripts/test_nvx_tools.py scripts/test_nvx_tools.py:19464 scripts/test_nvx_tools.py:19477
modified test def SandboxRootTokenAgentTests.test_agent_mounts_the_upper_that_the_tokens_name in scripts/test_nvx_tools.py scripts/test_nvx_tools.py:19573 scripts/test_nvx_tools.py:19663
modified test fn each_class_of_failure_ends_the_clone_with_its_own_status in worker::activation::tests tests/runtime-adapter/src/worker/activation/tests.rs:90 tests/runtime-adapter/src/worker/activation/tests.rs:90
modified test fn the_worker_assembles_an_image_over_ram_in_the_overlay_mode_of_its_configuration in guest_session (tests) tests/runtime-adapter/tests/guest_session.rs:1817 tests/runtime-adapter/tests/guest_session.rs:1821
modified test fn the_worker_assembles_a_gpt_disk_with_the_first_partition_bound_of_its_configuration in guest_session (tests) tests/runtime-adapter/tests/guest_session.rs:1843 tests/runtime-adapter/tests/guest_session.rs:1849
modified test fn a_layered_launch_plans_its_blocks_and_boot_tokens_with_the_adapters_plan in layered_launch (tests) tests/runtime-adapter/tests/layered_launch.rs:239 tests/runtime-adapter/tests/layered_launch.rs:239
removed hook the test hooks of fn outputs in host::vm (impl VmDir) nvx-rs/src/host/vm.rs:105

Test data

Change What Before After
modified file nvx-rs/tests/fixtures/root-tokens.json nvx-rs/tests/fixtures/root-tokens.json nvx-rs/tests/fixtures/root-tokens.json

Relocated unchanged: 1; added: 53. Compared the merge base 8ed1f53e3452 with ae25aa40807b.

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

The launcher can resolve relative artifact paths against the wrong working directory and report success despite a nonzero VMM exit status.

2 open issues
What changed in this PR

This PR advances #1076 by letting external callers take ownership of a prepared cold VM launch, building on the preparation API from #1342 without adding spawning to host::vm.

Changes:

  • Add Prepared::into_command(), owning VmmCommand, and platform-owned inherited resources.
  • Add a compiled external-launch example that boots a guest and checks its response and teardown report.
  • Document the handoff contract, test ownership preservation, and update both public API snapshots.
File Description
nvx-rs/​src/​host/​vm/​tests.rs Test resource identity, captured launch inputs, and platform ownership conversions.
nvx-rs/​src/​host/​vm.rs Add owning command handoff and inherited-resource types.
nvx-rs/​README.md Document command ownership, launcher obligations, and example usage.
nvx-rs/​public-api/​windows.txt Record the new Windows public API surface.
nvx-rs/​public-api/​linux.txt Record the new Linux public API surface.
nvx-rs/​examples/​external-launch.rs Demonstrate a caller-owned cold launch without a sandbox store.
nvx-rs/​Cargo.toml Register the example with the required host feature.

Review effort: Balanced

Comment thread nvx-rs/examples/external-launch.rs Resolved
Comment thread nvx-rs/examples/external-launch.rs Resolved

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

Caller-relative executable and artifact paths resolve under the wrong directory and can break launches, while unchecked launcher exit status can falsely report success.

2 open issues

Review effort: Balanced

Resolve all three artifact paths against the caller before preparing the VM's working directory. Expose the existing status-bearing launch wait to host consumers and require actual VMM success alongside the guest report and teardown.

Cover host-only timeout, zero/nonzero status and repeated waits with the existing public handoff fixture. Preserve non-Unix cfg compilation and document the reaped-child lifetime; regenerate both API snapshots.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4820e3a0-adc3-4382-8ccc-ae8b30d282d0

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.

🟢 Approval recommended

No active review issues are reported for the prepared cold-launch handoff and exit-status API changes.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@esaurez
Enrique Saurez (esaurez) force-pushed the esaurez/slim-2.2.1-sl2.8-20261107 branch 2 times, most recently from e2d5624 to 49ee94b Compare November 8, 2026 20:02
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the esaurez/slim-2.2.1-sl2.8-20261107 branch from 1017e0d to 0701ea5 Compare November 8, 2026 21:25
Base automatically changed from esaurez/slim-2.2.1-sl2.8-20261107 to feature/nvx-refactor November 9, 2026 01:22
@esaurez
Enrique Saurez (esaurez) deleted the esaurez/slim-2.2.1-sl2.8b-20261107 branch November 13, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat-nvx-refactor tests-modified Changes existing tests, test data, or test wiring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants