Skip to content

feat: add experimental nested virtualization - #1054

Merged
DorianZheng merged 4 commits into
mainfrom
agent/nested-virtualization-rc
Jul 28, 2026
Merged

feat: add experimental nested virtualization#1054
DorianZheng merged 4 commits into
mainfrom
agent/nested-virtualization-rc

Conversation

@DorianZheng

@DorianZheng DorianZheng commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

  • add runtime-scoped ExperimentalFeature::NestedVirtualization and a hidden --nested-virtualization CLI opt-in
  • persist the requirement, fail closed on unsupported hosts or older guests, and map /dev/kvm through a generic Docker-style devices transport into the OCI workload
  • keep REST create/get-or-create and untrusted archive imports closed during the RC; do not add stable Python, Node.js, Go, or C request knobs
  • update libkrunfw to v5.4.0 with KVM host support, plus architecture docs and an opt-in hardware smoke workflow

Usage

BOXLITE_EXPERIMENTAL=nested-virtualization \
  boxlite run --nested-virtualization IMAGE

Verification

  • make fmt:check
  • make clippy
  • make test:unit:rust (899 BoxLite + 47 shared tests)
  • make test:integration:cli FILTER=nested_virtualization SETUP_DONE=1 (5 passed)
  • BOXLITE_TEST_NESTED_VIRTUALIZATION=1 make test:integration:cli FILTER=test_nested_virtualization_can_create_kvm_vm
  • Python untrusted-import tests, reference-server tests, and Node options tests
  • real nested launch: built BoxLite inside a nested-enabled Box and used it to boot an inner Alpine VM, which reported BOXLITE_INSIDE_BOXLITE_POSTREBASE_OK and aarch64

Summary by CodeRabbit

  • New Features

    • Added release-candidate nested virtualization support with strict opt-in and improved guest /dev/kvm device handling.
    • Added support for reproducing device nodes into container workloads.
    • Expanded import capabilities to treat uploaded archives as untrusted when applicable.
  • Bug Fixes

    • Improved error reporting to clearly distinguish unsupported configurations from engine failures.
    • Strengthened REST and import-time validation for host-only experimental options.
  • Documentation

    • Published complete nested virtualization RC guidance, including enablement, persistence, security constraints, and troubleshooting.
  • Chores

    • Updated local end-to-end test triggering and nested virtualization probing behavior.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c15435d2-44f0-4367-a37f-0a4eef406730

📥 Commits

Reviewing files that changed from the base of the PR and between 7972146 and c5829b4.

📒 Files selected for processing (2)
  • .github/workflows/e2e-local.yml
  • src/guest/src/container/spec.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/guest/src/container/spec.rs

📝 Walkthrough

Walkthrough

This PR adds release-candidate nested virtualization with experimental opt-in, runtime and import-policy enforcement, VMM/libkrun activation, /dev/kvm delivery to guest workloads, typed error propagation, CLI and CI coverage, documentation, and libkrunfw updates.

Changes

Nested virtualization support

