Skip to content

tests: run the host's order of a layered root in the adapter's host program - #875

Open
Enrique Saurez (esaurez) wants to merge 1 commit into
devfrom
esaurez/822-pr07-host-order-20261023
Open

Enrique Saurez (esaurez) wants to merge 1 commit into
devfrom
esaurez/822-pr07-host-order-20261023

Conversation

@esaurez

@esaurez Enrique Saurez (esaurez) commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Part of #822 (PR 7 of 11: the host's order).

The runtime adapter's host program sent the root configuration, took any Ready as the guest's readiness, whatever the guest agent's build, and went on to its exchanges. It shared no host path with the root, sent no mapping table, and never started the sandbox, so the worker's order (#872) had no host side, and a guest agent of another build than the host ships went on serving.

Changes

Shares. launch takes:

  • --share HOST:TARGET[:ro], each a host directory or regular file at an absolute guest path in the root (the guest path starts at the last :/, so Windows drive letters work);
  • --deny PATH, host paths hidden inside the shares;
  • --reserved TARGET, guest trees that the adapter keeps, beside the container root's ReservedTargets::CONTAINER_ROOT (nvx-rs/src/host/filesystem.rs:85-125 at this base);
  • --share-root DIR, the host directories that the adapter authorizes.

The new sharing module holds them as a HostFsSharing of Shares, whose fields are private: each has a getter and a setter, and each list a method that adds an entry, as its option does. HostFsSharing::plan refuses a share outside the authorized directories, once links are resolved, before it plans the export with nvx::host::filesystem::plan through an ExportRequest. It then checks the export's directories and files again. The launch refuses what it cannot export before it touches the store. LayeredLaunch::share attaches the export, which LayeredLaunch::export returns, and announces its table in the root configuration's mapping count. LayeredLaunch::prepare checks the export with ExportPlan::verify, and the launch's OpenVMM arguments include ExportPlan::openvmm_arguments. A launch without shares is unchanged.

The order. In the new host order layer:

  1. host::ready sends the root configuration and waits for Ready, whose build must be the one that the host ships (GUEST_BUILD unless --guest-build names another). A guest agent of another build gets nothing more, and the launch fails, which ends the VM.
  2. host::start_sandbox sends the table in the parts that root::encode_maps splits it into, each once the guest applied the one before, then Start, and waits for Started. The launch commits only after Started.

A part that the guest fails ends the order: the host sends no more of the table, nor Start, but Stop, which tears the root down. The launch then waits for the VM to end, and exits with the new status 6 once the VM ended with a success and a complete teardown; anything else exits 1. Client gains map, which answers a part with a MapReply, and start; failures are an OrderError. Each lives in a module of its own below host (host/map_reply.rs, host/order_error.rs), which re-exports both.

The launch prints build, table, mapped, and sandbox. The step hook's ready step now comes before the table, and commit after Started.

Tests

  • tests/host_session.rs, with the test broker: the order with tables of no mapping, of one, and of several parts, also in 7-byte records; another build and each root failure, after which the host sends nothing more; a table that does not encode, of which nothing is sent; a mapping failed at the first, a middle, and the last part, after which only Stop follows, with and without a teardown failure, and with a session that ends; wrong answers to Maps and Start, and undecodable MapFailed bodies, which end the client.
  • tests/layered_launch.rs: share parsing; the export of a table of shares, its arguments and mapping count; the export that prepare verifies; refusals outside the authorized directories (also through a link on Linux), of reserved targets, of a read-only share inside a read-write one, and of a missing hidden path; a launch with fake artifacts that refuses shares before it creates the store; usage errors.
  • tests/vm_restart.rs: a launch whose guest agent is of another build is torn down, and the next launch claims the scratch image. tests/vm_layered.rs checks the new keys of every launch that starts the sandbox.

Validation

On dev (4c29c1c5, with #872 merged):

  • Linux: the adapter's protocol-only, host-only, and guest-only (static musl) configurations: fmt, clippy, build, tests, MSRV.
  • Windows: the protocol-only and host-only configurations: fmt, clippy, build, tests, MSRV.

On #872's head (e3071ecf), with this PR's files unchanged since:

  • host_session 20 times on Linux and on Windows, without a failure.
  • VM suites (vm_layered 25, vm_restart 3, vm_steps 3): WHP 31/31 and MSHV 31/31. CI runs them on KVM, MSHV, and WHP.
  • By hand on WHP, before the rebase onto dev: a launch with four shares applied all four mappings and started the sandbox; a launch whose mapping the guest refused exited 6 after a graceful stop with success 0, and the next launch started the sandbox.

After the review (e54abbce), which moves code and adds accessors without changing behavior, on Windows: the protocol-only and host-only configurations: fmt, clippy, build, tests, MSRV. The exit statuses' enum follows in #906.

Mapping tables in VMs, with the probes on the host export, follow in PR 8.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-platform host-path authorization and failure-driven VM teardown warrant final human review despite no confirmed defects.

No open issues 🎉

What changed in this PR

Adds the host-side layered-root startup sequence to the runtime adapter, complementing #872’s guest-side work toward #822’s end-to-end cold sandboxes.

Changes:

  • Adds authorized host shares, export validation, and mapping-table configuration.
  • Checks the guest build, sends mapping parts sequentially, and waits for Started before committing; failed mappings trigger teardown.
  • Extends protocol, launch, and VM tests, and documents the new options and lifecycle.
File Description
tests/​runtime-adapter/​tests/​vm_restart.rs Tests build-mismatch teardown and subsequent scratch reuse.
tests/​runtime-adapter/​tests/​vm_layered.rs Checks build, mapping, and sandbox-start output.
tests/​runtime-adapter/​tests/​layered_launch.rs Tests share parsing, authorization, exports, and refusals.
tests/​runtime-adapter/​tests/​host_session.rs Tests startup ordering, mapping replies, and failure handling.
tests/​runtime-adapter/​src/​root.rs Exposes guest-path validation within the crate.
tests/​runtime-adapter/​src/​lib.rs Documents host shares and startup ordering.
tests/​runtime-adapter/​src/​layered.rs Plans authorized exports and attaches them to launches.
tests/​runtime-adapter/​src/​host.rs Adds mapping and start requests with ordered startup handling.
tests/​runtime-adapter/​src/​hook.rs Updates lifecycle step documentation.
tests/​runtime-adapter/​src/​bin/​runtime-adapter-host.rs Integrates share options, startup ordering, and mapping-failure cleanup.
tests/​runtime-adapter/​README.md Documents shares, startup behavior, exit statuses, and tests.

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

Cross-platform filesystem authorization and VM failure cleanup warrant final human review of the implementation and hypervisor validation results.

No open issues 🎉

Review effort: Balanced

Comment thread nvx-rs/src/protocol/export.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-platform filesystem authorization and failure-driven VM teardown warrant human review of the reported validation across KVM, MSHV, and WHP.

No open issues 🎉

Review effort: Balanced

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.

LGTM

Comment thread tests/runtime-adapter/src/bin/runtime-adapter-host.rs
Comment thread tests/runtime-adapter/src/host.rs Outdated
Comment thread tests/runtime-adapter/src/layered.rs Outdated
…rogram

The runtime adapter's host program sent the root configuration, took any
Ready as the guest's readiness, whatever the guest agent's build, and went
on to its exchanges: it shared no host path with the root, sent no mapping
table, and never started the sandbox, so the worker's order had no host
side, and a guest agent of another build than the host ships went on
serving.

launch now takes shares: --share HOST:TARGET[:ro], each a host directory
or file at a guest path in the root; --deny PATH, host paths hidden inside
them; --reserved TARGET, guest trees that the adapter keeps beside the
container root's; and --share-root DIR, the host directories that the
adapter authorizes. The new sharing module holds them as a HostFsSharing
of Shares, neither of which exposes its fields: each field has a getter
and a setter, and each of HostFsSharing's lists a method that adds an
entry, as its option does. HostFsSharing::plan refuses a share outside the
authorized directories, once links are resolved, before it plans the
export with nvx::host::filesystem::plan, and checks the export's
directories and files again. The launch refuses what it cannot export
before it touches the store. LayeredLaunch::share attaches the export,
which LayeredLaunch::export returns, and whose table the root
configuration announces; LayeredLaunch::prepare checks it with
ExportPlan::verify, and OpenVMM's arguments export it, as
ExportPlan::openvmm_arguments renders them.

Once attached, host::ready sends the root configuration and checks that
the Ready names the build that the host ships; a guest agent of another
build gets nothing more, and the launch fails, which ends the VM.
host::start_sandbox then sends the table, each part once the guest applied
the one before, with Client::map, then Start, with Client::start, and
waits for Started; the launch commits only after. A part that the guest
fails ends the order: the host sends no more of the table, nor Start, but
Stop, which tears the root down, then waits for the VM to end, and exits
with 6 once it ended with a success and a complete teardown. The order
fails with an OrderError, and Client::map answers a part with a MapReply,
each in a module of its own below host, which re-exports both. The launch
prints build, table, mapped, and sandbox.

Part of #822.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 04632931-537b-49f9-acc9-b12024ad6f3a

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

Static review identified no blocking issues in share authorization, startup ordering, failure cleanup, or the supporting tests.

No open issues 🎉

Review effort: Balanced

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.

3 participants