Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9fbd256
feat(driver): add MXC compute driver for Windows isolation sessions
pkhodade-NV Jun 5, 2026
6f00649
wip(mxc): checkpoint hung-agent work (recon, policy_map embed, A1 wir…
jamieknvidia Jun 9, 2026
6072f23
test(mxc): fix lifecycle and policy unit-test compile drift
jamieknvidia Jun 9, 2026
c78544a
fix(mxc): downgrade missing sandbox_token to debug log
jamieknvidia Jun 9, 2026
e4230b3
fix(mxc): keep sandbox Ready after a successful one-shot agent exec
jamieknvidia Jun 9, 2026
e4aed16
feat(mxc): add processContainer backend for default-deny enforcement
jamieknvidia Jun 10, 2026
2860a6d
refactor(driver-mxc): embed policy mapper as a module; remove standal…
gburachas Jun 10, 2026
4b63f90
feat(driver-mxc): implement lossless split_policy for proxy-delegated…
gburachas Jun 10, 2026
76957ff
feat(driver-mxc): implement Pattern-C governed-egress split through t…
gburachas Jun 12, 2026
0737e99
fix(driver-mxc): emit MXC network.proxy as {localhost: port}
gburachas Jun 12, 2026
ac2a363
fix(driver-mxc): serialize isolation_session stop/deprovision as unit…
gburachas Jun 12, 2026
0118a86
test(driver-mxc): add Tier-0 mapper coverage matrix with schema drift…
gburachas Jun 12, 2026
8aec2a8
feat(driver-mxc): inject agent_env into sandbox process.env
jamieknvidia Jun 24, 2026
dd764cf
test(driver-mxc): avoid unsafe env mutation in resolve_agent_env test
jamieknvidia Jun 26, 2026
a374f59
fix(mxc): adapt MXC driver to current GitHub OpenShell API
jamieknvidia Jul 29, 2026
df93c04
feat(server): wire the MXC compute driver into the gateway on Windows
jamieknvidia Jul 29, 2026
9ca59af
fix(driver-mxc): implement GetGatewayListenerRequirements for #2496 base
jamieknvidia Aug 11, 2026
7beadcb
test(driver-mxc): add probe-gated real wxc-exec test lane (no mocks)
gburachas Jun 12, 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
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion crates/openshell-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub enum ComputeDriverKind {
Vm,
Docker,
Podman,
/// Microsoft MXC isolation session (Windows only).
Mxc,
}

impl ComputeDriverKind {
Expand All @@ -134,6 +136,7 @@ impl ComputeDriverKind {
Self::Vm => "vm",
Self::Docker => "docker",
Self::Podman => "podman",
Self::Mxc => "mxc",
}
}
}
Expand Down Expand Up @@ -174,8 +177,9 @@ impl FromStr for ComputeDriverKind {
"vm" => Ok(Self::Vm),
"docker" => Ok(Self::Docker),
"podman" => Ok(Self::Podman),
"mxc" => Ok(Self::Mxc),
other => Err(format!(
"unsupported compute driver '{other}'. expected one of: kubernetes, vm, docker, podman"
"unsupported compute driver '{other}'. expected one of: kubernetes, vm, docker, podman, mxc"
)),
}
}
Expand Down
4 changes: 4 additions & 0 deletions crates/openshell-core/src/telemetry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ pub enum TelemetryComputeDriver {
Kubernetes,
Podman,
Vm,
Mxc,
Unknown,
}

Expand All @@ -172,6 +173,7 @@ impl TelemetryComputeDriver {
Self::Kubernetes => "kubernetes",
Self::Podman => "podman",
Self::Vm => "vm",
Self::Mxc => "mxc",
Self::Unknown => "unknown",
}
}
Expand All @@ -183,6 +185,7 @@ impl TelemetryComputeDriver {
"k8s" | "kubernetes" => Self::Kubernetes,
"podman" => Self::Podman,
"vm" => Self::Vm,
"mxc" => Self::Mxc,
_ => Self::Unknown,
}
}
Expand All @@ -194,6 +197,7 @@ impl TelemetryComputeDriver {
Some(crate::ComputeDriverKind::Kubernetes) => Self::Kubernetes,
Some(crate::ComputeDriverKind::Podman) => Self::Podman,
Some(crate::ComputeDriverKind::Vm) => Self::Vm,
Some(crate::ComputeDriverKind::Mxc) => Self::Mxc,
None => Self::Unknown,
}
}
Expand Down
49 changes: 49 additions & 0 deletions crates/openshell-driver-mxc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