Layer / File(s) Summary
Options, feature gates, and import boundaries
src/boxlite/src/experimental*, src/boxlite/src/runtime/..., src/boxlite/src/rest/runtime.rs, openapi/..., sdks/python/...
Adds the nested-virtualization option and experimental gate, validates persisted-box reuse and REST requests, and marks remote uploads as untrusted with host-only options rejected.
VMM activation, sandbox access, and typed exits
src/boxlite/src/jailer/..., src/boxlite/src/vmm/..., src/boxlite/src/litebox/..., src/shim/src/main.rs, src/deps/libkrun-sys/...
Propagates nested virtualization to libkrun, grants read-only probe paths, adds typed Engine/Unsupported exit metadata, and exposes the libkrun capability probe.
Guest capability and /dev/kvm delivery
src/shared/proto/..., src/guest/src/container/..., src/guest/src/service/container.rs, src/boxlite/src/portal/interfaces/container.rs, src/boxlite/src/litebox/init/tasks/guest_init.rs
Carries device mappings through container initialization, validates them into OCI devices, standardizes init error kinds, and supplies /dev/kvm for nested workloads.
CLI, CI, dependency, and documentation support
src/cli/..., .github/workflows/e2e-local.yml, docs/..., src/deps/libkrun-sys/build.rs
Adds hidden CLI opt-in and integration coverage, documents the RC feature, expands E2E triggers and hardware gating, and updates libkrunfw checksum-aware caching.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Runtime
  participant ShimController
  participant Krun
  participant Guest
  CLI->>Runtime: Enable nested_virtualization with experimental opt-in
  Runtime->>ShimController: Pass nested virtualization in InstanceSpec
  ShimController->>Krun: Probe and enable nested virtualization
  Krun-->>Runtime: Return success, Unsupported, or Engine result
  ShimController->>Guest: Send ContainerInitRequest with /dev/kvm
  Guest->>Guest: Validate device and build OCI LinuxDevice
  Guest-->>Runtime: Return categorized init result
Loading

Possibly related issues

  • feat: Box Snapshot API #205: The PR changes archive import policy and runtime import validation related to the issue’s export/import objectives.

Possibly related PRs

Suggested reviewers: xhebox

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: experimental nested virtualization support.
Description check ✅ Passed It covers the summary and verification details, and the missing Changes heading is effectively folded into Summary.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/nested-virtualization-rc

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cla-assistant

cla-assistant Bot commented Jul 26, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


tester seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

1 similar comment
@cla-assistant

cla-assistant Bot commented Jul 26, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


tester seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@DorianZheng
DorianZheng force-pushed the agent/nested-virtualization-rc branch 5 times, most recently from 43cde51 to 78e0f73 Compare July 27, 2026 05:52
@DorianZheng
DorianZheng marked this pull request as ready for review July 27, 2026 16:33
@boxlite-agent

boxlite-agent Bot commented Jul 27, 2026

Copy link
Copy Markdown

📦 BoxLite review — looks good · c5829b4

Review evidence

  • git diff --numstat origin/main...HEAD && git diff origin/main...HEAD — 46 files, +1800/-150 across rust/py/proto reviewed
  • cargo check -p boxlite -p boxlite-cli --tests — cargo not installed in this sandbox
  • inspect trust boundaries: REST reject, untrusted import, device confinement — each boundary has explicit tests covering rejection paths

Risk notes

  • host/guest device passthrough — guest resolve_device confines source+destination under /dev, checks node type, rejects .. and /dev itself; tested
  • experimental feature gating — nested-virt gated by BOXLITE_EXPERIMENTAL, CLI flag hidden, REST/import paths reject it explicitly; get_or_create prevents silent downgrade reuse
  • box reuse one-way check — rt_impl.rs validate_compatibility now errors if requested nested_virt but existing box lacks it; covered by two new tests
  • libkrun-sys build.rs checksum fix — pre-existing bug fixed in passing: verify_sha256 now always runs even when tarball cached, preventing stale/corrupt cached artifact reuse
  • sampled only — CI workflow yml, docs, lifecycle.rs/mod.rs/start.rs (3-line diffs), openapi yaml/server.py, options.rs roundtrip test only skimmed; low risk metadata/doc/test-glue changes
src/boxlite/src/runtime/import.rs
  options_from_manifest/ArchiveImportPolicy  +146/-5  untrusted-archive policy rejection
src/boxlite/src/runtime/rt_impl.rs
  validate_compatibility  +118/-2  one-way nested-virt reuse check
src/guest/src/container/spec.rs
  resolve_device/validate_device_path  +212/-7  device node confinement to /dev
src/guest/src/service/container.rs
  Init handler error kinds  +77/-40  typed ContainerInitErrorKind plumbing
