Repository navigation
host: delete the old config types and launch paths (SL6.3) - #1530
Pedro Henrique Penna (ppenna) merged 8 commits into
Conversation
This pull request changes existing testsIt modifies or removes 372 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
... and 319 more, which the job's summary lists. Test data
End-to-end tests
Relocated unchanged: 33; added: 45. Compared the merge base |
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues remain for the legacy launch API removal and transition to CLI-owned lifecycle and identity tokens.
No open issues 🎉
What changed in this PR
This PR implements SL6.3 of #1122, advancing #1076’s move toward a smaller NVX library centered on host::vm. It removes obsolete configuration and launch APIs while preserving the current VM launch path.
Changes:
- Removes legacy launch, checked-file handoff, capture-class, and share-rendering code.
- Gives
external-launchits own minimal launcher and switches guest initialization to CLI-owned lifecycle and identity tokens. - Relocates or updates retained tests and documents the path-based image model and retired coverage.
| File | Description |
|---|---|
scripts/test_nvx_tools.py |
Tests new init routing and rejection of obsolete identity tokens. |
scripts/test_microvm_tests.py |
Checks scenarios supply CLI-owned boot tokens. |
scripts/nvx_tools/microvm_tests.py |
Adds identity and lifecycle tokens to direct OpenVMM scenarios. |
nvx-rs/tests/vectors/snapshot-key-v1.txt |
Removes capture-class vectors; preserves key vectors. |
nvx-rs/tests/vectors/README.md |
Documents snapshot-key vectors without capture classes. |
nvx-rs/tests/host_modules.rs |
Removes the deleted supervisor dependency assertion. |
nvx-rs/tests/cli/openvmm.rs |
Replaces deleted rendering helpers with explicit fixture tokens. |
nvx-rs/src/protocol/mod.rs |
Removes the account-token export and narrows workload gating. |
nvx-rs/src/protocol/boot.rs |
Deletes WORKLOAD_ACCOUNT_TOKEN. |
nvx-rs/src/protocol/app.rs |
Makes workload identity crate-private and narrows feature gating. |
nvx-rs/src/host/sys/process.rs |
Deletes descriptor relocation used by checked-file handoff. |
nvx-rs/src/host/sys/mod.rs |
Removes unused identity helpers and descriptor-helper exports. |
nvx-rs/src/host/supervisor/mod.rs |
Deletes the transitional supervisor module. |
nvx-rs/src/host/spawn/tests/linux.rs |
Houses retained Linux inheritance and umask tests. |
nvx-rs/src/host/spawn.rs |
Removes legacy spawn wrappers and narrows remaining types’ visibility. |
nvx-rs/src/host/snapshot/tests.rs |
Builds snapshot fixtures from capture contexts. |
nvx-rs/src/host/snapshot/key.rs |
Removes capture classes and the legacy key constructor. |
nvx-rs/src/host/snapshot/capture/tests.rs |
Uses the shared capture-context fixture. |
nvx-rs/src/host/snapshot/canonical.rs |
Updates module comments to describe key encoding only. |
nvx-rs/src/host/snapshot.rs |
Removes capture-class exports and updates documentation. |
nvx-rs/src/host/session/tests/managed_lifecycle.rs |
Updates a comment to reference vm::spawn. |
nvx-rs/src/host/seal/windows/tests.rs |
Retires tests for deleted final-path handling. |
nvx-rs/src/host/seal/windows.rs |
Deletes Windows final-path resolution helpers. |
nvx-rs/src/host/seal.rs |
Removes the final-path wrapper. |
nvx-rs/src/host/sandbox/scratch/tests.rs |
Checks the Windows claim through its retained field. |
nvx-rs/src/host/sandbox/scratch.rs |
Removes handoff-only accessors and updates claim documentation. |
nvx-rs/src/host/sandbox/options.rs |
Deletes preflight tied to SandboxLaunch. |
nvx-rs/src/host/sandbox/mount/tests.rs |
Retains planning checks while retiring renderer assertions. |
nvx-rs/src/host/sandbox/mount/request.rs |
Deletes the bootstrap-token rendering helper. |
nvx-rs/src/host/sandbox/mount/mod.rs |
Removes renderer exports and obsolete token constants. |
nvx-rs/src/host/sandbox/mount/host_paths.rs |
Allows the CLI-only recheck to be unused without cli. |
nvx-rs/src/host/sandbox/mount/boot.rs |
Removes boot rendering while retaining path-text conversion. |
nvx-rs/src/host/sandbox/mount/aggregate.rs |
Removes legacy aggregate naming and argument rendering. |
nvx-rs/src/host/sandbox/layer.rs |
Updates documentation after BlockRole removal. |
nvx-rs/src/host/sandbox/distro/tests.rs |
Removes the deleted binding-accessor assertion. |
nvx-rs/src/host/sandbox/distro.rs |
Deletes handoff-only fields and accessors. |
nvx-rs/src/host/restore/tests/live_init.rs |
Uses private strict spawning and confirmed cleanup. |
nvx-rs/src/host/restore/tests.rs |
Replaces the deleted spawn helper with test-owned locking. |
nvx-rs/src/host/restore_driver/tests.rs |
Specifies workload identity directly in fixtures. |
nvx-rs/src/host/process.rs |
Removes inherited-handle closure and updates spawn documentation. |
nvx-rs/src/host/platform/windows/tests.rs |
Adapts retained spawn tests and retires handle-closure coverage. |
nvx-rs/src/host/platform/windows/spawn.rs |
Deletes legacy timed termination and annotates CLI-only waiting. |
nvx-rs/src/host/platform/windows/process.rs |
Deletes cross-process inherited-handle closure. |
nvx-rs/src/host/platform/inherit.rs |
Removes generic spawning and descriptor-path APIs; keeps private locking. |
nvx-rs/src/host/mod.rs |
Removes launch and supervisor modules and updates module documentation. |
nvx-rs/src/host/config/tests.rs |
Checks rendered configuration directly instead of comparing legacy launches. |
nvx-rs/src/host/config/mod.rs |
Updates legacy comments and annotates a CLI-only check. |
nvx-rs/src/host/cli/store/tests/recovery.rs |
Adapts recovery fixtures to private spawning. |
nvx-rs/src/host/cli/store/tests/liveness.rs |
Adapts liveness fixtures to private spawning. |
nvx-rs/src/host/cli/snapshots/capture/tests.rs |
Uses capture contexts and private spawn fixtures. |
nvx-rs/src/host/cli/sandbox/state.rs |
Removes legacy-plan comparisons from documentation. |
nvx-rs/examples/external-launch.rs |
Adds a minimal caller-owned launcher and process identity capture. |
guest/common/init |
Stops reading obsolete tokens and routes layered roots to nvx-init. |
doc/project-structure.md |
Documents current init routing and inactive legacy scripts. |
doc/design/5.1-boot-protocol.md |
Documents CLI-owned identity and lifecycle tokens. |
doc/design/4.2-guest-agents-and-workload-model.md |
Describes nvx-init as the layered-root init. |
doc/acceptance-case-matrix.md |
Records retired handoff coverage and updated test locations. |
Review effort: Balanced
de3c4bc to
93469a4
Compare
c04cd8a to
604d8da
Compare
93469a4 to
b06d52f
Compare
The external-launch example handed the command that vm::create prepares to host::supervisor::spawn_vm, the strict low-level spawn that SL6.1 left public only as a transitional path. SL6.3 deletes that path, and as SL2.8b designed it, the caller of vm::create supplies its own spawn: the library keeps no public low-level spawn besides vm::spawn. The example now starts the VMM with a minimal launcher of its own, on std::process: it writes the capability into a pipe that it closes to writers before the spawn, gives the VMM that pipe as its standard input and the log as its standard output and error, holds the process through a ProcessRef and Process::open, and kills and reaps it if anything fails once it runs. It reads the ProcessRef's start time itself, as ProcessRef defines it: the starttime field of /proc/<pid>/stat on Linux, and the process's creation time on Windows. So it uses nothing of host::platform, which SL6.14 makes crate-private, and takes Transport from host::transport, which re-exports it. Its docs list what it leaves out of the launch contract of vm::VmmCommand, which a production launcher adds, as vm::spawn does: it passes no descriptor or handle besides the standard streams, and refuses a command that allows any; on Linux it starts the VMM in a process group of its own, but not in a new session, and leaves the caller's umask; on Windows it starts the VMM without a console, but with every inheritable handle of the caller and in no log-named job. The README's description of the example, and its row in the case matrix, which stays kept, say so. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A PreparedLaunch handed OpenVMM the files that the checks of a plan's images opened: /proc/self/fd/N on Linux, which the VMM inherited through the supervisor's allowlist, and on Windows the checked files' final paths, which their handles held, and which PreparedLaunch::release closed in the VMM through ProcessHandle::close_inherited. No launch uses it any more: the CLI's start and run name their images by path in the VM's configuration, and pass the VMM only the scratch image's claim, through Prepared::inherit. So the prepared launch goes: host::sandbox::prepared and PreparedLaunch, with PreparedLaunch::adapter_arguments, and the checked-file handoff that only it used: Inherited::proc_path and the crate-private Process::close_inherited and ProcessHandle::close_inherited of Windows. The crate-private code that only they used goes too: move_above_standard_streams on Linux, seal::final_path on Windows, and the file_mut of CheckedDistro and CheckedScratch, and CheckedDistro's bound(), whose identity field then went unread. CheckedScratch::claim, which only the CLI reads now, as it hands the claim to the VMM, is gated by cli, and the claim's field, which holds the claim whoever reads it, is allowed to go unread without cli. The docs say what stays: a launch names its images by path, so what takes an image's path after its check is what OpenVMM opens, and callers stage their images in a directory that only their own account can write, as the docs of distro, scratch and seal require, so that no other account can replace a checked image. The README's "Checked handoff" section becomes "Images by path", and the claims of the scratch image no longer say that the VMM opens /proc/self/fd/N or that a release closes its copies. Tests: the handoff's cases retire with it: the 4 cases of tests/checked_handoff.rs that hand a prepared launch's images to a VMM fixture, with their launcher fixture and helpers; the 10 unit tests of host::sandbox::prepared; the Windows platform's a_child_loses_only_the_inherited_handle_that_is_closed_in_it, the test of close_inherited; and seal's final_paths_hold_no_nul_whatever_their _length, the test of final_path. checked_handoff.rs keeps its 2 cases of the spawn that stays, a wait's exit status and the strict cleanup, which SL6.3 moves to their owner with the supervisor. The test of the spawn's allowed descriptors no longer checks proc_path, and the test of a GPT binding's check no longer checks bound(). The case matrix retires the doc test of PreparedLaunch and the adapter's scenario images_replaced_after_the_checks_never_reach_the_vm, and stops naming the deleted handoff test as coverage of a_layered_launch_hands_openvmm_the_checked_images. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`host::supervisor` re-exported the low-level spawn of a VMM, `spawn`, `spawn_vm`, `VmmCommand`, `Launched` and `Inherited`, and `spawn_command`, for the code that still used them after SL6.1: the `external-launch` example, which now launches its VMM with a launcher of its own, and the tests of the spawn in `tests/supervisor.rs` and `tests/checked_handoff.rs`. `host::vm` spawns VMMs. The module goes, with what only it made public or used: - `spawn`, the spawn without the strict log job, `spawn_vm`, its strict twin, and `VmmCommand::new`. `vm::spawn` keeps the strict spawn, `spawn_vm_with_mode`, which takes their documentation, and builds its command whole. - `Launched::kill_and_wait`, the legacy time-bounded cleanup, with the Windows `LaunchedProcess::terminate` that only it called. `kill_and_confirm_exit` stays. - `spawn_command`, which spawned a `std::process::Command` under the crate's spawn lock. The tests spawn theirs with `spawn_locked`. `VmmCommand`, `Launched` and `Inherited` become crate-private. What only the CLI's one-shot runs use outside the tests, `Launched::wait_timeout` with its reaping and status helpers, the Windows `LaunchedProcess::wait_timeout`, and `KILL_TIMEOUT`, carries an `allow(dead_code)` for builds without the `cli` feature, as do the spawn lock outside Windows, which only the tests take there, and `VmmCommand::breakaway_from_job`, which only Windows reads. Tests move to the owners of the code that they test: - `tests/supervisor.rs` becomes `tests/process.rs`, with its seven tests of `nvx::host::process`, whose processes a fixture of its own starts through `std::process` now: `processes_can_be_shared_between_threads`, `a_child_that_exits_wakes_its_waiter`, `a_process_that_is_not_a_child_wakes_its_waiters`, `a_reused_process_id_is_never_signaled`, `references_that_name_no_process_are_never_opened`, and on Windows `a_process_that_this_user_may_not_query_has_an_unknown_state` and `a_process_that_this_user_may_not_terminate_is_waited_for_but_never_signaled`. - Its four tests of the spawn, `working_directory_limits_include_trailing_separators` (Windows), `a_restarted_launcher_finds_its_vmm_again_and_ends_it`, `vmms_inherit_only_their_streams_and_allowed_descriptors_while_others_spawn` and `a_job_that_ends_its_vmm_wakes_the_waiters` (Windows), and the two of `tests/checked_handoff.rs`, `launched_waits_return_and_retain_the_actual_exit_status` and `strict_cleanup_terminates_and_confirms_a_running_child`, move to the spawn's unit tests, `src/host/spawn/tests.rs`, which now build on Linux and Windows, with one VMM fixture for the two files' fixtures, and the launcher fixture. The spawn's Linux tests move to `src/host/spawn/tests/linux.rs`, unchanged but for the strict spawn. - In the unit tests, which run beside hundreds of others, the check that a process that `std::process` spawns while VMMs spawn holds none of their descriptors looks again until the objects are gone or a second passes. The kernel wakes `posix_spawn`'s parent before the child's exec closes its close-on-exec descriptors, so for an instant the child's table still lists every descriptor of the parent, which the busier process made the check see as a leak. - The tests that spawned through the old paths spawn through `spawn_vm_with_mode`, and end their children with `kill_and_confirm_exit` or `terminate_and_wait`. The Windows test of a log that is no file of a disk volume keeps its refusal by the strict spawn and loses the start without a job that only `spawn` made, as `a_vmm_whose_log_is_no_file_of_a_disk_volume_is_refused`. `the_graph_holds_well_known_dependencies_of_the_sources` loses the edge from `supervisor` to `spawn`. Docs: the README loses the module's row and section; the `nvx::host::vm` section takes its notes on the umask and the working-directory limit, and names the spawn's tests. The case matrix's row of the module's doc test says where its tests went. The public-API snapshots lose the module. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`CaptureClass`, the invariant inputs of a template's capture that an adapter requested, with its canonical encoding and `ClassIdentity`, and `SnapshotKey::new`, which derived a key from a class and its capture's manifest, served only the old capture path and the tests. A capture's key comes from its `CaptureContext`, which `vm::create` prepares and `finish_capture` reads, through `SnapshotKey::from_capture`. The class goes, with its identity and its domain, and the import of `PROCESSOR_COUNTS` that only its check used. The docs of the key, of its canonical encoding, and of the snapshot module no longer name a class. Tests: - The snapshot fixtures `class()` and `network_class()` become `context()` and `network_context()`, the contexts of the same captures, and build their keys with `from_capture`; the fixtures of the capture and restore tests take them. - The key's tests derive their keys from contexts, through `from_capture`, and change the contexts where they changed the class: `each_part_of_the_key_changes_it`, `a_generations_own_metadata_leaves_the_key_as_it_is`, `complete_capture_time_round_trips_without_changing_compatibility_identity`, `a_key_holds_what_its_capture_made`, `a_capture_that_does_not_match_its_class_is_refused`, which loses the case of a network whose policy attaches no NIC, since a context holds the NIC itself, `a_class_selects_a_profile_as_openvmm_does`, `keys_read_back_from_their_canonical_encoding`, `keys_with_the_removed_guest_build_field_are_refused`, `a_key_that_holds_its_network_s_lowering_after_its_invariants_is_refused`, `keys_of_machines_that_no_manifest_describes_are_refused`, and `the_conformance_vectors_decode_and_encode`, which loses the class vectors. - `invalid_classes_are_refused` becomes `captures_of_invalid_contexts_are_refused`: the same invalid inputs, which `from_capture` refuses with the messages of the context's checks. - Retired with the class: `the_guest_build_is_not_part_of_a_snapshot_key` and `each_field_of_a_class_changes_its_identity`, and the class's part of `identities_have_a_text_form`. - `tests/vectors/snapshot-key-v1.txt` loses its `CLASS` vectors; its `KEY` vectors do not change. Docs: the README's snapshot section and the vectors' README describe the key alone. The public-API snapshots lose the class. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`SandboxPlan`, the typed plan of a cold layered launch, with its `SandboxDistro`, `SandboxUpper`, `SandboxNetwork`, `BlockRole` and persistable form, and `SandboxLaunch` and `SandboxSettings`, the launch of `nvx-rs sandbox` that made such a plan, served only the old launch path and the tests: the CLI checks and launches a sandbox through its `VmConfig`, and checks the command line that it launches since SL6.0f. They go, with `PLAN_VERSION`, the profile's `KERNEL_COMMAND_LINE_MAX_SIZE`, `OPENVMM_COMMAND_LINE_RESERVE` and `SANDBOX_COMMAND_LINE_MAX_SIZE`, the workload limits (`PIDS_MAX_LIMIT` and the settings' checks), and `options::validate_sandbox_systemd_policy`, the preflight of a `SandboxLaunch`, whose two checks, `validate_sandbox_entrypoint` and `DistroBinding::verify`, the CLI calls itself. The boot rendering of shares goes too: `BootShares`, `boot_shares`, `aggregate_share_tokens`, `aggregate_command_line_fragment`, `export_command_line_fragment`, `aggregate_child_name`, `aggregate_child_argument`, `mount_argument`, and the private `command_line_fragment` and bootstrap-token constants of `mount`. `plan_mounts`, `plan_mounts_with` and `path_text` stay for What only the CLI uses now allows `dead_code` without the `cli` feature, as `spawn` does: `mount::check_distinct_export_roots` and its re-export beside `HostQueries`, and `config::reject_container_path`. Tests: - `host::sandbox`'s own tests retire the plan's and the launch's cases: `launch_contract_builds_agent_command_line`, `launch_contract_rejects_duplicates_and_reserved_tokens`, `launch_settings_are_checked_in_order`, `launch_rejects_limits_the_guest_cgroup_cannot_store`, `launch_contract_attaches_mount_and_reserves_bootstrap_tokens`, `launch_contract_attaches_several_shares_as_an_aggregate`, `launch_bounds_shares_by_the_kernel_command_line` and `launch_contract_rejects_disk_option_delimiters_and_unbalanced_brackets`, whose refusal `config`'s tests and `tests/cli/validation.rs` keep. `launch_contract_attaches_a_file_as_an_aggregate_child` becomes `file_shares_take_no_policy_paths_or_reserved_targets`, its checks of shares without the rendering, and `launch_validation_requires_the_layers_and_the_scratch_image` becomes `missing_files_are_named_with_their_components_alone`, its check of `require_file`. The share checks plan their shares with `plan_mounts` and check the plan again as a start does, with `check_distinct_export_roots` and `ExportPlan::verify`: `launch_validation_rejects_overlapping_or_foreign_host_paths`, `shares_that_only_a_verbatim_path_names_are_refused`, `launch_validation_rejects_shares_that_came_to_overlap` and `launch_validation_requires_plain_mount_directory`. The fixtures `exported`, `deny`, `with_export` and `distro` go; `host_text` is Windows-only. - The specification tests retire `aggregate_child_name_known_answer`, `launch_arguments_follow_the_openvmm_contract`, `accepted_launch_shapes_keep_their_arguments_and_kernel_tokens`, `shares_follow_the_openvmm_and_guest_contracts`, `launch_settings_follow_the_guest_contract`, `caller_parameters_follow_linux_and_guest_rules`, `aggregate_child_names_follow_the_restore_contract`, `kernel_command_line_stays_within_1024_bytes` and `reserved_kernel_tokens_are_always_refused`, which the CLI's tests of the command line that it launches cover. `layer_values_are_role_path_uuid`, `kernel_token_values_refuse_separators`, `the_reproduction_of_microsoft_nvx_723_is_refused` and `accepted_values_stay_one_kernel_parameter` keep their checks of layers and targets, and `canonical_layer_uuids_reach_the_guest` becomes `canonical_layer_uuids_round_trip`. - The share tests retire `aggregate_child_names_pin_their_targets` and `boot_tokens_refuse_what_the_shell_cannot_bind`, and drop the boot rendering from `mount_parser_defaults_to_read_only_and_accepts_rw`, `mount_parser_accepts_host_paths_with_commas`, `mount_owner_defaults_to_vmm_and_forwards_caller`, `mount_access_policy_is_validated_and_forwarded` and `shares_are_planned_through_the_export_planner`. - The option tests' preflight calls `validate_sandbox_entrypoint` and `DistroBinding::verify`, as the CLI does, in `distro_manifest_binds_the_layer`, `systemd_entrypoints_and_images_are_refused_independently`, `sandbox_allows_non_systemd_sbin_init`, `the_entrypoint_check_needs_no_manifest_and_precedes_the_distro_verification`, `sandbox_rejects_systemd_from_bound_distro_metadata` and `distro_manifests_are_strict_json`. Their shares give the export plan's OpenVMM arguments and kernel token, which `sandbox_command_shares_a_file` and `sandbox_command_attributes_mount_deny_to_the_preceding_mount` check. - `cold_command_lines_keep_the_old_root_view_and_mapping_values` compared a configuration's command line with those of `LaunchSpec` and `SandboxPlan`. As `cold_command_lines_carry_the_root_the_view_and_the_mapping_count`, it checks the line against the configuration: the root's image and upper beside its other tokens, the view, and the mapping count. - `tests/cli/openvmm.rs`'s `two_share_command_line_room` spells the tokens that OpenVMM appends for the shares. Docs: the README's sandbox section and module row, "Images by path", "Sandbox input contract", which describes the CLI's check of the command line, and "Specification tests"; the case matrix row that named the config test; the docs of `layer`, `mount`, the CLI's sandbox state and the snapshot key. The public-API snapshots lose the deleted items. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`host::launch`, the OpenVMM command line of a managed microVM that a `LaunchSpec` described, with `VmmLaunch`, the inputs that it shared with an adapter's launch, served only the old launch path and the tests: `VmConfig` and `vm::create` render and check every launch, and the CLI renders the guest's tokens. The module goes whole: `LaunchSpec` with `check`, `kernel_command_line`, `openvmm_arguments`, `vmm_launch` and `check_process_command_line`; `VmmLaunch` with `RESERVE` and `arguments`; `WorkloadIdentity`'s `DEFAULT` and `select`; `MAX_TIMEOUT`, `DEFAULT_MEMORY_MIB`, `DEFAULT_HOSTNAME`, `base_command_line`, `kernel_parameters_problem` and `timeout_problem`; and its re-exports of `host::config`'s `COMMAND_LINE_BUDGET`, `DEFAULT_GUEST_NETWORK` and Windows command-line helpers, which stay in `host::config`, as `OPENVMM_COMMAND_LINE_RESERVE` does for `VmConfig::check_command_line`. `protocol::WORKLOAD_ACCOUNT_TOKEN`, which only `LaunchSpec` rendered, goes too; the fake OpenVMM spells the token itself. What the deletion leaves unused goes with it: `host::sys::effective_ids`, which only `WorkloadIdentity::select` called. `protocol`'s `WorkloadIdentity`, which activation payloads carry, was public only through `host::launch`, so it becomes `pub(crate)`, and `protocol` re-exports its module only for the CLI and the guest, its remaining users. Tests: `host::launch`'s tests retire with it: `kernel_command_line_sets_the_hostname`, `arguments_select_the_managed_direct_guest`, `mappings_add_the_export_and_the_mapping_count`, `oversized_process_command_lines_are_rejected`, `launches_may_use_the_reserve_that_provisioning_keeps`, `every_launch_names_its_own_inputs_alike`, `the_reserve_of_a_plan_holds_the_rest_of_a_launch_of_inputs_of_max_path`, `kernel_parameters_are_checked`, `kernel_parameters_are_read_as_the_kernel_reads_them`, `reserved_parameters_are_refused_whatever_separates_them`, `the_kernel_reads_the_hostname_after_accepted_parameters`, `every_command_line_checks_the_specification`, `timeouts_are_bounded` and `workloads_that_map_host_paths_take_the_host_identity`. `config`'s tests keep checking the Windows command-line helpers. The restore driver's test workload spells the identity that `DEFAULT` named. Docs: the README loses `host::launch`'s section and module row, and `host::config`'s part says what the helpers count; the docs of the reserve and of `boot_arguments` no longer name the old planning. The public-API snapshots lose the module and the token. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The shell `/init` read the tokens that OpenVMM appends for its `--microvm-lifecycle` and `--microvm-workload-identity` options, `nvx_lifecycle=`, `nvx_workload_uid=` and `nvx_workload_gid=`, beside the CLI's own, `nvx_mode=` and `nvx_identity=`, and handed a layered root whose command line held `nvx_lifecycle=` to the older init agent, `nvx-init-agent`. Since the old launch paths are gone, no launch of NVX gives those tokens: the CLI names the lifecycle and the identity with its own. The init no longer reads the three tokens, and starts `nvx-init` for every layered root, whose `nvx_exec=` it no longer runs either, as it did not for a layered root without the token. A blockless guest takes its lifecycle from `nvx_mode=` and its workload identity from `nvx_identity=` alone. The `workload-identity` and `managed-lifecycle` scenarios start OpenVMM directly, with its options, which OpenVMM itself checks: they now also give the CLI's tokens, `nvx_identity=` for each identity, and `nvx_mode=managed nvx_identity=65534:65534`, so that the guest's init selects what OpenVMM's options did. Tests: - `test_old_lifecycle_tokens_keep_the_old_layered_init` becomes `test_old_lifecycle_tokens_no_longer_select_the_old_layered_init`: the same layered roots start `nvx-init`. - `test_old_workload_identity_tokens_name_no_identity` checks that a one-shot workload named only by `nvx_workload_uid=` and `nvx_workload_gid=` has no identity. - `test_exec_override_cannot_bypass_the_new_sandbox_init` and `test_missing_helpers_or_selected_init_fail_without_fallback` expect `nvx-init` for a layered root with `nvx_lifecycle=managed`, and its failure when it is missing. - The scenarios' unit tests, `test_workload_identity_scenario_checks_enforcement_and_rejection` and `test_managed_lifecycle_runs_the_nvx_rs_test_and_checks_what_it_leaves`, check the CLI's tokens on the command line. Docs: the boot protocol says that `/init` ignores OpenVMM's identity and lifecycle tokens, the guest-agent design that a layered root runs `nvx-init`, and the project structure what `init` starts and that it no longer starts the older sandbox scripts. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Since the shell /init stopped reading OpenVMM's lifecycle and workload tokens, OpenVMM's --microvm-workload-identity no longer names the identity of a guest's workload, and a guest ignored it. OpenVMM's documentation of that option asks the guest to fail closed when it cannot apply the identity. So /init fails closed. When the command line has OpenVMM's nvx_workload_uid= or nvx_workload_gid=, a boot goes on only if nvx_identity= names the same UID and GID. Otherwise /init stops with NVX-WORKLOAD-ERROR and status 125 before it starts anything: an nvx_exec= program, a one-shot or managed workload, the shares, or nvx-init. It recognizes the two tokens only to refuse a mismatch: it still takes the identity from nvx_identity= alone, and still ignores nvx_lifecycle=. NVX's own launches don't change: the CLI and the library pass no OpenVMM identity, and the scenarios that pass one also pass the same nvx_identity=. A caller that launches OpenVMM directly with --microvm-workload-identity adds nvx_identity= with the same identity to its command line. Docs: the boot protocol (5.1) says that /init fails closed on OpenVMM's identity tokens, and the machine model (2.1.2) that NVX's launchers name the workload identity and lifecycle with tokens of their own, which the machine profile's tokens no longer select. The case matrix's row of workload-identity names its new checks. Tests: GuestInitRoutingTests' test_old_workload_identity_tokens_name_no_identity becomes test_openvmm_workload_identity_needs_the_same_nvx_identity, which refuses OpenVMM's identity without nvx_identity=, with its UID alone, and with another nvx_identity=, on the nvx_exec, one-shot, managed and sandbox routes, before anything starts, and lets the same identity boot on. The workload-identity scenario boots twice more, with OpenVMM's identity and no nvx_identity=, and with an nvx_identity= of another identity, and requires both to fail closed with the refusal; its unit tests check those boots, and that a guest that runs either fails the scenario. Part of #1122 (SL6.3). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
604d8da to
c5d2ee8
Compare
9b8f35e
into
feature/nvx-refactor
Leaving code only. This PR changes only code that this effort removes from NVX: the old config types (
LaunchSpec,SandboxPlan,SandboxLaunch,SandboxSettings,SandboxNetwork,CaptureClass), the rest ofhost::launch, the prepared launch and its checked-file handoff, the transitionalhost::supervisorwithspawn_command, the boot rendering of shares,WORKLOAD_ACCOUNT_TOKEN, and the shell/init's reading of OpenVMM's lifecycle and workload tokens, with the crate-private code that only they used and the edits that remove references to them. Nothing that stays changes, and no later PR uses what it changes, so the size limits for kept code don't apply.Beyond what leaves, it carries out the decisions that the orchestrator made for Pedro Henrique Penna (@ppenna) on #1122 (D1 to D6): the
external-launchexample starts its VMM with a minimal launcher of its own (D1); theworkload-identityandmanaged-lifecyclescenarios also give the CLI's tokens (D5); the shell/initfails closed when OpenVMM's workload identity and NVX'snvx_identity=disagree, or NVX's is missing (decided for Pedro Henrique Penna (@ppenna) on #1122 after review); and the tests of code that stays move out of the deleted test files to the owners of that code. What only the CLI uses now allows dead code without theclifeature, ashost::spawndoes.Part of #1122 (SL6.3, "The old config types are gone"). Umbrella #1076.
Based on
feature/nvx-refactor230a1b0877d, which holds SL6.0f (#1526, merged): the CLI checks the command line that it launches there, so this PR deletes the old types whole (D2, D3). SL6.3 was built on SL6.1's branch (#1520,5bffcd7f), then stacked on #1526; since both merged, its 7 commits are rebased on230a1b0877d, where only the case matrix conflicted (the line oflib.rs's doc test, now 57, and the Docs counts, now 36, 25, 3 and 8, beside the rows of SL6.11a and SL6.11c), and an eighth commit adds the fail-closed check.What and why
SL6.1 (#1520) left the old launch path without callers: the CLI's
sandbox startandrunname their images by path in aVmConfig,vm::createandvm::spawnlaunch every VM, and since SL6.0f the CLI checks the command line that it launches. What remained of the old path served only itself, the transitionalhost::supervisorre-exports and the tests. The commits, in order (consumers before providers):7c967b7fcd2examples: launch the external-launch VM with a launcher of its own (D1). The example handedvm::create's command tosupervisor::spawn_vm. It now starts the VMM onstd::process: the capability through a pipe closed to writers before the spawn, the log as standard output and error, a process group of its own, and on Windows no console and the command's breakaway flag. It holds the VMM through aProcessRefwhose start time it reads itself, asProcessRefdefines it (thestarttimefield of/proc/<pid>/staton Linux, the creation time on Windows), and takesTransportfromhost::transport, so it uses nothing ofhost::platform, which SL6.14 (host: make the platform layer private to nvx (SL6.14) #1529) makes crate-private. Its docs list what it leaves out, which a production launcher adds, asvm::spawndoes: it passes no descriptor or handle besides the standard streams (and refuses a command that allows any); on Linux no new session and the caller's umask; on Windows every inheritable handle of the caller and no log-named job. No public API is added.313b00b2681host: delete the prepared launch and its checked-file handoff.host::sandbox::prepared(PreparedLaunch, withadapter_arguments),Inherited::proc_path, WindowsProcess::close_inheritedandProcessHandle::close_inherited, and what only they used: Linuxmove_above_standard_streams, Windowsseal::final_path,CheckedDistro's andCheckedScratch'sfile_mut, andCheckedDistro::bound.CheckedScratch::claim, which only the CLI reads, is gated bycli. The README's "Checked handoff" section becomes "Images by path" (D6, below).d4459183915host: delete the transitional supervisor path of the spawn.host::supervisorgoes whole, withspawn,spawn_vm,VmmCommand::new,Launched::kill_and_waitwith the WindowsLaunchedProcess::terminatethat only it called, andspawn_command.VmmCommand,LaunchedandInheritedbecome crate-private;spawn_vm_with_modetakes their docs. The spawn lock and the termination after a failed spawn stay, asvm::spawn's private foreground mode does (D4:inherit_only,SpawnMode::Foreground, WindowsLaunchedProcess::wait_timeout).2853ff49c4fhost: delete the capture class.CaptureClass,ClassIdentity, its domain andSnapshotKey::new; a key comes from itsCaptureContextthroughSnapshotKey::from_capture. The conformance vectors lose theirCLASSlines; theKEYvectors don't change.11ac217c9b0host: delete the old sandbox plan and launch.host::sandbox::plan(SandboxPlan,SandboxDistro,SandboxUpper,SandboxNetwork,BlockRole,PLAN_VERSION),SandboxLaunch,SandboxSettings, the profile'sKERNEL_COMMAND_LINE_MAX_SIZE,OPENVMM_COMMAND_LINE_RESERVEandSANDBOX_COMMAND_LINE_MAX_SIZE, the workload limits,options::validate_sandbox_systemd_policy, and the boot rendering of shares:BootShares,boot_shares,aggregate_share_tokens,aggregate_command_line_fragment,export_command_line_fragment,aggregate_child_name,aggregate_child_argumentandmount_argument.plan_mounts,plan_mounts_withandpath_textstay for nvx-rs slimming 4.3.1: image staging, artifact discovery, the policy-file reader and the mount syntax are private to the CLI #1124, at their owners.83b4141a789host: delete the old launch.host::launchgoes whole:LaunchSpec,VmmLaunchwithRESERVEandarguments,WorkloadIdentity'sDEFAULTandselect,MAX_TIMEOUT,DEFAULT_MEMORY_MIB,DEFAULT_HOSTNAME,base_command_line,kernel_parameters_problem,timeout_problem,check_process_command_line, and its re-exports ofhost::config's helpers, which stay there withCOMMAND_LINE_BUDGET,DEFAULT_GUEST_NETWORK,OPENVMM_COMMAND_LINE_RESERVEandVmConfig::check_command_line, unchanged.protocol::WORKLOAD_ACCOUNT_TOKENgoes; the fake OpenVMM spells its own.3e30b910961guest: stop reading OpenVMM's lifecycle tokens in the shell init.guest/common/initno longer readsnvx_lifecycle=,nvx_workload_uid=ornvx_workload_gid=, and startsnvx-initfor every layered root instead of handing one withnvx_lifecycle=tonvx-init-agent. A blockless guest takes its lifecycle fromnvx_mode=and its identity fromnvx_identity=alone. Theworkload-identityandmanaged-lifecyclescenarios, which start OpenVMM directly, keep OpenVMM's--microvm-workload-identityand--microvm-lifecycle, which OpenVMM itself checks, and also give the CLI'snvx_identity=andnvx_mode=managed(D5). No NVX launch passes OpenVMM's options any more: the old launch paths are gone.c5d2ee8d0b7guest: fail closed on OpenVMM's workload identity without nvx_identity. When the command line has OpenVMM'snvx_workload_uid=ornvx_workload_gid=, which--microvm-workload-identityappends,/initboots on only ifnvx_identity=names the same UID and GID; otherwise it stops withNVX-WORKLOAD-ERRORand status 125 before it starts anything: annvx_exec=program, a one-shot or managed workload, the shares ornvx-init. So the guest fails closed when OpenVMM's identity and NVX's disagree, or NVX's is missing, as OpenVMM's documentation of--microvm-workload-identityasks of a guest that cannot apply it./initrecognizes the two tokens only to refuse a mismatch: it still takes the identity fromnvx_identity=alone, and still ignoresnvx_lifecycle=. NVX's own launches don't change: the CLI and the library pass no OpenVMM identity, and the scenarios that pass one also pass the samenvx_identity=. Theworkload-identityscenario boots twice more, with OpenVMM's identity and nonvx_identity=, and with annvx_identity=of another identity, and requires both to fail closed. The boot protocol (5.1) and the machine model (2.1.2) say so; 2.1.2 still said that the machine profile's tokens name the workload identity and lifecycle.Breaking change, for #1131's migration notes (SL6.10h). NVX's guests take the workload identity and lifecycle only from
nvx_identity=UID:GIDandnvx_mode=one-shotornvx_mode=managedon the kernel command line. A caller that launches OpenVMM directly with--microvm-workload-identityor--microvm-lifecyclealso gives these tokens in--cmdline, with the same identity: a boot with OpenVMM's identity and nonvx_identity=, or another one, now fails closed withNVX-WORKLOAD-ERRORand status 125. The CLI and the library pass neither OpenVMM option, so their launches don't change.Public API. The snapshots lose 231 items on Linux and 230 on Windows, and gain none: the modules
host::launch,host::supervisor,host::sandbox::planandhost::sandbox::prepared, the plan's re-exports fromhost::sandbox, the boot rendering ofhost::sandbox::mount,options::validate_sandbox_systemd_policy,CaptureClass,ClassIdentityandSnapshotKey::new, andprotocol::WORKLOAD_ACCOUNT_TOKEN.protocol'sWorkloadIdentity, which activation payloads carry and which was public only throughhost::launch, becomespub(crate).Crate-private code that the deletions leave unused, as warning-denied builds of every feature set find it on Linux and Windows, goes:
move_above_standard_streams(Linux),seal::final_path(Windows),CheckedDistro::file_mutandbound,CheckedScratch::file_mut,Process::close_inheritedandProcessHandle::close_inherited(Windows),LaunchedProcess::terminate(Windows),host::sys::effective_ids, andmount::request::command_line_fragmentwith the bootstrap-token constants ofmount. What only the CLI uses now allows dead code withoutcli, with a reason, ashost::spawndoes:host::process::KILL_TIMEOUT,Launched::wait_timeoutand its reaping and status helpers, WindowsLaunchedProcess::wait_timeout,CheckedScratch's claim (its field, and Windows'claim(), which only the CLI calls),mount::check_distinct_export_rootsand its re-export besideHostQueries, andconfig::reject_container_path; outside Windows, the spawn lock, which only the tests take there, andVmmCommand::breakaway_from_job, which only Windows reads.protocolre-exports itsworkloadmodule only for the CLI and the guest.The by-path model (D6, Pedro Henrique Penna (@ppenna)'s note on #1122)
Confirmed as the intended model: a launch names its images by path. The checks,
DistroBinding::checkandScratchBinding::check, find a staged image unchanged from its metadata alone and return it open, but what takes an image's path after its check is what OpenVMM opens. The docs ofhost::sandbox::distro,host::sandbox::scratchandhost::sealrequire callers to stage their images in a directory that only their own account can write, so no other account can replace a checked path. On Windows, a held checked distro layer also denies other opens for writing or deleting it, and the scratch image's guard denies deleting and renaming it; the VMM inherits the scratch claim. SL5.1a's security checklist checks the precondition (tests/security_checklist.rs::a_staged_image_that_was_replaced_fails_its_check). The README's "Images by path" section states it, and the case matrix retiresimages_replaced_after_the_checks_never_reach_the_vmunder it and dropschecked_handoff.rsfrom the coverage ofa_layered_launch_hands_openvmm_the_checked_images.Every removed test, and its fate
python scripts/check_test_changes.py --base origin/feature/nvx-refactor(230a1b0877d) reports 372 changes to existing tests: 78 removed tests, 76 modified tests, 96 removed and 92 modified helpers, and imports, attributes and modules; 33 tests relocate unchanged and 45 are added (moved, renamed or new). No removed test is named in the case matrix, as coverage or otherwise (git grepof each name), but for the doc test ofPreparedLaunchand the module doc test ofhost::supervisor, whose rows say where their coverage went. The fates, by deleted code:host::launch: 14 retirekernel_command_line_sets_the_hostname,arguments_select_the_managed_direct_guest,mappings_add_the_export_and_the_mapping_count,oversized_process_command_lines_are_rejected,launches_may_use_the_reserve_that_provisioning_keeps,every_launch_names_its_own_inputs_alike,the_reserve_of_a_plan_holds_the_rest_of_a_launch_of_inputs_of_max_path,kernel_parameters_are_checked,kernel_parameters_are_read_as_the_kernel_reads_them,reserved_parameters_are_refused_whatever_separates_them,the_kernel_reads_the_hostname_after_accepted_parameters,every_command_line_checks_the_specification,timeouts_are_bounded,workloads_that_map_host_paths_take_the_host_identity. The helpers that stay keep their tests inhost::config:process_command_lines_are_measured_as_windows_quotes_them,a_process_command_line_fits_while_it_leaves_its_reserveandconfiguration_command_lines_keep_the_same_reserve_on_every_host, withvm::tests::creation_checks_the_complete_actual_command_line_at_the_windows_boundary.host::sandbox::plan: 23 retireadapter_launches_are_planned_with_room_for_the_rest_of_the_launch,adapter_plans_persist_without_settings_or_an_export,adapter_plans_refuse_the_settings_of_their_root_that_they_do_not_name,adapter_plans_refuse_what_their_root_and_openvmm_own,adapter_plans_render_their_root_and_devices_alone,every_format_and_upper_plans_and_renders,launches_carry_their_network_into_their_plans,launches_plan_the_image_that_the_binding_of_their_distro_layer_records,launches_plan_their_distro_layer_over_ram,launches_plan_their_distro_layer_over_their_scratch_image,networks_check_their_guest_network_and_their_policy,persisted_plans_that_break_the_form_or_the_checks_are_refused,plans_check_the_images_of_their_block_devices_against_the_host,plans_check_their_export_plan_for_the_container_root,plans_check_their_settings_as_launches_do,plans_persist_in_their_versioned_form,plans_refuse_the_command_lines_that_the_guest_refuses,plans_refuse_the_tokens_that_the_guest_init_reads_in_quoted_values,plans_render_and_report_their_network,plans_require_properly_nested_disk_path_brackets,the_guest_reads_the_root_of_every_plan_from_its_command_line,the_longest_boot_tokens_fit_the_command_line_budget_to_the_byte,the_managed_lifecycle_exports_the_shares_and_announces_their_mapping_table. What stays of their checks is tested where it lives now: the CLI's command line instarts_check_the_kernel_command_line_that_they_launchandcold_share_command_lines_fit_the_kernel_budget_to_the_byte(SL6.0f), the rendering of roots, networks and exports inhost::config'scold_boot_arguments_*tests, the disk paths incold_boot_arguments_refuse_disk_syntax_in_image_and_scratch_pathsandtests/cli/validation.rs, and the proxy's URL innetwork::tests::proxy_urls_name_the_gateway_as_the_guest_sees_it.host::sandbox::preparedand the checked-file handoff: 16 retire, 2 moveThe 10 unit tests of
prepared:a_release_through_a_process_that_inherited_nothing_closes_none_of_its_handles,an_adapter_s_launch_renders_complete_arguments_that_fit_a_command_line,an_upper_in_ram_takes_no_scratch_image,gpt_disks_are_prepared_from_their_bindings,no_plan_encodes_root_as_the_workload_identity,prepared_launches_accept_balanced_brackets_in_final_paths,prepared_launches_hand_the_vmm_the_checked_files,prepared_launches_refuse_final_paths_that_openvmm_cannot_take,prepared_launches_take_only_the_checked_files_of_their_plan,staging_checking_and_preparing_a_launch_read_no_content. The 4 handoff cases oftests/checked_handoff.rs:a_prepared_launch_hands_the_vmm_its_checked_images_alone,a_vmm_keeps_the_scratch_images_claim_once_its_launcher_is_gone,a_vmm_finds_the_checked_images_past_replaced_links_from_another_directory,a_launch_passes_a_checked_file_that_took_a_standard_streams_descriptor. Windowsa_child_loses_only_the_inherited_handle_that_is_closed_in_it(ofclose_inherited) andseal::windows::tests::final_paths_hold_no_nul_whatever_their_length(offinal_path). The file's 2 cases of the spawn that stays,launched_waits_return_and_retain_the_actual_exit_statusandstrict_cleanup_terminates_and_confirms_a_running_child, move tohost::spawn's unit tests, and itsexit_status_fixturejoins theirvmm_fixture.gpt_disks_bind_by_their_disk_guidno longer checksbound(), andchecks_claim_the_image_without_reading_itno longer checksproc_path.host::supervisor: the 11 kept cases moveAs the notes on #1122 and D1 ask,
tests/supervisor.rsbecomestests/process.rs, with its 7 tests ofhost::process, whose processes a fixture of its own starts throughstd::process:processes_can_be_shared_between_threads,a_child_that_exits_wakes_its_waiter,a_process_that_is_not_a_child_wakes_its_waiters,a_reused_process_id_is_never_signaled,references_that_name_no_process_are_never_opened, and on Windowsa_process_that_this_user_may_not_query_has_an_unknown_stateanda_process_that_this_user_may_not_terminate_is_waited_for_but_never_signaled. Its 4 tests of the spawn move tosrc/host/spawn/tests.rs, which now builds on Linux and Windows:working_directory_limits_include_trailing_separators(Windows),a_restarted_launcher_finds_its_vmm_again_and_ends_it(the breakaway),vmms_inherit_only_their_streams_and_allowed_descriptors_while_others_spawnanda_job_that_ends_its_vmm_wakes_the_waiters(Windows), with the launcher fixture; itsvmm_fixturejoins the spawn tests' one. The spawn's Linux tests move tosrc/host/spawn/tests/linux.rs, unchanged but for the strict spawn. Windowsa_vmm_whose_log_is_no_file_of_a_disk_volume_starts_without_a_jobbecomes..._is_refused: the start without a job that onlysupervisor::spawnmade goes, its refusal by the strict spawn stays. The tests that spawned through the old paths spawn throughspawn_vm_with_mode(host::platform::windows::tests,host::restore::tests,host::cli::store::tests::liveness), andhost_modules' graph test loses the edge fromsupervisortospawn.CaptureClass: 2 retire, 13 rewrittenthe_guest_build_is_not_part_of_a_snapshot_keyandeach_field_of_a_class_changes_its_identityretire, with the class's part ofidentities_have_a_text_form. The key's other tests derive their keys from contexts throughfrom_capture(a_capture_that_does_not_match_its_class_is_refused, which loses the case of a network whose policy attaches no NIC,a_class_selects_a_profile_as_openvmm_does,a_generations_own_metadata_leaves_the_key_as_it_is,a_key_holds_what_its_capture_made,a_key_that_holds_its_network_s_lowering_after_its_invariants_is_refused,complete_capture_time_round_trips_without_changing_compatibility_identity,each_part_of_the_key_changes_it,keys_of_machines_that_no_manifest_describes_are_refused,keys_read_back_from_their_canonical_encoding,keys_with_the_removed_guest_build_field_are_refused,the_conformance_vectors_decode_and_encode), andinvalid_classes_are_refusedbecomescaptures_of_invalid_contexts_are_refused. The snapshot fixturesclass()andnetwork_class()becomecontext()andnetwork_context()(snapshot_open_refuses_*, the capture tests).The sandbox profile's own tests: 17 retire, 21 rewritten
Retired with the plan and the launch:
launch_contract_builds_agent_command_line,launch_contract_rejects_duplicates_and_reserved_tokens,launch_settings_are_checked_in_order,launch_rejects_limits_the_guest_cgroup_cannot_store,launch_contract_attaches_mount_and_reserves_bootstrap_tokens,launch_contract_attaches_several_shares_as_an_aggregate,launch_bounds_shares_by_the_kernel_command_line,launch_contract_rejects_disk_option_delimiters_and_unbalanced_brackets(the CLI's refusal stays tested intests/cli/validation.rs); the specificationsaggregate_child_name_known_answer,launch_arguments_follow_the_openvmm_contract,accepted_launch_shapes_keep_their_arguments_and_kernel_tokens,shares_follow_the_openvmm_and_guest_contracts,launch_settings_follow_the_guest_contract,caller_parameters_follow_linux_and_guest_rules,aggregate_child_names_follow_the_restore_contract,kernel_command_line_stays_within_1024_bytesandreserved_kernel_tokens_are_always_refused; and the share testsaggregate_child_names_pin_their_targetsandboot_tokens_refuse_what_the_shell_cannot_bind.Rewritten, keeping their checks of code that stays:
launch_contract_attaches_a_file_as_an_aggregate_childbecomesfile_shares_take_no_policy_paths_or_reserved_targetsandlaunch_validation_requires_the_layers_and_the_scratch_imagebecomesmissing_files_are_named_with_their_components_alone(require_file);launch_validation_rejects_overlapping_or_foreign_host_paths,shares_that_only_a_verbatim_path_names_are_refused,launch_validation_rejects_shares_that_came_to_overlapandlaunch_validation_requires_plain_mount_directoryplan their shares withplan_mountsand check them again as a start does, withcheck_distinct_export_rootsandExportPlan::verify; the specificationslayer_values_are_role_path_uuid,kernel_token_values_refuse_separators,the_reproduction_of_microsoft_nvx_723_is_refusedandaccepted_values_stay_one_kernel_parameterkeep their checks of layers and targets, andcanonical_layer_uuids_reach_the_guestbecomescanonical_layer_uuids_round_trip; the share testsmount_parser_defaults_to_read_only_and_accepts_rw,mount_parser_accepts_host_paths_with_commas,mount_owner_defaults_to_vmm_and_forwards_caller,mount_access_policy_is_validated_and_forwardedandshares_are_planned_through_the_export_plannerdrop the boot rendering; and the option testsdistro_manifest_binds_the_layer,systemd_entrypoints_and_images_are_refused_independently,sandbox_allows_non_systemd_sbin_init,the_entrypoint_check_needs_no_manifest_and_precedes_the_distro_verification,sandbox_rejects_systemd_from_bound_distro_metadataanddistro_manifests_are_strict_jsonrun the CLI's preflight,validate_sandbox_entrypointandDistroBinding::verify, whilesandbox_command_shares_a_fileandsandbox_command_attributes_mount_deny_to_the_preceding_mountcheck the export plan's kernel token.Elsewhere: 1 renamed, helpers adjusted
config::tests::cold_command_lines_keep_the_old_root_view_and_mapping_valuescompared a configuration's command line with those ofLaunchSpecandSandboxPlan; ascold_command_lines_carry_the_root_the_view_and_the_mapping_count, it checks the line against the configuration, and its case-matrix row follows the rename. The restore driver's test workload spells the identity thatWorkloadIdentity::DEFAULTnamed, andtests/cli/openvmm.rs'stwo_share_command_line_roomthe tokens that OpenVMM appends. The CLI's capture and store tests buildVmmCommandas a struct.The shell
/initand the scenariostest_old_lifecycle_tokens_keep_the_old_layered_initbecomestest_old_lifecycle_tokens_no_longer_select_the_old_layered_init, and the newtest_openvmm_workload_identity_needs_the_same_nvx_identitychecks that OpenVMM's identity tokens without the samenvx_identity=(none, its UID alone, or another identity) stop every route,nvx_exec, one-shot, managed and sandbox, withNVX-WORKLOAD-ERRORbefore anything starts, and that the same identity boots on;test_exec_override_cannot_bypass_the_new_sandbox_initandtest_missing_helpers_or_selected_init_fail_without_fallbackexpectnvx-initfor a layered root withnvx_lifecycle=. All four fail on the old init. The scenarios' unit tests check the CLI's tokens on the command line, andtest_workload_identity_scenario_checks_enforcement_and_rejectionand the newtest_workload_identity_scenario_fails_a_guest_that_does_not_fail_closedtheworkload-identityscenario's two boots that must fail closed.Size
Measured against
230a1b0877d, by #1076's rules: leaving code only, no limit. The workstream's measuring script counts 221 added or changed code lines in 29 Rust files, plus 38 inscripts/nvx_tools/microvm_tests.pyand 10 inguest/common/init: 31 counted files. Of the 221, the 117 innvx-rs/srconly gate items byclior by platform, make items crate-private, or shorten the import and re-export lists of what goes, and so don't count; the other 104 are the example's own launcher (D1). The 48 lines of the scenarios (D5 and the refused boots) and of the init (its remaining case and condition, and the 8 lines of the fail-closed check) count. The estimate was 0 core lines and 9 counted files. 77 files change: +2916 and −12615 lines, tests and docs included.BOOT_CONTRACT_VERSIONandCONTROL_CONTRACT_REVISIONdon't change.Left as is
nvx-init-agentand the container scripts, which no launch starts any more;doc/project-structure.mdsays so. Their removal is not in SL6.3's Scope.runacceptsnvx_lifecycle=,nvx_workload_uid=andnvx_workload_gid=in--cmdlineas aliases of its ownnvx_mode=andnvx_identity=, which it renders before the guest reads them, and the fake OpenVMM keeps emulating OpenVMM's options, as nvx-rs slimming 3.1.4:runuses the new interface and the CLI's own guest tokens #1109 left it.doc/modules, which CI draws again after the merge.Not in this PR
Rewriting, refactoring or improving retained mount planning, path handling, VM configuration or VM spawning; re-homing the deleted APIs or adding replacements (no public constructor of
ProcessRefwas added for the example); deletingplan_mounts,plan_mounts_withorpath_text(#1124); changingDEFAULT_GUEST_NETWORK,COMMAND_LINE_BUDGET, the Windows command-line helpers, the private spawn lock or the failed-spawn termination; incrementing a contract version.Validation
The checks ran on
a3d93c075ad, and the test suites again onc04cd8a7b18, whose tree differs only by one Linux test helper (below), then on604d8dacccband on this head,c5d2ee8d0b7(after the tables), with Rust 1.95.0 andNVX_BUNDLE=skip, locally on Windows, on nvx-mshv-test (Azure Linux 3, kernel 6.18, linux-mshv, virtual machine), nvx-kvm-test (Azure Linux 3, kernel 6.6, linux-kvm, virtual machine) and nvx-whp-test (Windows, WHP, virtual machine), in temporary worktrees. The gates are those thatlocal_gates.py --filesselects, run from this branch's actions.cargo fmt --all --check-D warnings:--all-targets --all-features,--lib,--lib --no-default-features,--lib --no-default-features --features serde,--lib --bins --features cli,--lib --bins --no-default-features --features testing,--all-targets--target x86_64-unknown-linux-gnu; every commit also passescargo check --all-targets --all-featureson bothcargo check --all-targets --all-features --target aarch64-apple-darwin; guest Clippy forx86_64-unknown-linux-muslcargo test --locked --all-featuresa3d93c075ad; the change since is Linux-only)guest::failures of the base on kernel 6.6, the same names, and none elsecargo test --lockedcargo build --lib --no-default-features,cargo test --lib --no-default-featuresRUSTDOCFLAGS=-D warnings cargo doc --no-deps --all-featurespublic_api.py--update, then passedcargo +1.89 check --all-targets --all-features(MSRV)check-guest-binaries, thenbuild-guest-binariesandtest-guest-binariesguest::failures on kernel 6.6check_test_layout.py,check_markdown_links.py, SL5.2'scheck_matrix.pyruff check,ruff format --check,pyright(Linux and Windows) of the changed scripts;shellcheck --shell=sh guest/common/init;GuestInitRoutingTests,GuestInitWorkloadIdentityTestsand the scenarios' unit testsThe microVM scenarios and the example ran on
a3d93c075adwith the staticnvx-rsthat each host built, the Alpine initramfs thatnvx.py build-initramfsbuilt from this branch on nvx-kvm-test (its/initisguest/common/initbyte for byte; copied to the other hosts and checked by SHA-256), and CI run 43168368915's kernel, Ubuntu distro layer, scratch template and OpenVMM builds of the pin14dc4116, with their provenance:workload-identity,managed-lifecycle(D5)guest-boot,lifecycle,vm-lifecyclesandbox-lifecycle,sandbox-ram-upper,sandbox-blocks,managed-exec-configsandbox-gpt-layer,sandbox-proxy-onlyfilesystem-shares,snapshot-core,command-line-limit,structured-outcomefilesystem-comma-paths,filesystem-owner,platform-filesystem,platform-aggregate-exportexternal-launch: a cold boot, then a restore up to its restore-ready event from a snapshot thatnvx-rs snapshot capturecapturedThe microVM scenarios ran with the default signal dispositions. They also passed on
38dd99330ba, before the restack onf03c21c3f0c.604d8dacccb, before the rebase onto230a1b0877d, differs fromc04cd8a7b18only by #1526's fix of its review thread, insandbox/lifecycle/start.rsand its tests. On it, Windows passedcargo test --all-features(16 suites, 1279 tests, 25 ignored),cargo test(13 suites, 847 tests),cargo test --lib --no-default-features(246),cargo docwith-D warnings,public_api.py,check_test_layout.py, and Clippy--all-targets --all-features,--lib --no-default-featuresand--lib --bins --features cli, natively and forx86_64-unknown-linux-gnu, with the macOS check. nvx-mshv-test passedcargo test --all-features(95 suites, 2292 tests, 65 ignored),cargo test(13 suites, 840 tests), Clippy--all-targets --all-features, andsandbox-lifecycle,sandbox-ram-upper,managed-exec-config,workload-identityandmanaged-lifecyclewithnvx-rsbuilt at that commit.This head,
c5d2ee8d0b7: Windows passed the full Clippy matrix of check-nvx-rs with-D warningson the rebased commits, natively and forx86_64-unknown-linux-gnu, with the macOS check; and on this headcargo test --all-features(16 suites, 1225 tests, 25 ignored),cargo test(13 suites, 790 tests),cargo test --lib --no-default-features(190),cargo docwith-D warnings,public_api.py,check_test_layout.py,check_markdown_links.py, SL5.2'scheck_matrix.py,ruff check,ruff format --check,pyrightfor Linux and Windows,shellcheck, andGuestInitRoutingTests,GuestInitWorkloadIdentityTestsand the scenarios' unit tests. nvx-kvm-test passedshellcheckandshfmtof the shell scripts with CI's pinned images, the same Python unit tests, andworkload-identity,managed-lifecycle,guest-boot,lifecycle,vm-lifecycle,sandbox-lifecycle,sandbox-ram-upperandmanaged-exec-config, with the Alpine initramfs thatnvx.py build-initramfsbuilt from this head (SHA-256beb5d8e5, copied to the other hosts) andnvx-rsbuilt at this head. nvx-mshv-test passed the same scenarios and unit tests, andcargo test --all-features(95 suites, 2200 tests, 65 ignored). nvx-whp-test passedworkload-identity,managed-lifecycle,guest-boot,lifecycle,sandbox-lifecycleandmanaged-exec-config. On each host, theworkload-identityscenario's two new boots stopped withNVX-WORKLOAD-ERROR: nvx_identity must name OpenVMM's workload identity. CI run 43203015701 passed on this head: 33 jobs, the microVM shards, guests and sandboxes, and platform jobs of KVM, MSHV and WHP among them, with 9 skipped (publication, recording and persistence). A code-review agent found no issue in the new commit, and Copilot's review of this head reports none.Changes to existing tests (
tests-modified)check_test_changes.py --base origin/feature/nvx-refactorlists 372 changes, explained by deleted code in "Every removed test, and its fate" above: the tests of deleted code retire; the tests of code that stays move to its owners, or drop the assertions on deleted rendering, or run what the CLI runs; one renamed test follows its new reference. Two changes go beyond a move:vmms_inherit_only_their_streams_and_allowed_descriptors_while_others_spawnnow runs beside the crate's other unit tests, where its check that a process spawned throughstd::processholds none of the VMMs' descriptors failed on Linux, consistently in the default-feature lib binary on nvx-mshv-test: the kernel wakesposix_spawn's parent before the child's exec closes its close-on-exec descriptors, so for an instant the child's table still lists every descriptor of the parent, both ends of the test's pipes included.held_objectslooks again until the objects are gone or a second passes: an inherited descriptor stays for the child's life. The same check intests/supervisor.rshad this race; it showed in the busier process. With the fix, 20 runs of that binary passed on each Linux host, where 20 of 20 failed without it.tests/vectors/snapshot-key-v1.txtloses itsCLASSvectors, whose type goes; itsKEYvectors don't change.