Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
11b430d
host: reconcile verified stop outcomes onto feature
Nov 10, 2026
99d0045
host: journal CLI launches and persist saved VM records
Nov 10, 2026
1cb779e
guest: serve snapshot capture requests from init
Nov 10, 2026
dc669fa
tests: keep adapter sandbox names short below data roots
Nov 10, 2026
adeb1d4
tests: format the compact sandbox creation diagnostic
Nov 10, 2026
13bbbc8
host: verify CLI launch liveness from its log and endpoint
Nov 10, 2026
92ac710
host: reconcile recorded process opening onto qualified stop
Nov 10, 2026
797d300
host: open strict private snapshot directories
Nov 10, 2026
8752816
guest: retain restored ingress as an init helper
Nov 10, 2026
9785ad4
Merge qualified VM reattach input into CLI launch liveness
Nov 10, 2026
4662351
host: join qualified CLI store and snapshot reader inputs
Nov 10, 2026
b134e70
integration: adapt CLI liveness to qualified process opening proofs
Nov 10, 2026
a81a6c8
host: keep immutable named CLI snapshots
Nov 10, 2026
cc4ded0
cli: recover interrupted launches under the sandbox lock
Nov 10, 2026
573f0ba
guest: activate repaired init sessions
Nov 10, 2026
8921c45
test: reconnect the owned Windows recovery control fixture
Nov 10, 2026
206b3f1
test(nvx-rs): exercise restored init with native readiness
Nov 10, 2026
71f3c50
host: prepare blockless capture launches
Nov 10, 2026
5316731
host: compile the capture allowlist reference as an item
Nov 10, 2026
8df64c2
host: record the capture preparation API
Nov 10, 2026
4ca3e62
host: keep the capture fixture warning-free on Windows
Nov 10, 2026
d56d3d3
guest: route new sandbox boots through nvx-init
Nov 10, 2026
2a0451d
host: finish exited captures into snapshot entries
Nov 10, 2026
06e7f9e
Merge published SL3.7a named snapshot store input
Nov 10, 2026
94c8e4a
Merge published SL3.3b bounded launch recovery input
Nov 10, 2026
1911901
Merge published SL7.8a init boot routing input
Nov 10, 2026
ce7fa06
Reconcile joined init test seam inventory
Nov 10, 2026
d4d8927
host: retain capture time without changing compatibility identity
Nov 10, 2026
e1f7611
Reconcile restored-init fixture with typed host results
Nov 10, 2026
b70d7e9
Format typed exit checks in joined fixture
Nov 10, 2026
d814df2
Merge pinned public SL2.14 full-time contract into capture inputs
Nov 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions guest/common/init
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ case "$cmdline" in
*" nvx_sandbox=1 "*) sandbox_mode=true ;;
*) sandbox_mode=false ;;
esac
new_init=false
if [ "$sandbox_mode" = true ]; then
case "$cmdline" in
*" nvx_lifecycle="*) ;;
*) new_init=true ;;
esac
fi

fatal() {
echo "$*" >&2
Expand Down Expand Up @@ -189,7 +196,7 @@ for token in $cmdline; do
esac
done
set +f
if [ -n "$nvx_exec" ]; then
if [ -n "$nvx_exec" ] && [ "$new_init" = false ]; then
case "$nvx_exec" in
/*) ;;
*) fatal "nvx_exec must be an absolute initramfs path" ;;
Expand All @@ -206,6 +213,7 @@ if [ "$sandbox_mode" = false ]; then
mount_virtfs
fi
# virt-net: if --net attached a NIC, configure the only non-loopback interface.
announcer_pid=
nip=$(sed -n 's/.*virtnet_ip=\([^ ]*\).*/\1/p' /proc/cmdline)
if [ -n "$nip" ]; then
nmask=$(sed -n 's/.*virtnet_mask=\([^ ]*\).*/\1/p' /proc/cmdline)
Expand Down Expand Up @@ -289,6 +297,7 @@ if [ -n "$nip" ]; then
allow | host-loopback)
if [ -n "$ngw" ] && [ -x /sbin/nvx-ingress ]; then
/sbin/nvx-ingress "$ngw" </dev/null &
announcer_pid=$!
else
virtnet_error "$ningress ingress needs /sbin/nvx-ingress and an IPv4 gateway"
fi
Expand All @@ -308,9 +317,24 @@ if [ -n "$nip" ]; then
fi
fi
if [ "$sandbox_mode" = true ]; then
[ -x /sbin/nvx-init-agent ] ||
if [ "$new_init" = false ]; then
[ -x /sbin/nvx-init-agent ] ||
workload_fatal "selected guest cannot act as sandbox control"
exec /sbin/nvx-init-agent
fi
[ -x /sbin/nvx-init ] ||
workload_fatal "selected guest cannot act as sandbox control"
exec /sbin/nvx-init-agent
# nvx-time boot returns before its child publishes the daemon PID.
tries=0
while [ ! -r /run/nvx/time/daemon.pid ] && [ "$tries" -lt 600 ]; do
sleep 0.05
tries=$((tries + 1))
done
time_daemon=$(cat /run/nvx/time/daemon.pid) ||
workload_fatal "time daemon process ID is unavailable"
set -- "$time_daemon"
[ -z "$announcer_pid" ] || set -- "$@" "$announcer_pid"
exec /sbin/nvx-init "$@"
fi
case "$workload_lifecycle" in
one-shot)
Expand Down
71 changes: 57 additions & 14 deletions nvx-rs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ changes only when the module's purpose does.
| [`nvx::Hypervisor`](#nvxhypervisor) | KVM, MSHV, or WHP, with its serde form behind the `serde` feature |
| [`nvx::exec`](#nvxexec) | The execution engine: the streams, credit, and outcome of an execution's two sides, without I/O, for any framing |
| [`nvx::host::runtime`](#nvxhostruntime) | `Runtime`: what every launch shares, the runtime's files and their identity, the hypervisor and its probe, and the launch options |
| [`nvx::host::vm`](#nvxhostvm) | A private VM directory, cold preparation, verified detached launch, confirmed stop, and caller-saved reattachment |
| [`nvx::host::snapshot`](#nvxhostsnapshot) | Strict private snapshot directories, verified keys and manifests, time eligibility, and the input of a future VM restore |
| [`nvx::host::vm`](#nvxhostvm) | A private VM directory, cold and capture preparation, verified detached launch, confirmed stop, and caller-saved reattachment |
| [`nvx::host::snapshot`](#nvxhostsnapshot) | Strict private snapshots, post-exit capture finishing, verified keys and manifests, and time eligibility |
| [`nvx::host::config`](#nvxhostconfig) | `VmConfig` and `CaptureConfig`: pure configuration, cold-boot kernel/OpenVMM arguments, portable length checks, and capture identity |
| [`nvx::host::restore`](#nvxhostrestore) | A caller-driven restore to Ready without I/O or a clock, and its peer-verified restore-ready listener |
| [`nvx::host::artifacts`](#nvxhostartifacts) | Locating the OpenVMM executable and the guest artifacts that a VM runs, and their runtime identity |
Expand Down Expand Up @@ -515,11 +515,23 @@ failure never hides confirmed exit.
`Prepared` launch without starting a process or binding a listener. It requires
`config.boot`, refuses a snapshot input, rechecks the directory's privacy, and
creates a new private log. Existing log, outcome and Linux endpoint entries
are refused rather than replaced. Only the log is created before a spawn;
OpenVMM creates the remaining outputs when it runs. A failed preparation
closes and removes only its new log, preserving all pre-existing entries and
are refused rather than replaced. An ordinary cold boot creates only the log
before a spawn; OpenVMM creates its remaining outputs when it runs. A failed preparation
closes and removes only its new files, preserving all pre-existing entries and
caller-owned inputs, and reports a cleanup failure with the original error.

With `boot.capture`, creation requires a blockless root and refuses every
filesystem export. It creates private sparse `capture-image.raw` and
`capture-scratch.raw` files, verifies their actual complete geometries, and
targets `<vm_dir>/openvmm`. A configured NIC keeps its resolved address but
uses the complete deny-all policy, whatever its configured policy.
`Prepared::capture_context()` exposes a cloneable, serializable
`snapshot::CaptureContext` with the checked capture configuration and disk
geometries, NIC and console devices, runtime identity, hypervisor and CPU
profile. The caller chooses whether and how to persist it. Creation writes
no context file, `key.bin` or `snapshot.json`, and does not finish or publish
a capture.

On Linux, the generated control and boot-console socket names must be valid
Unicode and shorter than 108 bytes both as supplied and with the directory's
ancestor links resolved. Supplied names must hold no comma or equals sign,
Expand Down Expand Up @@ -569,8 +581,8 @@ responsive shell input, and a verified clean exit; it downloads no artifact.
### `nvx::host::snapshot`

`SnapshotKey` and `SnapshotManifest` own the compatibility key and strict
OpenVMM manifest reader. `SnapshotManifest::time` exposes the capture's
`TimeContract`, whose `eligibility` checks its restore window at a `HostTime`;
OpenVMM manifest reader. `SnapshotManifest::time` and `SnapshotKey::time` expose
the capture's `TimeContract`, whose `eligibility` checks its restore window at a `HostTime`;
`HostTime::now` samples the host's clock and identities. The existing
`host::template` names remain aliases of these same types.

Expand All @@ -579,6 +591,12 @@ The key's canonical encoding and identity use the snapshot names and omit
and no reader or migration of the prior encoding is supported. `CaptureClass`
still records the legacy capture inputs, including its guest build.

The persisted key includes the complete per-snapshot time contract and must
agree with the manifest's time. Its compatibility identity excludes capture
anchors, host and boot identities, lineage and cut-to-anchor time: captures
at different times can have different key bytes and the same `KeyIdentity`.
The declared rates and time ABI remain compatibility inputs.

`Snapshot::open` checks exactly `key.bin`, `snapshot.json` and
`openvmm/{manifest.bin,memory.bin,state.bin}`. Directories are private, files
are regular and private to their owner, artifact lengths equal the strict
Expand All @@ -593,6 +611,20 @@ or lock. `Snapshot` remains an opaque input of a future restore:
`vm::create` still refuses `Some(snapshot)` with `ErrorKind::Unsupported`;
only cold boots are supported.

`CaptureContext` records a prepared capture's checked configuration and
effective devices independently of runtime paths or network policy.
`vm::Prepared::capture_context` returns it for the caller to clone and
serialize; NVX owns no capture-context store or persistence format.

`finish_capture(&VmDir, &CaptureContext, &Exited)` requires the capture VM's
proved exit and successful outcome, checks the OpenVMM snapshot against the
context, and atomically writes `key.bin` and informational `snapshot.json`
beside `openvmm/`. It returns `CapturedSnapshot { key }`. The caller moves
only those three entries into its own private, immutable snapshot directory;
logs, outcomes and other VM files remain where they are. A failure can be
corrected and retried while the VM directory and capture context stay intact,
including when one metadata file was already written.

### `nvx::host::config`

`VmConfig`: the configuration of a VM as one value, its processors, its memory
Expand Down Expand Up @@ -670,12 +702,15 @@ The renderer emits neither `--microvm-lifecycle` nor
`--microvm-workload-identity`. Callers inspect the complete arguments through
`Prepared::arguments()`.

Both argument entry points refuse a `Boot` with a capture as `Unsupported`
rather than silently omit its devices and resource capacities.
They also refuse non-Unicode export child roots instead of lossily rendering
a different host path.
`VmConfig::check` and `kernel_command_line` retain their existing behavior for
valid capture configurations.
For a capture, `CaptureConfig` supplies the processor capacity, the boot-online
processor limit, and the boot memory and its capacity; the ordinary VM's cold
resource counts need not match. Boot memory must be aligned to 128 MiB.
The kernel text omits root, view, mapping and workload tokens and admits only
OpenVMM's named platform allowlist. Caller-supplied tier, processor, console,
device and network tokens are refused by name even when allowlisted: the
builder owns them. OpenVMM adds exactly one `nvx_snapshot_tier=platform` from
`--snapshot-tier platform`; callers may not supply or duplicate it.
Non-Unicode export child roots are still refused rather than lossily rendered.

`VmConfig::check_command_line()` checks the configuration's known arguments on
every host, before any host change, with 2048 UTF-16 code units reserved for the
Expand Down Expand Up @@ -3227,7 +3262,15 @@ disk's block device.

Each binary's command line, exit statuses, and byte output are compatibility
contracts; the [`nvx::guest`](src/guest/mod.rs) documentation describes each
program. Guests run them as static `x86_64-unknown-linux-musl` executables. On
program. After a restored platform capture, `nvx-init` keeps one activation
across control-session replacements, with its deadline anchored to the repair
acknowledgement. It applies the restore's root and network, mounts the runtime,
starts and retains an announcer only for published listeners, switches once,
then completes and reports Ready. The host supplies the complete mapping table
before the first valid EXEC starts the restored workload; later executions and
byte-identical activation retries reuse the retained state.

Guests run them as static `x86_64-unknown-linux-musl` executables. On
Linux, with the musl target and a C compiler driver, `cc`, `nvx.py` builds them:

```bash
Expand Down
7 changes: 7 additions & 0 deletions nvx-rs/public-api/linux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3037,6 +3037,9 @@ field nvx::host::snapshot::CaptureClass::processors
field nvx::host::snapshot::CaptureClass::runtime
field nvx::host::snapshot::CaptureClass::scratch
method nvx::host::snapshot::CaptureClass::to_bytes
struct nvx::host::snapshot::CaptureContext
struct nvx::host::snapshot::CapturedSnapshot
field nvx::host::snapshot::CapturedSnapshot::key
struct nvx::host::snapshot::ClassIdentity
method nvx::host::snapshot::ClassIdentity::as_bytes
method nvx::host::snapshot::ClassIdentity::from_bytes
Expand Down Expand Up @@ -3112,6 +3115,7 @@ method nvx::host::snapshot::SnapshotKey::processors
method nvx::host::snapshot::SnapshotKey::runtime
method nvx::host::snapshot::SnapshotKey::scratch
method nvx::host::snapshot::SnapshotKey::speaks_current_contracts
method nvx::host::snapshot::SnapshotKey::time
method nvx::host::snapshot::SnapshotKey::to_bytes
struct nvx::host::snapshot::SnapshotManifest
method nvx::host::snapshot::SnapshotManifest::created_at
Expand All @@ -3135,6 +3139,7 @@ field nvx::host::snapshot::TimeContract::host_id
field nvx::host::snapshot::TimeContract::lineage
field nvx::host::snapshot::TimeContract::tsc_frequency_hz
field nvx::host::snapshot::TimeContract::tsc_tolerance_ppm
fn nvx::host::snapshot::finish_capture
mod nvx::host::store
struct nvx::host::store::ArtifactIdentity
method nvx::host::store::ArtifactIdentity::as_str
Expand Down Expand Up @@ -3689,6 +3694,7 @@ method nvx::host::template::TemplateKey::processors
method nvx::host::template::TemplateKey::runtime
method nvx::host::template::TemplateKey::scratch
method nvx::host::template::TemplateKey::speaks_current_contracts
method nvx::host::template::TemplateKey::time
method nvx::host::template::TemplateKey::to_bytes
struct nvx::host::template::TemplateManifest
method nvx::host::template::TemplateManifest::created_at
Expand Down Expand Up @@ -3770,6 +3776,7 @@ field nvx::host::vm::Launched::process
struct nvx::host::vm::Prepared
method nvx::host::vm::Prepared::arguments
method nvx::host::vm::Prepared::capability
method nvx::host::vm::Prepared::capture_context
method nvx::host::vm::Prepared::inherit
method nvx::host::vm::Prepared::log
method nvx::host::vm::Prepared::outputs
Expand Down
7 changes: 7 additions & 0 deletions nvx-rs/public-api/windows.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,9 @@ field nvx::host::snapshot::CaptureClass::processors
field nvx::host::snapshot::CaptureClass::runtime
field nvx::host::snapshot::CaptureClass::scratch
method nvx::host::snapshot::CaptureClass::to_bytes
struct nvx::host::snapshot::CaptureContext
struct nvx::host::snapshot::CapturedSnapshot
field nvx::host::snapshot::CapturedSnapshot::key
struct nvx::host::snapshot::ClassIdentity
method nvx::host::snapshot::ClassIdentity::as_bytes
method nvx::host::snapshot::ClassIdentity::from_bytes
Expand Down Expand Up @@ -1698,6 +1701,7 @@ method nvx::host::snapshot::SnapshotKey::processors
method nvx::host::snapshot::SnapshotKey::runtime
method nvx::host::snapshot::SnapshotKey::scratch
method nvx::host::snapshot::SnapshotKey::speaks_current_contracts
method nvx::host::snapshot::SnapshotKey::time
method nvx::host::snapshot::SnapshotKey::to_bytes
struct nvx::host::snapshot::SnapshotManifest
method nvx::host::snapshot::SnapshotManifest::created_at
Expand All @@ -1721,6 +1725,7 @@ field nvx::host::snapshot::TimeContract::host_id
field nvx::host::snapshot::TimeContract::lineage
field nvx::host::snapshot::TimeContract::tsc_frequency_hz
field nvx::host::snapshot::TimeContract::tsc_tolerance_ppm
fn nvx::host::snapshot::finish_capture
mod nvx::host::store
struct nvx::host::store::ArtifactIdentity
method nvx::host::store::ArtifactIdentity::as_str
Expand Down Expand Up @@ -2274,6 +2279,7 @@ method nvx::host::template::TemplateKey::processors
method nvx::host::template::TemplateKey::runtime
method nvx::host::template::TemplateKey::scratch
method nvx::host::template::TemplateKey::speaks_current_contracts
method nvx::host::template::TemplateKey::time
method nvx::host::template::TemplateKey::to_bytes
struct nvx::host::template::TemplateManifest
method nvx::host::template::TemplateManifest::created_at
Expand Down Expand Up @@ -2355,6 +2361,7 @@ field nvx::host::vm::Launched::process
struct nvx::host::vm::Prepared
method nvx::host::vm::Prepared::arguments
method nvx::host::vm::Prepared::capability
method nvx::host::vm::Prepared::capture_context
method nvx::host::vm::Prepared::inherit
method nvx::host::vm::Prepared::log
method nvx::host::vm::Prepared::outputs
Expand Down
Loading
Loading