Skip to content

feat(mxc-sdk): add the importable in-process sandbox library crate#556

Merged
MGudgin merged 14 commits into
microsoft:mainfrom
caarlos0:mxc-sdk
Jun 24, 2026
Merged

feat(mxc-sdk): add the importable in-process sandbox library crate#556
MGudgin merged 14 commits into
microsoft:mainfrom
caarlos0:mxc-sdk

Conversation

@caarlos0

@caarlos0 caarlos0 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

📖 Description

Part 3 of 3 splitting #524. This PR adds mxc-sdk (lib mxc_sdk), an importable Rust library for starting MXC sandboxes in-process without a pty, built on the SandboxBackend interfaces (#554) and the unified backends (#555). Callers stream a sandboxed process without shelling out to the executor binaries or depending on the @microsoft/mxc-sdk TypeScript module.

Public surface — crate-owned types, so wxc_common stays an implementation detail callers don't depend on:

  • build_request(&SandboxPolicy) -> SandboxRequest, then spawn_sandbox -> Sandbox: a handle for bidirectional stdio (take_stdin/take_stdout/take_stderr), try_wait, id, kill (process-tree), and wait -> WaitOutcome (Exited(i32) | TimedOut; Err reserved for an actual OS/wait failure), plus stdout/stderr closers.
  • Error / ErrorCode mirror the wire-format error one-for-one.
  • mxc_sdk::policy ports the SDK's config building (createConfigFromPolicy plus available_tools_policy / user_profile_policy / temporary_files_policy); platform_support ports getPlatformSupport.

Backends: Bubblewrap (Linux), Seatbelt (macOS), Windows ProcessContainer (AppContainer + BaseContainer). Other backends and LXC return UnsupportedContainment (LXC has no non-pty capture path); dry_run is rejected for streaming spawns.

Adds wxc_common::config_parser::load_request_from_value so the crate maps a config it already holds as JSON without a base64 round-trip. The in-crate backend dispatch (dispatch.rs) and host probe (platform.rs) are marked provisional — a follow-up moves them into a shared mxc engine crate that both this library and the executor binaries call into.

🔗 References

🔍 Validation

  • cargo test -p mxc-sdk (macOS, toolchain 1.93): 44 pass (12 lib-unit, sandbox 7, sdk_helpers 10, streaming 14, +1 doc-test); Windows ProcessContainer integration tests are #[ignore]d (need an elevated, host-prepped Windows host).
  • cargo fmt --all -- --check and cargo clippy --all-targets -- -D warnings clean on macOS, Windows, and Linux targets.
  • cargo test -p wxc_common 268 pass (validates the load_request_from_value addition).

✅ Checklist

📋 Issue Type

  • Bug fix
  • Feature
  • Task
Microsoft Reviewers: Open in CodeFlow

caarlos0 and others added 3 commits June 24, 2026 09:43
…d / SandboxProcess / Runner)

Introduce the shared, no-pty execution surface that the containment backends
and a future in-process library build on. Purely additive: no existing code
path uses these yet, so behavior is unchanged.

- `SandboxProcess` — a handle to a running sandboxed child: `take_stdin` /
  `take_stdout` / `take_stderr`, `try_wait`, `id`, `kill` (process-tree), and
  `wait` (drains any untaken stdio, honors `scriptTimeout`), plus stdout/stderr
  closers for abandoning a backgrounded-descendant-held read without a kill.
- `SandboxBackend` — `validate` + `spawn(request, logger, StdioMode) ->
  SandboxProcess` + a `diagnose_exit` hook; `StdioMode::{Pipes, Inherit}`.
- `Runner<B>` — the generic adapter bridging any `SandboxBackend` to the
  run-to-completion `ScriptRunner` (spawn `Inherit`, then `wait`).
