Skip to content

host: make the export planner and its host rechecks private to the CLI (SL6.5a2) - #1544

Merged
Pedro Henrique Penna (ppenna) merged 2 commits into
feature/nvx-refactorfrom
agents/slim-sl6-5a2-path-rules-private
Nov 12, 2026
Merged

Pedro Henrique Penna (ppenna) merged 2 commits into
feature/nvx-refactorfrom
agents/slim-sl6-5a2-path-rules-private

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Part of #1125 (SL6.5a2, "Path rules are private to the CLI"). Parent #1088, umbrella #1076.

It was stacked on #1543 (SL6.6d), which merged, and its base is now feature/nvx-refactor. SL6.6d deleted the five planner items that this PR would otherwise have left without a caller, resolve_guest_path among them (note on #1125), so that this one stays visibility-only. It needed SL6.3 (#1530), SL6.4 (#1533) and SL6.7b (#1539), which merged too.

What and why

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, but the export planner and ExportPlan::verify were public API of nvx. This PR does SL6.5a2's Scope: it makes them private to the CLI where they are, without changing what NVX's programs plan, refuse or pin. Two commits:

  1. tests: check the export planner through its unit tests and the CLI (d46ca5a4): the two integration tests that reached the planner through its public paths move beside its owner or drive the binary, with the same assertions (Test changes, below). It changes no production code, so it passes on its own, before the visibility change.
  2. host: make the export planner and its host rechecks private to the CLI (43ba6882):
    • The planner: plan, ExportRequest, Mapping, Target and PathList become pub(crate) and take cli, where they are in host::filesystem, 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.
    • verify's host rechecks: ExportPlan::verify 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 every launch from a recorded export (check_images in host::cli::sandbox::state), as before.
    • host::paths is already crate-private. Its resolve, which only the CLI calls, took cli in SL6.7b; the rest of it serves host::vm, host::snapshot and the VM directory too, so it stays ungated and unchanged.
    • host::platform::file_identity, crate-private since SL6.14 (nvx-rs slimming 4.3.4: NVXC, the host's platform layer and the guest's space are private #1127), has no caller outside the CLI and the tests once the planner, its limits and verify take cli, so the warning-denied build without cli finds it dead. As SL6.14 did for process_start_time, it and its re-exports take cfg(any(test, feature = "cli")), since the unit tests of host::vm and host::snapshot compare the files and volumes that paths name with it. On Windows, handle_identity and the five imports that only the two use take it too, and on Linux the identity module, whose other items already take cli. The cli build keeps all of them, so the binary doesn't change. scripts/test-layout-allowlist.json records the 11 hooks as seams: linux/mod.rs 1 → 3, windows/mod.rs 1 → 2, and new entries for windows/identity.rs (7) and other.rs (1).
    • 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, GUEST_EXPORT, MAX_CHILDREN, RESERVED_TARGETS, and guest_path, at nvx::host::filesystem:: and at nvx::. The crate root re-exports guest_path alone; SL6.6d deleted resolve_guest_path.
    • Docs: host's and host::filesystem's module docs, and those of ExportPlan and check, describe the export that a caller records, checks and lowers, and name the planner and the recheck as the CLI's, without linking to them. The README's nvx::host::filesystem row and section say the same, PathList::name leaves the lowering's naming note, and Sandbox input contract says that the sandbox plans its shares through the private planner.
    • The public API snapshots lose 20 lines on each platform: plan, ExportPlan::verify, and ExportRequest, Mapping, PathList and Target with their fields and variant. Nothing is added. guest_path stays listed in host::filesystem and at the root.

Canonicalization, the protected and reserved targets, the allow, deny and write-path rules, aliases, OpenVMM's limits, the identity pins, error texts and accepted spellings don't change, and neither do BOOT_CONTRACT_VERSION and CONTROL_CONTRACT_REVISION.

Size

Measured against d67a2d5ab57 (feature/nvx-refactor with SL6.6d), by #1076's rules, with #1125's note that privatizing counts as a move. This PR is visibility-only: 0 core lines and no counted files, as estimated.

Core lines Counted files
Estimate (#1125) 0 0
Measured 0 0
  • nvx-rs/src: 0 core lines, no counted file. The measuring script counts 101 added code lines in 10 production files, and every one of them makes an item crate-private (pub(crate)), gates it by cli, or, for file_identity, by any(test, feature = "cli"), or is an import that the gates force, with its continuation lines. The rest of the production diff is docs.
  • 18 files change: +437 and −278 lines, tests, docs, snapshots and the allowlist included.

Old tests of the area

  • Moved unchanged, from tests/security_checklist.rs to host::filesystem's unit tests, the owner of plan and verify, each checking the requirement that it checked:
    • an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves: a mapping's guest target must be an absolute path other than the root, without empty, . or .. components or NUL characters (Target::Guest's docs), and free in the root's ReservedTargets (plan's); a plan of a free target passes check and verify.
    • an_export_refuses_a_read_only_path_inside_a_writable_directory: a read-only path inside a part that the guest may write is refused on every host, since the host could not keep it read-only (host::filesystem's docs and plan's).
    • the_caller_owner_is_refused_on_windows: the caller owner needs a Linux host (plan's docs and Owner::Caller's).
    • an_exported_object_that_a_workload_could_move_is_checked_again_before_a_start: the plan pins the objects that a workload could move, inside a writable part, and the check before each start refuses a decoy at a pinned path with ErrorKind::Other and leaves the moved object as it is (host::filesystem's docs and verify's).
  • Kept: every unit test of host::filesystem, with the same assertions. The 23 of the planner and of verify, and the four moved ones, now build with cli, as the planner does, and CI's cargo test --all-features runs them; the six of guest_path, within, outermost, the whole-volume refusal, the reserved targets and check still run without it. The CLI's tests that plan shares, host::sandbox's and host::cli::run::guest_tokens's, already build with cli.
  • Rewritten to drive the binary: the helper cold_run_expected of tests/cli/openvmm.rs (Test changes).
  • Retired: none.

