Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,13 @@ See [docs/diagnostics.md](docs/diagnostics.md) for full diagnostics reference.
wxc-exec.exe --audit policy.json
```

Successful non-dry-run audits require capture metadata, actionable denials JSON, and a retained ETL. The CLI relocates the backend-selected paths to `denials.json` and `trace.etl` in the per-user audit directory, then generates a source-config snapshot and `Adjusted_*.json` from the actionable JSON without decoding the ETL again. Base64-only input keeps JSON and ETL but has no source config to snapshot or adjust. Truncated analysis keeps JSON, ETL, and the source snapshot but skips adjusted-config generation. Use `--audit-verbose` to print learned-policy details.
Successful non-dry-run audits require capture metadata, actionable denials JSON, its verbose diagnostic sibling, and a retained ETL. The CLI relocates the backend-selected paths to `denials.json`, `denials.verbose.json`, and `trace.etl` in the per-user audit directory, then generates a source-config snapshot and `Adjusted_*.json` from the actionable JSON without decoding the ETL again. Base64-only input keeps both JSON files and the ETL but has no source config to snapshot or adjust. Truncated analysis keeps both JSON files, the ETL, and the source snapshot but skips adjusted-config generation. Use `--audit-verbose` to print learned-policy details.

> **Warning:** `--audit` injects `permissiveLearningMode` β€” AppContainer restrictions are **not** enforced for the duration of the run. Use only for policy authoring. It cannot be combined with `processContainer.captureDenials`; use `captureDenials.mode: "allow"` for permissive application-driven capture. `learningModeLogging` and `permissiveLearningMode` are reserved internal capability names and are rejected in `processContainer.capabilities`. See [docs/learning-mode/capabilities.md](docs/learning-mode/capabilities.md) for the three learning-mode flows.

## Telemetry

MXC supports optional TraceLogging ETW telemetry for execution observability. When enabled, structured events (`MXC.Execution` and `MXC.Error`) are emitted to the local ETW subsystem via the Rust [`tracelogging`](https://crates.io/crates/tracelogging) crate. Every event includes common fields (Version, Channel, IsDebugging, `UTCReplace_AppSessionGuid`) as Part C custom event data.
MXC supports optional TraceLogging ETW telemetry for execution observability. When enabled, structured events (`MXC.Execution`, `MXC.Error`, and the sanitized Learning Mode artifact event `MXC.VerboseDenials`) are emitted by the `Microsoft.MXC` provider to the local ETW subsystem via the Rust [`tracelogging`](https://crates.io/crates/tracelogging) crate. Every event includes common fields (Version, Channel, IsDebugging, `UTCReplace_AppSessionGuid`) as Part C custom event data.

Telemetry requires:
1. Top-level `"telemetry": { "enabled": true }` in the JSON config
Expand Down Expand Up @@ -259,9 +259,21 @@ Windows user consent is granted and administrative policy allows collection.

#### What official builds send

Official/shipped Microsoft builds set a TraceLogging provider group GUID at build time and route `MXC.Execution` and `MXC.Error` events to Microsoft through the UTC pipeline when telemetry is enabled β€” that same build-time setting also selects the correct Measures keyword and Product-and-Service-Usage privacy tag for the events, so telemetry routing and event classification always agree. **Local and open-source builds send nothing to Microsoft by default** β€” the public source ships without a provider group GUID, so events are emitted to the local ETW subsystem only, use a provider-local keyword with no UTC meaning, and carry no privacy classification tag, and are not routed to any Microsoft collection pipeline. Internal builds that set the `MXC_TELEMETRY_PROVIDER_GROUP_GUID` environment variable at build time enable the Microsoft-routed path.

No PII is collected. Events contain only execution metrics (duration, backend type, exit code) and a bounded error category (`error_type`). Free-form error message text is never emitted, so paths, usernames, and credentials cannot leak through telemetry. If you use the SDK to build applications, you are responsible for providing appropriate telemetry notices to your own users.
Official/shipped Microsoft builds set a TraceLogging provider group GUID at build time and route `MXC.Execution`, `MXC.Error`, and `MXC.VerboseDenials` events to Microsoft through the UTC pipeline when telemetry is enabled β€” that same build-time setting also selects the correct Measures keyword and Product-and-Service-Usage privacy tag for the events, so telemetry routing and event classification always agree. **Local and open-source builds send nothing to Microsoft by default** β€” the public source ships without a provider group GUID, so events are emitted to the local ETW subsystem only, use a provider-local keyword with no UTC meaning, and carry no privacy classification tag, and are not routed to any Microsoft collection pipeline. Internal builds that set the `MXC_TELEMETRY_PROVIDER_GROUP_GUID` environment variable at build time enable the Microsoft-routed path.

No PII is collected. Execution/error events contain only execution metrics
(duration, backend type, exit code) and a bounded error category
(`error_type`). When a ProcessContainer run successfully produces a Learning
Mode verbose artifact, `MXC.VerboseDenials` can include sanitized
provider/event identifiers, process IDs, closed outcome reasons,
access/resource classifications, occurrence counts, and truncation state. The
telemetry projection derives provider GUIDs from a closed provider enum and
drops all verbose property names and values. MXC never emits commands,
credentials, complete file paths, usernames, workload-derived properties, sandbox output,
raw ETL, actionable denial documents, general logger text, or free-form error
text. The verbose-event data inventory requires explicit privacy/release review
before shipment. If you use the SDK to build applications, you are responsible
for providing appropriate telemetry notices to your own users.

Privacy information can be found at https://privacy.microsoft.com and in the Microsoft privacy statement at https://go.microsoft.com/fwlink/?LinkID=824704.

Expand Down
8 changes: 8 additions & 0 deletions docs/learning-mode/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,14 @@ is intentionally absent from stderr pointers and Rust, Node, C#, and FFI output
metadata; callers derive it from the actionable output path using the naming rule
above.

When stable telemetry is enabled and authorized, MXC may validate, compact, and
send this redacted verbose document through `Microsoft.MXC/MXC.VerboseDenials`. Each
event contains a valid JSON array of complete signatures and document
reconstruction metadata. Before emission, MXC derives provider GUIDs from the
closed provider enum and drops every verbose property name and value. MXC does
not send the actionable denials file, workload-derived properties, or raw ETL
through telemetry. See [MXC telemetry](../telemetry/telemetry.md).

**Locating the file.** Set `captureDenials.outputPath` to name the file
explicitly (its parent directory must already exist). MXC inserts a unique
per-run identifier (process id plus random suffix) into the file stem
Expand Down
13 changes: 9 additions & 4 deletions docs/telemetry/telemetry-consent-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ MXC ships the canonical consent resource, persistent consent storage, and
consent-management APIs described below. Telemetry remains off by default and
is enabled only when every gate in this contract permits collection.

The purpose of the MXC Learning Mode Data Loop is to analyze collected data to
identify usage patterns, improve Windows security, and inform MXC about
application compatibility in containers with minimal capabilities.

MXC telemetry is Windows-only and fails closed. Collection requires all four
conditions at the time each event is written:

Expand All @@ -30,23 +34,23 @@ native UI, but may not substitute wording.

Current resource:

- Resource version: `1`
- Resource version: `3`
- Locale: `en-US`
- Mandatory fallback: `en-US`
- Privacy link: <https://go.microsoft.com/fwlink/?linkid=521839>

### Title

```text
Help improve Microsoft eXecution Container (MXC)
Help improve Microsoft Products
```

### Body

```text
Help improve MXC by sharing optional diagnostic data with Microsoft.
Help improve MXC and other Microsoft product including Windows by sharing optional diagnostic data with Microsoft.