src/boxlite/src/vmm/krun/context.rs
  enable_nested_virtualization  +54/-8  probe-before-enable libkrun call
src/boxlite/src/vmm/exit_info.rs
  ExitErrorKind  +129/-1  backward-compat error categorization
src/boxlite/src/rest/runtime.rs
  reject_remote_experimental_options  +91/-5  REST rejects host-only RC options
src/boxlite/src/vmm/controller/spawn.rs
  ShimSpawner::additional_path_access  +113/-9  minimal readonly probe-path grants
src/boxlite/src/jailer/builder.rs
  with_additional_path_access  +32/-0  plumbs extra sandbox paths
src/deps/libkrun-sys/build.rs
  Fetcher::fetch  +23/-16  checksum now verified on cache hit too
src/cli/src/cli.rs
  ManagementFlags::require_enabled  +70/-3  hidden flag gated by experimental features
src/shared/proto/boxlite/v1/service.proto
  ContainerDevice/ContainerInitErrorKind  +17/-0  new fields, zero-default backward compatible

reviewed c5829b4 in a BoxLite microVM · @boxlite-agent review to re-run · powered by BoxLite

@DorianZheng DorianZheng added the e2e-local Triggers the local (in-process) E2E suite on the self-hosted runner label Jul 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/guest/src/container/spec.rs (1)

36-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add is_empty() alongside len() for Clippy.

ContainerDevices exposes a public len() without a public is_empty(), so clippy::len_without_is_empty will flag this impl. Add pub fn is_empty(&self) -> bool { self.0.is_empty() } or explicitly allow the lint if it should intentionally be omitted.

♻️ Proposed fix
     pub fn len(&self) -> usize {
         self.0.len()
     }