Test changes

python scripts/check_test_changes.py --base d67a2d5ab57 lists 46 changes, 42 to existing tests and 4 loosened allowlist entries, and 12 additions, 2 helpers and 10 test hooks, hence tests-modified:

  • cli gates, bodies unchanged (35), in nvx-rs/src/host/filesystem/tests.rs: the 23 tests of the planner and of verify, from unrelated_directories_are_exported_with_their_own_access to mapped_paths_resolve_to_utf8_paths, their helpers FilesystemPolicy, convention, plain_request, root, canonical, sources, option_values, second_volume and at, and the imports of display_path and platform, which only they use (33); two tests that already had a platform cfg merge it with cli. The helper plan takes cli too, but the script pairs it with the checklist's removed plan and lists that pair as "moved", and this file's old plan as "removed" (2); in fact this file's plan only takes cli, and the checklist's plan and request helpers go with the tests that called them.

  • The four moved tests (4), listed as moved from nvx-rs/tests/security_checklist.rs to nvx-rs/src/host/filesystem/tests.rs (Old tests, above), with their bodies as they were, but for plan becoming the new helper plan_blockless, which plans into the blockless root through plain_request, as the checklist's plan did through its request, and the caller-owner test's request built with plain_request. They take cli with the other planner tests.

  • nvx-rs/tests/security_checklist.rs (2): its imports drop the planner's types, and its helpers plan and request go; its module docs say that the checks of an export, which only the CLI plans and checks again, are unit tests of host::filesystem, as those of a staged image and of a scratch image's claim are of theirs.

  • nvx-rs/tests/cli/openvmm.rs (1, and 1 added): cold_run_expected planned a cold-run fixture's shares through filesystem::plan before it lowered them through the public VM contract. The new helper fixture_export builds the fixture's ExportPlan as host::filesystem documents an export, independently of the CLI's planner, as the harness already is of its parser and token renderer: each share is a child of its own at its resolved host path, in their order; the policy paths are resolved, deduplicated and sorted inside the child that holds them, and a read-write share is writable whole or only below its write paths; each denied path that a workload could move carries a zero identity, since ExportPlan::check requires one there but no command line carries it, and nvx::host::platform::file_identity, which gave the real one, has been crate-private since SL6.14; and each share binds its child's root at its target, the shallower targets first. The dry_run and one_shot tests that call it pass unchanged, so they compare the CLI's command line with an export that they derive on their own.

  • scripts/test-layout-allowlist.json (4 loosened entries, and 10 added hooks): the any(test, feature = "cli") gates of file_identity (What and why, above), which keep it for the unit tests of host::vm and host::snapshot without cli. No test changes for them.

