Repository navigation
doc: separate OpenVMM, nvx and its callers in the host design (SL6.10b) - #1553
Pedro Henrique Penna (ppenna) wants to merge 8 commits into
Conversation
SL6.7b (#1124) makes host::sandbox private to the CLI. Twelve of its items have no caller in any NVX program, only in the public API and in the module's own tests, so they would be dead once private. This change deletes them first, as SL6.6c (#1122) records: - MountAccess::from_name, MountOwner::from_name and MountKind::from_name, with their helper setting_from_name, which read a share's settings by name, as a recorded share gave them. The CLI maps the choices of --mount-owner itself and records a sandbox's export plan, not its shares' settings. - SandboxMount's accessors guest_target, access, policy, owner and kind, and absolute and absolute_policy_paths, which called absolute_with and absolute_policy_paths_with with the current directory. plan_mounts and the checks of host paths call those variants, whose docs now say what the wrappers' said, and read the fields; host_path stays for sandbox_mounts. plan_mounts' docs no longer name absolute, and say how making a host path absolute fails. - SandboxOptions::new, the options of an operation with the defaults of nvx-rs sandbox, which the CLI builds field by field instead. The tests keep what they check of the code that stays: - The share tests compare whole shares with the shares that SandboxMount::new makes, or read the fields that the mount module shows them, and make shares absolute with absolute_with and absolute_policy_paths_with and the current directory, as the deleted wrappers did. - The option tests build their options with a helper of their own, defaults, which holds what SandboxOptions::new did, and compare the shares of sandbox_mounts with whole shares, policies included. - The checks of from_name's refusals go with it: they were the only callers of what they checked. The public API snapshots lose 21 lines on each platform, the eleven public methods at both of their paths and SandboxOptions::new, and gain none. Part of #1122 (SL6.6c). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.7b (#1124) makes host::network::policy and host::sandbox private to the CLI. Two of the CLI's scenario tests reached them through their public paths, which they cannot once those are private, so they drive the nvx-rs binary alone, with the same expectations: - egress_compile_prints_the_library_lowering compared what `nvx-rs egress compile` printed with the rules of compile_policy_file, and its refusals with the reader's error. It keeps every case's native rules, error code and message fragments, which the binary must print, and the grammar, model and property tests of host::network::policy check the reader's own rules and refusals. - two_share_command_line_room spells the tag of OpenVMM's virtio-fs device, `microvm`, as the lifecycle tests do, in place of MOUNT_TAG, and cold_run_expected splits a fixture's --mount and --mount-child values as OpenVMM reads them, with a helper of its own, in place of parse_mount_value: independently of the CLI's parser, as its documentation says. Part of #1124 (SL6.7b). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… CLI host::network::policy and host::sandbox were public API of nvx, although only NVX's CLI reads egress policy files and the options of nvx-rs sandbox and nvx-rs run: the policy-file reader and its limits, the rules that it compiles, the --mount syntax, the shares that it requests and their plan, the checks of the options, and the sandbox's defaults. They become crate-private where they are, gated by the features of their users, with no change of behavior: - host::network::policy becomes a pub(crate) module that only the cli feature builds, with its JSON reader, compile_policy_file, compile_policy_bytes, compile_policy and CompiledEgressPolicy, and its limits, MAX_RULES_PER_ACTION, MAX_POLICY_FILE_SIZE and MAX_JSON_DEPTH. The lowering already takes MAX_RULES directly, and the shared normalization stays public: EgressRule, Destination, PortSelector and NetworkPolicy::native_egress_rules. - host::sandbox becomes pub(crate). Its options module, with SandboxOptions, PolicyPathOption, SandboxOperation and the checks of the options, takes cli, and so do, in its mount module, the --mount syntax, SandboxMount, the mount types and limits, plan_mounts and plan_mounts_with, the checks of host paths and path_text, and, at its root, the defaults, parse_workload_identity, parse_decimal, has_kernel_separator and require_file. What the crate uses outside the CLI stays ungated: block_geometry and BlockGeometry, which host::vm and host::snapshot read, MOUNT_TAG, which a snapshot's key names, refused and os_error. - host::sandbox no longer re-exports the mount types, nor its mount module the reserved targets of protocol::share or validate_mount_target, which nothing reads at those paths once they are private. The sandbox's tests import the mount types from the mount module, and validate_mount_target through the mount module's tests, as they do validate_mount_host_paths_with. - What these users leave to the CLI takes cli too: host::artifacts::require_existing, which only require_file and the CLI's require_artifact call, and host::paths::resolve, with without_verbatim_prefix and its two tests, which only the CLI and the checks of shares call. The unit tests of host::network::policy and host::sandbox, and the two host::paths tests of resolve, take cli with their modules, so the all-features tests run them as before. The public API snapshots lose 132 lines on each platform, every path under nvx::host::sandbox and nvx::host::network::policy, and gain none. The docs of host, host::network and host::sandbox, and the doc links of openvmm_arguments, Destination and the lowering, name the reader and the profile as the CLI's; the README drops the two modules' rows and sections and holds their details in Egress policy files and Sandbox input contract. Part of #1124 (SL6.7b). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.5a2 (#1125) makes the export planner crate-private and gates it with cli. Five of its items have no caller in any NVX program, only in the public API and in tests, so the warning-denied build of the cli feature would find them dead once they are private. This deletes them first, so that SL6.5a2 stays visibility-only: - resolve_guest_path, with its re-exports at nvx:: and nvx::host::filesystem::, which gave the guest path of a host path once resolved, or as spelled when it did not resolve. No NVX program translates a host path that way. guest_path, the convention itself, stays public at both paths. - Target::Convention, with its branch of resolve_mapping, which derived a mapping's target from its resolved host path, and Mapping::convention, which mapped a list's paths there. NVX's callers, nvx-rs run and the sandbox's shares, give every target. resolve_mapping takes the target that the mapping gives, and checks it as before. - ExportRequest::new, and PathList::EMPTY, which only it used. The CLI builds its requests field by field. The docs of host::filesystem and of plan say that the caller gives each target, which guest_path may derive, and the README's filesystem section follows. The tests keep what they checked of the code that stays: - host::filesystem's tests place each path of their plan helper at the guest path that guest_path derives from the resolved host path, as the convention did, with a convention helper, and build their requests directly: plain_request holds what ExportRequest::new did. - resolved_guest_paths_canonicalize_temp_directory_case_aliases retires with resolve_guest_path. On Windows, spellings_of_one_object_share_its_guest_path now takes its case, the object's whole path in capitals, that of the temporary directory included, whose guest path as spelled is not the resolved path's: it plans to the object's one child, at the resolved path's guest path. - planned_boot_shares_keep_table_sources_targets_access_and_file_kind and the security checklist build their requests directly, the checklist through a helper that takes the owner, which the_caller_owner_is_refused_on_windows sets. The public API snapshots lose 6 lines on each platform, the five items with resolve_guest_path at both of its paths, and gain none. Part of #1122 (SL6.6d). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.5a2 (#1125) makes the export planner and its host rechecks private to the CLI. Two integration tests reached them through their public paths, which they cannot once those are private, so each case moves beside its owner or drives the nvx-rs binary alone, with the same assertions: - The security checklist's four checks of an export, which only the CLI plans and checks again before a start, an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves, an_export_refuses_a_read_only_path_inside_a_writable_directory, the_caller_owner_is_refused_on_windows and an_exported_object_that_a_workload_could_move_is_checked_again_before_a_start, move unchanged to the unit tests of host::filesystem, where plan_blockless plans their mappings into the blockless root, as the checklist's plan did. - cold_run_expected planned the shares of a cold-run fixture through filesystem::plan before it lowered them through the public VM contract. fixture_export now builds the fixture's ExportPlan as host::filesystem documents an export, independently of the CLI's planner, as of its parser and token renderer, so the dry-run and one-shot tests compare the CLI's command line with an export that they derive on their own. The case matrix names the moved checklist tests where they now are. Part of #1125 (SL6.5a2). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The export planner was public API of nvx, although path resolution, the protected and reserved targets, the allow, deny and write rules, aliases and the host rechecks before a start are the CLI's policy: only nvx-rs run and the sandbox's shares plan exports, and only the CLI checks a recorded export again before it starts a VM. They become crate-private where they are, gated by cli, with no change of behavior: - host::filesystem's plan, ExportRequest, Mapping, Target and PathList become pub(crate) and take cli, with the helpers that only they use: resolve_mapping, check_targets, shows, Mapped and unsupported_inspection in the module, identity and canonicalize_lenient in host_path, check_root and check_policy_paths in limits, and the resolution and checks of policy paths in policy. - ExportPlan::verify, the host recheck before each start, becomes pub(crate) and takes cli, with bound, changed_object, uninspected, loops, check_caller_roots and CALLER_OWNER_ON_WINDOWS, which only it and the planner use. The CLI keeps the identity pins, and calls verify before each launch as before. - What stays public doesn't change: ExportPlan with its children, binds, owner and identities, check, openvmm_arguments, kernel_token and guest_table, ReservedTargets, Owner, FileIdentity, the constants, and guest_path, at nvx::host::filesystem:: and nvx::. host::paths is already crate-private; resolve, which only the CLI calls, took cli in SL6.7b, and the rest serves host::vm, host::snapshot and the VM directory too, so it stays ungated. The 27 unit tests of the planner and of verify in host::filesystem take cli with their 11 helpers, so the all-features tests run them as before; the six tests of guest_path, within, outermost, the whole-volume refusal, the reserved targets and check run without it. The public API snapshots lose 20 lines on each platform, the planner's items with their fields and ExportPlan::verify, and gain none. The docs of host and host::filesystem, and those of ExportPlan and check, name the planner and the recheck as the CLI's, and the README's filesystem section and module row follow. Part of #1125 (SL6.5a2). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ExportPlan, the public description of a VM's export, combined the host
paths with the file identities that only the CLI's store needs: each
child's denied_identities, each bind's identity, and FileIdentity, with
check's rules that a recorded plan pins each object that a workload
could move. The paths are what nvx lowers; the identities are the CLI's
recheck of its own records before each start.
The CLI now owns PlannedExport { description: ExportPlan, pins: Pins },
crate-private and cli-gated beside the planner and the verifier that
SL6.5a2 made private:
- The planner returns a PlannedExport: the description, and the pins
of each child's denied paths and of each bind, in their orders,
which it computes as before. The binds keep their pins as they are
sorted.
- PlannedExport::check runs ExportPlan::check, then the pin rules that
moved out of it: a slot for each child and each of its denied paths,
one for each bind, and the identity of each denied or mapped object
strictly inside a part that the guest may write, with the same
messages. PlannedExport::verify is the old ExportPlan::verify, which
reads the identities from the pins.
- The sandbox's config.json keeps the description under export, paths
only, where CI's share checks read it, and records the pins beside it
under export_pins, as it records each image beside its binding.
Config::new requires the field and refuses an export without pins or
pins without an export as malformed; Config::check checks and
verifies the pair before vm_config passes the description to the VM.
plan_mounts, provision's ProvisionConfig and check_images carry the
PlannedExport; nvx-rs run, which launches its plan at once and never
again, keeps the description and checks no pins, as before.
nvx's public API loses FileIdentity, ExportChild::denied_identities,
Bind::identity, and ExportPlan::openvmm_arguments and kernel_token,
which only VmConfig's lowering calls and which become pub(crate);
lowering is unchanged. ExportPlan::check stays structural and needs no
identity data. host::filesystem documents what the caller keeps stable:
the launch race, the writable-part recheck and durable denials.
A configuration that an earlier build wrote has no export_pins, so a
start refuses it as "sandbox configuration has no export pins;
deprovision the sandbox and provision it again", as for every field
that the record gained before; nothing is migrated, and the format
stays 10.
Tests: the planner's and verifier's unit tests read the pins from the
PlannedExport, and narrowed_writes_pin_only_what_lies_in_writable_paths
also checks the new slot rules; ExportPlan's own tests and fixtures,
in host::config, host::vm, the restore tests and tests/cli/openvmm.rs,
build plans without identities. A new state test records an export
with its pins, reads both back, and refuses a moved, a gone and an
uninspectable pinned object at Config::check. The CLI's lifecycle
tests expect export_pins in each record, and malformed_configuration
refuses a record without it, an export without pins, and pins without
an export.
Part of #1125 (SL6.5b).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The host and lifecycle design still described an NVX launcher and a host control library that keep per-sandbox state, supervise VMMs and deliver the mapping table, snapshot tiers as lifecycle points with a sharing scope, template compatibility keys, and a managed sandbox lifecycle of the host. The slim nvx library keeps no state and runs no supervisor: its callers own their stores, paths, outputs and locks. Design 1.3-1.5, 2.1, 3.4-3.5 and 5.1-5.6 now split each responsibility between OpenVMM, the nvx library and its callers: - 1.3 names callers, such as NVX's CLI, the nvx library and the caller-owned VM and snapshot directories, and the guest's init and helpers with the nvx guest library. - 1.4 adds what nvx checks and what its caller keeps: stable, private paths and directories, its outputs, per-snapshot locks on Linux, and its own spawns on Windows; and how nvx handles the capability. - 1.5 gives each contract its owner, adds the boot contract, the activation record, the snapshot key and the control protocol, and describes snapshot compatibility through the key and Snapshot::accepts, persisted state, and the runtime identity and its labels. - 2.1, 3.4 and 3.5 describe configuration ownership, the one platform capture of nvx and its restore-time inputs, block identities as OpenVMM implements them (SHA-256 by default, or a storage generation), and the NIC template whose restore installs its own policy. - 5.1 separates OpenVMM's, nvx's and the caller's boot tokens; 5.2 defines Ready, the host's mapping table and the public MappingTable, and the lifecycle operations of nvx, with NVX's CLI as one caller. - 5.3 and 5.4 describe tiers as device configurations, the capture that nvx configures and finishes, and the strict snapshot directory, the envelope of key.bin and snapshot.json around OpenVMM's openvmm/. - 5.5 adds the order of a restore's activation to Ready with its own network policy, and who repairs a platform restore; 5.6 adds the repair and activation statuses of nvx::protocol::status, the error kinds that callers act on, and RestoreError's attribution. The restore packet, the order of a restore with a new network policy, and the host-clock correction in the time samples keep their place. Part of #1130 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The missing OpenVMM submodule prevents verification of the SHA-256 block identity, shorter-image, absent-scratch, and dormant-slot aggregate restore claims against the pinned implementation.
No open issues 🎉
What changed in this PR
Updates the host and lifecycle design for the slim nvx library under #1130, separating OpenVMM’s responsibilities from library mechanisms and caller-owned policy and state. The PR changes documentation only, with no runtime or API changes.
Changes:
- Clarifies ownership of configuration, paths, outputs, locks, runtime identities, and guest behavior.
- Documents snapshot compatibility, strict directory layout, capture completion, and restore-time attachments.
- Defines boot-token ownership, Ready, mapping-table delivery, restore activation, and failure handling.
| File | Description |
|---|---|
doc/design/5.6-shutdown-and-failure-semantics.md |
Documents exit evidence, repair statuses, and caller-facing errors. |
doc/design/5.5-restore-protocol.md |
Details platform repair and activation through Ready. |
doc/design/5.4-snapshot-artifact-and-attachment-model.md |
Defines the strict snapshot envelope, validation, tiers, and attachments. |
doc/design/5.3-snapshot-protocol.md |
Clarifies capture configuration, barriers, deadlines, and completion. |
doc/design/5.2-readiness-and-runtime-control.md |
Separates Ready, mapping delivery, library operations, and CLI lifecycle. |
doc/design/5.1-boot-protocol.md |
Distinguishes OpenVMM, library, and caller boot tokens. |
doc/design/3.5-network.md |
Explains caller-selected networking and restore-specific policy activation. |
doc/design/3.4-block-storage.md |
Clarifies block identities and platform image/scratch rules. |
doc/design/2.1-machine-model-and-configuration.md |
Assigns configuration ownership and describes restore-time inputs. |
doc/design/1.5-compatibility-and-versioning-model.md |
Defines contract owners, snapshot keys, and runtime identity. |
doc/design/1.4-trust-boundaries.md |
Documents library checks and caller path, output, and lock obligations. |
doc/design/1.3-system-components-and-responsibilities.md |
Separates callers, library, VMM, and guest responsibilities. |
Review effort: Balanced
|
No change needed for Copilot's review note on the OpenVMM claims, which it could not check because the review had no OpenVMM submodule. Each one holds at the pinned OpenVMM,
|
21ce29a to
03b7ccb
Compare
This pull request changes existing testsIt modifies or removes 463 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 413 more, which the job's summary lists. Relocated unchanged: 0; added: 10. Compared the merge base |
Part of #1130 (SL6.10b, "The host and snapshot design separates the VMM, the library and its users"). Parent #1090, umbrella #1076.
Stacked on #1549 (SL6.5b).
What and why
The host and lifecycle design still described an NVX launcher and a host control library that keep per-sandbox state, supervise VMMs and deliver the mapping table, snapshot tiers as lifecycle points with a sharing scope, template compatibility keys, and a managed sandbox lifecycle of the host. The slim
nvxkeeps no durable state and runs no supervisor: its callers own their stores, paths, outputs and locks. This PR does SL6.10b's Scope and no more. It edits the named pages in place, with one split of each responsibility between what OpenVMM provides, whatnvxchecks or drives, and what callers (an orchestrator, or NVX's CLI) and guest inits own:nvxlibrary, which keeps no durable state, takes no lock but its internal Windows spawn lock, and starts no process but OpenVMM; the caller-owned VM and snapshot directories; and the guest's init and helpers with thenvxguest library, whose space is nvx-init's private reference code.nvxchecks (private VM directories, the strict snapshot directory, verified processes and endpoint peers, the runtime identity) and what its caller keeps (1.4.6): stable, private paths and directories and the export's paths; its outputs, whichnvxremoves none of once a launch is created; per-snapshot locks on Linux, with why; and its own spawns on Windows. The capability's handling, and block identities, follow the code.nvx's boot contract, activation record, snapshot key and control protocol, replaces "Template Compatibility" with snapshot compatibility through the key,KeyIdentityandSnapshot::accepts, and adds persisted state and the runtime identity and its labels (1.5.4).nvx(a blockless boot with a placeholder image and a dormant scratch) and its complete restore-time inputs (a shorter image, an absent scratch, an aggregate on the dormant slot, a NIC template's own policy), and caller-owned identity and proxy.nvx's and the caller's boot tokens; 5.2 defines Ready (5.2.4), the host's mapping table and the publicMappingTable, whose mapper is the private space's (5.2.5), and the lifecycle operations ofnvx, with NVX's CLI's sandbox as one caller (5.2.6).nvxconfigures, who prepares the guest, finishing a capture (5.3.8), and the strict snapshot directory: the envelope ofkey.binandsnapshot.jsonaround OpenVMM'sopenvmm/, its checks, and its hard-linked restore view.nvx::protocol::status, theErrorKinds that callers act on, andRestoreError's attribution.Kept accurate and in place. 5.5.5's restore packet is unchanged: the issue's "restore packet 6" is now version 1 of OpenVMM's v4 microVM (
RESTORE_PACKET_VERSION = 1innvx-rs/src/contract.rs), whoseNETWORKflag carries what version 6 added. The order of a restore with a new network policy stays in 3.5.6, now with the platform clone's order, which 5.5.9 details. The host-clock correction of the time samples stays in 5.5.7's step 3.The final state, where later slices change the code.
ExportPlanholds paths only, and the caller keeps them stable (SL6.5b, this PR's base).host::sandboxandhost::network::policyare crate-private (SL6.7b). Callers act onErrorKind, not codes (SL6.8c). The guest's space and mapper are private, and onlyMappingTableand the mapping values stay public (SL6.13b). NVXC v2 is the only control protocol, internal, and its Ready carries the protocol version, which NVX's host checks (SL4.4a to SL4.4d).OpenVMM claims corrected on the way. Checking each claim against the code also corrected pages that described OpenVMM's paired tiers out of date: a bound block's identity is the SHA-256 digest of its file by default, and a storage generation only when its owner opts in (
openvmm/openvmm/openvmm_entry/src/cli_args/microvm.rs); a platform restore may attach a shorter image, declare its scratch absent, and bind a new aggregate to the dormant slot.Not in this PR, per #1130: new design documents or other design pages (design 4.* is SL6.10c's, #1550; the library guide SL6.10a's; the CLI, build, CI and migration documents later slices'), new tiers, formats, packet fields or behavior, tier types, and removed stores or supervisors as library services.
Size. 0 core lines and 0 counted files (estimate 0): documentation only.
BOOT_CONTRACT_VERSION,CONTROL_CONTRACT_REVISIONand the public API are unchanged.Validation
The orchestration checkout's
local_gates.py --filesover the twelve pages selectstest-changes,markdown-links,test-layoutandnvx-cli, run here from this branch's own definitions:python scripts/check_markdown_links.pypython scripts/check_test_layout.pypython scripts/check_test_changes.py --base origin/agents/slim-sl6-5b-export-paths-onlypython -m compileall -q scripts, itspython -m unittestmodules,python scripts\test_adversarial.py, andnvx.pyhelpcheck_matrix.py, SL5.2)nvx-rs/src,openvmm/,guest/commonanddoc/guest-agent-guidelines.mdvm::create, output cleanup and a missing report,KeyIdentity's exclusions, the report-only restore finish's processes, the capture request's deadline, and the CLI's pass-through ofnvx_workload_account=createNo code, runtime behavior or test changes, so no build, host or microVM scenario ran. Left to CI: the documentation-only run that its change classification selects.