+
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/guest/src/container/spec.rs` around lines 36 - 54, Add a public is_empty
method to ContainerDevices alongside len, delegating to the wrapped Vec via
self.0.is_empty(), so the type satisfies Clippy’s len_without_is_empty lint.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/e2e-local.yml:
- Line 348: Update the E2E workflow around BOXLITE_TEST_NESTED_VIRTUALIZATION so
nested virtualization tests run only on runners whose reused or newly created
instance has verified nested-virtualization support. Add a dedicated
hardware-smoke gate or validate the reused runner and recreate it when
unsupported before enabling the nested-test environment variable.

In `@src/boxlite/src/runtime/options.rs`:
- Around line 997-1010: Update the JSON fixtures in
nested_virtualization_option_roundtrips so both BoxOptions deserialization
inputs include valid values for the required rootfs, env, volumes, network, and
ports fields, while preserving the true nested_virtualization assertion and the
legacy default-to-false assertion.

In `@src/deps/libkrun-sys/vendor/libkrunfw`:
- Line 1: Update the vendored libkrunfw submodule reference at libkrunfw to a
commit that exists on its configured remote, preserving the intended v5.4.0/KVM
host-support and FFI compatibility changes so reviewers can inspect the resolved
source.

---

Nitpick comments:
In `@src/guest/src/container/spec.rs`:
- Around line 36-54: Add a public is_empty method to ContainerDevices alongside
len, delegating to the wrapped Vec via self.0.is_empty(), so the type satisfies
Clippy’s len_without_is_empty lint.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5389da0e-435b-4660-bd9b-315f2b27c11c

📥 Commits

Reviewing files that changed from the base of the PR and between 71ea6b3 and 3417407.

📒 Files selected for processing (50)
  • .github/workflows/e2e-local.yml
  • docs/architecture/README.md
  • docs/experimental/nested-virtualization.md
  • openapi/box.openapi.yaml
  • openapi/reference-server/server.py
  • openapi/reference-server/tests/test_handle_cache.py
  • sdks/node/src/options.rs
  • sdks/python/src/runtime.rs
  • sdks/python/tests/test_untrusted_import.py
  • src/boxlite/src/experimental.rs
  • src/boxlite/src/experimental/nested_virtualization.rs
  • src/boxlite/src/jailer/builder.rs
  • src/boxlite/src/jailer/mod.rs
  • src/boxlite/src/jailer/sandbox/mod.rs
  • src/boxlite/src/litebox/crash_report.rs
  • src/boxlite/src/litebox/init/mod.rs
  • src/boxlite/src/litebox/init/tasks/guest_connect.rs
  • src/boxlite/src/litebox/init/tasks/guest_init.rs
  • src/boxlite/src/litebox/init/tasks/vmm_spawn.rs
  • src/boxlite/src/portal/interfaces/container.rs
  • src/boxlite/src/portal/interfaces/guest.rs
  • src/boxlite/src/portal/interfaces/mod.rs
  • src/boxlite/src/rest/runtime.rs
  • src/boxlite/src/runtime/core.rs
  • src/boxlite/src/runtime/import.rs
  • src/boxlite/src/runtime/options.rs
  • src/boxlite/src/runtime/rt_impl.rs
  • src/boxlite/src/vmm/controller/shim.rs
  • src/boxlite/src/vmm/controller/spawn.rs
  • src/boxlite/src/vmm/exit_info.rs
  • src/boxlite/src/vmm/krun/context.rs
  • src/boxlite/src/vmm/krun/engine.rs
  • src/boxlite/src/vmm/mod.rs
  • src/cli/src/cli.rs
  • src/cli/src/commands/create.rs
  • src/cli/src/commands/run.rs
  • src/cli/src/commands/serve/handlers/advanced.rs
  • src/cli/src/commands/serve/mod.rs
  • src/cli/tests/nested_virtualization_rc.rs
  • src/deps/libkrun-sys/build.rs
  • src/deps/libkrun-sys/src/lib.rs
  • src/deps/libkrun-sys/vendor/libkrunfw
  • src/guest/src/container/lifecycle.rs
  • src/guest/src/container/mod.rs
  • src/guest/src/container/spec.rs
  • src/guest/src/container/start.rs
  • src/guest/src/service/container.rs
  • src/guest/src/service/guest.rs
  • src/shared/proto/boxlite/v1/service.proto
  • src/shim/src/main.rs

Comment thread .github/workflows/e2e-local.yml Outdated
Comment thread src/boxlite/src/runtime/options.rs
Comment thread src/deps/libkrun-sys/vendor/libkrunfw
Fold the shim exit-file error category into a single ExitInfo::Error
field, replacing the parallel write and read structs and their helper
functions. The shim now writes the type the host reads, and the exit
file is parsed once through CrashReport instead of twice.

Resolve container devices directly into an oci_spec LinuxDevice,
dropping the intermediate mapping type, the arbitrary device cap, and
the duplicate-destination scan. Device failures now report their own
context instead of borrowing the container-creation message.

Relocate the RC nested-virtualization option under `advanced`, beside
`kernel`, so both release-candidate knobs sit behind the same facade.

Keep a single path-access builder in the jailer and append caller
grants in Jailer::context, thread nested virtualization into
ShimSpawner explicitly rather than cloning BoxOptions to override one
field, and reduce the untrusted-import rejections to one shared rule.

An unrecognized error category now decodes as a generic engine failure
rather than discarding the whole record: a box keeps its exit file
across upgrades, so the BoxLite reading one is not always the BoxLite
that wrote it.

Claude-Session: https://claude.ai/code/session_01YL9HKQHBrZR9u1qY7FDyKd
@DorianZheng
DorianZheng force-pushed the agent/nested-virtualization-rc branch from 3417407 to 7972146 Compare July 27, 2026 17:49

@boxlite-agent boxlite-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📦 BoxLite review — looks good

Comment on lines +57 to +76
fn resolve_device(device: ProtoContainerDevice) -> BoxliteResult<LinuxDevice> {
let source = validate_absolute_path("source", &device.source)?;
let destination = validate_absolute_path("destination", &device.destination)?;
if destination == Path::new("/dev") || !destination.starts_with("/dev") {
return Err(unsupported_device(
&destination,
"must be below /dev".to_string(),
));
}
if let Some(file_mode) = device.file_mode {
if file_mode & !0o777 != 0 {
return Err(unsupported_device(
&destination,
format!("has invalid file mode {file_mode:#o}"),
));
}
}

let metadata = std::fs::symlink_metadata(&source)
.map_err(|error| unsupported_device(&source, format!("is unavailable: {error}")))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 device source path unrestricted to /dev
resolve_device confines destination under /dev but not source, so any absolute normalized path could be requested as a device source if a future caller exposes ContainerDevice beyond the current hardcoded /dev/kvm use in GuestInitTask::kvm_device.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/boxlite/src/runtime/options.rs (1)

1113-1127: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Same missing-required-fields bug as before — now under advanced, still unfixed.

serde_json::from_str for both stored and legacy omits rootfs, env, volumes, network, ports, which have no #[serde(default)] (per test_box_options_serde_defaults's own comment: "Must include all required fields that don't have serde defaults"). Both .unwrap() calls will panic on missing-field deserialization errors before the assertions run.

🐛 Proposed fix
     fn nested_virtualization_option_roundtrips() {
-        let stored: BoxOptions =
-            serde_json::from_str(r#"{"advanced":{"nested_virtualization":true}}"#).unwrap();
+        let stored: BoxOptions = serde_json::from_str(
+            r#"{
+                "rootfs": {"Image": "alpine:latest"},
+                "env": [],
+                "volumes": [],
+                "network": {"Enabled": {"allow_net": []}},
+                "ports": [],
+                "advanced": {"nested_virtualization": true}
+            }"#,
+        )
+        .unwrap();
         assert!(stored.advanced.nested_virtualization);
         assert_eq!(
             serde_json::to_value(stored).unwrap()["advanced"]["nested_virtualization"],
             serde_json::Value::Bool(true)
         );

-        let legacy: BoxOptions = serde_json::from_str("{}").unwrap();
+        let legacy: BoxOptions = serde_json::from_str(
+            r#"{
+                "rootfs": {"Image": "alpine:latest"},
+                "env": [],
+                "volumes": [],
+                "network": {"Enabled": {"allow_net": []}},
+                "ports": []
+            }"#,
+        )
+        .unwrap();
         assert!(!legacy.advanced.nested_virtualization);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/boxlite/src/runtime/options.rs` around lines 1113 - 1127, Update the