doc/acceptance-case-matrix.md names three of the moved tests as coverage in 7 rows; those references now name nvx-rs/src/host/filesystem/tests.rs, and the counts don't change. check_matrix.py passes.

Validation

local_gates.py --files (from dev) selects test-changes, markdown-links, test-layout, the check-nvx-rs steps, nvx-cli and the microVM tests; I ran them from this branch's action definitions, with Rust 1.95.0, locally on Windows and on nvx-mshv-test (Azure Linux 3, kernel 6.18, linux-mshv, virtual machine), in temporary worktrees. Everything below ran first on 1f2c4f61996 and again on c765ea3687d, on SL6.6d's earlier heads, and passed, with the microVM scenarios below. Then the guest and NVXC chains, SL6.6c and SL6.7b landed under it, and both commits were rebased onto SL6.6d's c6c3a9b66fb, with two changes:

  • tests/security_checklist.rs conflicted with the base's move of the VM-liveness checks to host::vm's unit tests: its module docs keep both moves, and its imports drop the planner's types and those that the base dropped.
  • fixture_export read the identity of each pinned denied path through nvx::host::platform::file_identity, which SL6.14 made crate-private; it now gives a zero identity, which ExportPlan::check requires and no command line carries.

Clippy without cli then found file_identity dead, and its any(test, feature = "cli") gates followed (What and why). SL6.6d merged as d67a2d5ab57, with the tree of c6c3a9b66fb, and the commits moved onto it as d46ca5a4232 and 43ba68825f0, with the tree of 87cd9e8d593, which the checks below ran on (git range-diff: = for both). On that tree:

Check Windows (local) Linux (MSHV, kernel 6.18)
cargo fmt --all --check passed passed
Clippy -D warnings: --all-targets --all-features, --lib, --lib --no-default-features, and serde, cli and testing alone passed, natively and for --target x86_64-unknown-linux-gnu, and --all-targets with default features, natively and for x86_64-unknown-linux-gnu, which builds the tests without cli passed, and --all-targets --no-default-features --features guest
Guest Clippy, --target x86_64-unknown-linux-musl --no-default-features --features guest -D warnings passed passed (check-guest-binaries)
cargo check --target aarch64-apple-darwin: --all-targets --all-features, and --all-targets and --lib with default features passed; its one warning, in host/snapshot/tests.rs, is the base's --all-targets --all-features passed, the same warning
cargo test --locked --all-features passed: lib 1064 passed, 18 ignored; cli 113 passed, 2 ignored; security_checklist 3 passed; every other integration and doc test passed: lib 1767 passed, 59 ignored; cli 123 passed; security_checklist 3 passed; every other integration and doc test
cargo test --locked, cargo build --locked --lib --no-default-features, cargo test --locked --lib --no-default-features passed (lib 518 passed, 10 ignored, without the cli tests; 191 passed) passed (lib 520 passed, 10 ignored; 191 passed)
RUSTDOCFLAGS=-D warnings cargo doc --locked --no-deps --all-features passed passed
MSRV: cargo +1.89 check --locked --all-targets --all-features passed passed
python scripts/public_api.py passed passed
check_test_layout.py, check_matrix.py <worktree> 99d2022085f passed
  • microVM scenarios on MSHV, on the earlier base: python3 scripts/nvx.py test-microvm --backend mshv on c765ea3687d, with NVX_AUTO_DOWNLOAD=0, its release nvx-rs, and the artifacts of CI run 43238436289, the push run of 8ae0617b1eb, whose guest code and OpenVMM pin (14dc4116ec7) are this base's: the kernel, the Alpine initramfs, the Ubuntu distro layer and scratch template, and OpenVMM, each checked by SHA-256 against the run's artifacts and OpenVMM's provenance. All 14 passed:
    • the public sandbox scenarios, which provision, start and run sandboxes through the CLI's checks before a launch: managed-exec-config, sandbox-gpt-layer, sandbox-lifecycle, sandbox-proxy-only, sandbox-ram-upper, snapshot-core, snapshot-tiers, untiered-network-policy and vm-lifecycle;
    • the --mount and filesystem-policy scenarios: filesystem-comma-paths, which shares directories through nvx-rs run --mount and so plans them through the now-private planner, alone and as an aggregate with denied paths, and filesystem-shares, filesystem-policy, filesystem-owner and denied-filesystem-paths, which check the shares, policy paths and owner that OpenVMM enforces for such exports, and their refusals.
    • No microVM scenario changes or hides a pinned object between a plan and a start, so none covers a changed or uninspectable pin; the unit tests swapped_objects_fail_verification, objects_that_cannot_be_inspected_fail_verification_by_what_the_failure_shows, narrowed_writes_pin_only_what_lies_in_writable_paths and an_exported_object_that_a_workload_could_move_is_checked_again_before_a_start do, and pass.
    • The same 14 passed on 1f2c4f61996, on the earlier base, with CI run 43203015701's artifacts, which SL6.7b used.
  • On the new base, the CLI's build is the one that ran these scenarios but for the base's own changes: the file_identity gates keep everything in the cli build, and fixture_export is test code. CI's microVM jobs run them on KVM, MSHV and WHP with artifacts built from this head (below).
  • The first commit, tests only, passes on its own on Windows, as d46ca5a4232: Clippy with -D warnings for --all-targets with every feature and with default features, cli, and no default features, and the tests of host::filesystem (32 passed), cli (113 passed, 2 ignored) and security_checklist (3 passed).
  • A code-review subagent reviewed the whole diff, and the file_identity gates again, and found no issue.