If enabled, MXC sends diagnostic information about product usage, performance, and reliability. MXC does not send your commands, file paths, credentials, or other customer content.
You can change your choice at any time.
```

### Actions
Expand Down Expand Up @@ -195,6 +199,7 @@ The public ETW event identities remain:

- `MXC.Execution`
- `MXC.Error`
- `MXC.VerboseDenials`

Collectors may continue filtering those names; consent stabilization does not
rename the provider or events.
Expand Down
92 changes: 88 additions & 4 deletions docs/telemetry/telemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ C++ shim, WIL, or FFI is required.
β”‚ wxc_common::telemetry β”‚
β”‚ (Rust β€” config resolution, sanitisation, types) β”‚
β”‚ β”‚
β”‚ init() / log_execution() / log_error() / shutdown() β”‚
β”‚ init() / log_execution() / log_error() / β”‚
β”‚ log_verbose() / shutdown() β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ Direct Rust function calls
β–Ό
Expand Down Expand Up @@ -113,9 +114,12 @@ targets for this work.

### ETW privacy and collection contract

- Events contain bounded enums, opaque MXC identities, numeric status fields,
and schema field paths only. They do not contain command lines, environment
values, raw paths, UPNs, tokens, or free-form error text.
- Execution, error, and M-ETW requirement events contain bounded enums, opaque
MXC identities, numeric status fields, and schema field paths only.
`MXC.Verbose` is separately limited to the sanitized, typed inventory below.
- Events do not contain command lines, environment values, complete file paths,
UPNs, tokens, sandbox output, raw ETL, actionable denial documents, general
logger text, or free-form error text.
- `MXC.PolicyHash` uses the same effective container identity as the runner
(`CLI` when no container ID was supplied), then applies the standard identity
redaction. Valid opaque IDs are preserved; UPN-shaped or otherwise unsafe
Expand All @@ -141,6 +145,11 @@ targets for this work.

## Events

The provider-qualified event identities include
`Microsoft.MXC/MXC.Execution`, `Microsoft.MXC/MXC.Error`, and
`Microsoft.MXC/MXC.VerboseDenials`. `Microsoft.MXC` is the TraceLogging provider
name. The M-ETW requirement events listed above share that provider.

### MXC.Execution

Emitted when a one-shot execution completes (success or failure). It is also
Expand Down Expand Up @@ -184,6 +193,76 @@ Emitted on execution errors.
> attribution fields, the `error_type` category, and the numeric `exit_code` β€”
> never the message string itself.

### MXC.VerboseDenials

Emitted when a telemetry-enabled ProcessContainer run successfully produces a
Learning Mode `captureDenials` verbose logging artifact. MXC reads the
versioned `*.verbose.json` sibling, validates it as a
`VerboseLoggingDocument`, derives each provider GUID from the document's
closed provider enum, drops every verbose property name and value, and
serializes that telemetry-specific projection as compact JSON. The event never
contains the actionable denials file, raw ETL, commands, sandbox output, or
general logger text.

One verbose document may require multiple ETW events. Every `mxc.content`
value is an independently parseable compact JSON array of complete verbose
signature objects; MXC never splits a JSON object or UTF-8 code point.
Streaming callers must use `wait` to finalize capture metadata. A terminal
result observed only through nonblocking `try_wait` emits completion telemetry
but not the optional verbose artifact event.

| Field | Type | Description |
|-------|------|-------------|
| `mxc.sandbox_kind` | string | Caller-requested containment kind |
| `mxc.backend` | string | Concrete containment backend |
| `mxc.phase` | string | Lifecycle phase; empty for current one-shot capture |
| `__TlgCV__` | string | Lifecycle correlation vector; empty for current one-shot capture |
| `mxc.document_id` | string | Random identifier shared only by chunks of one verbose artifact |
| `mxc.document_version` | uint32 | `VerboseLoggingDocument` schema version |
| `mxc.chunk_index` | uint32 | Zero-based chunk index |
| `mxc.chunk_count` | uint32 | Total number of chunks |
| `mxc.document_bytes` | uint64 | Compact telemetry-projection byte count |
| `mxc.document_sha256` | string | SHA-256 of the compact telemetry projection |
| `mxc.content` | string | Valid compact JSON array of complete verbose signatures |
| `mxc.summary` | string | Valid compact JSON verbose-document summary |

Consumers group by the existing app-session identifier plus
`mxc.document_id`, order by `mxc.chunk_index`, parse and concatenate the
`mxc.content` arrays, then rebuild `{version, signatures, summary}`. The byte
count and SHA-256 allow consumers to reject incomplete or corrupted
reconstructions.

### Data inventory

MXC's optional diagnostic events contain:

- MXC version and channel
- Whether the build has debug assertions enabled (`IsDebugging`)
- Caller-requested sandbox kind and the concrete backend selected on the host
- Run outcome, exit code, duration, bounded failure category, and lifecycle
phase
- `UTCReplace_AppSessionGuid`, which asks the telemetry pipeline to supply a
random per-session app identifier
- An MXC-internal random lifecycle correlation vector
- Sanitized Learning Mode verbose signatures when `captureDenials` produces a
verbose artifact: provider/event identifiers, PID, closed outcome reason,
access/resource classifications, occurrence counts, and truncation state.
Provider GUIDs are derived from a closed provider enum; verbose property
names and values are dropped.

MXC does not emit commands, credentials, complete file paths, usernames,
workload-derived properties, sandbox output, raw ETL, actionable denial
documents, general logger text, or free-form error text.

### Privacy review status

The canonical version 3 `en-US` consent wording is privacy-reviewed. The
verbose-event inventory, current WinExt classification, retention, access,
regional processing, deletion, and localization/accessibility decisions
require explicit privacy/release review. The canonical wording and presenter
contract are documented in
[Telemetry consent design](telemetry-consent-design.md).

### Correlating a lifecycle

The state-aware lifecycle runs each phase (`provision` β†’ `start` β†’ `exec` β†’
Expand Down Expand Up @@ -314,6 +393,11 @@ administrative policy, and provider availability. See
[`telemetry-consent-design.md`](telemetry-consent-design.md). Local diagnostic
audit records are a separate operator-selected sink and are not uploaded.

The privacy-reviewed version 3 `en-US` consent wording is the canonical
disclosure. Its title, body, action labels, and privacy link are documented in
[Telemetry consent design](telemetry-consent-design.md#canonical-consent-resource)
and must be rendered verbatim by every EXE and SDK presenter.

The optional ETW events contain MXC version/channel, debug-build state,
caller-requested sandbox kind, selected backend, bounded outcomes and failure
categories, numeric status values, lifecycle phase, policy fingerprints, and
Expand Down
6 changes: 6 additions & 0 deletions sdk/dotnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,12 @@ MXC telemetry is Windows-only and remains off until both of these are true:

Telemetry remains off by default unless the caller opts in with `SandboxPolicy.TelemetryEnabled = true` (or the equivalent phase-level `TelemetryEnabled` setting for state-aware requests) and applicable Windows consent/policy gates permit collection.

When a telemetry-enabled Windows ProcessContainer run successfully produces a
Learning Mode `captureDenials` verbose artifact, telemetry can include its
sanitized technical signatures. It does not include commands, credentials,
complete file paths, usernames, sandbox output, raw ETL, or general logger
text. See the [telemetry data inventory](../../docs/telemetry/telemetry.md#data-inventory).

Any .NET consent surface should stay UI-agnostic, present the canonical
resource verbatim through a host callback, persist only explicit yes/no
decisions, treat dismissal and failures as non-grants, and follow the rules in
Expand Down
7 changes: 7 additions & 0 deletions sdk/node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ Full TypeScript definitions ship with the package (`dist/index.d.ts`). All expor

Telemetry is off-by-default unless the caller opts in with top-level `telemetry.enabled: true` and the applicable Windows consent/policy gates permit collection.

When a telemetry-enabled Windows ProcessContainer run successfully produces a
Learning Mode `captureDenials` verbose artifact, telemetry can include its
sanitized technical signatures. It does not include commands, credentials,
complete file paths, usernames, sandbox output, raw ETL, or general logger
text. See the
[telemetry data inventory](https://github.com/microsoft/mxc/blob/main/docs/telemetry/telemetry.md#data-inventory).

Telemetry consent behavior follows
[`docs/telemetry/telemetry-consent-design.md`](https://github.com/microsoft/mxc/blob/main/docs/telemetry/telemetry-consent-design.md):
the SDK stays UI-agnostic, renders the canonical resource verbatim through a
Expand Down
2 changes: 2 additions & 0 deletions src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions src/core/mxc-sdk/src/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ impl Sandbox {

// Take both streams before waiting so `wait` won't discard them, and
// read each on its own thread so the child never blocks on a full pipe.
let warnings = self.inner.warnings().to_vec();
let stdout = capture(self.inner.take_stdout());
let stderr = capture(self.inner.take_stderr());
let outcome = self.wait()?;
let warnings = self.inner.warnings().to_vec();
let output_metadata = self.inner.output_metadata().cloned();
Ok(Output {
outcome,
Expand Down Expand Up @@ -205,6 +205,7 @@ mod tests {

struct FakeProcess {
warnings: Vec<String>,
wait_warning: Option<String>,
output_metadata: Option<SandboxOutputMetadata>,
}

Expand Down Expand Up @@ -242,15 +243,20 @@ mod tests {
}

fn wait(&mut self) -> std::io::Result<i32> {
if let Some(warning) = self.wait_warning.take() {
self.warnings.push(warning);
}
Ok(0)
}
}

#[test]
fn sandbox_and_output_expose_security_warnings() {
let warning = "permissive mode weakens containment".to_string();
let wait_warning = "telemetry emission failed".to_string();
let sandbox = Sandbox::new(Box::new(FakeProcess {
warnings: vec![warning.clone()],
wait_warning: Some(wait_warning.clone()),
output_metadata: Some(SandboxOutputMetadata {
capture_denials: Some(CaptureDenialsOutput {
kind: CaptureDenialsOutput::KIND.to_string(),
Expand All @@ -267,7 +273,7 @@ mod tests {
assert_eq!(sandbox.warnings(), [warning.as_str()]);

let output = sandbox.wait_with_output().expect("wait succeeds");
assert_eq!(output.warnings, [warning]);
assert_eq!(output.warnings, [warning, wait_warning]);
assert_eq!(
output
.output_metadata
Expand Down
Loading
Loading