- `StreamCloser`, `group_kill` (Unix leader-first SIGKILL of the child's group),
  and `wait_with_timeout` (adaptive 1ms->50ms backoff poll).
- `interruptible_reader` (Unix self-pipe + `poll`) and the Windows pipe helpers
  in `process_util` (`InterruptiblePipeReader` / `PipeReadCanceller` /
  `create_std_pipes`) for out-of-band-cancelable streaming reads.
- `FailurePhase::Timeout` so a timeout is distinguishable from other failures.

The library backends and executor binaries are migrated onto this surface in a
follow-up PR, and the importable `mxc-sdk` crate is built on top of it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
…ute binaries via Runner

Migrate the three in-process backends — Seatbelt (macOS), Bubblewrap (Linux),
and Windows ProcessContainer (AppContainer + BaseContainer) — onto the
SandboxBackend / SandboxProcess interfaces added in the previous PR, and route
the executor binaries (wxc-exec, lxc-exec, mxc-exec-mac) through the generic
Runner<B> adapter. The old per-backend run-to-completion logic is removed; each
backend now exposes only spawn(), and Runner provides the single ScriptRunner
the binaries dispatch on (spawn StdioMode::Inherit, then wait).

Each backend gains a streaming handle with whole-process-tree termination
(Unix process-group SIGKILL; Windows job-object terminate) and a uniform
io::ErrorKind::TimedOut on scriptTimeout.

Intentional behavior changes for existing binaries (call-outs for review):
- Seatbelt now always env_clear()s the child (previously only when process.env
  was non-empty), aligning the binary with the SDK's documented "host env is
  not inherited" contract.
- Seatbelt resolves an empty process.cwd to a policy read-write path (or "/")
  instead of the launcher's cwd.
- Seatbelt/Bubblewrap inherit the executor's own stdio (StdioMode::Inherit) —
  Seatbelt no longer allocates a private pty, and Bubblewrap no longer forces
  stdin to /dev/null or post-exit-captures stdout/stderr (it streams live).
- BaseContainer now places the child in a UiJobObject for tree-kill (it had
  none before); the child is created suspended, assigned to the job, then
  resumed so no descendant can escape the kill window.
- kill() is a no-op once the child has been reaped, so it never signals a
  recycled pid/process-group.

The macOS Seatbelt characterization suite is updated to assert the new env/cwd/
streaming/timeout behavior; the LXC and Seatbelt backend docs are updated to
match. The default LXC path keeps its native pty and is unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Add `mxc-sdk` (lib `mxc_sdk`), a Rust library for starting MXC sandboxes
in-process without a pty, built on the SandboxBackend interfaces and the
unified backends from the previous PRs. Callers stream a sandboxed process
without shelling out to the executor binaries or depending on the TypeScript
SDK.

Public surface (crate-owned types — `wxc_common` stays an implementation
detail):
- `build_request(&SandboxPolicy)` -> `SandboxRequest`, then `spawn_sandbox`
  -> `Sandbox`: a handle for bidirectional stdio (`take_stdin`/`take_stdout`/
  `take_stderr`), `try_wait`, `id`, `kill` (process-tree), and `wait` ->
  `WaitOutcome` (`Exited(i32)` | `TimedOut`), plus stdout/stderr closers.
- `Error` / `ErrorCode` mirror the wire-format error one-for-one.
- `mxc_sdk::policy` ports the SDK's config building (`createConfigFromPolicy`
  plus `available_tools_policy` / `user_profile_policy` /
  `temporary_files_policy`); `platform_support` ports `getPlatformSupport`.

Backends: Bubblewrap (Linux), Seatbelt (macOS), Windows ProcessContainer
(AppContainer + BaseContainer). Other backends and LXC return
`UnsupportedContainment` (LXC has no non-pty capture path); `dry_run` is
rejected for streaming spawns.

Adds `wxc_common::config_parser::load_request_from_value` so the crate maps a
config it already holds as JSON without a base64 round-trip. The in-crate
backend dispatch (`dispatch.rs`) and host probe (`platform.rs`) are marked
provisional — a follow-up moves them into a shared `mxc` engine crate that both
this library and the executor binaries call into.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
@caarlos0 caarlos0 requested a review from a team as a code owner June 24, 2026 13:15
Copilot AI review requested due to automatic review settings June 24, 2026 13:15
@caarlos0 caarlos0 mentioned this pull request Jun 24, 2026
7 tasks

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.

Pull request overview

Adds a new importable Rust library crate (mxc-sdk / mxc_sdk) to spawn MXC sandboxes in-process with a handle-based, no-pty streaming API. To support this, it introduces shared streaming execution interfaces in wxc_common, refactors supported backends to implement them, and routes existing executor binaries through a single run-to-completion adapter.

Changes:

  • Introduce wxc_common::sandbox_process (SandboxBackend / SandboxProcess / Runner) plus supporting timeout + interruptible-stdio plumbing.
  • Refactor Seatbelt (macOS), Bubblewrap (Linux), and ProcessContainer (Windows) backends to expose streaming handles and route CLI executors through Runner.
  • Add the mxc-sdk crate (API, policy helpers, platform probing) with tests and documentation updates.
Show a summary per file
File Description
src/testing/wxc_e2e_tests/tests/e2e_seatbelt_characterization.rs Updates macOS Seatbelt characterization assertions to match the unified runner behavior (env/cwd semantics).
src/core/wxc/src/main.rs Switches Windows ProcessContainer CLI execution to use Runner adapter.
src/core/wxc_common/src/sandbox_process.rs Adds new streaming execution traits, helpers, and Runner bridge.
src/core/wxc_common/src/process_util.rs Adds Windows pipe reader/writer + interruptible read cancellation support.
src/core/wxc_common/src/models.rs Adds FailurePhase::Timeout to distinguish timeout from normal nonzero exits.
src/core/wxc_common/src/lib.rs Exposes new sandbox_process module and unix-only interruptible_reader.
src/core/wxc_common/src/interruptible_reader.rs Adds unix interruptible pipe reader for cancelable blocking reads.
src/core/wxc_common/src/config_parser.rs Adds load_request_from_value to map already-parsed JSON into ExecutionRequest.
src/core/wxc_common/Cargo.toml Broadens libc dependency from linux-only to all unix targets.
src/core/mxc-sdk/tests/streaming.rs Adds streaming API tests (stdio, kill, timeout); includes Windows integration test (ignored).
src/core/mxc-sdk/tests/sdk_helpers.rs Adds tests for policy helper ports and platform support probing.
src/core/mxc-sdk/tests/sandbox.rs Adds end-to-end library tests for env isolation, cwd defaulting, and timeout behavior.
src/core/mxc-sdk/src/sandbox.rs Defines public Sandbox handle and WaitOutcome wrapper over internal streaming handle.
src/core/mxc-sdk/src/platform.rs Implements host platform support detection for the Rust library.
src/core/mxc-sdk/src/lib.rs Defines crate public surface and spawn_sandbox entrypoint.
src/core/mxc-sdk/src/error.rs Adds crate-owned Error / ErrorCode facade over wxc_common errors.
src/core/mxc-sdk/src/dispatch.rs Implements backend selection + spawn for supported streaming backends.
src/core/mxc-sdk/README.md Documents crate usage, streaming model, and supported backends.
src/core/mxc-sdk/Cargo.toml Adds new mxc-sdk crate and its per-platform backend dependencies.
src/core/mxc_darwin/src/main.rs Routes macOS executor through Runner.
src/core/lxc/src/main.rs Routes Bubblewrap executor path through Runner.
src/Cargo.toml Registers new workspace member core/mxc-sdk and adds seatbelt_common workspace dep.
src/Cargo.lock Adds mxc-sdk package; updates Seatbelt deps after removing mxc_pty usage.
src/backends/seatbelt/common/src/seatbelt_runner.rs Refactors Seatbelt backend to SandboxBackend + streaming handle (pipes/inherit), plus cwd/env changes.
src/backends/seatbelt/common/src/profile_builder.rs Updates TTY rules comments and exports expand_tilde for cwd resolution.
src/backends/seatbelt/common/Cargo.toml Removes mxc_pty dependency from Seatbelt backend crate.
src/backends/bubblewrap/common/src/bwrap_runner.rs Refactors Bubblewrap backend to SandboxBackend + streaming handle with proper teardown.
src/backends/appcontainer/common/src/probe.rs Makes UiCapabilitySupport cloneable.
src/backends/appcontainer/common/src/network_manager.rs Refactors firewall COM initialization to be per-call RAII, thread-safe for teardown on different threads.
src/backends/appcontainer/common/src/job_object.rs Adds job-object termination helper for process-tree kill.
src/backends/appcontainer/common/src/dispatcher.rs Wraps ProcessContainer runners in Runner for run-to-completion path.
src/backends/appcontainer/common/src/base_container_runner.rs Refactors BaseContainer to SandboxBackend + streaming handle; adds job-based tree-kill and capture pipes.
docs/sandbox-policy/v1/policy.md Updates allowedHosts/blockedHosts allowOutbound requirements across backends.
docs/macos-support/seatbelt-backend.md Documents Seatbelt environment-clearing and cwd defaulting behavior.
docs/lxc-support/lxc-backend.md Updates LXC env semantics wording after Seatbelt behavior change.
.github/copilot-instructions.md Documents new mxc-sdk crate and the new streaming execution model (sandbox_process).