[package]
name = "openshell-driver-mxc"
description = "MXC (Windows isolation session) compute driver for OpenShell"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true

[lib]
name = "openshell_driver_mxc"

[dependencies]
openshell-core = { path = "../openshell-core" }
tokio = { workspace = true }
tonic = { workspace = true }
futures = { workspace = true }
tokio-stream = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
base64 = { workspace = true }
tracing = { workspace = true }
thiserror = { workspace = true }
uuid = { workspace = true }

[dev-dependencies]
tokio = { workspace = true }
# tempfile is not a workspace dependency; 3.27 is already resolved in Cargo.lock.
tempfile = "3"
# Used only by the Windows-only example + integration test (parse policy YAML
# into the typed proto, and drive the CLI). Inert on non-Windows.
openshell-policy = { path = "../openshell-policy" }
clap = { workspace = true }
anyhow = { workspace = true }
# Needed by the real-wxc integration test (wxc_exec_real.rs) which builds
# --config-base64 payloads without going through the async WxcExecInvoker.
# base64 and serde_json are already [dependencies] but dev-dependency resolution
# is independent; explicit entries make them visible to integration tests.
base64 = { workspace = true }
serde_json = { workspace = true }
# Used by the drift guard test (handled_fields_inventory) to parse YAML into a
# generic serde_json::Value for key enumeration.
serde_yml = { workspace = true }

[lints]
workspace = true
145 changes: 145 additions & 0 deletions crates/openshell-driver-mxc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# openshell-driver-mxc

OpenShell compute driver backed by **Microsoft MXC** (`wxc-exec`) on Windows.

## Design

This driver implements the gateway's `ComputeDriver` gRPC contract as an
**in-process library** linked into `openshell-gateway`. It drives MXC through
the state-aware lifecycle (`provision` → `start` → `exec` → `stop` →
`deprovision`), runs the agent **inside the driver** (exec-in-driver), and
**self-reports readiness** — there is no in-sandbox supervisor, no host-side
surrogate, and no `ConnectSupervisor` relay. See
`docs/reference/mxc-compute-driver-design.mdx` for Shailendra's full
architectural rationale (decisions D1–D4).

## Capability Matrix (June 15 demo slice)

| Capability | MXC driver | Closing it requires |
|---|---|---|
| Filesystem policy (read-write / read-only grants) | ✅ provision-time AppContainer shares | — |
| Governed egress (CONNECT proxy + OPA + L7) | Available behind `egress_proxy` on `process_container`; host proxy integration is the next consumer | `implement-openshell-mxc-egress-proxy` |
| Network policy | Split into MXC `network.proxy` + trimmed OpenShell policy on `process_container`; `isolation_session` still rejects network config | MXC feedback item M1 for persistent sessions |
| Process policy (seccomp, uid/gid) | ❌ host-side governance design; OS isolation only | not pursued |
| Interactive exec/connect/forward | ❌ exec runs in-driver, no client attach | `adapt-openshell-gateway-windows` |
| Bundled agent image | ❌ no OCI image; relies on Windows host install | — |
| Restart durability | ❌ in-memory registry; restart orphans live sessions | follow-on |
| Concurrent sandboxes | ⚠️ isolation_session v1 is single-session | MXC backend feature |

The June 15 demo proof point is **filesystem policy enforcement**:
- **Positive**: write to the in-policy `share_dir` succeeds; `hello.txt` appears on the host.
- **Negative**: write outside the policy fails with Windows access-denied; driver emits a
`DriverPlatformEvent` denial and the exec exits non-zero.

## Configuration (`[openshell.drivers.mxc]`)

```toml
[openshell.drivers.mxc]
# Path to wxc-exec.exe (required for live runs)
wxc_exec_path = "C:\\path\\to\\wxc-exec.exe"
# MXC backend: "isolation_session" (default) or "process_container"
backend = "process_container"
# MXC configurationId — never use "small" (known OS bug)
default_configuration_id = "composable"
# process_container-only options
pc_least_privilege = false
pc_capabilities = []
# Agent command executed inside the sandbox
agent_command = ["cmd", "/c", "echo hello > C:\\work\\demo\\hello.txt"]
# Working directory for the agent (defaults to share_dir)
agent_cwd = "C:\\work\\demo"
# Host directory mapped read-write into the sandbox
share_dir = "C:\\work\\demo"
# Pattern C governed egress. Requires backend = "process_container" until
# MXC M1 adds network.proxy support for isolation_session.
egress_proxy = false
egress_proxy_addr = ""
# Enable --debug on wxc-exec invocations
debug = false
```

Or via environment / CLI:
```
OPENSHELL_DRIVERS=mxc openshell-gateway ...
openshell-gateway --drivers mxc ...
```

## Prerequisites (live runs)

- Windows 11 Insider build ≥ 26300.8553
- `IsoSessionApp.dll` present and registered
- `wxc-exec.exe` built with `--features isolation_session`

For off-box smoke tests against the in-process mock shim (no `wxc-exec`,
no isolation session needed), set `OPENSHELL_MXC_MOCK_WXC=1`.

## PolicyMapper seam

Policy translation (`SandboxPolicy` → MXC `ContainerConfig`) is delegated to
a `policy::PolicyMapper` trait. The primary implementation,
`EmbeddedPolicyMapper`, calls the embedded [`policy_map`](src/policy_map/)
module's `map_to_mxc` directly on the typed proto (no YAML bridge), then
normalizes the resulting filesystem paths to Windows form. `policy_map/` is
the **source of truth** for the OpenShell→MXC mapping — it was the standalone
`openshell-policy-mapper` crate, now embedded as a module here. The original
`StubPolicyMapper` is retained as a documented, compile-only fallback that only
maps `share_dir`.

When `egress_proxy` is enabled, `EmbeddedPolicyMapper` uses `split_policy`
instead: MXC receives filesystem grants plus a loopback `network.proxy`
redirect, and the driver stores the trimmed network-only `SandboxPolicy` for
the host CONNECT proxy. The development export surface remains the
[`policy-to-mxc`](examples/policy-to-mxc.rs) example; there is no production
`openshell policy export-mxc` subcommand yet.

Everything in this crate — including the mapper, the
[`policy-to-mxc`](examples/policy-to-mxc.rs) example, and the parity tests in
[`tests/policy_mapper_examples.rs`](tests/policy_mapper_examples.rs) — is
Windows-only (`#[cfg(target_os = "windows")]`); the crate is an empty stub on
other platforms. The mapper's parity tests therefore run on the Windows MSVC
test lane (`mise run windows:test:x64`), not the Linux lane.

## Packaging the demo for the demo box

Use [`examples/package-demo.ps1`](examples/package-demo.ps1) to assemble
the gateway EXE, CLI EXE, runtime DLLs (`libz3.dll`), `demo.yaml`, the
gateway config, and the runbook into one folder, then copy that folder to
the demo Windows host and follow `mxc-demo-runbook.md` inside it. The
script prints a SHA256 manifest so the operator can sanity-check what
landed before moving it.

## Real-MXC test lane

Three tasks drive real `wxc-exec.exe` hardware; all are **skip-safe** — any test
or scenario that requires an absent binary or backend prints a SKIP reason and
exits 0 rather than failing.

| Task | What it runs | When to use |
|---|---|---|
| `windows:test:mxc-real:x64` | `tests/wxc_exec_real.rs` — Tier-2 invoker tests with `--ignored --test-threads=1` | Pre-merge on any Windows host that has `wxc-exec`; dry-run tests always pass; enforcement tests probe-gate themselves |
| `windows:e2e:mxc` | `examples/run-mxc-e2e.ps1` — Tier-3 scenario runner, real binary, probe-gated | Demo box / nightly; needs the gateway + CLI binaries in the script directory |
| `windows:e2e:mxc:mock` | Same runner with `-Mock` — wiring-only, no real `wxc-exec` needed | Any Windows host (CI, dev machine); validates wiring and the network-reject scenario |

**Probe script:** `examples/probe-mxc-host.ps1` emits a JSON capability report
(OS build, wxc-exec path/version, dry-run exit code, per-backend trial result,
and a `verdicts` object). Run it before the real-MXC lane to understand what
will PASS vs SKIP on a given host:

```powershell
powershell -NoProfile -ExecutionPolicy Bypass `
-File crates/openshell-driver-mxc/examples/probe-mxc-host.ps1
```

**Skip semantics:** tests in `wxc_exec_real.rs` are marked
`#[ignore = "requires real wxc-exec"]` — the standard `windows:test:x64` suite
never runs them. `OPENSHELL_WXC_EXEC_PATH` overrides the default
`C:\mxc\wxc-exec.exe` lookup. See `docs4gtb/mxc-box-capabilities.md` for the
empirical capability snapshot of the development box (build 26200, processcontainer
velocity keys not enabled, isolation_session absent).

## Deferred work

- **Interactive exec/connect/forward** → `adapt-openshell-gateway-windows`
- **Governed egress proxy implementation** → `implement-openshell-mxc-egress-proxy`
- **Restart durability** (deprovision orphaned sessions on startup) → follow-on
- **GPU passthrough** → not pursued in host-side-governance design
25 changes: 25 additions & 0 deletions crates/openshell-driver-mxc/examples/demo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# demo.yaml — June 15 MXC filesystem-policy proof.
#
# Minimal filesystem policy granting the shared host folder read-write;
# everything else is implicitly denied (default-deny). The granted path MUST
# match `share_dir` / OPENSHELL_MXC_SHARE_DIR and the agent_command target.
#
# NOTE: the canonical OpenShell policy YAML key is `filesystem_policy`
# (parsed by the `openshell-policy` crate into SandboxPolicy.filesystem), NOT
# `filesystem`. The MXC driver's policy bridge then re-emits this under the
# `filesystem_policy` key the embedded mapper expects.
version: 1

filesystem_policy:
include_workdir: false
read_only: []
read_write:
- "C:/work/openshell-mxc-demo" # = OPENSHELL_MXC_SHARE_DIR (host-visible share)

# No landlock / process / network_policies for the demo. (Network policy on
# isolation_session is REJECTED by the driver — see the crate README. Adding a
# network_policies block here would make `sandbox create` fail with a precise
# invalid_argument naming the rule, never a silent drop.)
15 changes: 15 additions & 0 deletions crates/openshell-driver-mxc/examples/e2e-policies/fs-empty.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# fs-empty.yaml — Empty filesystem policy (default-deny) scenario.
#
# No paths are granted. With processcontainer (AppContainer), every write is
# denied by the OS without any host ACL configuration — genuine default-deny.
# This scenario is processcontainer-only (isolation_session has no deny primitive).
# Used by the fs-default-deny-empty scenario in run-mxc-e2e.ps1.
version: 1

filesystem_policy:
include_workdir: false
read_only: []
read_write: []
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# fs-readonly.yaml — Read-only grant + read-write share scenario.
#
# The read_only path is a prepared directory whose content the agent can read
# but not write; the read_write path is DemoDir (host-visible share).
# Used by the fs-readonly scenario in run-mxc-e2e.ps1.
version: 1

filesystem_policy:
include_workdir: false
read_only:
- "C:/work/openshell-mxc-e2e-ro-src"
read_write:
- "C:/work/openshell-mxc-e2e"
14 changes: 14 additions & 0 deletions crates/openshell-driver-mxc/examples/e2e-policies/fs-rw.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# fs-rw.yaml — Filesystem read-write grant scenario.
#
# Grants read-write access to the DemoDir (substituted at runtime).
# Used by the fs-rw-positive-negative scenario in run-mxc-e2e.ps1.
version: 1

filesystem_policy:
include_workdir: false
read_only: []
read_write:
- "C:/work/openshell-mxc-e2e"
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# network-reject.yaml — Network policy rejection scenario.
#
# A filesystem grant plus a network_policies rule. On isolation_session the
# driver rejects sandbox create at map time with invalid_argument naming the
# network rule (M1 not yet landed). On processcontainer with egress_proxy
# disabled, network policy is also rejected.
#
# This scenario requires NO live backend — it passes even on this box and in
# mock mode because the rejection happens in the policy mapper before wxc-exec
# is invoked. It is the only scenario that never SKIPs.
version: 1

filesystem_policy:
include_workdir: false
read_only: []
read_write:
- "C:/work/openshell-mxc-e2e"

network_policies:
test_rule:
name: test-network-reject
endpoints:
- host: api.example.com
port: 443
protocol: rest
enforcement: enforce
access: read-only
Loading
Loading