CI run 43309903121 on 43ba68825f0 passed: 33 jobs succeeded, among them the microVM scenarios on KVM, MSHV and WHP, with filesystem-shares, filesystem-policy, filesystem-owner, filesystem-comma-paths, denied-filesystem-paths and the public sandbox scenarios, and 9 were skipped as for every pull request (OpenVMM CI of the pinned revision, for the unchanged pin, the debug kernels, publishing and performance records). Copilot's review of 43ba68825f0 recommends approval, with no comments.

@ppenna Pedro Henrique Penna (ppenna) added tests-modified Changes existing tests, test data, or test wiring feat-nvx-refactor labels Nov 12, 2026
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

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

Test code

Change What Before After
modified helper struct FilesystemPolicy in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:9 nvx-rs/src/host/filesystem/tests.rs:12
modified helper fn convention in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:51 nvx-rs/src/host/filesystem/tests.rs:56
modified helper fn plain_request in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:60 nvx-rs/src/host/filesystem/tests.rs:66
modified helper fn root in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:78 nvx-rs/src/host/filesystem/tests.rs:85
modified helper fn canonical in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:96 nvx-rs/src/host/filesystem/tests.rs:104
modified helper fn sources in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:100 nvx-rs/src/host/filesystem/tests.rs:109
modified helper fn option_values in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:108 nvx-rs/src/host/filesystem/tests.rs:118
modified helper fn second_volume in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1081 nvx-rs/src/host/filesystem/tests.rs:1106
modified helper fn at in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1115 nvx-rs/src/host/filesystem/tests.rs:1142
modified helper fn cold_run_expected in cli/openvmm (tests), impl Options`` nvx-rs/tests/cli/openvmm.rs:261 nvx-rs/tests/cli/openvmm.rs:379
modified helper fn plan in security_checklist (tests) (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where any ( target_os = "linux" , windows ) and feature = "host" did) nvx-rs/tests/security_checklist.rs:47 nvx-rs/src/host/filesystem/tests.rs:21
modified imports the imports of host::filesystem::tests nvx-rs/src/host/filesystem/tests.rs:1 nvx-rs/src/host/filesystem/tests.rs:2
modified imports the imports of security_checklist (tests) nvx-rs/tests/security_checklist.rs:13 nvx-rs/tests/security_checklist.rs:14
modified test fn unrelated_directories_are_exported_with_their_own_access in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:167 nvx-rs/src/host/filesystem/tests.rs:178
modified test fn host_paths_may_contain_commas in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:232 nvx-rs/src/host/filesystem/tests.rs:244
modified test fn mapped_files_are_exported_alone in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:301 nvx-rs/src/host/filesystem/tests.rs:314
modified test fn policies_beyond_the_children_of_an_aggregate_are_refused in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:402 nvx-rs/src/host/filesystem/tests.rs:416
modified test fn nested_mappings_merge_into_the_outermost_directory in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:459 nvx-rs/src/host/filesystem/tests.rs:474
modified test fn read_only_paths_inside_read_write_directories_are_refused in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:518 nvx-rs/src/host/filesystem/tests.rs:534
modified test fn denied_paths_belong_to_the_directory_that_contains_them in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:603 nvx-rs/src/host/filesystem/tests.rs:620
modified test fn unenforceable_policies_are_rejected in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:656 nvx-rs/src/host/filesystem/tests.rs:674
modified test fn spellings_of_one_object_share_its_guest_path in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:725 nvx-rs/src/host/filesystem/tests.rs:744
modified test fn paths_that_only_a_verbatim_path_names_are_refused in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test and windows hold, not where feature = "host" and test and windows did) nvx-rs/src/host/filesystem/tests.rs:758 nvx-rs/src/host/filesystem/tests.rs:777
modified test fn policy_paths_follow_openvmm_rules in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:801 nvx-rs/src/host/filesystem/tests.rs:821
modified test fn openvmm_limits_are_checked_per_directory in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:847 nvx-rs/src/host/filesystem/tests.rs:868
modified test fn swapped_objects_fail_verification in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:880 nvx-rs/src/host/filesystem/tests.rs:902
modified test fn objects_that_cannot_be_inspected_fail_verification_by_what_the_failure_shows in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:942 nvx-rs/src/host/filesystem/tests.rs:965
modified test fn read_only_binds_that_the_host_cannot_enforce_fail_verification in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1037 nvx-rs/src/host/filesystem/tests.rs:1061
modified test fn directories_on_other_volumes_are_exported_too in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1092 nvx-rs/src/host/filesystem/tests.rs:1118
modified test fn explicit_targets_place_mappings_at_any_free_guest_path in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1125 nvx-rs/src/host/filesystem/tests.rs:1153
modified test fn policy_paths_hide_show_and_narrow_writes in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1329 nvx-rs/src/host/filesystem/tests.rs:1358
modified test fn narrowed_writes_pin_only_what_lies_in_writable_paths in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1492 nvx-rs/src/host/filesystem/tests.rs:1522
modified test fn the_caller_owner_reaches_openvmm_on_linux_hosts in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1569 nvx-rs/src/host/filesystem/tests.rs:1600
modified test fn read_write_mappings_to_which_writes_are_narrowed_stay_visible in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1628 nvx-rs/src/host/filesystem/tests.rs:1660
modified test fn denied_mapped_directories_inside_denied_ones_show_their_allowed_paths in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where feature = "host" and test did) nvx-rs/src/host/filesystem/tests.rs:1689 nvx-rs/src/host/filesystem/tests.rs:1722
modified test fn mapped_paths_resolve_to_utf8_paths in host::filesystem::tests (moved, and it now compiles where feature = "cli" and feature = "host" and target_os = "linux" and test hold, not where feature = "host" and target_os = "linux" and test did) nvx-rs/src/host/filesystem/tests.rs:1788 nvx-rs/src/host/filesystem/tests.rs:1821
modified test fn an_export_refuses_guest_targets_that_are_not_canonical_or_that_a_root_reserves in security_checklist (tests) (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where any ( target_os = "linux" , windows ) and feature = "host" did) nvx-rs/tests/security_checklist.rs:52 nvx-rs/src/host/filesystem/tests.rs:1855
modified test fn an_export_refuses_a_read_only_path_inside_a_writable_directory in security_checklist (tests) (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where any ( target_os = "linux" , windows ) and feature = "host" did) nvx-rs/tests/security_checklist.rs:87 nvx-rs/src/host/filesystem/tests.rs:1891
modified test fn the_caller_owner_is_refused_on_windows in security_checklist (tests) (moved, and it now compiles where feature = "cli" and feature = "host" and test and windows hold, not where any ( target_os = "linux" , windows ) and feature = "host" and windows did) nvx-rs/tests/security_checklist.rs:110 nvx-rs/src/host/filesystem/tests.rs:1917
modified test fn an_exported_object_that_a_workload_could_move_is_checked_again_before_a_start in security_checklist (tests) (moved, and it now compiles where feature = "cli" and feature = "host" and test hold, not where any ( target_os = "linux" , windows ) and feature = "host" did) nvx-rs/tests/security_checklist.rs:120 nvx-rs/src/host/filesystem/tests.rs:1930
removed helper fn plan in host::filesystem::tests nvx-rs/src/host/filesystem/tests.rs:17
removed helper fn request in security_checklist (tests) nvx-rs/tests/security_checklist.rs:31

