Mount live virtio-fs shares inside the sandbox container - #294
Merged
Pedro Henrique Penna (ppenna) merged 3 commits intoOct 1, 2026
Merged
Conversation
Accept --mount GUEST_TARGET,HOST_PATH[,ro|rw] and repeatable --mount-deny for sandbox run and provision, and forward them to OpenVMM's microVM virtio-fs export. The host-side export enforces the access mode and the denied paths. After the guest agent assembles the container overlay and verifies the workload identity, it creates the target inside the container root one component at a time, refuses symbolic links, and mounts the share with nosuid,nodev before the workload enters its private mount namespace. Invalid targets, reserved runtime paths, and mount failures abort the sandbox instead of starting the workload without its share. Teardown unmounts the share before the overlay. Managed sandboxes persist the share in a new configuration format so older NVX releases refuse it rather than start without the share. CI now round-trips guest writes through a read-write share, hides a denied subdirectory, and requires a read-only share to reject writes. Part of #290. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot started reviewing on behalf of
Pedro Henrique Penna (ppenna)
October 1, 2026 06:42
View session
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Managed shutdown bypasses the new ordered share-unmount path.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds live virtio-fs host-directory sharing to sandbox workloads.
Changes:
- Adds CLI validation, OpenVMM forwarding, and managed-state persistence.
- Mounts and validates shares inside guest container root filesystems.
- Adds documentation, unit tests, and cross-platform smoke coverage.
| File | Description |
|---|---|
scripts/nvx.py |
Adds sandbox mount CLI options. |
scripts/nvx_tools/sandbox.py |
Implements mount validation and launch arguments. |
scripts/nvx_tools/sandbox_lifecycle.py |
Persists and restores managed mounts. |
guest/common/nvx-init-agent |
Mounts and unmounts guest shares. |
guest/common/nvx-sandbox-smoke |
Tests guest share behavior. |
scripts/test_nvx_tools.py |
Covers parsing, persistence, and guest logic. |
.github/workflows/run-nvx-microvm-tests.yml |
Adds Linux and Windows smoke tests. |
doc/run.md |
Documents live-share behavior. |
doc/usage.md |
Documents CLI options. |
doc/ci.md |
Documents CI coverage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This was referenced Oct 1, 2026
Give config.json its own format constants instead of reusing the runtime-state format, so the no-share and live-share configuration formats can evolve independently of runtime.json. Add regression tests showing that a format-1-only reader rejects a mounted configuration and that persisting a relative mount path keeps symbolic-link components for OpenVMM to reject instead of resolving them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot started reviewing on behalf of
Pedro Henrique Penna (ppenna)
October 1, 2026 14:48
View session
A managed sandbox exec'd nvx-managed-agent from nvx-init-agent, and the agent's stop handler powered the VM off directly. The live share, overlay, layers, and scratch therefore stayed mounted on every managed stop, and fatal errors after mounting also powered off with the share mounted. In sandbox mode, nvx-init-agent now supervises the managed agent, which returns after a stop request so both lifecycles share one teardown that unmounts the share before the overlay, layers, and scratch. fatal unmounts the share before powering off, and lifecycle validation runs before the share is mounted. Direct managed mode still powers off from the agent. Write the workload machine ID for managed sandboxes as well. The container entry helper requires it, so every managed sandbox exec previously failed with status 125. Cover the teardown order with shell tests, the agent stop path with a pty-driven test of the compiled agent, and the full managed flow in CI, where a managed stop must leave the scratch filesystem cleanly unmounted. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot started reviewing on behalf of
Pedro Henrique Penna (ppenna)
October 1, 2026 15:39
View session
Pedro Henrique Penna (ppenna)
deleted the
fix/issue-290-virtiofs-sandbox
branch
October 1, 2026 16:58
Pedro Henrique Penna (ppenna)
added a commit
that referenced
this pull request
Oct 2, 2026
dev moved from ae123d1 to 20353f8: bounded egress (#289), the shared git output runner (#287), Ubuntu manifest errors (#291), the perf gate history reset (#293), sandbox teardown through the init agent (#294), virtiofs symlinks with openvmm 2728f33ea (#302), the required CI result check (#305), and new performance baselines. - .github/actions/validate-nvx/action.yml: run dev's test_egress_policy.py and the time ABI's test_guest_time.py and test_time_abi.py. - scripts/nvx.py: keep the doctor parser import and dev's compile_policy_file import. - scripts/test_nvx_tools.py: keep both the re and select imports. - scripts/test_microvm_tests.py (no textual conflict): dev's L3/L4 egress dispatch test expects the Ubuntu guest's default memory, which 25bac37 raised from 256 to 512 MiB on this branch. The openvmm gitlink takes dev's 2728f33ea (microvm/v2.1); lockstep moves it to the time ABI head rebased onto it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

Closes #300. Part of #290 (requirement 1 and the NVX side of requirement 4).
What
Sandbox mode can now live-share a host directory into the workload container, removing the stage-then-copy-back step described in the issue.
sandbox run/sandbox provisionaccept--mount GUEST_TARGET,HOST_PATH[,ro|rw](defaultro) and repeatable--mount-deny HOST_PATH, forwarded to OpenVMM's existing microVM virtio-fs export, which enforces the access mode and denied paths on the host side.--mountis rejected forstart/exec/stop/deprovision;--mount-denyrequires--mount;virtfs_*tokens in--cmdlineare reserved; and the OpenVMM-appended bootstrap tokens count toward the 1024-byte sandbox command-line budget.nvx-init-agent): after overlay assembly and workload-identity checks, the agent validates the target (absolute, canonical;/,/etc, and the/proc,/sys,/dev,/.nvx-agenttrees are reserved because the container runtime mounts or binds over them), creates it inside the container rootfs one component at a time while refusing symbolic links from a layer, and mountsvirtiofswith<ro|rw>,nosuid,nodevbeforenvx-container-launchenters the private mount namespace (so it survivesunshare --mountandchroot). Any failure exits with status 125 instead of starting the workload without its share. A one-shot exit, a managedstop, and any failure after mounting all unmount the share before the overlay or power-off. In sandbox mode the init agent now supervisesnvx-managed-agent, which returns on stop instead of powering the VM off itself.config.jsonand reattached on everystart. Mounted configurations use config format2so an older NVX refuses them rather than silently dropping the share; format1configs (no share) still load. Onstop, the init agent unmounts the share, overlay, layers, and scratch before powering off; previously a managed stop powered off with all of them mounted. This also fixes managed sandboxexec, which always failed with status 125 ondevbecause/run/nvx/workload-machine-idwas written only for one-shot runs.run-nvx-microvm-tests.yml, Linux and Windows): runs/sbin/nvx-sandbox-smokeagainst anrw/workspaceshare with a denied subdirectory, verifies the guest's file and directory reach the host, then against anro/opt/hostedtoolcacheshare and requires writes to fail. A managed sandbox repeats therwcheck through provision/start/exec/stop and must report success with a cleanly unmounted scratch filesystem (ext4 journal-recovery flag clear).doc/run.md,doc/usage.md,doc/ci.md,doc/project-structure.md.Validation
python -m unittest scripts/test_performance.py scripts/test_nvx_tools.py scripts/test_microvm_tests.py scripts/test_development_release.py(390 tests),scripts/test_adversarial.py, ruff check/format, pyright (Linux + Windows), shellcheck + shfmt on guest scripts: all pass.nvx-init-agentshare functions (mount placement, reserved/non-canonical targets, symlink refusal, teardown order,fatalunmounting the share). A Linux test compilesnvx-managed-agent.cwith the production flags and drives the control protocol over a pty; sandbox-modeSTOPmust return exit 0 (the previous agent exits 125).rwshare read/write round-trip as UID 65534,nvx-deniedhidden,roshare rejectedtouchwithRead-only file system,/bin/share(symlinked/binin Ubuntu) failed closed with status 125, and a managed provision/start/exec/stop/deprovision cycle with a share (exec succeeds, the outcome is success, and scratch is clean; with thedevguest, exec fails with 125 and scratch is leftneeds_recovery). The new Windows CI steps also passed locally. KVM/MSHV are covered by CI.Not in this PR (needs OpenVMM /
nanvix/openvmmchanges and a pin promotion)fs:microvm0) and a single-share snapshot contract.--mount-owner calleridentity mapping and root squash (req. 3, Sandbox: map virtio-fs file ownership to the caller identity with root squash (--mount-owner caller) #297): requires per-requestsetfsuid/setfsgidin HostFs. Until then, guest permission checks use the VMM-reported owner and mode, as documented.rwshare (req. 4, Sandbox: write narrowing and read masking for subtrees of virtio-fs shares #299): needs per-subtree access policy in HostFs; read masking already works via--mount-deny.check_symlink_allowedreturnsENOTSUP.v0.1.0-dev.*release with the full capability set.