Skip to content

sandbox: record the launch's options without the old launch profile (SL3.10d) - #1503

Merged
Pedro Henrique Penna (ppenna) merged 1 commit into
feature/nvx-refactorfrom
agents/slim-sl3-10d-cli-record
Nov 12, 2026
Merged

Pedro Henrique Penna (ppenna) merged 1 commit into
feature/nvx-refactorfrom
agents/slim-sl3-10d-cli-record

Conversation

@ppenna

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

Copy link
Copy Markdown
Contributor

Part of #1112: SL3.10b, step 3 of 3 (the CLI no longer uses the old launch, store or config APIs). Follows #1497 and #1501, which have merged.

What and why

SL3.10b removes the last uses of nvx's old launch, store and config APIs from the CLI's four shared sandbox modules: host/cli/sandbox/{mod,options,state}.rs and sandbox/lifecycle/mod.rs. Its measured scope came to about ten times its estimate of 20 core lines, since SandboxLaunch, SandboxSettings, SandboxUpper and SandboxNetwork still carry provision, start and the sandbox's record. The split of SL3.10b into three stacked pull requests, each with one goal, was approved for Pedro Henrique Penna (@ppenna):

  1. sandbox: name the runtime identity and gateway without the old store and plan (SL3.10b) #1497: the store and old-plan leftovers.
  2. sandbox: record the network's options and build its policy at each start (SL3.10c) #1501: the sandbox network moves to NetworkConfig, and the record to format 10.
  3. This pull request: SandboxLaunch, SandboxSettings and SandboxUpper leave the four modules for the CLI's record and a VmConfig.

Before, run_from made a SandboxLaunch of the layers, a SandboxUpper and SandboxSettings; provision and sandbox run serialized the record from it; and each start and run read the record back into one, to check it and to take its images, workload identity and shares, through Config::launch. Now:

  • provision and sandbox run pass the distro layer, the scratch image, and the options that the record keeps, the hostname, workload identity and export plan among them, in ProvisionConfig.
  • The launch's checks move into the CLI's record (sandbox/state.rs), with their messages, codes and order: check_workload refuses the entrypoint, arguments, hostname and a root identity as the plan's settings did; check_images refuses the images and the shares as the plan's validated did; and Config::check checks a record at each start as Config::launch did: the RAM upper's cap, the layer's UUID, the workload with the default entrypoint, the export plan for the container root, and the images. Config::vm_config takes the workload identity and the shares from the record itself.
  • run_from refuses duplicate layers with the launch's message, and verifies the distro layer with DistroBinding::verify, which validate_sandbox_systemd_policy called after its systemd-entrypoint refusal; SandboxOptions::check, earlier in run_from, already refuses those entrypoints for run, provision and exec. As before, the workload that it checks for a run and for a restore is the default /bin/sh, since theirs are exec requests that no boot token carries.
  • refuse_own_files takes the image, the scratch image and the export plan in place of the launch, for a state directory, a run's VM directory and a restored sandbox's snapshot store alike.
  • start.rs changes only where removing the types forces it: start, run and record take the record's accessors. It keeps every refusal, including that of the user's nvx_* and virtfs_* boot tokens, a NUL, and a command line over the 1024-byte budget, which VmConfig::check makes only in part. Its new check_command_line still builds the old plan of the sandbox profile from the record for that refusal alone, so the old launch leaves the four modules, but not yet start.rs; see Left for later slices. cli/run.rs does not change.

No output, record, message or public API changes.

Size. 261 core lines, 4 counted files: sandbox/state.rs 118, sandbox/mod.rs 72, sandbox/lifecycle/start.rs 58 and sandbox/lifecycle/mod.rs 13. The public API, BOOT_CONTRACT_VERSION and CONTROL_CONTRACT_REVISION do not change.

Stack. This branch is based on feature/nvx-refactor 533bbb81f8d, which holds #1497 and #1501. Review its one commit, c7fec0980ca.

