Repository navigation
host: read strict snapshots through the platform layer (SL6.0a) - #1479
Merged
Pedro Henrique Penna (ppenna) merged 1 commit intoNov 11, 2026
Merged
Pedro Henrique Penna (ppenna) merged 1 commit into
Pedro Henrique Penna (ppenna) merged 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the relocation of strict snapshot-read helpers into the platform layer.
No open issues 🎉
What changed in this PR
Moves strict snapshot file reads into host::platform, preparing for removal of the legacy stores under #1120. The refactor preserves size limits, regular-file checks, refusal classification, and the public API.
Changes:
- Relocates bounded-read helpers and reparse-point detection to the platform layer, retaining compatibility aliases.
- Switches snapshot manifest and key readers to use the platform helpers directly.
- Adds tests for bounded reads, non-regular-file rejection, and shared refusal classification.
| File | Description |
|---|---|
nvx-rs/src/host/store/tests.rs |
Tests that store-entry refusals retain platform classification. |
nvx-rs/src/host/store/regular.rs |
Retains aliases and delegates regular-file checks to platform helpers. |
nvx-rs/src/host/snapshot/manifest.rs |
Reads manifests through the platform layer. |
nvx-rs/src/host/snapshot.rs |
Reads snapshot keys through the platform layer. |
nvx-rs/src/host/platform/tests.rs |
Adds bounded-read and link/directory refusal tests. |
nvx-rs/src/host/platform/mod.rs |
Owns strict file-read helpers and refusal classification. |
nvx-rs/src/host/filesystem/host_path.rs |
Re-exports reparse-point detection from its new platform owner. |
Review effort: Balanced
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/slim-sl6-0a-strict-reads
branch
from
November 11, 2026 15:36
597569d to
f5436a7
Compare
SnapshotManifest::read and Snapshot::open read a snapshot's manifest and key with open_regular and read_at_most from host::store::regular, so the strict snapshot reads depended on file helpers and a refusal classification that the store owns, and later pull requests delete the store. Move open_regular, read_at_most, is_refused, the private Refused type and their regular-file support (not_regular, refused_open and regular) to host::platform, which stays and already holds the host's file helpers. regular() needs is_reparse_point, which moves down from host::filesystem::host_path to host::platform and stays re-exported where it was, since filesystem builds on platform and the children of host depend on one another without cycles. The store keeps open_regular_in, which builds its link and non-regular-file refusals with the moved refused_open and regular, and keeps open_regular, read_at_most and is_refused as aliases for its remaining callers until #1121 deletes them. SnapshotManifest::read, and read_attachments, which shares its read, and Snapshot::open's read of key.bin use host::platform directly. The maximum-length error, the refusal of links, directories and other files that are not regular files, and the refusal classification stay as they were. finish_capture, the CLI's sandbox store and the CLI's capture still read through the aliases, since they also use the store's private-file helpers, which this change does not move. The manifest reader's tests, which refuse a missing manifest, one over MAX_MANIFEST_LEN, a directory, a link, a junction and a FIFO, the snapshot tests, and the clone path's keys_that_their_read_refuses_for_what_they_are_are_failures_of_the_template pass unchanged. New platform tests pin the moved reads' bound, messages and refusal classification, and a store test checks that open_regular_in refuses a link and a directory with refusals that host::platform recognizes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pedro Henrique Penna (ppenna)
force-pushed
the
agents/slim-sl6-0a-strict-reads
branch
from
November 11, 2026 17:30
f5436a7 to
bb21897
Compare
Pedro Henrique Penna (ppenna)
merged commit Nov 11, 2026
66fd431
into
feature/nvx-refactor
48 checks passed
Pedro Henrique Penna (ppenna)
deleted the
agents/slim-sl6-0a-strict-reads
branch
November 11, 2026 17:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #1120 (SL6.0a, "Strict snapshot reads survive the stores' removal"). Parent #1087, umbrella #1076.
What and why
SnapshotManifest::readandSnapshot::openread a snapshot's manifest and itskey.binwithopen_regularandread_at_mostfromhost::store::regular. So the strict snapshot reads depended on file helpers and a refusal classification that the store owns, and #1121 deletes the store. This PR moves those helpers to the host's platform layer and switches the retained snapshot readers to it:open_regular,read_at_most,is_refused, the privateRefusedtype and their regular-file support (not_regular,refused_open,regular) move fromhost::store::regulartohost::platform, which stays. The moved code is unchanged, except thatrefused_openandregularbecomepub(crate)for the store'sopen_regular_in.regularneedsis_reparse_point, which moves down fromhost::filesystem::host_pathtohost::platformand stays re-exported where it was:filesystembuilds onplatform, and the children ofhostdepend on one another without cycles (tests/host_modules.rs).open_regular_in, which now builds its link and non-regular-file refusals with the movedrefused_openandregular. It keepsopen_regular,read_at_mostandis_refusedas aliases for its remaining callers until nvx-rs slimming 4.2.2: the old clone path, template store and sandbox store are gone #1121 deletes them.SnapshotManifest::read,read_attachments, which shares its read, andSnapshot::open's read ofkey.binusehost::platformdirectly.The maximum-length error, the refusal of links, directories and other files that are not regular files, and the refusal classification are unchanged. The public API doesn't change: every moved item is crate-private, and
scripts/public_api.pyfinds both snapshots current.BOOT_CONTRACT_VERSIONandCONTROL_CONTRACT_REVISIONdon't change. The issue's Scope names the manifest reader at its old path,host/template/manifest.rs, which SL2.12a moved tohost/snapshot/manifest.rs.Scope extension:
Snapshot::openThe Scope names only
SnapshotManifest::read, which was the only strict snapshot reader when #1120 was written. SL2.12b (#1440) then addedSnapshot::open, which readskey.binthrough the same store helpers. The slice's Objective says that retained readers use their new owner, so, as the orchestrator decided, this PR switchesSnapshot::openas well: one import and two calls inhost/snapshot.rs, which keeps the PR within its limits.Not in this PR: callers to move before SL6.1
These retained callers still use the store's helpers and must move before SL6.1 (#1121) deletes
host/store/. Besides the aliases, they use the store's private-file helpers inhost::store::files(write_private,sync_dir,create_new), which this slice doesn't move, so they belong to a later slice:finish_capture, inhost/snapshot/capture.rs:open_regularandread_at_mostthrough the aliases, andwrite_privateandsync_dir;host/cli/store/files.rs:open_regularandread_at_mostthrough the aliases, andhost::store::files;host/cli/snapshots/capture.rs:create_new;host/cli/snapshots.rs:sync_dir.The store and clone callers keep the aliases until their deletion, as the Scope says.
History: the first implementation
Enrique Saurez (@esaurez)'s first implementation is
esaurez/slim-4.2.1-sl6.0a-20261108(6231b876, checkpoint on #1120): one commit that moved the helpers and switched the manifest reader. This PR replays it as its only commit, with Enrique Saurez (@esaurez) as its author, and corrects it:host::platform's tests, became two platform tests without store references and a store test ofopen_regular_in;host::platform,is_refusedandhost::store::regulardescribe the new owner;Snapshot::openswitches too, as above.Size
Measured against
feature/nvx-refactorab7c9b5f, as againstd40228beanda53a2626before it, since the rebases left the patch unchanged: 83 core lines (estimate 150, stop 300) in 5 counted files:host/platform/mod.rs,host/store/regular.rs,host/snapshot/manifest.rs,host/snapshot.rsandhost/filesystem/host_path.rs. The two test files don't count.Tests of the area
Every existing test is kept, unchanged. These read through the moved helpers:
host::snapshot::manifest::tests:read_reads_the_manifest_of_a_snapshot,read_refuses_a_missing_manifest_as_not_found,read_refuses_more_than_a_manifest_may_hold,read_refuses_a_directory,read_refuses_a_link,read_refuses_a_junction(Windows),read_refuses_a_fifo_without_waiting_for_a_writer(Unix),the_manifests_that_openvmm_writes_are_readand thethe_attachments_*tests now read throughhost::platform.host::snapshot::tests:snapshot_open_uses_the_strict_manifest_and_bounded_key_decoders, which still refuses an oversized key, and the othersnapshot_open_*tests now open keys throughhost::platform; so doeshost::snapshot::key::tests::snapshot_open_refuses_other_key_contracts_and_filesystem_tags.host::template::clone::tests::keys_that_their_read_refuses_for_what_they_are_are_failures_of_the_templatestill classifies a link, a directory and an oversized key as refusals through the aliases, andfiles_that_their_paths_do_not_name_as_checked_are_refusedandonly_a_path_that_no_longer_names_its_supplied_file_is_the_request_skeep the refusal's message.links_are_refused,records_that_are_not_regular_files_fail_at_once,payloads_are_checked_as_they_are_readandlinks_and_unsafe_ownership_are_refused_before_the_vm_startskeep their messages.Added:
host::platform::tests::a_bounded_read_refuses_a_regular_file_that_holds_more_than_its_bound;host::platform::tests::an_open_of_a_regular_file_refuses_a_link_and_a_directory(Unix);host::store::tests::entries_that_are_links_or_not_regular_files_are_refused_as_the_platform_refuses_them(Linux and Windows):open_regular_in's refusals are ones thathost::platformrecognizes.Validation
feature/nvx-refactorhas noscripts/local_gates.py, sodev's copy selected the gates and ran them with this branch's own action commands and pinned toolchain (1.95.0; MSRV 1.89), on Windows locally and on Linux onnvx-kvm-test(KVM, virtual machine, Azure Linux 3). The full matrix ran on67213558, based on5947e4e8.Snapshot::open's switch came next, and the branch was then rebased onto8b775211(SL2.16), ontod40228be(after SL4.3 and SL6.0b), ontoa53a2626(after SL3.5a, #1466) and ontoab7c9b5f(after SL3.9, #1469), without conflicts;git range-diffshows the same patch each time, andrebase_check.py verifypassed after each of the last two rebases. CI passed on597569d5(run 42995101590: 37 passed, 9 skipped), wherecargo doc --all-featuresalso built without warnings and a code review of the whole diff found no issue.On the head,
bb218975, based onab7c9b5f, these ran again on Windows:cargo fmt --all --check, and the five Clippy runs of the Lint step, among themcargo clippy -p nvx --lib --no-default-features -- -D warnings: passed;host::snapshot,host::platform,host::storeandmanifestselect, with the clone path's refusal test: 217 passed with--all-featuresand 211 with the default features;tests/host_modules.rs(22 tests),check_test_layout.py,check_test_changes.py, andpublic_api.py, whose Linux and Windows snapshots are unchanged: passed.On
f5436a77, the previous head, the same library tests withhost::vm,host::restoreandhost::cli::storeadded passed 285 with the default features. With--all-features, 333 passed andhost::restore_driver::tests::ready_has_sixty_seconds_and_start_thirty_from_ready_for_each_pending_accept_and_read(SL4.3), which thehost::restorefilter also selects, failed once: in that parallel run, itsactivate-readcase expired after 59.99996 of its 60 seconds. It passed 2 runs in 2 alone, and failed the same way, after 59.9994 seconds, in thenvx-rs / windows-latestjob offeature/nvx-refactor's own push CI ofa53a2626(run 42994995631).host::restore_driveruses none of the moved helpers.CI passed on
f5436a77(run 43050110604: 34 passed, 9 skipped,Required status checkamong the passed). The push-triggered Copilot Setup Steps off5436a77(run 43050098502), which isn't part of CI, failed in its first two attempts: itsnative-buildsandarchivessteps couldn't resolveazure.archive.ubuntu.comandcdimage.ubuntu.com(Temporary failure in name resolution), as every setup run that ran from 15:36 to 16:40 UTC did,dev's among them. Once other branches' setup runs passed again, its third attempt, a rerun of the failed job, passed.CI passed on
bb218975(run 43068922503: 34 passed, 9 skipped,Required status checkamong the passed), and so did its Copilot Setup Steps (run 43068910907).67213558cargo fmt --all --check-D warnings, the five feature sets of the Lint stepcargo test --locked --all-featuresguest::*failures, belowcargo test --lockedcargo buildandcargo test --lib,--no-default-featurescargo doc --all-featureswith-D warningsscripts/public_api.py(both snapshots)597569d5)cargo +1.89 checknvx.py check-guest-binariesguest::*failures, belownvx.py build-guest-binaries,test-guest-binariescheck_test_layout.py,check_markdown_links.py,check_test_changes.pyvalidate-nvx)pipEvery failure also fails at the base on the same host:
host::cli::snapshots::capture::tests::a_capture_ack_and_successful_output_without_timely_exit_are_stopped_but_never_finished(a 1-second capture deadline: 3 runs in 3 at the head, 2 in 3 at the base),tests/template_capture.rs'svms_that_never_end_are_torn_down_at_the_deadline(a 2-second deadline: 5 in 5 at both, run alternately), and, once in the default-feature run,host::platform::windows::tests::children_inherit_only_their_standard_handles, which passes 3 runs in 3 alone at both. With--no-fail-fast, every other unit test, integration test and doctest passes. The CLI checks'scripts/test_microvm_tests.pyhas 16 errors in its scenario-script tests at the head and 18 at the base; no script changes.--all-features, the same 28 tests ofguest::{entry, exec, init, managed_agent}fail at both revisions, and the guest musl suite ofcheck-guest-binariesfails the same 26 at both. These tests reach none of the changed modules, which the guest build doesn't compile.No microVM scenario ran: the change moves crate-private helpers without changing their behavior. CI runs the selected hypervisor suites on KVM, MSHV and WHP.
Changes to existing tests
python3 scripts/check_test_changes.py --base origin/feature/nvx-refactorlists no change to an existing test, and the 3 added tests above, so this PR has notests-modifiedlabel.The
openvmmgitlink doesn't move.