Repository navigation
SL3.5a: provision typed EROFS/GPT images and bounded RAM uppers - #1466
Conversation
This pull request changes existing testsIt modifies or removes 27 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
End-to-end tests
CI test wiring
Relocated unchanged: 0; added: 3. Compared the merge base |
There was a problem hiding this comment.
🔵 Needs a closer look
Reported final-head Ubuntu RAM-upper acceptance failures on both MSHV and WHP require maintainer resolution of the runtime/oracle contract and successful real-guest validation.
No open issues 🎉
What changed in this PR
This PR implements SL3.5a on top of the SL3.5b lifecycle migration, extending persistent sandbox provisioning with typed EROFS/GPT images and bounded RAM uppers.
Changes:
- Replaces legacy configuration records with format 9: one typed image and either a scratch path or a RAM cap.
- Adds provision-only
--layer-formatand--ram-upper-percentoptions, with caps from 1–90%, defaulting to 50%, and shares configuration projection between provision and start. - Updates regression tests, acceptance checks, CI assertions, and documentation for the new contract.
The PR reports that full Ubuntu RAM acceptance remains blocked by the initial mount-namespace check on both tested platforms.
| File | Description |
|---|---|
scripts/test_microvm_tests.py |
Updates RAM fixtures and adds wrong-format and wrong-cap fault cases. |
scripts/nvx_tools/sandbox_ram_upper_tests.py |
Requires typed format-9 RAM records with the default cap. |
nvx-rs/tests/cli/usage.rs |
Updates expected help for image formats and RAM caps. |
nvx-rs/tests/cli/lifecycle.rs |
Adapts lifecycle fixtures and malformed-record checks. |
nvx-rs/tests/cli/formats.rs |
Covers image/upper combinations and rejects legacy or invalid records. |
nvx-rs/tests/cli.rs |
Adapts layer rejection and binding assertions to the single-image record. |
nvx-rs/src/host/cli/sandbox/tests.rs |
Tests cap parsing and provision-only option restrictions. |
nvx-rs/src/host/cli/sandbox/state.rs |
Defines format 9 and the shared typed VM configuration projection. |
nvx-rs/src/host/cli/sandbox/options.rs |
Adds image-format and RAM-cap parsing and help. |
nvx-rs/src/host/cli/sandbox/mod.rs |
Enforces option scope and passes format/cap choices into provision. |
nvx-rs/src/host/cli/sandbox/lifecycle/start.rs |
Uses the shared projection to consume recorded image and upper settings. |
nvx-rs/src/host/cli/sandbox/lifecycle/mod.rs |
Carries the optional RAM cap in provision configuration. |
nvx-rs/README.md |
Documents the typed record and rejection of older formats. |
doc/usage.md |
Documents new options, defaults, and restrictions. |
doc/run.md |
Updates managed configuration format and reprovisioning guidance. |
.github/workflows/run-nvx-microvm-tests.yml |
Updates five configuration-version assertions to format 9. |
Review effort: Balanced
369ad2d to
5b7882a
Compare
d417f1a to
5121ab9
Compare
d9c518e to
bcaaa60
Compare
5121ab9 to
22e9805
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: aec73065-9547-4d77-a63b-a6307a637d10
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: aec73065-9547-4d77-a63b-a6307a637d10
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: aec73065-9547-4d77-a63b-a6307a637d10
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: aec73065-9547-4d77-a63b-a6307a637d10
22e9805 to
74844c4
Compare
a53a262
into
feature/nvx-refactor
|
Merged by rebase onto |
Prerequisites merged: #1460, the SL3.5b lifecycle that this pull request was stacked on, merged into
feature/nvx-refactor, as did every input that #1458 joined. This pull request now targets that branch, as the next section describes. The RAM-upper acceptance blocker below is resolved there: #1460's acceptance checks executions as nvx-init runs them.Rebase onto
feature/nvx-refactor#1460 merged at
821de193f45fa1f592f6a37d99e6f7793e6dde66, after #1470, so this pull request's four own commits are rebased onto it as2beec1cb2d..22e9805b0632057917285fb96a1d0274cb2b745d, tree0e8ff8c9dc30b6f8588544747945fa48f33e88a3. The four merge commitsf5004c83,7ad108c4,8ed81bc3andd417f1a7, which joined #1460's published fixes, are dropped:git show --remerge-diffshows no change of their own, and #1460's merge carries their inputs.git range-diff 369ad2d512..d417f1a7b5 821de193f4..22e9805b06reports two of the four patches identical. Keep provision acceptance consumers on the typed configuration differs only in context, the lines that #1460 changed beside its own. The first, Record typed sandbox roots and bounded RAM uppers, carries two resolutions:nvx-rs/src/host/cli/sandbox/state.rswith host: keep immutable named CLI snapshots #1445, which merged intofeature/nvx-refactorafter this branch's original base and records the immutable named snapshot of a restored sandbox:source_snapshot.Configgains it as an optional field, whichdeny_unknown_fieldsthen admits; it is omitted when absent and read back asNone.serialize_launchdelegates to host: keep immutable named CLI snapshots #1445'sserialize_launch_with_snapshot, which records it. host: keep immutable named CLI snapshots #1445's accessorConfig::source_snapshotstays, unused outside tests until SL3.8a.host::cliand itsstate/tests.rsmodule, and importsPathBufagain for format 9's projection.restored_sandbox_records_round_trip_only_their_own_snapshot_namesets the newProvisionConfig::ram_upper_percenttoNone. It still checks that only a restored record carries the name, that the record reads it back, and that a malformed name is refused.start'svm_configinto the typed record's projection instate.rs, where SL3.5b: migrate persistent sandbox lifecycle to CLI-owned VM state #1460's sandbox: generate the machine ID of a started sandbox's VM had changed the view's machine ID. The projection keeps the generated machine ID that SL3.5b: migrate persistent sandbox lifecycle to CLI-owned VM state #1460 chose, as the sandbox agent gave one.check_test_changes.py --base origin/feature/nvx-refactorreports 27 changed existing items and 3 added ones: the 26 changed items and 3 added tests that the dispositions below explain, and #1445's round-trip test above.CI passed every job at
22e9805b, run 42985903207. #1476 then merged intofeature/nvx-refactorat35cedfdbc3a86ba9da289af014a91f5a3775172b, so the four commits are rebased onto it asb448ed6497..74844c49cdc7536838a5e18633a1fcf448393958, tree658bfe85dc45fb07653002544530043d060cf221. They apply without conflict: #1476 also editsnvx-rs/README.md, elsewhere. CI runs on this head.The RAM-upper acceptance's namespace failure, below, came from the smoke probe's check of the sandbox agent's private namespaces. #1460 checks the executions of a started sandbox as #1115 has nvx-init run them, as plain processes in the VM's root, through the probe's
initargument, whichRamUpperAcceptance.check_managedpasses. CI runs the acceptance on this head.Rechecked on Windows at
22e9805b, and again at74844c49, with the commands ofcheck-nvx-rsthat apply:-D warningsfor--all-targets --all-features,--lib,--lib --no-default-features,--lib --bins --features cliand--lib --bins --no-default-features --features testing, and for--all-targets --all-featuresand--lib --bins --features clionx86_64-unknown-linux-musl;cargo +1.89 check --all-targets --all-features; rustdoc with-D warnings;cliintegration tests, with--all-features;scripts/public_api.py, the test layout and Markdown links.At the same commits on #1460's previous head
d9c518e3, Ruff, and Pyright for Windows and Linux, of the two changed Python files passed.PublicManagedExecAcceptanceTests,PublicSandboxLifecycleTests,PublicSandboxProxyOnlyTests,PublicSandboxRamUpperTestsandSandboxSmokeProfileTests, 43 tests, passed on Linux under WSL.Scope and dependency
Refs #1110, SL3.5a only, under #1076. Ordinary dependent Draft on #1460, base
esaurez/sl35b-lifecycle-4d48405a-20261110; no native-stack metadata is created or changed. SL3.5a needs SL3.5b only; SL3.5c follows this layer, not the reverse.Before the rebase above, the original independently captured parent was
b6fd473991dcb186579b121798ea9d2c207001bd, treede9de23cfe46228de24bb3335791c72e01adf62a. Explicit coordinator-routed published fixes10a90cee,9bf02890,068da312, then369ad2d5were joined with ordinary own-branch merges, never private producer edits, rebases, force pushes or conflict resolution. Selected parent is369ad2d51297e4bd1d3249d0ff3786d20a1e6efb, tree4e7357a0d2dd8262ba5c94869d16c9829832f841; its last incoming deltas are only the producer-owned Python SavedVm acceptance port and its typing fix. No parent qualification is inherited.Provision now writes only typed configuration format 9: one image
{format, path, identity}and an upper tagged as scratch with its path, or RAM withmax_memory_percent. Start reconstructs the sameRootConfig::Layered/UpperConfigprojection that provision checks. RAM caps are integers from 1 through 90; omission records 50, and each start consumes that exact recorded value.The existing single-image
--layer distro,PATH,UUIDinput remains. New provision-only--layer-format {erofs,gpt}selects the actual image format, EROFS by default;--ram-upper-percent PERCENTrequires--upper ram. Invalid inputs are refused. There is no format discovery, EROFS wrapper for GPT, layers-array record, legacy-format reader, converter, registry, or dual writer.The parent's lifecycle lock, prepared journal, verified process/runtime identity, recovery, reattach, graceful/forced stop, owned removal, image-binding refusals and scratch claims remain. Caller-owned image paths stay stable while the VM uses them. No retired descriptor/Ready-guard guarantee is revived. No SL3.5c protected paths, stateless-run migration, exec admission, capture/restore, guest/native/protocol change, public API, or unrelated option/output redesign is included.
Validation and known limits
Final source:
d417f1a7b5a045d1da60cbc567118ec172dc73cd, treef042bf0f51a2c2b3a4141c3d09c303635cb1f905, merge parents8ed81bc3and the selected published369ad2d5.The complete Rust CLI/library, runtime-adapter, native pin and artifact-input Git blobs are byte-identical to independently checked own commit
7ad108c4e0d677a0ba742c74661e7cd1e194240b, tree9edaa05530051de301e1deff70c87a41bdbcb69e. Onlydoc/run.mdand the two incoming Python acceptance/test files changed afterward. The following executed-source mapping is explicit; older executions are not relabeled as runs at the final merge.7ad7ad7ad--lib --no-default-features7ad7add417d417d417a80e9883d417, correct standard fixtureThe
a80e9883f6375cd5c693e81b88325c7d34592ffbhardware source, tree1aa34ff4434e5f88b7740d4a2bdd6ab374c1181f, uses the exact same compiled production inputs/binaries as finald417. Each matrix uses EROFS and GPT, each with scratch and RAM; RAM covers omitted/default 50, explicit 1 and explicit 90. Every case provisions, starts/executes/stops twice, then deprovisions. The real guest reports UID 65534 and actual format/cap boot tokens; configuration hashes stay unchanged between starts. Actual outcomes and logs are retained, and all owned state is removed. Historicalc50full and7adfocused receipts remain labeled with their real executed tuples.Resolved producer failures, not suppressed: parent
068da312introduced four strict Pyright Unknown-list errors, reproduced on both approved hosts at own8ed. The exact public producer fix369ad2d5was then explicitly routed and joined, and both actual final Pyright runs pass. That helper has no own delta relative to the selected parent; no stubs, oracle weakening or eighth own production path were added here. The earlier parent Windows Clippy/guard-fixture failures were likewise resolved through the explicitly published parent fixes and the actual7adchecks above. Earlier failed gates remain in the evidence rather than being relabeled.Acceptance blocker, since resolved by #1460 as the rebase section describes: the unmodified
RamUpperAcceptance.check_managedwas executed on both real hosts at finald417with the validated standard Ubuntu layer and manifest, not the earlier minimal fixture. Typed format-9/default-50, provision, start, SavedVm reader and home checks pass. The first real probe exec fails withNVX-UBUNTU-SANDBOX-FAIL: the workload shares the initial mnt namespace. This runtime/oracle boundary is routed to the coordinator for ownership and contract resolution; it is not silently fixed, attributed or retired here. Full Ubuntu RAM acceptance is not qualified, and this Draft is not Ready. Actual CLI stop/deprovision return 0 and remove all owned state on both hosts. No HOME, passwd or namespace override, fake guest outcome, assertion skip or guest/native/source patch was used.The standard fixture was produced with the existing isolated
python scripts/nvx.py build-distro-layer --guest ubuntu --output .../guest/ubuntu-distro.erofstarget, current converter digest465bc196458c27873b7f4b77555a63d71979ff0a81fd5c9339408c8b3696a485, image SHA-256f8a9328bf7990241b498bd96e31883bbc4ef3a828e76aedb370b0f3a6b28d387, manifest5697e70813e2ec51a652b8ace484eb5c1708f9bb6c1c1905ad7e60ea846f2261, UUID465bc196-458c-2787-3b7f-4b77555a63d7. Current customization/package-lock inputs, standard manifest, full rootfs digest and fsck were verified before admission; existing qualified guest helpers were reused. Docker, Cargo, native, kernel, guest binaries and initramfs were not rebuilt. Earliera80old-runtime-reader failures and8edwrong-minimal-fixture home failures remain separately preserved, not counted as current qualification.The own pure-production CLI binaries were built separately from testing-feature targets: Linux SHA-256
225afdef7b6cc77696ef99c11ad2d45836f51d4ed35e7963faaf8f7af3ac7397; Windowsf2fe4408d084b8cda1f7fff8e1d3b6bef459dfc4a229cf5876e6603739c28a31. Actual consumed CLI-source digest is333b8febacaddbcf98e5aee67d28de0b3a8272732311620db7734dca843ea9f2. Native source remains14dc4116ec7e57567633c4b7b07892aca3a58522. Reuse independently matched full consumed-input dictionaries, all 170 initramfs inputs, all guest-binary hashes, native/kernel source/config and actual executable hashes. No guest/native/kernel rebuild or provenance relabel was needed. Guest source digest is023d97724f25ff4db66c5ecf8b88b85409fdfc9cd1b3310d0a2923690f669955; nvx-init is5e304155a3e1439d468696ecbd07ca27698b4cb62fca9a526990ac0aadbad613, initramfs3f9378a386bc6b0a3fbfcd91c4fec6c9f65b7f05fd1095b3bafbe49a2fe0bdcb, kernel692ac2a9f351aa5a31dcf1810782d82c1a83a0f1fd0b3edcf4fad9c0d94cfe81. The GPT/ext4 fixture was assembled from the verified existing root using the existing adapter's disk layout.Actual
a80full hardware receipt SHA-256: MSHV9e4be63d1cb7dc6d31180c563fb33c1f09fb7106d1373c987433d88518d9b49b; WHPa78d70ad040664de7018d93428e066fe24a8d1ad5fcc8629603e01fa2b7991e9. Actual finald417standard-Ubuntu failed-attempt receipts: MSHVc47a3e1ef11c7090247db115d9d51e4b8212e77464015289261a8335c43e54f5; WHPeeff51c6583b481809e523180599e6cd87bc8de42296e344c5d6c26cc0dbf09a.Independent introduced-code/test logical review: CLEAN for exact base
369ad2d5to headd417f1a7/treef042bf0f, including the small Python port/type-guard integration. Actual reviewer profile isclaude-opus-5.5/max/long_context(native responseclaude-opus-5-5, 952000 max prompt tokens); the worker root isgpt-6.1-sol/max/long_context. The initial High finding about old acceptance/workflow consumers was fixed, not waived. Review does not substitute for the failed/unperformed gates above.Ignored/skipped software tests are not counted as hardware results. No manual full CI, Ready, merge, auto-merge, native-stack mutation or issue closure is performed. A dedicated final-head Copilot review request is separate from the independent verdict; request admission is not a completed Copilot verdict.
Existing-test dispositions
check_test_changes.py --base 369ad2d51297e4bd1d3249d0ff3786d20a1e6efbreports 26 existing-test/helper/wiring entries and 3 added tests. Five CI version conditions appear in both its added-line and modified-line categories; these are the same five assertion updates, not ten new skips. No existing scenario or assertion is silently dropped.the_upper_is_scratch_or_rama_sandbox_whose_configuration_names_another_layer_role_does_not_startlayersinto the single-image record; refusal before spawn and deprovision remain asserted.provision_binds_a_linked_distro_layer_where_start_checks_itimage.path. Target/alias manifests and binding refusals remain.configurations_of_every_format_start_and_execlifecycle_of_a_sandbox_whose_upper_is_in_ramminimal_configmalformed_configurationHELPcli/formatsimportsStart,reader,formats,renderincli/formatsold_configuration_formats_are_refused_without_migration._FakeRamUpperSandboxCli._provisiontest_acceptance_detects_ram_upper_regressionsRamUpperAcceptance.check_managedinitargument.Added
provision_options_do_not_change_other_commands,old_configuration_formats_are_refused_without_migration, andinvalid_recorded_roots_are_refused_before_spawn. Existing identity, journal/recovery, scratch-claim, binding, stable-path and stop/error-order regressions were kept and executed.Measured size
231 added/changed nonblank core lines, 7 conservatively counted existing paths; 223 deleted core lines reported separately, never subtracted. Tests, comments and docs are excluded. Five existing Rust modules cover parsing, dispatch, typed record/shared projection, start's reader and the one-line RAM-cap field in
lifecycle/mod.rs. The two directly coupled existing CI/acceptance consumers were explicitly approved and conservatively counted after logical review exposed their stale record contract. No new production module or framework is added.The incoming producer-owned SavedVm Python port/type fix is separate: 80 additions and 4 deletions across its two existing acceptance/test files relative to
9bf02890, unchanged from published369ad2d5. It is not disguised as an own eighth production path or inherited runtime proof.