Case matrix. No row of doc/acceptance-case-matrix.md lists a test that this changes or names one as coverage, and the new CLI test belongs to none of its inventoried sets.

Left for later slices

Old launch, store and config APIs that the CLI still uses outside the four modules, which this split leaves alone:

  • sandbox/lifecycle/start.rs: check_command_line builds SandboxLaunch, SandboxSettings and SandboxUpper for the command-line refusal above, until VmConfig::check refuses what the old plan's kernel_command_line refuses.
  • sandbox/lifecycle/stop.rs: host::supervisor::StopOutcome.
  • sandbox/lifecycle/directory.rs: host::store::SandboxStore.
  • store/files.rs: host::store::{files, regular}.
  • snapshots/capture.rs: host::store::files::create_new.
  • cli/run.rs: host::sandbox::SANDBOX_COMMAND_LINE_MAX_SIZE and mount::export_command_line_fragment, the old plan's command-line budget and rendering.
  • Tests: sandbox/lifecycle/tests.rs (host::supervisor::StopOutcome), store/tests.rs (host::store), store/tests/{liveness,recovery}.rs and snapshots/capture/tests.rs (host::spawn), snapshots/tests.rs and snapshots/capture/tests.rs (host::store::files), and run/tests.rs (the command-line budget).

Validation

At this head (c7fec0980ca), on feature/nvx-refactor 533bbb81f8d; this step's commit has had the same content since 53a4cf1e61d, which Copilot reviewed:

Check Result
Windows: cargo fmt --check; Clippy --all-targets --all-features with -D warnings; cargo test --all-features --lib -- host::cli and --test cli; test_microvm_tests.PublicSandboxRamUpperTests and PublicSandboxGptLayerTests, and test_nvx_tools.CiConfigurationTests; check_test_layout.py; check_markdown_links.py Passed: lib 226, cli 111
Linux (nvx-kvm-test, Azure Linux 3, KVM, virtual machine): the same, with all of scripts/test_microvm_tests.py (353 tests) Passed: lib 226, cli 120
Linux, KVM: nvx.py test-microvm --backend kvm with every public sandbox scenario: managed-exec-config, sandbox-gpt-layer, sandbox-lifecycle, sandbox-proxy-only, sandbox-ram-upper, snapshot-core, snapshot-tiers and vm-lifecycle Passed: nvx-rs and the Alpine initramfs built at this head; OpenVMM, the kernel and the scratch template of release v0.1.0-dev.53ad09678bc1, which pins the same OpenVMM; the Ubuntu distro layer of feature/nvx-refactor 64ad98afacc's CI run, whose guest inputs this head keeps
Linux, KVM, at the tree of 53a4cf1e61d and at that of its base, feature/nvx-refactor 14ca2671205: snapshot capture; snapshot restore with a RAM upper and a workload with whitespace and double quotes; sandbox exec, stop, start, exec, stop and deprovision of the restored sandbox; run --restore-snapshot with a RAM upper and with a scratch upper, with a workload that exits with status 7, and with --net and --workload-user 0:0, which it refuses The same statuses, outputs and messages at both, but for the record's format, 10 rather than 9. run --restore-snapshot with --workload-user 1000:1000 and --hostname restored fails at both, with guest-exit status 125

Earlier rebases onto #1489 and #1491, then onto SL5.1b, SL5.1c, SL5.2, #1508 and #1511, and then onto #1497 and #1501 as they merged, changed none of this step's content after the first of them, which resolved three conflicts with #1489: in sandbox/mod.rs, a restore's workload is the default one too, as run's, which run_from keeps; in start.rs, a restored start refuses a share of its snapshot store, which refuse_own_files now does with the record's image, scratch image and shares; and in start/tests.rs, whose restore tests SL3.8a moved to start/tests/restore.rs, where a_restored_start_refuses_a_share_of_its_snapshot_store, which came with SL3.8a, also builds its record without a SandboxLaunch. The size grew from 253 to 261 core lines then. rebase_check.py verify reports only #1501's commit, which merged as 533bbb81f8d.

