Enforce per-field schema version availability at parse time - #783
Open
Gudge (MGudgin) wants to merge 1 commit into
Open
Conversation
This PR adds per-field schema version availability: a wire field can declare the
range of config schema versions it is valid in, and the parser rejects any use
outside that range. It is what makes shape-only support for older schema
versions real — until now such an annotation would have been documentation that
nothing honoured.
Details
* New `mxc_version_derive` proc-macro crate. `#[derive(VersionAvailability)]`
lifts `#[mxc_version(since = "0.8")]` / `until` off `wire.rs` into metadata
normal builds carry, so one declaration feeds both the parser and schema
generation (published as `x-mxc-since` / `x-mxc-until`). A derive rather than
`#[schemars(extend(...))]`, which sits behind the `schema-gen` feature and so
can never be consulted by the parser.
* The mechanism fails **open** if a derived JSON name ever disagrees with what
serde accepts — the range simply never fires — so that case is guarded twice:
the macro compile-errors on every serde construct it cannot model exactly
(`flatten`, split `rename`/`rename_all`, unknown `rename_all` rules,
data-carrying variants), and a conformance test cross-checks all 32 wire types
against the names `schemars` independently derives.
* The gate runs immediately after deserialisation in every entry point, because
`convert_wire_config` moves fields out of the config; state-aware requests are
gated on the original document, not the experimental-masked copy.
* `version` is now **required** — it selects the legal field surface, so an
absent one would silently opt out of every range.
* New `version_incompatible` code across all five surfaces (Rust `MxcErrorCode`,
engine `ErrorCode`, TS, C#, `MXC_STATUS_VERSION_INCOMPATIBLE = 13`) carrying
`details: { field, declaredVersion, since, until }`. The supported-range error
migrates onto it. NOTE: this changes an existing error's observable shape — a
consumer string-matching the old range message is affected.
* Three annotations, each checked against real corpus usage first: `seatbelt`
since 0.7, `processContainer.captureDenials` / `learningMode` since 0.8. The
central subtlety is what is deliberately **not** annotated: schema-first-
appearance is only a lower bound on accepted surface. `experimental` was an
open block before 0.8, and state-aware requests declare 0.6 while carrying
`phase` / `sandboxId` / `correlationVector` — annotating those from schema
data would reject configs that have always worked. (Measured: 66 properties
are unannotated yet absent from the 0.6 schema; 8 are covered transitively by
an annotated ancestor, and the rest legitimately carry no range.)
* New `check-version-availability.js` oracle gate derives each field's true
first appearance from the frozen 0.6/0.7 and dev schemas and fails on
disagreement. It is fail-closed on the surfaces above, which also catches a
range that would leak onto the permissive `experimental` surface via a shared
type.
* Corpus and callers migrated: 61 configs versioned (state-aware to 0.6.0-alpha,
matching what the SDK emits; one-shot to 0.8.0-alpha), ~200 Rust test
literals, the PowerShell lifecycle helpers (stamped centrally), and the SDK
builders, which no longer synthesise a top-level `seatbelt` marker below 0.7.
Tests
* On the final tip: `cargo fmt --all -- --check`,
`cargo check --workspace --all-targets`,
`cargo clippy --workspace --all-targets -- -D warnings`, and the per-package
test suites (`wxc_common` incl. the corpus test, `mxc_schema_gen`,
`mxc_version_derive`, `mxc_engine`, `mxc-sdk`, `mxc_ffi`, `wxc`,
`wxc_e2e_tests::e2e_state_aware`) all clean.
* Feature-gated builds covering every flag this diff can reach, all clean:
`wxc_common` {schema-gen, microvm}, `mxc_ffi` {dotnetsdk}, `mxc_engine`
{isolation_session}, `wxc` {isolation_session, microvm, tier2_bfs, wslc,
hyperlight}.
* `wxc_common` 594 unit tests plus a new corpus test asserting all 195 configs
declare a version and still parse, with the out-of-range fixture pinned as a
negative case by exact code and bounds. Versioning gate tests 71 → 94.
* Node SDK build + 223 tests; C# SDK 35 tests; ErrorCode parity 17 codes;
bindings codegen OK. All 11 CI gates pass.
* Non-regression: the PR #676 replay still yields exactly 6 findings naming
`allowLocalNetwork`, `allowedHosts`, `blockedHosts`, `defaultPolicy`,
`enforcementMode`, `proxy`; detector baselines hold (dev vs dev = 0,
0.6→0.7 = 6, 0.7→dev = 12); the dev-schema gate passes; `SUPPORTED_VERSION`
unchanged at `>=0.6, <=0.8`.
* Converged through a 2-round adversarial review (14 findings; 12 fixed, 1
pushback accepted, 1 pre-existing). Two blockers were genuine test failures an
earlier verification pass had masked with a faulty grep.
* **Not executed on this host** (Windows): the macOS Seatbelt paths, the Windows
Sandbox and IsolationSession PowerShell lifecycle suites, and the host-gated
MicroVM / Hyperlight E2E configs. The macOS code does **cross-compile** —
`cargo check --target aarch64-apple-darwin --all-targets` is clean for
`mxc_engine`, `wxc_common` and `mxc-sdk`, including the new
`cfg(target_os = "macos")` regression tests — but it has not been run.
(`mxc_darwin` cannot be cross-checked at all: pre-existing issue #735.)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 21bb36ae-131a-4ab6-b062-a830ba488428
Generated-with: claude-opus-5
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
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.
This PR adds per-field schema version availability: a wire field can declare the range of config schema versions it is valid in, and the parser rejects any use outside that range. It is what makes shape-only support for older schema versions real — until now such an annotation would have been documentation that nothing honoured.
Replaces #775 (closed), rebased onto the current
maintip with three compile breaks fixed.Details
mxc_version_deriveproc-macro crate.#[derive(VersionAvailability)]lifts#[mxc_version(since = "0.8")]/untiloffwire.rsinto metadata normal builds carry, so one declaration feeds both the parser and schema generation (published asx-mxc-since/x-mxc-until). A derive rather than#[schemars(extend(...))], which sits behind theschema-genfeature and so can never be consulted by the parser.flatten, splitrename/rename_all, unknownrename_allrules, data-carrying variants), and a conformance test cross-checks all 32 wire types against the namesschemarsderives independently.convert_wire_configmoves fields out of the config. State-aware requests are gated on the original document, not the experimental-masked copy.versionis now required — it selects the legal field surface, so an absent one would silently opt out of every range.version_incompatiblecode across all five surfaces (RustMxcErrorCode, engineErrorCode, TS, C#,MXC_STATUS_VERSION_INCOMPATIBLE = 13) carryingdetails: { field, declaredVersion, since, until }. The supported-range error migrates onto it. This changes an existing error's observable shape — a consumer string-matching the old range message is affected.seatbeltsince 0.7,processContainer.captureDenials/learningModesince 0.8). What is deliberately not annotated matters more: schema-first-appearance is only a lower bound on accepted surface, soexperimental(an open block before 0.8) and the state-aware discriminators carry no range — annotating them from schema data would reject configs that have always worked. The newcheck-version-availability.jsoracle gate is fail-closed on exactly those surfaces.main's feat(sdk): add captureDenials to the typed SandboxPolicy #748 addedcapture_denialsto the typedSandboxPolicy, which breaksSandboxPolicyliterals that git auto-merges cleanly, so they surface only at compile time.src/core/mxc-sdk/tests/sandbox.rsand two#[cfg(target_os = "macos")]tests inmxc_engine/src/policy.rsdid not compile on Enforce per-field schema version availability at parse time #775's head; the macOS pair is invisible to a Windowscargo check.Tests
cargo test --workspace— 2031 passed, 0 failed.cargo fmt --all -- --check,cargo check --workspace --all-targetsandcargo clippy --workspace --all-targets -- -D warningsall clean.cargo check --target aarch64-apple-darwin -p mxc_engine -p wxc_common -p mxc-sdk --all-targetsclean — this is what caught the two macOS test breaks that a green Windows run had hidden.wxc_common{schema-gen, microvm},mxc_ffi{dotnetsdk},mxc_engine{isolation_session},wxc{isolation_session, microvm, tier2_bfs, wslc, hyperlight}.check-version-availability(3 declared ranges agree with the 0.6 / 0.7 / 0.8 schemas),validate-configs(201 configs),check-schema-versions,check-schema-codegen,check-sdk-types-codegen, andcheck-dev-schema-compatagainst phase 7d all green.allowLocalNetwork,allowedHosts,blockedHosts,defaultPolicy,enforcementMode,proxy.SUPPORTED_VERSIONunchanged at>=0.6, <=0.8.Stacked on #732 (phase 7d). Replaces #775.
Co-authored-by: Branden Bonaby bbonaby@microsoft.com
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com