Skip to content
Open
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
18 changes: 17 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ npm test
npm run test:integration

# C# SDK (from sdk/dotnet/)
dotnet test Microsoft.Mxc.Sdk.slnx # requires mxc_ffi built (cargo build -p mxc_ffi); resolver finds it in src/target/{debug,release}
dotnet test Microsoft.Mxc.Sdk.slnx # Debug only; requires mxc_ffi built (cargo build -p mxc_ffi); resolver finds it in src/target/{debug,release}
# the telemetry tests need the debug-only MXC_TEST_LOCALAPPDATA_OVERRIDE, so `-c Release` fails by design

# Local PowerShell helpers β€” run from repo root, require built binaries
tests\scripts\run_test_configs.ps1 # All test configs via wxc_test_driver
Expand All @@ -92,6 +93,7 @@ tests\scripts\run_windows_sandbox_one_shot_tests.ps1 # Windows Sandbox one
tests\scripts\run_windows_sandbox_state_aware_tests.ps1 # Windows Sandbox state-aware lifecycle E2E (provision/start/exec*/stop/deprovision; requires the Windows Sandbox optional feature; skips if absent)
tests\scripts\run_lxc_all_tests.sh # All LXC tests (Linux)
tests\scripts\run_bwrap_all_tests.sh # All Bubblewrap tests (Linux, requires bwrap)
tests\scripts\run_telemetry_consent_smoke_test.ps1 # Telemetry consent + policy CLI E2E (Windows; debug binary only)

# E2E test crate β€” Rust executor integration tests (from src/)
cargo test -p wxc_e2e_tests # Invokes MXC binaries directly
Expand Down Expand Up @@ -153,6 +155,7 @@ Core references:
- `docs/diagnostics.md` β€” diagnostic logging knobs (env vars, log file format)
- `docs/host-prep.md` β€” `wxc-host-prep.exe` host setup binary (`prepare-system-drive` / `unprepare-system-drive` for the AppContainer ACEs on the system-drive root, plus `prepare-null-device` / `verify-null-device` / `dump-null-device` for the `\Device\Null` security descriptor that AppContainer-based backends require). Owns elevation via embedded `requireAdministrator` manifest β€” `wxc-exec.exe` no longer self-elevates.
- `docs/sandbox-policy/v1/policy.md` β€” sandbox policy v1 specification
- `docs/telemetry/telemetry.md` β€” telemetry overview; `docs/telemetry/telemetry-consent-design.md` (Windows-only consent design and per-SDK surface) and `docs/telemetry/telemetry-policy.md` (the MDM / Group Policy ceiling)

Per-backend guides:

Expand Down Expand Up @@ -228,6 +231,18 @@ The parser deserializes JSON directly into the typed wire model (`wxc_common::wi
- macOS: `mxc-exec-mac` (Seatbelt)
- Target triples: `x86_64-pc-windows-msvc`, `aarch64-pc-windows-msvc`, `x86_64-unknown-linux-gnu`, `aarch64-unknown-linux-gnu`, `aarch64-apple-darwin`

### Telemetry consent

Telemetry is **Windows-only** and is never collected without explicit user consent. Three independent conditions must all hold before anything is emitted: the user has granted consent, the administrative (MDM / Group Policy) ceiling permits it, and the config kill-switch has not disabled it. `wxc_common::telemetry::is_enabled()` is the single place those three terms are combined β€” do not re-derive enablement anywhere else.

- **Everything fails closed.** Any error, unreadable value, corrupt file, missing native library, or ambiguity must resolve to "no telemetry" (`Undetermined` consent / `Blocked` policy), never to a permissive state.
- **Policy may restrict, but may never substitute for, consent.** The administrative policy is a deny-only ceiling: it can subtract from what a user permitted, never add to it. An administrator cannot opt a user in β€” a denied or never-asked user stays opted out even under `AllowTelemetry=3`. Keep the terms combined with `&&`; never add a policy value or config path that grants collection on its own.
- **MXC owns its own consent state.** It must never read or infer from the Windows system telemetry consent. The consent store is a per-user JSON file; the policy is `HKLM\SOFTWARE\Policies\Mxc` β†’ `AllowTelemetry` (`REG_DWORD`).
- **One definition, distributed to the bindings.** The Rust `ConsentState` / `PolicyState` enums are the source of truth; the FFI, C#, and TypeScript layers marshal the same strings. `scripts/check-telemetry-policy-parity.js` fails if the four `PolicyState` spellings drift apart β€” it is currently an **on-demand check, not yet wired into any workflow**, so run it by hand after touching any of the three.
- **Test isolation.** The consent store and the policy key are process-global, each behind its own mutex. Use `wxc_common::telemetry::test_support::TelemetryTestEnv` whenever a test needs both; constructing `PolicyKeyGuard` and `LocalAppDataGuard` directly in the same test risks a lock-order deadlock. Both overrides are `cfg(debug_assertions)`-gated, so the smoke test refuses to run against a release binary. The `wxc_common` `test-support` feature re-exports the policy override for downstream crates' integration tests (`mxc_ffi` uses it) and must stay a dev-dependency-only feature.
- **Read-only queries must never be able to crash the host.** `NeedsConsentPrompt`/`needsTelemetryConsentPrompt` and `GetPolicy`/`getTelemetryPolicy` fail closed on *any* failure and never throw β€” including a non-`Success` FFI status, which covers a caught panic. The consent *read* and *write* still throw, because their callers must distinguish "not decided" from "could not read" and "did not persist"; when they do, they raise only the binding's documented exception type (`MxcException`), wrapping anything unexpected rather than letting a raw type escape.
- **Never swallow a failure silently.** Fail-closed return values are indistinguishable from legitimate ones, so a broken install would otherwise be invisible. Every swallowed failure is reported once per distinct failure per process (deduplicated β€” hosts poll these getters), and the reporter itself must never throw. At the FFI boundary, `catch_unwind` sites log the panic payload before returning `MXC_STATUS_PANIC`, which would otherwise be discarded.

### Package versioning

All Rust crates use `version.workspace = true` to inherit the version from `src/Cargo.toml` `[workspace.package]`. The npm SDK version in `sdk/node/package.json` and the C# SDK version (`<Version>` in `sdk/dotnet/Microsoft.Mxc.Sdk/Microsoft.Mxc.Sdk.csproj`) must match. Run `node scripts/check-version-sync.js` to validate they are in sync. When bumping the version, update `src/Cargo.toml` (workspace version), `sdk/node/package.json`, and the C# csproj in the same commit.
Expand All @@ -241,6 +256,7 @@ When changing behavior covered by existing documentation, update the relevant do
- **SDK API changes** (new exports, changed signatures, new options) β†’ update `sdk/node/README.md` and the JSDoc in `sdk/node/src/index.ts` (TypeScript SDK); the Rust `mxc-sdk` crate docs/`README.md`; and `sdk/dotnet/README.md` (C# SDK). If the `mxc_ffi` C ABI surface changes, the C# P/Invoke regenerates on the next C# build; keep the `ErrorCode` parity + bindings-codegen gates green.
- **New containment backends or major backend changes** β†’ update the relevant doc in `docs/` (e.g., `lxc-support/lxc-backend.md`, `windows-sandbox/windows-sandbox.md`)
- **Versioning or promotion changes** β†’ update `docs/versioning.md`
- **Telemetry consent or policy changes** β†’ update `docs/telemetry/telemetry-consent-design.md` and/or `docs/telemetry/telemetry-policy.md`, and keep `scripts/check-telemetry-policy-parity.js` green across all three bindings

### Policy versioning

Expand Down
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,17 +229,36 @@ wxc-exec.exe --audit policy.json

## Telemetry (Experimental)

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 (`Execution` and `Error`) 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 is **experimental** and requires:
1. The `--experimental` CLI flag
2. `"experimental": { "telemetry": { "enabled": true } }` in the JSON config
3. Explicit per-user telemetry consent on Windows
4. An administrative policy that permits collection, when a policy is configured

The configuration flag is an additional per-run opt-in; it cannot grant consent
or bypass an administrative block. Telemetry remains off unless every applicable
gate is open. MXC does not use the Windows Diagnostics & feedback setting as a
substitute for application consent.

On non-Windows platforms, all telemetry functions are no-ops.

### Data Collection

The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
The software may collect information about you and your use of the software and
send it to Microsoft when telemetry is enabled and all consent and policy gates
permit collection. Microsoft may use this information to provide services and
improve our products and services. Telemetry is off by default, and MXC does
not treat use of the software as consent. On Windows, the host application must
provide an appropriate notice and obtain explicit user consent before enabling
telemetry, and must provide a way to review or revoke that choice. If you use
these features to collect data from users of your applications, you must comply
with applicable law, including providing appropriate notices to your users
together with a copy of Microsoft's privacy statement. Our privacy statement
is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn
more about data collection and use in the help documentation and our privacy
statement.

#### How to turn telemetry off

Expand All @@ -248,13 +267,23 @@ Telemetry is **off by default**. MXC emits telemetry only when **both** of the f
1. The `--experimental` CLI flag is passed, **and**
2. `"experimental": { "telemetry": { "enabled": true } }` is present in the JSON config.

Omitting either (the default) turns telemetry off entirely. On non-Windows platforms all telemetry functions are no-ops.
Those settings are necessary but not sufficient: on Windows, explicit
per-user consent and an administrative policy that permits collection are also
required. Omitting any required gate (the default) turns telemetry off
entirely. On non-Windows platforms all telemetry functions are no-ops and
consent is not applicable.

#### 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. **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 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.
Official/shipped Microsoft builds set a TraceLogging provider group GUID at build time and route the `Execution` and `Error` events from the `Microsoft.MXC` provider to Microsoft through the UTC pipeline when telemetry is enabled. **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 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.
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. The SDKs expose consent status and grant/revoke
operations but do not render a consent dialog; applications built with the SDK
are responsible for providing appropriate telemetry notices and consent
controls to their 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
Loading