Copilot's findings

  • Files reviewed: 37/38 changed files
  • Comments generated: 3

Comment thread src/core/wxc_common/src/sandbox_process.rs
Comment thread src/backends/seatbelt/common/src/seatbelt_runner.rs
Comment thread src/core/mxc-sdk/tests/streaming.rs
caarlos0 and others added 10 commits June 24, 2026 11:41
…fely

Taking both take_stdout() and take_stderr() and reading them sequentially
can deadlock an output-heavy child (one pipe fills while the reader is
blocked on the other). Add wait_with_output(): it consumes the handle,
drains stdout and stderr concurrently on separate threads, and returns
Output { outcome, stdout, stderr } -- the safe, convenient default,
mirroring std::process::Child::wait_with_output. Review CR-24.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
…ent/host

The streaming dispatch in `dispatch.rs` only had direct tests for the
`dry_run` and macOS `guiAccess` rejection branches. Add two more so the
remaining guardrails are exercised in CI:

- `streaming_rejects_unsupported_containment`: drives the internal model
  with `containment = Lxc` and asserts `UnsupportedContainment` plus the
  backend name in the message.
- `host_support_ok_on_supported_platforms`: cfg-gated to Windows / Linux /
  macOS, guards against the `ensure_host_supported` cfg list dropping a
  supported platform.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
…set_env

set_env(Vec<String>) made the caller hand-format raw KEY=VALUE strings,
which diverged from the SDK's env channel -- injectEnvIntoConfig
(sdk/src/sandbox.ts) takes a structured { key: value } map and joins it to
the KEY=VALUE wire form internally.

Accept (key, value) pairs instead and do the formatting in the setter, so
the crate matches the SDK surface and callers can't forget the '='. The wire
representation (Vec<String> of KEY=VALUE) is unchanged, and iteration order
is preserved so a later duplicate key still wins downstream -- same as the
SDK. No eager validation is added: the SDK doesn't validate either, and
structured input already removes the malformed-entry foot-gun.

Adds a unit test asserting the pair-to-KEY=VALUE ordered mapping.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
The self-pipe used to wake `InterruptibleReader`'s `poll` was created with
`libc::pipe`, which does not set close-on-exec. Both wake fds would then leak
into any process the thread later forks+execs (e.g. another sandbox child) and
keep the wake pipe alive unexpectedly. Mark both ends `FD_CLOEXEC` after
`pipe()`, mirroring the fixup `mxc_pty` already does for PTY fds. The data pipe
is unaffected -- Rust already sets CLOEXEC on `Child` stdio.

Addresses a Copilot review comment on #555.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
`group_kill` discarded both `kill(2)` results and always returned `Ok(())`, so
`SandboxProcess::kill()` reported success even when it never signalled the
process group. Route both signals through a `send_sigkill` helper that returns
the error instead, treating only the "already gone" outcomes as success:
`ESRCH`, and `EPERM` -- which on macOS a redundant kill of an exited-but-unreaped
child's group reports in place of `ESRCH` (observed via the double-kill test).
The caller guards with `try_wait()` first, so the pid/pgid can't be recycled and
`EPERM` here can only be that benign race, never a real permission failure.

Addresses a Copilot review comment on #556.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
… file

`tests/streaming.rs` is `#![cfg(target_os = "macos")]`, so the
`#[cfg(target_os = "windows")]` ProcessContainer streaming test it contained
could never compile -- the intended Windows coverage was silently missing.
Move that test into its own `tests/streaming_processcontainer.rs`, gated
`#![cfg(target_os = "windows")]`, so it actually builds on Windows.

Addresses a Copilot review comment on #556.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
# Conflicts:
#	src/core/wxc_common/src/interruptible_reader.rs
#	src/core/wxc_common/src/sandbox_process.rs
MGudgin pushed a commit that referenced this pull request Jun 24, 2026
…ute binaries via Runner (#555)

* feat(wxc_common): add the sandbox execution interfaces (SandboxBackend / SandboxProcess / Runner)

Introduce the shared, no-pty execution surface that the containment backends
and a future in-process library build on. Purely additive: no existing code
path uses these yet, so behavior is unchanged.

- `SandboxProcess` — a handle to a running sandboxed child: `take_stdin` /
  `take_stdout` / `take_stderr`, `try_wait`, `id`, `kill` (process-tree), and
  `wait` (drains any untaken stdio, honors `scriptTimeout`), plus stdout/stderr
  closers for abandoning a backgrounded-descendant-held read without a kill.
- `SandboxBackend` — `validate` + `spawn(request, logger, StdioMode) ->
  SandboxProcess` + a `diagnose_exit` hook; `StdioMode::{Pipes, Inherit}`.
- `Runner<B>` — the generic adapter bridging any `SandboxBackend` to the
  run-to-completion `ScriptRunner` (spawn `Inherit`, then `wait`).
- `StreamCloser`, `group_kill` (Unix leader-first SIGKILL of the child's group),
  and `wait_with_timeout` (adaptive 1ms->50ms backoff poll).
- `interruptible_reader` (Unix self-pipe + `poll`) and the Windows pipe helpers
  in `process_util` (`InterruptiblePipeReader` / `PipeReadCanceller` /
  `create_std_pipes`) for out-of-band-cancelable streaming reads.
- `FailurePhase::Timeout` so a timeout is distinguishable from other failures.

The library backends and executor binaries are migrated onto this surface in a
follow-up PR, and the importable `mxc-sdk` crate is built on top of it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* refactor(backends): unify the library backends on SandboxBackend + route binaries via Runner

Migrate the three in-process backends — Seatbelt (macOS), Bubblewrap (Linux),
and Windows ProcessContainer (AppContainer + BaseContainer) — onto the
SandboxBackend / SandboxProcess interfaces added in the previous PR, and route
the executor binaries (wxc-exec, lxc-exec, mxc-exec-mac) through the generic
Runner<B> adapter. The old per-backend run-to-completion logic is removed; each
backend now exposes only spawn(), and Runner provides the single ScriptRunner
the binaries dispatch on (spawn StdioMode::Inherit, then wait).

Each backend gains a streaming handle with whole-process-tree termination
(Unix process-group SIGKILL; Windows job-object terminate) and a uniform
io::ErrorKind::TimedOut on scriptTimeout.

Intentional behavior changes for existing binaries (call-outs for review):
- Seatbelt now always env_clear()s the child (previously only when process.env
  was non-empty), aligning the binary with the SDK's documented "host env is
  not inherited" contract.
- Seatbelt resolves an empty process.cwd to a policy read-write path (or "/")
  instead of the launcher's cwd.
- Seatbelt/Bubblewrap inherit the executor's own stdio (StdioMode::Inherit) —
  Seatbelt no longer allocates a private pty, and Bubblewrap no longer forces
  stdin to /dev/null or post-exit-captures stdout/stderr (it streams live).
- BaseContainer now places the child in a UiJobObject for tree-kill (it had
  none before); the child is created suspended, assigned to the job, then
  resumed so no descendant can escape the kill window.
- kill() is a no-op once the child has been reaped, so it never signals a
  recycled pid/process-group.

The macOS Seatbelt characterization suite is updated to assert the new env/cwd/
streaming/timeout behavior; the LXC and Seatbelt backend docs are updated to
match. The default LXC path keeps its native pty and is unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix(wxc_common): set FD_CLOEXEC on the interruptible-reader wake pipe

The self-pipe used to wake `InterruptibleReader`'s `poll` was created with
`libc::pipe`, which does not set close-on-exec. Both wake fds would then leak
into any process the thread later forks+execs (e.g. another sandbox child) and
keep the wake pipe alive unexpectedly. Mark both ends `FD_CLOEXEC` after
`pipe()`, mirroring the fixup `mxc_pty` already does for PTY fds. The data pipe
is unaffected -- Rust already sets CLOEXEC on `Child` stdio.

Addresses a Copilot review comment on #555.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix(wxc_common): propagate non-benign group_kill signal errors

`group_kill` discarded both `kill(2)` results and always returned `Ok(())`, so
`SandboxProcess::kill()` reported success even when it never signalled the
process group. Route both signals through a `send_sigkill` helper that returns
the error instead, treating only the "already gone" outcomes as success:
`ESRCH`, and `EPERM` -- which on macOS a redundant kill of an exited-but-unreaped
child's group reports in place of `ESRCH` (observed via the double-kill test).
The caller guards with `try_wait()` first, so the pid/pgid can't be recycled and
`EPERM` here can only be that benign race, never a real permission failure.

Addresses a Copilot review comment on #556.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@MGudgin MGudgin merged commit ef592ca into microsoft:main Jun 24, 2026
18 checks passed
MGudgin pushed a commit that referenced this pull request Jun 24, 2026
This change adapts the Phase 2B strict-wire-model parser to two crates that
landed on main after 2B was branched, surfaced when rebasing 2B onto current
main: the new in-process `mxc-sdk` library crate (#556) and the
`load_request_from_value` entrypoint (#554/#556).

Details:
- config_parser.rs: port `load_request_from_value` (added on main against the
  deleted `RawConfig` API) to 2B's wire model — deserialize into
  `wire::MxcConfig` and call `convert_wire_config`, matching its sibling
  `load_request_with_options`.
- core/mxc-sdk/src/policy.rs: stop emitting `processContainer.name` (the wire
  `ProcessContainer` is strict and has no `name` field; the id is already carried
  at top-level `containerId`). Suppress the now-unused `container_id` in the
  Windows block.
- sdk/src/sandbox.ts: likewise stop emitting `processContainer.name`; drop the
  now-unused `containerId` parameter from `buildProcessBaseContainerConfig`.

Tests:
- cargo test --workspace -> all pass (the 6 mxc-sdk parse failures from the
  rejected `name` field are resolved).
- cargo fmt --check + cargo clippy --workspace -D warnings -> clean.
- schema codegen + corpus (169/169) + schema-version gates -> green.
- cd sdk && npm test -> 183 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Generated-with: claude-opus-4.8
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.

3 participants