nested_virtualization_option_roundtrips test fixtures to include every required
BoxOptions field lacking #[serde(default)], including rootfs, env, volumes,
network, and ports, in both serialized JSON inputs. Preserve the existing
assertions for nested_virtualization being enabled when present and defaulting
to false when absent, consistent with test_box_options_serde_defaults.
🧹 Nitpick comments (2)
sdks/python/tests/test_untrusted_import.py (1)

44-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the public test function.

test_untrusted_import_rejects_nested_virtualization is a public module-level function without a docstring. Add one describing that untrusted archives requesting nested virtualization must be rejected before disk installation.

Suggested change
 `@pytest.mark.asyncio`
 async def test_untrusted_import_rejects_nested_virtualization(tmp_path) -> None:
+    """Reject untrusted nested-virtualization archives before disk installation."""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdks/python/tests/test_untrusted_import.py` around lines 44 - 45, Add a
docstring to the public test function
test_untrusted_import_rejects_nested_virtualization describing that untrusted
archives requesting nested virtualization are rejected before disk installation;
leave the test behavior unchanged.

Source: Coding guidelines

src/boxlite/src/runtime/rt_impl.rs (1)

488-514: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Doc comment is now inaccurate: nested virtualization is also compared.

The comment states only the capability policy is compared, but the function now also enforces the one-way nested_virtualization rule below it.

✏️ Proposed fix
     /// Reject reuse when the request disagrees with the box's stored options.
     ///
-    /// Only the capability policy is compared: silently adopting a box whose
-    /// privileges differ from the request is the case that matters for safety.
+    /// Compares the capability policy (must match exactly) and nested
+    /// virtualization (one-way: a nested-capable box satisfies any request,
+    /// not vice versa): silently adopting a box whose privileges differ from
+    /// the request is the case that matters for safety.
     fn check_options_compatibility(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/boxlite/src/runtime/rt_impl.rs` around lines 488 - 514, Update the doc
comment for check_options_compatibility to state that it compares capability
policy and enforces the one-way nested_virtualization compatibility rule, while
preserving the existing safety rationale and implementation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/boxlite/src/runtime/options.rs`:
- Around line 1113-1127: Update the nested_virtualization_option_roundtrips test
fixtures to include every required BoxOptions field lacking #[serde(default)],
including rootfs, env, volumes, network, and ports, in both serialized JSON
inputs. Preserve the existing assertions for nested_virtualization being enabled
when present and defaulting to false when absent, consistent with
test_box_options_serde_defaults.

---

Nitpick comments:
In `@sdks/python/tests/test_untrusted_import.py`:
- Around line 44-45: Add a docstring to the public test function
test_untrusted_import_rejects_nested_virtualization describing that untrusted
archives requesting nested virtualization are rejected before disk installation;
leave the test behavior unchanged.

In `@src/boxlite/src/runtime/rt_impl.rs`:
- Around line 488-514: Update the doc comment for check_options_compatibility to
state that it compares capability policy and enforces the one-way
nested_virtualization compatibility rule, while preserving the existing safety
rationale and implementation behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ba2bb140-a72e-4f83-8410-f53959f83cd7

📥 Commits

Reviewing files that changed from the base of the PR and between 3417407 and 7972146.

📒 Files selected for processing (46)
  • .github/workflows/e2e-local.yml
  • docs/architecture/README.md
  • docs/experimental/nested-virtualization.md
  • openapi/box.openapi.yaml
  • openapi/reference-server/server.py
  • openapi/reference-server/tests/test_handle_cache.py
  • sdks/python/src/runtime.rs
  • sdks/python/tests/test_untrusted_import.py
  • src/boxlite/src/experimental.rs
  • src/boxlite/src/experimental/nested_virtualization.rs
  • src/boxlite/src/jailer/builder.rs
  • src/boxlite/src/jailer/mod.rs
  • src/boxlite/src/jailer/sandbox/mod.rs
  • src/boxlite/src/litebox/crash_report.rs
  • src/boxlite/src/litebox/init/mod.rs
  • src/boxlite/src/litebox/init/tasks/guest_connect.rs
  • src/boxlite/src/litebox/init/tasks/guest_init.rs
  • src/boxlite/src/litebox/init/tasks/vmm_spawn.rs
  • src/boxlite/src/portal/interfaces/container.rs
  • src/boxlite/src/rest/runtime.rs
  • src/boxlite/src/runtime/advanced_options.rs
  • src/boxlite/src/runtime/import.rs
  • src/boxlite/src/runtime/options.rs
  • src/boxlite/src/runtime/rt_impl.rs
  • src/boxlite/src/vmm/controller/shim.rs
  • src/boxlite/src/vmm/controller/spawn.rs
  • src/boxlite/src/vmm/exit_info.rs
  • src/boxlite/src/vmm/krun/context.rs
  • src/boxlite/src/vmm/krun/engine.rs
  • src/boxlite/src/vmm/mod.rs
  • src/cli/src/cli.rs
  • src/cli/src/commands/create.rs
  • src/cli/src/commands/run.rs
  • src/cli/src/commands/serve/handlers/advanced.rs
  • src/cli/src/commands/serve/mod.rs
  • src/cli/tests/nested_virtualization_rc.rs
  • src/deps/libkrun-sys/build.rs
  • src/deps/libkrun-sys/src/lib.rs
  • src/deps/libkrun-sys/vendor/libkrunfw
  • src/guest/src/container/lifecycle.rs
  • src/guest/src/container/mod.rs
  • src/guest/src/container/spec.rs
  • src/guest/src/container/start.rs
  • src/guest/src/service/container.rs
  • src/shared/proto/boxlite/v1/service.proto
  • src/shim/src/main.rs
🚧 Files skipped from review as they are similar to previous changes (38)
  • src/deps/libkrun-sys/vendor/libkrunfw
  • src/boxlite/src/jailer/sandbox/mod.rs
  • src/guest/src/container/mod.rs
  • src/boxlite/src/experimental/nested_virtualization.rs
  • .github/workflows/e2e-local.yml
  • openapi/box.openapi.yaml
  • openapi/reference-server/tests/test_handle_cache.py
  • src/boxlite/src/litebox/init/mod.rs
  • docs/architecture/README.md
  • src/cli/src/commands/run.rs
  • src/boxlite/src/vmm/mod.rs
  • src/cli/tests/nested_virtualization_rc.rs
  • src/boxlite/src/jailer/mod.rs
  • openapi/reference-server/server.py
  • src/deps/libkrun-sys/src/lib.rs
  • src/cli/src/commands/create.rs
  • src/guest/src/container/start.rs
  • src/cli/src/commands/serve/handlers/advanced.rs
  • src/cli/src/commands/serve/mod.rs
  • src/boxlite/src/vmm/krun/engine.rs
  • src/boxlite/src/litebox/init/tasks/guest_connect.rs
  • src/boxlite/src/litebox/init/tasks/guest_init.rs
  • src/boxlite/src/jailer/builder.rs
  • src/shim/src/main.rs
  • src/boxlite/src/experimental.rs
  • src/boxlite/src/runtime/import.rs
  • src/boxlite/src/litebox/init/tasks/vmm_spawn.rs
  • src/boxlite/src/vmm/krun/context.rs
  • src/boxlite/src/vmm/exit_info.rs
  • src/guest/src/container/lifecycle.rs
  • src/boxlite/src/rest/runtime.rs
  • src/guest/src/service/container.rs
  • sdks/python/src/runtime.rs
  • src/boxlite/src/vmm/controller/shim.rs
  • src/guest/src/container/spec.rs
  • src/deps/libkrun-sys/build.rs
  • src/boxlite/src/vmm/controller/spawn.rs
  • src/cli/src/cli.rs

tester added 2 commits July 28, 2026 11:29
Device requests confined the destination but not the source, so a caller
could name any normalized absolute path as a device to read major/minor
from. Only /dev/kvm reaches this today, but the guest validates inbound
RPC rather than trusting the host, and one end of a two-ended check was
missing.

Both ends now go through the same validator.

Claude-Session: https://claude.ai/code/session_01YL9HKQHBrZR9u1qY7FDyKd
The E2E job set BOXLITE_TEST_NESTED_VIRTUALIZATION unconditionally, but
the runner is a reused tagged instance whose hardware this workflow does
not choose. A runner can expose /dev/kvm while its KVM module reports no
nesting, which turns an infrastructure gap into a confusing ioctl
failure inside the test.

Probe the loaded module first and enable the test only when it reports
nesting. When it does not, emit a warning annotation: a silent skip is
indistinguishable from a pass.

Claude-Session: https://claude.ai/code/session_01YL9HKQHBrZR9u1qY7FDyKd
@DorianZheng
DorianZheng merged commit e3563b3 into main Jul 28, 2026
52 of 53 checks passed
@DorianZheng
DorianZheng deleted the agent/nested-virtualization-rc branch July 28, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e2e-local Triggers the local (in-process) E2E suite on the self-hosted runner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant