Skip to content

Commit 7c288be

Browse files
GudgeCopilot
andcommitted
Phase 3d: add actionable configuration parse errors
This change reports malformed JSON separately from typed policy errors and makes configuration failures actionable without leaking secrets or allowing untrusted text to corrupt diagnostics. Details: - include complete JSON paths and source locations for one-shot and state-aware failures - preserve state-aware output ownership while rejecting trailing data and malformed experimental blocks - escape control characters, redact secret-bearing values, and avoid retaining a full untyped request tree - document the diagnostic contract and add focused parser coverage Tests: - cargo fmt --all -- --check - cargo check -p wxc_common -p wxc --all-targets - cargo clippy -p wxc_common -p wxc --all-targets -- -D warnings - cargo test -p wxc_common -p wxc - node scripts/versioning/check-schema-codegen.js - node scripts/versioning/check-sdk-types-codegen.js - node scripts/versioning/check-schema-versions.js Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Generated-with: gpt-5.6-sol Copilot-Session: f66f1e4b-72f7-4508-abb2-3bb3d4c808b9
1 parent fa32478 commit 7c288be

12 files changed

Lines changed: 905 additions & 122 deletions

File tree

.github/copilot-instructions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ The Rust workspace (`src/`) implements multiple sandboxing backends behind the `
118118

119119
### Config flow
120120

121-
1. User provides JSON config (file or base64) → `config_parser.rs` deserializes into the typed wire model (`wxc_common::wire`) → validates and maps to `ExecutionRequest` (the internal execution model in `models.rs`)
121+
1. User provides JSON config (file or base64) → `config_deserialize.rs` performs path-aware typed deserialization into the wire model (`wxc_common::wire`) → `config_parser.rs` validates and maps it to `ExecutionRequest` (the internal execution model in `models.rs`)
122122
2. `ExecutionRequest` includes the containment backend selection, process config, filesystem/network policies, and optional experimental features
123123
3. The appropriate `ScriptRunner` implementation executes the process and returns `ScriptResponse`
124124

@@ -210,7 +210,7 @@ The workspace is organized into six top-level directories under `src/`:
210210

211211
### Config parser pattern
212212

213-
The parser deserializes JSON directly into the typed wire model (`wxc_common::wire`), the single source of truth for the config shape (it also generates the JSON schema). `config_parser.rs` then maps the wire types to the validated domain structs in `models.rs`. The stable surface uses `deny_unknown_fields` (closed); the `experimental` block is permissive.
213+
The parser deserializes JSON directly into the typed wire model (`wxc_common::wire`), the single source of truth for the config shape (it also generates the JSON schema). All typed config deserialization goes through `config_deserialize.rs`, which distinguishes syntax errors from typed policy errors and adds the complete JSON path plus source line/column when available; state-aware backend errors are prefixed with their full `experimental.<backend>.<phase>` location. `config_parser.rs` then maps the wire types to the validated domain structs in `models.rs`. The stable surface uses `deny_unknown_fields` (closed); the `experimental` block is permissive.
214214

215215
### TypeScript conventions
216216

docs/state-aware-lifecycle/mxc-state-aware-sandbox-api.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,13 @@ state-aware mode so `stdout` remains parseable without sentinels. (One-shot disp
675675
keeps its existing `stdout` logger behaviour — the stricter routing applies to
676676
state-aware only.)
677677

678+
Configuration parse-phase failures follow the same state-aware contract: the typed
679+
`{error}` envelope is the only primary output, while the human-readable actionable
680+
parse diagnostic is written only to configured auxiliary sinks (`--log-file` and the
681+
Windows diagnostic console). It is not duplicated to the logger's primary
682+
console/buffer output, so a parse failure does not add stderr noise even with
683+
`--debug`.
684+
678685
For exec specifically, MXC diagnostic output mixes with the script's own stderr when
679686
`--debug` is passed. This is a small amount of pre- and post-dispatch noise; consumers
680687
wanting clean separation should use `--log-file <path>` instead, which routes diagnostic

docs/versioning.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,14 @@ HRESULT EnumerateSandboxSpecVersionInfo(
438438

439439
Negotiation failures are **typed and actionable** — never a silent fallback:
440440

441+
- **JSON and policy-shape failures** distinguish malformed JSON syntax from
442+
valid JSON that does not match the typed wire contract. Typed failures name
443+
the full policy path (for example, `network.proxy.localhost`), retain Serde's
444+
expected type/value information, and include source line/column when parsing
445+
directly from request text. State-aware per-backend configuration errors are
446+
prefixed with their full `experimental.<backend>.<phase>` location. Diagnostic
447+
text escapes control characters, and errors at secret-bearing paths redact the
448+
submitted value.
441449
- **Schema-range failures** (Stage 1) carry a clear "older than supported" /
442450
"newer than supported" message telling the caller whether to update the config
443451
or upgrade `wxc-exec`.

src/Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ windows = { version = "0.62", features = [
9494
windows-core = "0.62"
9595
serde = { version = "1", features = ["derive"] }
9696
serde_json = "1"
97+
serde_path_to_error = "0.1"
9798
thiserror = "2"
9899
anyhow = "1"
99100
base64 = "0.22"

src/core/wxc_common/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ schema-gen = ["dep:schemars"]
1212

1313
[dependencies]
1414
serde = { workspace = true }
15-
serde_json = { workspace = true }
15+
serde_json = { workspace = true, features = ["raw_value"] }
16+
serde_path_to_error = { workspace = true }
1617
thiserror = { workspace = true }
1718
base64 = { workspace = true }
1819
url = { workspace = true }

0 commit comments

Comments
 (0)