Test policy

Change What Before After
loosened allowlist entry nvx-rs/src/host/platform/linux/mod.rs (the seams allow 3 test hooks, up from 1) scripts/test-layout-allowlist.json
loosened allowlist entry nvx-rs/src/host/platform/other.rs (the seams allow 1 test hooks) scripts/test-layout-allowlist.json
loosened allowlist entry nvx-rs/src/host/platform/windows/identity.rs (the seams allow 7 test hooks) scripts/test-layout-allowlist.json
loosened allowlist entry nvx-rs/src/host/platform/windows/mod.rs (the seams allow 2 test hooks, up from 1) scripts/test-layout-allowlist.json

Relocated unchanged: 0; added: 12. Compared the merge base d67a2d5ab57c with 43ba68825f07.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues block approval of the changes making export planning and pre-launch host rechecks private to the CLI.

No open issues 🎉

What changed in this PR

This PR advances #1125’s library-slimming work by making export planning and pre-launch host rechecks private to the CLI. It preserves CLI policy behavior, identity pins, and the public export-description, structural-validation, and lowering APIs.

Changes:

  • Makes the planner, its input types, and host rechecks crate-private and gated by cli.
  • Moves export security tests beside their owner and replaces the CLI fixture’s planner dependency with an independently constructed export.
  • Updates documentation, acceptance-test references, and Linux/Windows public API snapshots.