Before those rebases, at d6029a97a3f on the temporary base, every gate of check-nvx-rs and validate-nvx passed on Windows and on nvx-kvm-test, but for failures that the base shares, and two Windows timeouts under load, which passed when rerun. A code review found no issue.

CI runs the remaining gates, MSHV and WHP among them.

Tests modified

check_test_changes.py --base origin/feature/nvx-refactor lists 6 changes to existing tests and 1 new test:

  • New: starts_refuse_the_kernel_tokens_of_the_sandbox_profile_and_of_its_mounts (tests/cli/lifecycle.rs). A start refuses nvx_entrypoint recorded at provision, nvx-sandbox=0 (dashed), "a nvx_mode=one-shot" (quoted) and virtfs_tag=microvm, with unsupported and the old messages, without changing the state directory. It fails once the refusal is removed.
  • deprovision_removes_a_restored_sandboxs_view_only_under_its_snapshots_lock and a_restored_start_refuses_a_share_of_its_snapshot_store (start/tests/restore.rs), run_checks_again_that_its_shares_do_not_overlap (start/tests.rs), and restored_sandbox_records_round_trip_only_their_own_source (state/tests.rs) build the record without a SandboxLaunch: the layer, the scratch path and the export plan, with the default hostname and workload identity in ProvisionConfig. They check what they checked before, and the imports of start/tests.rs and start/tests/restore.rs follow.

@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 6 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 imports the imports of host::cli::sandbox::lifecycle::start::tests nvx-rs/src/host/cli/sandbox/lifecycle/start/tests.rs:3 nvx-rs/src/host/cli/sandbox/lifecycle/start/tests.rs:3
modified imports the imports of host::cli::sandbox::lifecycle::start::tests::restore nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:1 nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:1
modified test fn run_checks_again_that_its_shares_do_not_overlap in host::cli::sandbox::lifecycle::start::tests nvx-rs/src/host/cli/sandbox/lifecycle/start/tests.rs:18 nvx-rs/src/host/cli/sandbox/lifecycle/start/tests.rs:20
modified test fn deprovision_removes_a_restored_sandboxs_view_only_under_its_snapshots_lock in host::cli::sandbox::lifecycle::start::tests::restore nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:660 nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:660
modified test fn a_restored_start_refuses_a_share_of_its_snapshot_store in host::cli::sandbox::lifecycle::start::tests::restore nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:716 nvx-rs/src/host/cli/sandbox/lifecycle/start/tests/restore.rs:717
modified test fn restored_sandbox_records_round_trip_only_their_own_source in host::cli::sandbox::state::tests nvx-rs/src/host/cli/sandbox/state/tests.rs:7 nvx-rs/src/host/cli/sandbox/state/tests.rs:8

Relocated unchanged: 0; added: 1. Compared the merge base 533bbb81f8d4 with c7fec0980ca5.

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 are blocking the sandbox CLI record refactor.

No open issues 🎉

What changed in this PR

This PR advances #1112 by replacing the sandbox CLI’s old launch-profile objects with CLI-owned records and VmConfig, while preserving existing behavior and record format.

Changes:

  • Carries images, hostname, workload identity, and shares through ProvisionConfig instead of SandboxLaunch.
  • Moves workload and image validation into the record layer and updates lifecycle code to use record accessors.
  • Retains the old launch plan only for command-line validation in start.rs, with new regression coverage for reserved boot tokens.
