Repository navigation
sandbox: accept only the distro layer and scratch - #576
Pedro Henrique Penna (ppenna) merged 2 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Existing validation assertions still expect four devices, and managed configurations can silently discard removed layer roles.
2 open findings
What changed in this PR
Implements the NVX portion of #556, restricting sandbox storage to one distro layer and writable scratch. The OpenVMM pin remains unchanged.
Changes:
- Restricts launcher and guest-agent layer handling to
distro. - Updates block discovery checks for two devices and unused former slots.
- Revises launch-contract tests and documentation.
| File | Description |
|---|---|
| scripts/test_nvx_tools.py | Tests the single-distro launch contract. |
| scripts/nvx_tools/sandbox.py | Restricts layer roles and count. |
| scripts/nvx_tools/microvm_tests.py | Attaches only distro and scratch. |
| scripts/nvx_tools/microvm_test_scripts/sandbox-blocks.sh | Checks two devices and freed windows. |
| guest/common/nvx-init-agent | Removes multi-layer mounting and teardown. |
| doc/usage.md | Documents distro-only layer support. |
| doc/run.md | Updates the sandbox storage description. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
3d3fb07 to
761dc6c
Compare
|
Thanks for this change! A heads-up: #597 (PR 4 of the #359 stack) moves |
619490c to
b2a43b2
Compare
b2a43b2 to
f285787
Compare
f285787 to
21c0d37
Compare
Nothing produces or attaches a runtime or custom layer. Remove both roles from the launcher, the guest init agent, the microVM test, and the docs. The sandbox-blocks check now verifies that the freed windows are absent. Refs microsoft#556. The OpenVMM side is a separate change; this one works with the current pin because the removed roles are never requested. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Signed-off-by: jay23606 <4602056+jay23606@users.noreply.github.com>
SandboxLaunch rejects any sole layer that is not distro, so a saved runtime or custom launch fails before it reaches the guest. The microVM test now expects the distro and scratch devices. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Signed-off-by: jay23606 <4602056+jay23606@users.noreply.github.com>
21c0d37 to
a7a0801
Compare
Pedro Henrique Penna (ppenna)
left a comment
There was a problem hiding this comment.
Verified on a merge with current dev: the validate-nvx unittest suite passes, and the sandbox-blocks checks hold for the current OpenVMM pin, which emits virtio_mmio.device= tokens only for attached blocks.
e8ff334
into
microsoft:dev
PR #576 (jay23606, refs #556) narrowed the sandbox to one EROFS distro layer and the scratch disk: the runtime and custom layers went, and their MMIO windows and interrupts stay unassigned. It merged after #595 had ported the launch profile to nvx-rs, and it changed scripts/nvx_tools/sandbox.py, which #359 retires, the guest agent, the sandbox-blocks scenario, and the docs, but not the launch profile of nvx-rs, which still accepted the three roles. Now that nvx.py sandbox runs nvx-rs, this ports #576's change to that launch profile, with the messages and checks of #576: - nvx::host::sandbox::layer: LAYER_ROLES, the roles that --layer accepts and a launch holds, is distro alone, so `--layer runtime,...` fails with `unsupported layer role 'runtime'; choose distro`, as does any other role. LayerRole keeps the retired Runtime and Custom roles, which from_name still reads, because the configuration of a sandbox that an older nvx.py provisioned may name them. - SandboxLaunch::new checks the duplicate roles first, over every role, and then requires exactly one layer, the distro layer: `a sandbox requires exactly one read-only distro layer`, which replaces `one to three read-only layers`. As in #576, the check holds for a saved launch as much as for parsed options, so `nvx.py sandbox start` of such a sandbox fails before OpenVMM starts. The golden records follow. In tests/fixtures/sandbox.json, the layer and launch cases are re-evaluated with the retired Python launch profile, from the commit before #359 retired it, which holds #576, with #579's change to sandbox.py applied. 168 layer values of the retired roles, 146 of which parsed and 22 of which had an invalid UUID, become refusals of their role, which is checked first; the refusals of 28 values of unknown roles list only distro; and 136 launches with retired roles now fail with the duplicate roles or the distro-layer requirement, which come before their other checks. No other record changes. The launch harness builds a retired role's layer as a saved configuration names it, since --layer no longer parses it. In tests/fixtures/cli.json, by hand, for POSIX and Windows alike: - `validation: invalid layer role` lists only distro, and a new `validation: retired layer role` shows `--layer runtime,...` refused with the same usage error; - `dry run: every layer and option` takes the distro layer alone, so its OpenVMM command loses the runtime and custom blocks and their nvx_layer tokens; - `lifecycle: network and launch options` provisions the distro layer alone, so its config.json and its OpenVMM arguments lose the runtime layer. A new CLI test edits a provisioned sandbox's configuration to add a runtime layer, as an older nvx.py wrote it, and checks that start refuses it with status 1 and the message above, leaving no runtime state, and that deprovision still removes it. Part of #359. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #576 (jay23606, refs #556) narrowed the sandbox to one EROFS distro layer and the scratch disk: the runtime and custom layers went, and their MMIO windows and interrupts stay unassigned. It merged after #595 had ported the launch profile to nvx-rs, and it changed scripts/nvx_tools/sandbox.py, which #359 retires, the guest agent, the sandbox-blocks scenario, and the docs, but not the launch profile of nvx-rs, which still accepted the three roles. Now that nvx.py sandbox runs nvx-rs, this ports #576's change to that launch profile, with the messages and checks of #576: - nvx::host::sandbox::layer: LAYER_ROLES, the roles that --layer accepts and a launch holds, is distro alone, so `--layer runtime,...` fails with `unsupported layer role 'runtime'; choose distro`, as does any other role. LayerRole keeps the retired Runtime and Custom roles, which from_name still reads, because the configuration of a sandbox that an older nvx.py provisioned may name them. - SandboxLaunch::new checks the duplicate roles first, over every role, and then requires exactly one layer, the distro layer: `a sandbox requires exactly one read-only distro layer`, which replaces `one to three read-only layers`. As in #576, the check holds for a saved launch as much as for parsed options, so `nvx.py sandbox start` of such a sandbox fails before OpenVMM starts. The golden records follow. In tests/fixtures/sandbox.json, the layer and launch cases are re-evaluated with the retired Python launch profile, from the commit before #359 retired it, which holds #576, with #579's change to sandbox.py applied. 168 layer values of the retired roles, 146 of which parsed and 22 of which had an invalid UUID, become refusals of their role, which is checked first; the refusals of 28 values of unknown roles list only distro; and 136 launches with retired roles now fail with the duplicate roles or the distro-layer requirement, which come before their other checks. No other record changes. The launch harness builds a retired role's layer as a saved configuration names it, since --layer no longer parses it. In tests/fixtures/cli.json, by hand, for POSIX and Windows alike: - `validation: invalid layer role` lists only distro, and a new `validation: retired layer role` shows `--layer runtime,...` refused with the same usage error; - `dry run: every layer and option` takes the distro layer alone, so its OpenVMM command loses the runtime and custom blocks and their nvx_layer tokens; - `lifecycle: network and launch options` provisions the distro layer alone, so its config.json and its OpenVMM arguments lose the runtime layer. A new CLI test edits a provisioned sandbox's configuration to add a runtime layer, as an older nvx.py wrote it, and checks that start refuses it with status 1 and the message above, leaving no runtime state, and that deprovision still removes it. Part of #359. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #576 (jay23606, refs #556) narrowed the sandbox to one EROFS distro layer and the scratch disk: the runtime and custom layers went, and their MMIO windows and interrupts stay unassigned. It merged after #595 had ported the launch profile to nvx-rs, and it changed scripts/nvx_tools/sandbox.py, which #359 retires, the guest agent, the sandbox-blocks scenario, and the docs, but not the launch profile of nvx-rs, which still accepted the three roles. Now that nvx.py sandbox runs nvx-rs, this ports #576's change to that launch profile, with the messages and checks of #576: - nvx::host::sandbox::layer: LAYER_ROLES, the roles that --layer accepts and a launch holds, is distro alone, so `--layer runtime,...` fails with `unsupported layer role 'runtime'; choose distro`, as does any other role. LayerRole keeps the retired Runtime and Custom roles, which from_name still reads, because the configuration of a sandbox that an older nvx.py provisioned may name them. - SandboxLaunch::new checks the duplicate roles first, over every role, and then requires exactly one layer, the distro layer: `a sandbox requires exactly one read-only distro layer`, which replaces `one to three read-only layers`. As in #576, the check holds for a saved launch as much as for parsed options, so `nvx.py sandbox start` of such a sandbox fails before OpenVMM starts. The golden records follow. In tests/fixtures/sandbox.json, the layer and launch cases are re-evaluated with the retired Python launch profile, from the commit before #359 retired it, which holds #576, with #579's change to sandbox.py applied. 168 layer values of the retired roles, 146 of which parsed and 22 of which had an invalid UUID, become refusals of their role, which is checked first; the refusals of 28 values of unknown roles list only distro; and 136 launches with retired roles now fail with the duplicate roles or the distro-layer requirement, which come before their other checks. No other record changes. The launch harness builds a retired role's layer as a saved configuration names it, since --layer no longer parses it. In tests/fixtures/cli.json, by hand, for POSIX and Windows alike: - `validation: invalid layer role` lists only distro, and a new `validation: retired layer role` shows `--layer runtime,...` refused with the same usage error; - `dry run: every layer and option` takes the distro layer alone, so its OpenVMM command loses the runtime and custom blocks and their nvx_layer tokens; - `lifecycle: network and launch options` provisions the distro layer alone, so its config.json and its OpenVMM arguments lose the runtime layer. A new CLI test edits a provisioned sandbox's configuration to add a runtime layer, as an older nvx.py wrote it, and checks that start refuses it with status 1 and the message above, leaving no runtime state, and that deprovision still removes it. Part of #359. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #576 (jay23606, refs #556) narrowed the sandbox to one EROFS distro layer and the scratch disk: the runtime and custom layers went, and their MMIO windows and interrupts stay unassigned. It merged after #595 had ported the launch profile to nvx-rs, and it changed scripts/nvx_tools/sandbox.py, which #359 retires, the guest agent, the sandbox-blocks scenario, and the docs, but not the launch profile of nvx-rs, which still accepted the three roles. Now that nvx.py sandbox runs nvx-rs, this ports #576's change to that launch profile, with the messages and checks of #576: - nvx::host::sandbox::layer: LAYER_ROLES, the roles that --layer accepts and a launch holds, is distro alone, so `--layer runtime,...` fails with `unsupported layer role 'runtime'; choose distro`, as does any other role. LayerRole keeps the retired Runtime and Custom roles, which from_name still reads, because the configuration of a sandbox that an older nvx.py provisioned may name them. - SandboxLaunch::new checks the duplicate roles first, over every role, and then requires exactly one layer, the distro layer: `a sandbox requires exactly one read-only distro layer`, which replaces `one to three read-only layers`. As in #576, the check holds for a saved launch as much as for parsed options, so `nvx.py sandbox start` of such a sandbox fails before OpenVMM starts. The golden records follow. In tests/fixtures/sandbox.json, the layer and launch cases are re-evaluated with the retired Python launch profile, from the commit before #359 retired it, which holds #576, with #579's change to sandbox.py applied. 168 layer values of the retired roles, 146 of which parsed and 22 of which had an invalid UUID, become refusals of their role, which is checked first; the refusals of 28 values of unknown roles list only distro; and 136 launches with retired roles now fail with the duplicate roles or the distro-layer requirement, which come before their other checks. No other record changes. The launch harness builds a retired role's layer as a saved configuration names it, since --layer no longer parses it. In tests/fixtures/cli.json, by hand, for POSIX and Windows alike: - `validation: invalid layer role` lists only distro, and a new `validation: retired layer role` shows `--layer runtime,...` refused with the same usage error; - `dry run: every layer and option` takes the distro layer alone, so its OpenVMM command loses the runtime and custom blocks and their nvx_layer tokens; - `lifecycle: network and launch options` provisions the distro layer alone, so its config.json and its OpenVMM arguments lose the runtime layer. A new CLI test edits a provisioned sandbox's configuration to add a runtime layer, as an older nvx.py wrote it, and checks that start refuses it with status 1 and the message above, leaving no runtime state, and that deprovision still removes it. Part of #359. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #576 (jay23606, refs #556) narrowed the sandbox to one EROFS distro layer and the scratch disk: the runtime and custom layers went, and their MMIO windows and interrupts stay unassigned. It merged after #595 had ported the launch profile to nvx-rs, and it changed scripts/nvx_tools/sandbox.py, which #359 retires, the guest agent, the sandbox-blocks scenario, and the docs, but not the launch profile of nvx-rs, which still accepted the three roles. Now that nvx.py sandbox runs nvx-rs, this ports #576's change to that launch profile, with the messages and checks of #576: - nvx::host::sandbox::layer: LAYER_ROLES, the roles that --layer accepts and a launch holds, is distro alone, so `--layer runtime,...` fails with `unsupported layer role 'runtime'; choose distro`, as does any other role. LayerRole keeps the retired Runtime and Custom roles, which from_name still reads, because the configuration of a sandbox that an older nvx.py provisioned may name them. - SandboxLaunch::new checks the duplicate roles first, over every role, and then requires exactly one layer, the distro layer: `a sandbox requires exactly one read-only distro layer`, which replaces `one to three read-only layers`. As in #576, the check holds for a saved launch as much as for parsed options, so `nvx.py sandbox start` of such a sandbox fails before OpenVMM starts. The golden records follow. In tests/fixtures/sandbox.json, the layer and launch cases are re-evaluated with the retired Python launch profile, from the commit before #359 retired it, which holds #576, with #579's change to sandbox.py applied. 168 layer values of the retired roles, 146 of which parsed and 22 of which had an invalid UUID, become refusals of their role, which is checked first; the refusals of 28 values of unknown roles list only distro; and 136 launches with retired roles now fail with the duplicate roles or the distro-layer requirement, which come before their other checks. No other record changes. The launch harness builds a retired role's layer as a saved configuration names it, since --layer no longer parses it. In tests/fixtures/cli.json, by hand, for POSIX and Windows alike: - `validation: invalid layer role` lists only distro, and a new `validation: retired layer role` shows `--layer runtime,...` refused with the same usage error; - `dry run: every layer and option` takes the distro layer alone, so its OpenVMM command loses the runtime and custom blocks and their nvx_layer tokens; - `lifecycle: network and launch options` provisions the distro layer alone, so its config.json and its OpenVMM arguments lose the runtime layer. A new CLI test edits a provisioned sandbox's configuration to add a runtime layer, as an older nvx.py wrote it, and checks that start refuses it with status 1 and the message above, leaving no runtime state, and that deprovision still removes it. Part of #359. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR #576 (jay23606, refs #556) narrowed the sandbox to one EROFS distro layer and the scratch disk: the runtime and custom layers went, and their MMIO windows and interrupts stay unassigned. It merged after #595 had ported the launch profile to nvx-rs, and it changed scripts/nvx_tools/sandbox.py, which #359 retires, the guest agent, the sandbox-blocks scenario, and the docs, but not the launch profile of nvx-rs, which still accepted the three roles. Now that nvx.py sandbox runs nvx-rs, this ports #576's change to that launch profile, with the messages and checks of #576: - nvx::host::sandbox::layer: LAYER_ROLES, the roles that --layer accepts and a launch holds, is distro alone, so `--layer runtime,...` fails with `unsupported layer role 'runtime'; choose distro`, as does any other role. LayerRole keeps the retired Runtime and Custom roles, which from_name still reads, because the configuration of a sandbox that an older nvx.py provisioned may name them. - SandboxLaunch::new checks the duplicate roles first, over every role, and then requires exactly one layer, the distro layer: `a sandbox requires exactly one read-only distro layer`, which replaces `one to three read-only layers`. As in #576, the check holds for a saved launch as much as for parsed options, so `nvx.py sandbox start` of such a sandbox fails before OpenVMM starts. The golden records follow. In tests/fixtures/sandbox.json, the layer and launch cases are re-evaluated with the retired Python launch profile, from the commit before #359 retired it, which holds #576, with #579's change to sandbox.py applied. 168 layer values of the retired roles, 146 of which parsed and 22 of which had an invalid UUID, become refusals of their role, which is checked first; the refusals of 28 values of unknown roles list only distro; and 136 launches with retired roles now fail with the duplicate roles or the distro-layer requirement, which come before their other checks. No other record changes. The launch harness builds a retired role's layer as a saved configuration names it, since --layer no longer parses it. In tests/fixtures/cli.json, by hand, for POSIX and Windows alike: - `validation: invalid layer role` lists only distro, and a new `validation: retired layer role` shows `--layer runtime,...` refused with the same usage error; - `dry run: every layer and option` takes the distro layer alone, so its OpenVMM command loses the runtime and custom blocks and their nvx_layer tokens; - `lifecycle: network and launch options` provisions the distro layer alone, so its config.json and its OpenVMM arguments lose the runtime layer. A new CLI test edits a provisioned sandbox's configuration to add a runtime layer, as an older nvx.py wrote it, and checks that start refuses it with status 1 and the message above, leaving no runtime state, and that deprovision still removes it. Part of #359. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>


Refs #556. Part one: the NVX side. The OpenVMM change is a separate PR and the pin is not bumped here.
Summary
distrolayer andscratch.runtimeandcustomare refused.sandbox-blocksguest check now expects two devices and verifies the freed windows0xd0004000/0xd0005000are absent.Test
python -m unittest test_nvx_tools: 533 tests pass (54 skipped as before).ruffcheck and format, and pyright strict on Linux and Windows: clean.bash -non the guest agent and the sandbox script.🤖 Generated with Claude Code