File Description
nvx-rs/​tests/​security_checklist.rs Removes export checks relocated to filesystem unit tests.
nvx-rs/​tests/​cli/​openvmm.rs Builds expected fixture exports without calling the private planner.
nvx-rs/​src/​host/​mod.rs Documents the distinction between public export operations and CLI planning.
nvx-rs/​src/​host/​filesystem/​verify.rs Privatizes and gates host rechecks while retaining public structural validation.
nvx-rs/​src/​host/​filesystem/​tests.rs Gates planner tests and receives the relocated security checks.
nvx-rs/​src/​host/​filesystem/​policy.rs Gates policy-resolution and checking helpers used by the CLI.
nvx-rs/​src/​host/​filesystem/​mod.rs Narrows planner visibility and documents the remaining public contract.
nvx-rs/​src/​host/​filesystem/​limits.rs Gates host-inspection helpers while retaining shared limit checks.
nvx-rs/​src/​host/​filesystem/​host_path.rs Gates identity lookup and lenient canonicalization helpers.
nvx-rs/​README.md Describes the public export API and private CLI path rules.
nvx-rs/​public-api/​windows.txt Removes privatized planner and verifier entries from the Windows snapshot.
nvx-rs/​public-api/​linux.txt Removes privatized planner and verifier entries from the Linux snapshot.
doc/​acceptance-case-matrix.md Points coverage references to the relocated filesystem tests.

Review effort: Balanced

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. A denied path that a workload could move
  carries a zero identity there: ExportPlan::check requires one, and
  no command line carries it.

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.

host::platform's file_identity, crate-private since SL6.14, then has
no caller outside the CLI and the tests: the planner, its limits and
verify were the others. Like process_start_time, it and its
re-exports take cfg(any(test, feature = "cli")), since the unit tests
of host::vm and host::snapshot compare the files and volumes that
paths name with it. On Windows, handle_identity and the five imports
that only the two use take it too, and on Linux the identity module,
whose other items already take cli. The test-layout allowlist records
the eleven hooks as seams: two more in linux/mod.rs, one more in
windows/mod.rs, seven in windows/identity.rs and one in other.rs.

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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues remain for the changes making export planning and pre-launch host rechecks private to the CLI.

No open issues 🎉

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) merged commit 19b5404 into feature/nvx-refactor Nov 12, 2026
87 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/slim-sl6-5a2-path-rules-private branch November 12, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants