Skip to content

hyperlight: move to hyperlight-unikraft 0.14.1 and add selectable guest runtimes - #1259

Open
Dan Chiarlone (danbugs) wants to merge 7 commits into
microsoft:mainfrom
danbugs:hyperlight-unikraft-0.14
Open

Dan Chiarlone (danbugs) wants to merge 7 commits into
microsoft:mainfrom
danbugs:hyperlight-unikraft-0.14

Conversation

@danbugs

@danbugs Dan Chiarlone (danbugs) commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Moves the Hyperlight backend from hyperlight-unikraft 0.12.1 to 0.14.1 and opens it up to all six driver-based runtimes: agent (default), python, python-shell, node, bash, and dotnet-jit.

  • API portSandboxBuilder/AppSandbox with from_initrd/from_snapshot, snapshot_to/restore, submit/step under a deadline; uses hluk's configure_surrogates and load_snapshot/save_snapshot
  • Per-runtime image homes — one directory per runtime under ~/.local/share/mxc-hyperlight/, each with its rootfs, snapshot, and version stamp; --setup-hyperlight[=RUNTIME,...] installs them
  • Confighyperlight.runtime field in the 0.10.0-alpha contract selects the runtime; policy identity hashes it only for Hyperlight containment
  • Disk footprint — 4x smaller; the rename from pyhl to mxc-hyperlight drops the old directory
  • Docs — replaces the old design note with a backend guide covering all runtimes, the image home, and troubleshooting
  • Tests — per-runtime e2e cases (python hello, node hello, node exit code) with per-case skip when a runtime isn't installed; CI installs agent, python, and node

Networking is documented as rejected in this release: 0.10 documents can't populate the legacy host lists, and wiring the directional egress model is a follow-up.

Microsoft Reviewers: Open in CodeFlow

0.13.0 was a ground-up rewrite of hyperlight-unikraft: the pyhl module
the backend was built on is gone, the kernel is embedded in the crate,
and the library API is SandboxBuilder/AppSandbox. 0.14.0 reshaped that
API again (cooperative step model, typed errors), and 0.14.1 lets a
restored guest take the mounts the restore names and keys snapshots by
the kernel and host contract they depend on. hyperlight-host and
hyperlight-common move to 0.17.0 with it.

Default features are off so the hluk CLI's clap and tracing-subscriber
are not pulled into mxc.

Signed-off-by: danbugs <danilochiarlone@gmail.com>
The pyhl install/runtime layer no longer exists, so the backend now
drives SandboxBuilder and AppSandbox directly:

- The Unikraft kernel ships inside the crate. An image home holds only
  the agent rootfs (initrd.cpio), the warmed snapshot directory, and a
  VERSION stamp naming the rootfs release. A home whose stamp is another
  release's, or whose snapshot was saved by a build with another
  snapshot key (the crate's kernel and host contract), is treated as not
  installed: --setup-hyperlight rebuilds it without --force, and a run
  warms a new snapshot by itself when only the snapshot is stale.
- Setup pulls ghcr.io/hyperlight-dev/hyperlight-unikraft/agent at the
  pinned initrd tag, boots it once, and saves the snapshot.
- Every request restores that one warm image with its own mounts and
  network policy; the kernel builds its mount table from the mounts the
  restore names. Later calls on the same runner rewind to it.
- Timeouts bound each step for a blocked guest and interrupt the vCPU
  from a watchdog thread for a busy one; either way the guest is
  dropped and the next call boots from the rewind point.
- CallFailed carries the guest's status, which becomes the exit code
  as before (sys.exit(N) -> N, uncaught exception -> 1).

The rootfs is needed only to warm: a home holding just a snapshot this
build loads runs, and setup keeps a rootfs of this release instead of
pulling it again. A warm is saved beside the snapshot directory and
swapped into place, so a failed or concurrent warm never leaves a
half-written layout. The e2e workflow fetches only the agent rootfs,
since the kernel is embedded in the crate.

On Windows the runner takes Hyperlight's single-VM mode through the
crate's configure_surrogates, skipping the 512 pre-spawned helper
processes (about 3.5 s); it holds one sandbox at a time.

Signed-off-by: danbugs <danilochiarlone@gmail.com>
pyhl was the 0.12 library's Python tool, gone since 0.13; nothing in the
backend is pyhl any more. The override is now $MXC_HYPERLIGHT_HOME (the
MXC_ prefix the other backends use) and the data directory
~/.local/share/mxc-hyperlight or %LOCALAPPDATA%\mxc-hyperlight, with the
dev fallbacks <exe>/mxc-hyperlight and <cwd>/.mxc-hyperlight. An old
pyhl home is simply no longer looked at.

Signed-off-by: danbugs <danilochiarlone@gmail.com>

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.

Copilot review overview

🟡 Changes recommended

Windows rootfs upgrades can fail, and the runtime-aware E2E prerequisite checks can incorrectly skip or run cases.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
What changed in this PR

Ports the Hyperlight backend to hyperlight-unikraft 0.14.1 and adds selectable guest runtimes with per-runtime installation and snapshots.

Changes:

  • Reworks Hyperlight boot, snapshot, timeout, mount, and OCI rootfs handling.
  • Adds six runtime choices across contracts, parsing, SDK types, and policy identity.
  • Adds runtime E2E fixtures, CI setup, and backend documentation.
File Description
tests/​configs/​hyperlight_python_hello.json Adds Python runtime fixture.
tests/​configs/​hyperlight_node_hello.json Adds Node hello fixture.
tests/​configs/​hyperlight_node_exit_code.json Adds Node exit-code fixture.
src/​testing/​wxc_e2e_tests/​tests/​e2e_windows.rs Adds per-runtime E2E cases and skipping.
src/​testing/​wxc_e2e_tests/​src/​lib.rs Updates Hyperlight installation probes.
src/​core/​wxc/​src/​main.rs Adds multi-runtime setup CLI handling.
src/​core/​wxc_common/​src/​wire.rs Adds Hyperlight wire configuration.
src/​core/​wxc_common/​src/​policy_identity.rs Includes runtime in Hyperlight policy identity.
src/​core/​wxc_common/​src/​models.rs Defines runtime and request models.
src/​core/​wxc_common/​src/​config_parser.rs Normalizes and validates Hyperlight configuration.
src/​core/​wxc_common/​src/​config_contract_adapters/​v0_9/​state_aware.rs Initializes the new IR field.
src/​core/​wxc_common/​src/​config_contract_adapters/​v0_9/​one_shot.rs Initializes the new IR field.
src/​core/​wxc_common/​src/​config_contract_adapters/​v0_8.rs Initializes the new IR field.
src/​core/​wxc_common/​src/​config_contract_adapters/​v0_7.rs Initializes the new IR field.
src/​core/​wxc_common/​src/​config_contract_adapters/​v0_6.rs Initializes the new IR field.
src/​core/​wxc_common/​src/​config_contract_adapters/​dev/​state_aware.rs Initializes state-aware Hyperlight IR.
src/​core/​wxc_common/​src/​config_contract_adapters/​dev/​one_shot.rs Converts development runtime configuration.
src/​core/​wxc_common/​src/​common_request_ir.rs Carries Hyperlight configuration in the IR.
src/​core/​mxc_engine/​src/​run.rs Adds Linux KVM availability checking.
src/​core/​mxc_engine/​src/​probe.rs Updates Hyperlight probe terminology.
src/​core/​mxc_engine/​src/​policy/​exact/​v0_10.rs Initializes the exact-contract field.
src/​core/​mxc_config_contract/​tests/​version_boundaries/​experimental.rs Tests the version boundary.
src/​core/​mxc_config_contract/​tests/​v0_10_0_alpha/​fixtures/​one_shot/​valid/​hyperlight_node.json Adds a valid Node fixture.
src/​core/​mxc_config_contract/​tests/​v0_10_0_alpha/​experimental/​root.rs Tests the root Hyperlight section.
src/​core/​mxc_config_contract/​tests/​v0_10_0_alpha/​experimental/​hyperlight.rs Tests runtime values and validation.
src/​core/​mxc_config_contract/​tests/​v0_10_0_alpha/​experimental.rs Registers Hyperlight contract tests.
src/​core/​mxc_config_contract/​src/​dev/​one_shot.rs Adds the development request field.
src/​core/​mxc_config_contract/​src/​dev/​mod.rs Exports Hyperlight contract types.
src/​core/​mxc_config_contract/​src/​dev/​experimental.rs Defines runtime contract types.
src/​core/​lxc/​src/​main.rs Adds Linux multi-runtime setup handling.
src/​Cargo.lock Updates Hyperlight and supporting dependencies.
src/​backends/​hyperlight/​common/​src/​lib.rs Implements the new runtime, snapshot, timeout, and installer paths.
src/​backends/​hyperlight/​common/​Cargo.toml Updates Hyperlight and OCI dependencies.
sdk/​node/​src/​types.ts Exposes Hyperlight runtime configuration.
sdk/​node/​src/​generated/​v0_10_0_alpha/​wire.ts Regenerates development wire types.
sdk/​node/​README.md Documents SDK backend support.
schemas/​dev/​mxc-config.schema.0.10.0-alpha.json Regenerates the development schema.
README.md Links the Hyperlight backend guide.
docs/​schema.md Documents the runtime field.
docs/​hyperlight/​hyperlight-backend.md Adds the comprehensive backend guide.
docs/​hyperlight-integration-plan.md Removes the superseded design document.
.github/​workflows/​hyperlight-e2e.yml Installs and tests selected runtimes in CI.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/backends/hyperlight/common/src/lib.rs
Comment thread src/testing/wxc_e2e_tests/src/lib.rs
Comment thread src/testing/wxc_e2e_tests/tests/e2e_windows.rs
Setup used docker or podman to pull the rootfs image and copy
initrd.cpio out of it, so a host without a container runtime could not
set Hyperlight up. It now speaks just enough of the OCI distribution
API itself: an anonymous pull token, the manifest (through an index
when the tag names one), and the layer tarballs, streamed through
gunzip and tar and checked against their digests. ureq (rustls with
ring, as the 0.12 crate used), flate2, tar, sha2 and serde_json come in
behind the hyperlight feature. The download is bounded (30 s to resolve
and connect, 60 s to a response, 30 min for a layer) so a dead link
fails instead of hanging setup.

The e2e workflow no longer needs crane: it runs --setup-hyperlight,
which also exercises the real install path in CI.

Signed-off-by: danbugs <danilochiarlone@gmail.com>
The design note from the original integration was the only document on
the backend, and it described the 0.12 shape: pyhl, a kernel file,
network rejected, tests that no longer exist. The guide covers what ships
now: setup and the image home, how a run works, the fields the backend
honours, what the guest has, the design choices that still hold, and the
messages to expect. The README and SDK backend table link it.

Signed-off-by: danbugs <danilochiarlone@gmail.com>
The Hyperlight backend can boot any of the guest runtimes
hyperlight-unikraft publishes, so a request needs a way to name one.
The `hyperlight` section's `runtime` says what process.commandLine is
source for: `agent` (the default), `python`, `python-shell`, `node`,
`bash` or `dotnet-jit`, each named as upstream names the image.

The section sits beside `wslc` and `windowsSandbox` in the 0.10.0-alpha
contract: the request IR, the domain model, the parser's section
validation, the adapters, the engine's exact builder and the policy
identity all carry it, and the generated schema and TypeScript are
regenerated. The runtime is part of the policy identity because it picks
the image the sandbox boots.

Signed-off-by: danbugs <danilochiarlone@gmail.com>
The image home now holds one directory per runtime (agent/, python/,
node/, ...), each with its rootfs, snapshot and stamp, so runtimes
install, upgrade and run independently. The runner picks the directory
from the request's hyperlight.runtime and keys its booted guest on it;
the image table gives each runtime its upstream image and scratch size.
The images that take source through a warm driver are selectable: agent,
python, python-shell, node, bash and dotnet-jit. The compiled images run
a program baked into the rootfs, so they are not.

--setup-hyperlight takes runtime names and installs agent by default,
and a run naming an uninstalled runtime fails at preflight with the
setup command to run. The e2e workflow installs agent, python and node,
and the suite gains a plain-Python hello, a Node.js hello and a Node.js
exit-code case on both platforms. The guide gains the runtime table and
the per-runtime layout.

Signed-off-by: danbugs <danilochiarlone@gmail.com>

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.

Copilot review overview

🔵 Needs a closer look

The suite-level agent prerequisite prevents the new independently installed Python and Node cases from running.

Review effort: Balanced
Findings: None

Resolved since last review (3)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants