openshell-driver-mxc
The Windows-only MXC compute driver runs each workload in a Microsoft MXC ProcessContainer while preserving OpenShell's standard RFC 0012 runtime split:
gateway / MXC driver
|
| gateway authentication and policy
v
openshell-supervisor --role=isolation-backend (host)
|
| generation-scoped TLS + sandbox JWT
v
openshell-windows-sandbox (ProcessContainer)
|
v
workload
Caller driver config is disabled by default, so command-based MXC workflows
need explicit administrator opt-in with allow_driver_config = true.
MXC does not support external-resource label admission. Host filesystem grants
rely on sandbox policy and a trusted gateway operator. See
resource admission configuration
for the independent caller configuration gate and resource admission controls.
This driver implements the gateway's ordinary in-process ComputeDriver
contract and is linked into openshell-gateway. Runtime readiness comes from
the authenticated host supervisor session, not a driver-reported condition.
The resolved create-time SandboxPolicy is carried by
DriverSandboxSpec.policy. The driver provisions a one-shot ProcessContainer,
launches the Windows boundary and separate host supervisor, and monitors both.
The boundary launches the workload only after authenticated confirmation.
The driver defaults its paired runtimes to info logging so native workload
launches remain observable. An explicit sandbox log-level setting takes
precedence. The boundary emits structured process activity and the Windows
branch's MXC agent launched acknowledgement only after native spawn succeeds.
The driver resolves its gateway endpoint and TLS server-name defaults from
generic gateway inputs. The host supervisor authenticates its gateway session
and retains main-process I/O. MXC has no foreground attachment adapter; create
command workloads with --detach. Preflight rejects foreground attachment
before provisioning. TCP readiness remains gated by authenticated session acceptance.
Windows boundary execution is implemented by the openshell-mxc-boundary
library behind the dedicated openshell-windows-sandbox.exe. The compute driver does not
embed the supervisor, and the sandbox does not link the compute driver.
Dynamic forwarding uses the shared protocol stream, not a dedicated relay
executable or a reverse connection to a new gateway listener.
The boundary establishes its control TCP connection outward from MXC to a generation-scoped loopback listener in the host isolation backend, matching the Windows branch relay's connection direction. The shared transport connector extension preserves pinned boundary TLS identity and supervisor JWT checks; the driver neither brokers protocol requests nor runs supervision. Discovery and attachment reuse the backend-owned listener, including reconnects. No host firewall rule changes are required for this control path.
Enforcement boundaries
The current port temporarily asserts main's required outer-fence guarantees
to permit Windows-branch compatibility testing. This is an unconditional
MXC-only stub, not verified enforcement evidence or production qualification.
Broad host-loopback access does not establish NoUnmanagedEgressPath, and
live access revocation has no verified native evidence. The provisioning TODO
tracks replacing these assertions with real enforcement. Audit metadata labels
egress as mxc-windows-parity-unverified-egress-stub. AppContainer identity,
authenticated transport, and generation checks remain required. Do not expose
sensitive host-local services to workloads using this compatibility path.
- MXC supplies the default-deny filesystem fence, AppContainer token, UI policy, and loopback-only network fence.
openshell-windows-sandboxconsumes its bootstrap files before launching untrusted code, authenticates the paired supervisor, and terminates workloads when an authenticated supervisor cannot recover within the reconnect deadline.- The host supervisor owns an authenticated per-generation explicit proxy. Missing or cross-sandbox credentials receive HTTP 407 before policy evaluation. MXC denies direct Internet egress.
- The explicit proxy resolves the actual socket-owning executable from the
Windows kernel TCP table, hashes it, and rechecks ownership before policy
evaluation. Allowing a launcher such as
cmd.exedoes not authorize a child such ascurl.exe; missing, ambiguous, or changed ownership denies the request. - The loopback fence permits
127.0.0.1/32; it does not isolate unrelated host services bound to that address. Treat the gateway host as trusted. - Host supervisor tokens and descriptors live beneath an owner-only Windows DACL. Boundary bootstrap secrets live in the ProcessContainer staging path and are deleted before workload launch.
Configuration
MXC does not implement external-resource label admission. Do not configure
resource_admission under its driver table; unsupported fields are rejected.
Host filesystem grants rely on workload policy and a trusted gateway operator,
not resource labels. Caller-supplied command configuration still requires
allow_driver_config = true. Native isolation, authenticated transport, and
outer-fence confirmation remain required.
The packaged openshell-supervisor.exe and openshell-windows-sandbox.exe default to
siblings of openshell-gateway.exe. Override their paths for development
builds.
[openshell.drivers.mxc]
wxc_exec_path = "C:\\mxc-kit\\bin\\wxc-exec.exe"
supervisor_binary_path = "C:\\OpenShell\\openshell-supervisor.exe"
sandbox_binary_path = "C:\\OpenShell\\openshell-windows-sandbox.exe"
# Defaults to %LOCALAPPDATA%\OpenShell\mxc.
state_dir = "C:\\Users\\operator\\AppData\\Local\\OpenShell\\mxc"
# Empty uses the gateway's loopback listener and TLS mode.
grpc_endpoint = ""
backend = "process_container"
pc_least_privilege = false
pc_capabilities = []
pc_allow_local_network = true
pc_minimal_env = false
debug = false
etw_audit = false
Only process_container supports this architecture. isolation_session is
rejected during sandbox validation.
MXC 1.0.0 is required. Pre-1.0 executors and the retired
default_configuration_id setting are not supported; remove that setting
before upgrading. Both live launches and standalone mapper output use the
stable directional network.egress / network.ingress schema. The standalone
mapper emits numeric CIDRs and TCP ports, and reports DNS and L7 semantics as
mapping losses; the host supervisor continues to enforce the full network policy.
Supply the workload command and working directory per sandbox:
$config = '{"mxc":{"command":["C:\\Windows\\System32\\cmd.exe","/d","/c","echo hello"],"cwd":"C:\\work"}}'
openshell sandbox create --name mxc-demo --policy policy.yaml `
--driver-config-json $config --no-tty
The command and working directory are required. The working directory contains
the generation-scoped bootstrap staging directory. When no generic canonical
command is supplied, the driver passes mxc.command to the supervisor rather
than starting a scratch workload. An explicit generic canonical command retains
precedence. Environment belongs in --env or --env-from, not gateway configuration.
When gateway TLS is enabled, configure the gateway-owned guest_tls_ca.
The host supervisor verifies the gateway certificate with that CA and uses
main's launch authentication bundle. Gateway client certificates and keys are
not required; driver-owned guest TLS fields are rejected.
Capabilities
| Capability | Status |
|---|---|
| Filesystem and UI policy | Mapped to the MXC ProcessContainer fence |
| Network policy and provider credentials | Standard host supervisor proxy; proxy-aware workloads only |
| Exec, signals, retained output | Authenticated Sandbox Protocol; ConPTY resize is not yet supported |
| Dynamic forwarding | Standard supervisor ForwardTcp path through sandbox loopback connect |
| ETW/OCSF audit | Optional Windows Sandboxing ETW consumer |
| Gateway restart recovery | Not yet supported; live MXC generations remain in-memory |
UI controls are startup settings in the sandbox policy:
ui:
allow_graphical_ui: true
clipboard: read
allow_input_injection: false
Omitted UI settings deny all three capabilities. Clipboard accepts none,
read, write, or all, from the workload's perspective. Clipboard and input
injection require graphical UI. Unknown fields/values and unsupported
containment targets are rejected before provisioning. MXC advertises
openshell.policy.ui.v1 through existing extension metadata. The gateway rejects
explicit UI policy (including {}) for drivers missing this capability; those
drivers need no UI-specific handling. UI policy itself does not require the
allow_driver_config opt-in. Recreate the sandbox to change these settings.
Validation
Windows release build tasks stage the pinned, target-matching libz3.dll beside
the gateway and verify its architecture and copied SHA256. Conflicting cached
DLLs fail the build instead of selecting an arbitrary runtime. Local E2E requires
this adjacent DLL; rebuild for the native architecture if preflight reports it
missing.
Remote Windows host
Build on a Windows MSVC development machine and run the unchanged real E2E harness on a separate MXC host:
.\tasks\scripts\test-mxc-remote.ps1 -HostName 172.16.178.137 -UserName test `
-WxcExecPath 'C:\Tools\MXC\wxc-exec.exe'
Install the public SSH key on the target and verify its host key before running.
The script defaults to ~/.ssh/openshell-mxc-test; override -IdentityFile as
needed. Both SSH and SCP must be on PATH locally. The target needs Windows
OpenSSH Server, OpenSSL on its SSH-session PATH, and a qualified MXC runtime,
but does not need Rust, MSVC, mise, or a source checkout.
The script detects native Windows architecture independently of the SSH shell,
uses the existing windows:build:* task, and validates the executable PE
architecture before testing. -BuildDirectory selects a dedicated Cargo cache.
-SkipBuild reuses existing artifacts without claiming they match current
sources. -Scenario selects an existing harness scenario.
The package includes libz3.dll from the target-specific Cargo build cache.
Windows prebuilt Z3 uses a dynamic runtime DLL. Supply -Z3DllPath if multiple
different cached versions exist or when using a custom Z3 build. The remote
host needs the native Visual C++ runtime; the runner validates DLL architecture
and gateway startup before invoking E2E.
The example gateway explicitly enables caller driver config so tests can submit their workload command and directory. MXC does not implement external-resource label admission. The temporary outer-fence assertions permit compatibility testing but do not qualify exclusive network mediation or live revocation.
Uploads are cached by SHA256 and verified before execution. Each run has an
isolated remote directory under %USERPROFILE%\openshell-mxc-tests; old runs
are retained. Full logs, host capabilities, source status, artifact hashes, and
the results ZIP return to target/windows-remote-results in this checkout.
Signing-key directories are not downloaded. Test failures and incomplete
coverage remain nonzero exits. Missing host-loopback evidence is not a pass,
and a qualified host does not close the outer-fence implementation gaps above.
Local Windows host
Run the Windows build lane on a native Windows MSVC host:
mise run --skip-tools windows:check:x64
mise run --skip-tools windows:lint:x64
mise run --skip-tools windows:build:x64
mise run --skip-tools windows:test:mxc-real:x64
mise run --skip-tools windows:e2e:mxc
The real-MXC tests are skip-safe when wxc-exec.exe or the required host
capabilities are absent. A complete integration run still requires a qualified
Windows MXC host; cross-compilation validates code shape but cannot validate
ProcessContainer networking or DACL behavior.
The real runtime requires native ProcessContainer directional egress and ingress
host-loopback support, reported by wxc-exec.exe --probe. AppContainer fallback
cannot supply these guarantees. Count test-internal SKIP messages separately
from Cargo's passed count.
The E2E runner uses native release artifacts (override with -BinaryDir), OpenSSL
on PATH for disposable Ed25519 keys, and per-run writable fixtures under
target/windows-e2e-results. It preserves the tracked gateway TOML and isolates
CLI registration via disposable APPDATA, LOCALAPPDATA, and XDG directories.
Inherited gateway overrides are cleared for the run and restored exactly
(including empty versus absent entries). The caller's gateway aliases are not
modified. Signing keys have an owner-only DACL,
remain outside result bundles, and are removed unless -KeepRunning is requested.
E2E runs real MXC only: there is no mock mode, and an inherited
OPENSHELL_MXC_MOCK_WXC=1 is rejected. Any skipped selected scenario makes the
run incomplete and exits non-zero; a passing exit requires all selected scenarios
to execute successfully. Unit-test mocks are separate from E2E coverage.
network-policy checks admission and workload execution, not real network
enforcement. All-skipped real runs report INCOMPLETE, not PASS.
The real-MXC HTTPS test uses the authenticated E2E gateway/supervisor harness.
Build native release binaries first; OPENSHELL_MXC_TEST_BINARY_DIR optionally
selects another binary directory. Its opt-in -Scenario https-ca requires
Internet access to https://example.com and Windows curl 8.3 or newer. Curl
explicitly loads the boundary-injected CA bundle and records the peer certificate;
success requires a nonempty response and the OpenShell proxy CA issuer. It does
not install a host trust root or disable CA/hostname verification. The fixture
uses best-effort Schannel revocation because the ephemeral private CA has no CRL
distribution point; it does not qualify revocation enforcement. The default seven E2E
scenarios remain independent of Internet access.
The forwarding scenario starts a TCP listener inside MXC, then verifies two
nonce-bound request/reply exchanges through openshell forward service, the
gateway, supervisor, and Windows boundary. Both listener ports are dynamically
assigned. Its native echo agent is a test-only Cargo example, built automatically
by the E2E mise task and remote runner, not a shipped runtime binary. It verifies
managed ingress, not denial of direct host-to-workload connections. Select it with
-Scenario forwarding on the local harness or remote runner.
The separate service-forwarding scenario runs the same native fixture in HTTP
mode, exposes a named endpoint with openshell service expose, and verifies two
unique GET responses through gateway host-based routing. It deletes the endpoint
and requires HTTP 404 afterward. Requests connect only to the gateway with the
exposed URL's Host header, so no wildcard DNS setup is required.
The default host-service scenario runs an HTTP fixture on host 127.0.0.1
and a dynamic port. A real MXC workload makes two direct curl requests; both
must return the fixture's nonce and appear in its host-side request log. The
host service is checked before launch and stopped after testing. Select it with
-Scenario host-service; no Internet access, LAN address, or firewall changes
are required. This verifies direct localhost connectivity.
The ws-agent.yaml and openclaw-gateway.yaml policies preserve the Windows
branch's workload grants. inference.yaml is a template: replace its filesystem,
curl executable, inference host, and port placeholders before use. Authorize
curl, which owns the network socket, not its cmd launcher. These policies have
parser/mapper regression coverage; they do not add live WebSocket, OpenClaw,
or provider-backed inference scenarios to the seven-scenario E2E runner.
With -KeepRunning, the runner restores the caller's environment but retains
the disposable CLI/runtime directory for the live gateway and prints its path.
Remove that directory only after stopping the gateway.
Focused native qualification
After building the native release binaries, run:
mise run --skip-tools windows:test:mxc-boundary
mise run --skip-tools windows:test:mxc-network
mise run --skip-tools windows:test:mxc-loopback
The network task runs real injected-CA HTTPS and both child-curl policy cases. It requires Internet access. Native target selection uses the machine architecture, including when SSH launches an emulated PowerShell. The loopback task hosts its test inside a real ProcessContainer with host loopback denied; it is a separate qualification and never relaxes the fence or reports an unsupported run as a pass. On the ARM64 test host (Windows build 28120, MXC 1.0.0), this qualification currently fails with socket error 10013. Enabling the documented private-network capability while retaining host-loopback denial also fails; no safe OpenShell workaround has been established.
Provider environment publications reject case-insensitive duplicate names, invalid environment entries, and names reserved for the six injected TLS trust variables before installing them. Rejected updates retain the prior revision.
For live ETW audit coverage, set OPENSHELL_WXC_EXEC_PATH and run
mise run --skip-tools windows:test:mxc-audit after building native release
binaries. This requires elevation or Performance Log Users membership. It checks
the shipped config and coverage classifier before requiring all seven event types
in the durable JSONL output; the ordinary E2E scenarios do not check this path.
On the ARM64 test host (Windows build 28120, MXC 1.0.0), Sandboxing ETW records come from the shared Appinfo broker rather than the driver-owned executor. The consumer cannot correlate these records using the executor's PID and process generation, so live audit qualification currently fails even though the workload completes. The executor diagnostic log redacts its container identity. A trusted broker-to-launch correlation is needed; treating the shared broker PID as a sandbox identity would misattribute concurrent sandboxes and is not supported.