User/shschaefer/rust lib#635
Merged
Merged
Conversation
added 9 commits
July 12, 2026 13:52
Contributor
There was a problem hiding this comment.
Pull request overview
This PR lays the groundwork for multi-language MXC SDKs by centralizing backend dispatch/execution into a single Rust “engine” crate, then layering a C ABI and a new C# SDK on top. It refactors the existing executor binaries and the Rust mxc-sdk to delegate dispatch to the engine, proving the shared boundary.
Changes:
- Introduce
mxc_engineas the shared execution/dispatch/probing/policy-building layer used bymxc-sdkand executors. - Add
mxc_ffi(cdylib/staticlib) exposing a panic-safe C ABI and generating C# P/Invoke bindings viacsbindgen. - Add a new
csharp/SDK and CI drift/version parity scripts for C# ↔ native bindings.
Show a summary per file
| File | Description |
|---|---|
| src/ffi/mxc_ffi/tests/ffi.rs | Integration tests for the C ABI surface |
| src/ffi/mxc_ffi/src/lib.rs | C ABI: mxc_run, result/free helpers, version |
| src/ffi/mxc_ffi/Cargo.toml | New FFI crate definition + csbindgen build-dep |
| src/ffi/mxc_ffi/build.rs | Generates checked-in C# P/Invoke bindings |
| src/core/wxc/src/main.rs | Refactor: delegate one-shot/state-aware dispatch to engine |
| src/core/wxc/Cargo.toml | Depend on mxc_engine; forward feature flags |
| src/core/wxc_common/src/cmdline.rs | Centralize backend→commandline-context mapping |
| src/core/mxc-sdk/tests/sandbox.rs | Tests for new mxc_sdk::run convenience |
| src/core/mxc-sdk/src/lib.rs | Re-export engine surface; add run() API |
| src/core/mxc-sdk/README.md | Docs updated for run() and engine relationship |
| src/core/mxc-sdk/Cargo.toml | Make mxc-sdk depend on mxc_engine |
| src/core/mxc_engine/src/state_aware.rs | Engine-owned state-aware dispatch entry point |
| src/core/mxc_engine/src/run.rs | Engine-owned run-to-completion backend resolution/execution |
| src/core/mxc_engine/src/policy.rs | Doc updates to reference spawn API |
| src/core/mxc_engine/src/platform.rs | Update prose: probing now lives in engine |
| src/core/mxc_engine/src/lib.rs | New engine crate public surface (spawn/run/probe/policy) |
| src/core/mxc_engine/src/error.rs | Engine error facade over wxc_common errors |
| src/core/mxc_engine/src/dispatch.rs | Streaming backend dispatch implementation moved/updated |
| src/core/mxc_engine/Cargo.toml | New engine crate definition + feature wiring |
| src/core/mxc_darwin/src/main.rs | Refactor: delegate run-to-completion to engine |
| src/core/mxc_darwin/Cargo.toml | Depend on mxc_engine instead of seatbelt directly |
| src/core/lxc/src/main.rs | Refactor: delegate run-to-completion to engine |
| src/core/lxc/Cargo.toml | Depend on mxc_engine; forward feature flags |
| src/Cargo.toml | Add core/mxc_engine and ffi/mxc_ffi to workspace |
| src/Cargo.lock | Lockfile updates (incl. csbindgen, new crates) |
| scripts/check-version-sync.js | Enforce Cargo ↔ npm ↔ C# version parity |
| scripts/check-csharp-errorcode-parity.js | CI gate: C# ErrorCode matches native status constants |
| scripts/check-csharp-bindings-codegen.js | CI gate: regenerate and diff C# P/Invoke bindings |
| microvm-perf-results.json | Added perf results JSON file at repo root |
| csharp/README.md | New C# SDK docs and usage guidance |
| csharp/Microsoft.Mxc.Sdk/SandboxPolicy.cs | C# policy POCOs with JSON annotations |
| csharp/Microsoft.Mxc.Sdk/RunResult.cs | C# run-to-completion result model |
| csharp/Microsoft.Mxc.Sdk/Native/NativeMethods.g.cs | Generated P/Invoke layer from csbindgen |
| csharp/Microsoft.Mxc.Sdk/Native/NativeLibraryResolver.cs | Native library resolution for dev/NuGet layouts |
| csharp/Microsoft.Mxc.Sdk/MxcSandbox.cs | Public C# entrypoint wrapping the native ABI |
| csharp/Microsoft.Mxc.Sdk/MxcException.cs | Typed exception mapping native codes |
| csharp/Microsoft.Mxc.Sdk/Microsoft.Mxc.Sdk.csproj | New SDK project file + runtime assets packing |
| csharp/Microsoft.Mxc.Sdk/ErrorCode.cs | C# enum mirroring native status codes |
| csharp/Microsoft.Mxc.Sdk.Tests/MxcSandboxTests.cs | xUnit tests for load path + error mapping + JSON |
| csharp/Microsoft.Mxc.Sdk.Tests/Microsoft.Mxc.Sdk.Tests.csproj | Test project definition |
| csharp/Microsoft.Mxc.Sdk.slnx | Solution definition including sample/tests/sdk |
| csharp/Microsoft.Mxc.Sdk.Sample/Program.cs | Console sample wiring policy→run→print |
| csharp/Microsoft.Mxc.Sdk.Sample/Microsoft.Mxc.Sdk.Sample.csproj | Sample project definition |
| csharp/.gitignore | Ignore build artifacts + staged runtimes |
| build.bat | Stage mxc_ffi.dll into C# NuGet runtime assets (Windows) |
| .github/copilot-instructions.md | Document new engine/FFI/C# SDK structure & commands |
Review details
- Files reviewed: 44/46 changed files
- Comments generated: 3
- Review effort level: Low
Collaborator
Author
|
Ran the dependency-feed-check. Needs to pickup csbindgen dependency. |
…ature is enabled The `lxc` crate's `main.rs` calls `hyperlight_common::setup` under `#[cfg(all(feature = "hyperlight", target_arch = "x86_64"))]`, but `hyperlight_common` was not declared as a dependency. This caused a compile error across Hyperlight E2E, Windows x64, Linux x64/lint jobs. Follow the same pattern as `wxc/Cargo.toml`: - Add `hyperlight_common` as an optional workspace dep scoped to x86_64 - Update `hyperlight` feature to activate `dep:hyperlight_common` and enable its `hyperlight` sub-feature
MGudgin
reviewed
Jul 13, 2026
MGudgin
reviewed
Jul 13, 2026
mxc_ffi's build.rs unconditionally ran csbindgen to regenerate the C# P/Invoke, so every whole-workspace build (including the backend feature matrix, e.g. --features hyperlight) compiled csbindgen and wrote into the source tree. Make csbindgen an optional build-dependency behind a new `csharpsdk` cargo feature (off by default). Normal and backend builds no longer compile csbindgen; only the drift gate (scripts/check-csharp-bindings-codegen.js) opts in via `cargo build -p mxc_ffi --features csharpsdk` to regenerate the committed bindings. Updates the C# README and copilot-instructions accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4efbd7c8-05fc-47ac-9a4b-4d92414a822a
…at build - Remove the committed microvm-perf-results.json CI test-output artifact and gitignore microvm-perf-results*.json (root .gitignore). - Stop committing the generated C# P/Invoke: gitignore *.g.cs and remove NativeMethods.g.cs. The csproj's GenerateNativeBindings MSBuild target now regenerates it before each compile (cargo build -p mxc_ffi --features csharpsdk), and mxc_ffi's build.rs emits rerun-if-changed on the output so a missing (gitignored) file reliably re-triggers codegen. The bindings-codegen gate is repurposed from a drift check to a generation check (asserts the expected entry points are produced). - Fix the csproj runtimes comment: only build.bat stages the Windows native library today; a build stages only its own host platform's mxc_ffi. - csharp/README.md: describe the binding as a .NET binding (implemented in C#). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4efbd7c8-05fc-47ac-9a4b-4d92414a822a
MGudgin
reviewed
Jul 13, 2026
|
|
||
| ### C# SDK | ||
|
|
||
| - **C# SDK** (`csharp/`, `Microsoft.Mxc.Sdk`) — a managed binding that P/Invokes the native `mxc_ffi` library (which wraps the Rust `mxc-sdk` → `mxc_engine`), rather than spawning an executor. `MxcSandbox.Run(policy, command)` / `RunAsync` run a command to completion and return a `RunResult` (`ExitCode`, `TimedOut`, `Stdout`, `Stderr`); policy POCOs (`SandboxPolicy`, `FilesystemPolicy`, `NetworkPolicy`, `UiPolicy`) serialize to the same camelCase JSON the native layer expects. `MxcException` carries a typed `ErrorCode` that mirrors the native `MXC_STATUS_*` codes (parity-gated by `scripts/check-csharp-errorcode-parity.js`). `Native/NativeMethods.g.cs` is **generated** by csbindgen from the Rust FFI and is **not committed** (gitignored) — the csproj's `GenerateNativeBindings` MSBuild target regenerates it before each C# compile via `cargo build -p mxc_ffi --features csharpsdk`, so a `dotnet build` needs the Rust toolchain on PATH. `NativeLibraryResolver` finds `mxc_ffi` via `MXC_FFI_DIR`, the assembly dir / `runtimes/<rid>/native`, or `src/target/{debug,release}`. Projects: `Microsoft.Mxc.Sdk` (library), `Microsoft.Mxc.Sdk.Sample` (console), `Microsoft.Mxc.Sdk.Tests` (xUnit), in `Microsoft.Mxc.Sdk.slnx`. This first increment exposes run-to-completion only. |
Member
MGudgin
reviewed
Jul 13, 2026
| - `mxc_engine` is the **single execution engine** — the one home for "given an `ExecutionRequest`, run it". It owns: run-to-completion backend selection (`run` / `resolve_runner`, covering **all** backends, incl. the Windows ProcessContainer BaseContainer/AppContainer BFS/DACL fallback tiers via `appcontainer_common::dispatcher::dispatch_with_fallback`, and every experimental backend, feature-gated); streaming (`spawn` → `Box<dyn SandboxProcess>`); state-aware lifecycle dispatch (`run_state_aware`); host probing (`platform_support` / `PlatformSupport`); and config building (`build_request`, `SandboxPolicy` + sections, `available_tools_policy`/`user_profile_policy`/`temporary_files_policy`). It depends on the backend crates (cfg-split: appcontainer/windows_sandbox/isolation_session/wslc/nanvix on Windows, bubblewrap/lxc/nanvix on Linux, seatbelt on macOS) so it can't live in `wxc_common`. Both the executor binaries and `mxc-sdk` call into it. `ResolvedRunner` carries the boxed runner plus (Windows only) the optional `DaclManager` guard, so `wxc-exec` can park the guard for its signal handler. | ||
| - `mxc-sdk` is the **public Rust SDK** — a thin facade over `mxc_engine`. Build a `SandboxRequest` with `build_request`, then either `run(request)` (run-to-completion; returns an `Output` with the `WaitOutcome` + captured `stdout`/`stderr`) or `spawn_sandbox(request)` (returns a `Sandbox` handle for live bidirectional stdio — `take_stdin`/`take_stdout`/`take_stderr`, `kill()`, `wait()` returning a `WaitOutcome` (`Exited(i32)` / `TimedOut`) as `io::Result`, or `wait_with_output()`). It re-exports the engine's config-building surface (`build_request`, `mxc_sdk::policy::{SandboxPolicy sections}`, discovery helpers) and `platform_support`; `mod sandbox` (wrapping the engine's `SandboxProcess` in `Sandbox`) is its only local module. No pty is ever allocated. Streaming supports Seatbelt (macOS), Bubblewrap (Linux), and Windows ProcessContainer (AppContainer + BaseContainer); other backends return `ErrorCode::UnsupportedContainment`. | ||
| - The lower-level execution surface lives in `wxc_common::sandbox_process`: the `SandboxBackend` trait (`validate` + `spawn(request, logger, StdioMode) -> Box<dyn SandboxProcess>` + a `diagnose_exit` hook) and the generic `Runner<B>` adapter that bridges any `SandboxBackend` to the run-to-completion `ScriptRunner` (via `spawn(StdioMode::Inherit)` then `wait()`). `StdioMode::Pipes` hands the caller live stdin/stdout/stderr (what the `mxc-sdk` streaming path uses); `StdioMode::Inherit` lets the child inherit the host's stdio (what the executor binaries use, preserving the TTY under a pty). `SandboxBackend` is implemented for Seatbelt, Bubblewrap, and Windows ProcessContainer. | ||
| - `mxc_ffi` (`ffi/mxc_ffi`, `crate-type = ["cdylib", "staticlib", "lib"]`) is a flat, panic-safe **C ABI over `mxc-sdk`** for language bindings. `mxc_run(policyJson, command, out)` runs a sandbox to completion, filling a `#[repr(C)] MxcRunResult` (status + exit_code + timed_out + owned stdout/stderr/error C strings); every entry point is `catch_unwind`-wrapped so a panic becomes a status code, never an unwind. Its `build.rs` runs **csbindgen** to generate the C# P/Invoke (`csharp/Microsoft.Mxc.Sdk/Native/NativeMethods.g.cs`), gated behind the crate's **`csharpsdk`** feature (off by default, so the whole-workspace backend build matrix doesn't compile csbindgen). The generated file is **not committed** (gitignored); the C# csproj regenerates it at build time and `scripts/check-csharp-bindings-codegen.js` runs the codegen in CI and asserts the expected entry points are produced. The C ABI is **not a stable external contract** (native + binding are co-versioned and generated together; see the crate docs). Currently exposes run-to-completion only; streaming + state-aware over FFI are deferred. |
Member
caarlos0
added a commit
to caarlos0/mxc
that referenced
this pull request
Jul 13, 2026
Integrate upstream microsoft#635 (Rust FFI library + C# SDK), which extracted the mxc-sdk engine internals (policy/dispatch/platform/error) into a new internal `mxc_engine` crate and added the `mxc_ffi` crate and `csharp/` bindings. Git auto-followed the `mxc-sdk/src/policy.rs` -> `mxc_engine/src/policy.rs` rename and applied this branch's Seatbelt-proxy edits to the moved file: the "not supported on macOS" proxy rejection is dropped, the host-rule flag is renamed to `accepts_host_rules_without_outbound`, and the `macos_proxy_is_accepted_and_mapped` test moves with it. The ported SDK helper test keeps using the `mxc_sdk::{build_request, ...}` re-exports, which now forward to `mxc_engine`. Workspace members (unix_test_proxy) and copilot-instructions.md sections from both sides are preserved. Validated: mxc_engine/mxc-sdk/seatbelt_common/ wxc_common/unix_test_proxy/mxc_darwin build + test green (incl. the moved proxy test), clippy -D warnings clean, non-macOS seatbelt_common cross-check clean, version-sync OK, SDK build + unit tests green (3 pre-existing PowerShell-on-macOS failures only). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3191c12-2deb-452b-8379-3abbcd5eeb68 Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📖 Description
This PR begins the work necessary to create SDKs for multiple languages. We refactor MXC so the executor binaries become thin CLI shells over a single execution library, then prove that boundary by adding a C ABI and a C# SDK that binds to it.
Previously each executor ( wxc-exec , lxc-exec , mxc-exec-mac ) carried its own match request.containment backend-selection logic, and the public Rust SDK ( mxc-sdk ) was a provisional streaming-only wrapper that duplicated dispatch. This PR consolidates all dispatch into one engine and layers the public surfaces on top.
New crates
• core/mxc_engine (internal) — the single home for "given an ExecutionRequest , run it": run-to-completion selection over all backends (incl. the Windows ProcessContainer BaseContainer/AppContainer BFS/DACL fallback tiers and every experimental backend), streaming spawn , state-aware lifecycle dispatch, host probing, and policy/config building. Absorbs the logic previously duplicated across the executors and the old mxc-sdk internals.
• ffi/mxc_ffi ( cdylib / staticlib ) — a flat, panic-safe C ABI over mxc-sdk . mxc_run(policyJson, command, out) runs a sandbox to completion and returns captured stdout/stderr + exit outcome via a #[repr(C)] MxcRunResult . Every entry point is catch_unwind -wrapped; JSON in, bytes+status out. A build.rs runs csbindgen to generate the C# P/Invoke layer.
Refactors
• mxc-sdk is now a thin public facade re-exporting the engine, and gains run() (run-to-completion capture) alongside spawn_sandbox() (live streaming).
• wxc-exec / lxc-exec / mxc-exec-mac reduced to arg-parse + config-load + maintenance modes + delegate to mxc_engine ; no backend match remains in any binary. The ContainmentBackend → CommandLineContext mapping moved into wxc_common::cmdline as the single source of truth.
New C# SDK ( csharp/ )
• Microsoft.Mxc.Sdk — MxcSandbox.Run/RunAsync → RunResult , policy POCOs mirroring the Rust wire shape, MxcException / ErrorCode , and a dev/NuGet native-library resolver. Plus a console sample and xUnit tests, wired into a solution.
🔗 References
Follow phase will add streaming and state-awareness over the FFI and through the C# SDK.
🔍 Validation
Rust (Windows host):
• cargo fmt --all -- --check , cargo clippy --workspace --all-targets -- -D warnings
• cargo test for mxc_engine , mxc-sdk , mxc_ffi , wxc , lxc , mxc_darwin , wxc_common — all pass
• cargo test -p wxc_e2e_tests — one-shot + state-aware + experimental (microvm/hyperlight/windows-sandbox) suites pass; host-prep-gated cases #[ignore] d
• Live: wxc-exec basic_processcontainer.json -- cmd /c echo … runs through the engine; experimental-gate + state-aware provision error envelopes verified
Cross-platform (Windows→Linux cargo check , no-link): mxc_engine (incl. microvm ), mxc-sdk , wxc_common , mxc_ffi type-check clean; engine clippy for the Linux target clean. macOS/Hyperlight-feature arms are faithful mirrors of already-compiling code (toolchains unavailable on the dev host).
C# (.NET 8): dotnet test on the solution — 5/5 pass (native load, serialization, error mapping); the sample ran a real sandbox end-to-end from C# ( hello from MXC , exit 0), exercising C# → P/Invoke → mxc_ffi.dll → mxc-sdk → engine → ProcessContainer.
CI gates (new): check-csharp-errorcode-parity.js (16 codes), check-csharp-bindings-codegen.js (csbindgen drift), and the extended check-version-sync.js (Cargo ↔ npm ↔ C# = 0.7.0) — all pass. Existing TS SDK contract unchanged.
✅ Checklist
Cargo.lock, thedependency-feed-checkcheck passes (see docs/pull-requests.md)📋 Issue Type
GitHub Actions runs the PR validation build automatically. The ADO pipeline
(
MXC-PR-Build) is the Azure version of the PR pipeline, kept in parity with the GitHubActions build; it runs on merge to
main, and Microsoft reviewers with write access can trigger iton a PR with
/azp run. See docs/pull-requests.md.If the
dependency-feed-checkcheck fails on a new dependency, the crate must be added tothe feed before the PR can pass. See docs/pull-requests.md
for the steps.
Microsoft Reviewers: Open in CodeFlow