File Description
nvx-rs/​tests/​cli/​lifecycle.rs Adds coverage for reserved command-line token refusals without state changes.
nvx-rs/​src/​host/​cli/​sandbox/​state/​tests.rs Builds record round-trip fixtures without launch-profile objects.
nvx-rs/​src/​host/​cli/​sandbox/​state.rs Adds record-owned validation and accessors; constructs VmConfig directly.
nvx-rs/​src/​host/​cli/​sandbox/​mod.rs Prepares images and recorded options without the old launch types.
nvx-rs/​src/​host/​cli/​sandbox/​lifecycle/​start/​tests.rs Adapts lifecycle and share-overlap tests to the new record inputs.
nvx-rs/​src/​host/​cli/​sandbox/​lifecycle/​start.rs Uses record accessors while retaining legacy command-line checks.
nvx-rs/​src/​host/​cli/​sandbox/​lifecycle/​mod.rs Expands ProvisionConfig and provisions records from explicit image inputs.

Review effort: Balanced

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 outstanding review issues remain for the sandbox launch-configuration migration.

No open issues 🎉

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/slim-sl3-10c-network-record branch from 8b606c6 to 83b0eca Compare November 12, 2026 03:59
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/slim-sl3-10c-network-record branch from 83b0eca to b107c09 Compare November 12, 2026 04:18
@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/slim-sl3-10c-network-record branch from b107c09 to c5afedc Compare November 12, 2026 04:41
Base automatically changed from agents/slim-sl3-10c-network-record to feature/nvx-refactor November 12, 2026 05:21
The four shared sandbox modules still built and read back the launch of
`host::sandbox`, the old launch profile: `run_from` made a
`SandboxLaunch` of the layers, a `SandboxUpper` and `SandboxSettings`,
`provision` and `sandbox run` serialized the configuration from it, and
each start and run read the configuration back into one, to check it
and to take its images, its workload identity and its shares.

`provision` and `sandbox run` now pass the distro layer, the scratch
image and the options that the configuration records, the hostname, the
workload identity and the export plan among them, in
`ProvisionConfig`. The checks that the launch made move into the CLI's
record, in `state.rs`, with the old messages and order:
`check_workload` refuses the entrypoint, arguments, hostname and a root
identity as the plan's settings did; `check_images` refuses the images
and the shares as the plan's `validated` did; and `Config::check`
checks a recorded configuration at each start as `Config::launch` did,
the RAM upper's cap, the layer's UUID, the workload, the export plan and
the images. `run_from` refuses duplicate layers as the launch did, and
verifies the distro layer with `DistroBinding::verify`, which
`validate_sandbox_systemd_policy` called once it had refused a systemd
entrypoint, which the options' own check already refuses. As before,
the workload that `run_from` checks is the default one for a run and a
restore, whose workloads are exec requests that no boot token carries.
`refuse_own_files` takes the image, the scratch image and the export
plan in place of the launch, for a state directory, a run's VM
directory and a restored sandbox's snapshot store alike.
`Config::vm_config` reads the workload identity and the shares from the
record itself.

A start and a run still refuse the user's `nvx_*` and `virtfs_*` boot
tokens, a NUL, and a command line over the 1024-byte budget as the
plan of the sandbox profile did, which `VmConfig::check` does only in
part. The new `check_command_line` in `start.rs` builds that plan from
the record for this alone, so the old launch leaves the four modules
but not yet `start.rs`, which a later slice handles.

This is the third and last step of SL3.10b, whose split was approved
once its measured scope came to about ten times its estimate.

Tests: the new `starts_refuse_the_kernel_tokens_of_the_sandbox_profile_and_of_its_mounts`
in tests/cli/lifecycle.rs checks that a start refuses the profile's and
`--mount`'s tokens, also in their dashed and quoted forms, without
changing the state directory, and fails without that refusal. The
restore tests of `deprovision` and of a share of the snapshot store,
the overlap test of `sandbox run` and the round trip of a restored
sandbox's record build the configuration without a `SandboxLaunch`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ppenna
Pedro Henrique Penna (ppenna) marked this pull request as ready for review November 12, 2026 05:22
@ppenna
Pedro Henrique Penna (ppenna) merged commit 580adf0 into feature/nvx-refactor Nov 12, 2026
82 of 85 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/slim-sl3-10d-cli-record branch November 12, 2026 06:09
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