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
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,19 @@ Successful non-dry-run audits require capture metadata, canonical denials JSON,

> **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 (Experimental)
## 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.

Telemetry is **experimental** and requires:
1. The `--experimental` CLI flag
2. `"experimental": { "telemetry": { "enabled": true } }` in the JSON config
Telemetry requires:
1. Top-level `"telemetry": { "enabled": true }` in the JSON config
2. Explicit per-user telemetry consent on Windows
3. 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.

Expand All @@ -245,12 +251,11 @@ The software may collect information about you and your use of the software and

#### How to turn telemetry off

Telemetry is **off by default**. MXC emits telemetry only when **both** of the following are set, so no action is required to keep it disabled:

1. The `--experimental` CLI flag is passed, **and**
2. `"experimental": { "telemetry": { "enabled": true } }` is present in the JSON config.
Telemetry is **off by default**. To keep it off, do not set
`"telemetry": { "enabled": true }` for the run.

Omitting either (the default) turns telemetry off entirely. On non-Windows platforms all telemetry functions are no-ops.
If telemetry is enabled in config, collection still does not occur unless
Windows user consent is granted and administrative policy allows collection.

#### What official builds send

Expand All @@ -277,6 +282,8 @@ Privacy information can be found at https://privacy.microsoft.com and in the Mic
| [docs/windows-sandbox/windows-sandbox.md](docs/windows-sandbox/windows-sandbox.md) | Windows Sandbox backend |
| [docs/state-aware-lifecycle/mxc-state-aware-sandbox-api.md](docs/state-aware-lifecycle/mxc-state-aware-sandbox-api.md) | State-aware sandbox lifecycle API |
| [docs/telemetry/telemetry.md](docs/telemetry/telemetry.md) | TraceLogging telemetry architecture |
| [docs/telemetry/telemetry-consent-design.md](docs/telemetry/telemetry-consent-design.md) | Telemetry consent contract |
| [docs/telemetry/telemetry-administrative-policy.md](docs/telemetry/telemetry-administrative-policy.md) | Administrative telemetry controls |

## Contributing

Expand Down
17 changes: 6 additions & 11 deletions docs/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ production configs and the dev schema when working on experimental features:
"nestedPty": true, // Allow inner process to allocate its own pty (posix_openpt)
"keychainAccess": false // Allow Keychain via securityd / trustd / cfprefsd / lsd.*
},
"telemetry": { // Telemetry (experimental, Windows only)
"telemetry": { // Telemetry (Windows only)
"enabled": true // Emit TraceLogging ETW events via pure Rust tracelogging crate
}
}
Expand All @@ -134,17 +134,12 @@ production configs and the dev schema when working on experimental features:
> **State-aware fields.** The `phase` top-level field is the **state-aware
> discriminator**: a request that includes it is parsed as a state-aware
> lifecycle request (see below), *not* the one-shot config above. The `sandboxId`
> and `correlationVector` top-level fields are state-aware-only — a one-shot
> request carrying either is rejected with a parse error. `correlationVector` is
> the Microsoft Correlation Vector (MS-CV) seeded at `provision` and relayed by
> the client onto later phases (emitted under the TraceLogging `__TlgCV__` field
> when experimental telemetry is enabled). The client relays the value verbatim;
> the executor validates it on each non-`provision` phase and *spins* a fresh
> child element off a mutable base, passes an already-frozen vector through
> unchanged, and reseeds a new base if the relayed value is missing or malformed.
> See
> top-level field is state-aware-only — a one-shot request carrying `sandboxId`
> is rejected with a parse error. Callers cannot supply `correlationVector`;
> it is rejected as an unknown field because lifecycle correlation is internal
> to MXC and is not part of the request or response contract. See
> [`docs/state-aware-lifecycle/mxc-state-aware-sandbox-api.md`](state-aware-lifecycle/mxc-state-aware-sandbox-api.md)
> and [`docs/telemetry/telemetry.md`](telemetry/telemetry.md#correlating-a-lifecycle).
> and [`docs/telemetry/telemetry.md`](telemetry/telemetry.md).

### Working Directory

Expand Down
4 changes: 1 addition & 3 deletions docs/state-aware-lifecycle/mxc-state-aware-sandbox-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,6 @@ type DeprovisionMetadataFor<C extends StateAwareContainmentBackend> =
interface ProvisionResult<C extends StateAwareContainmentBackend> {
sandboxId: SandboxId<C>;
metadata?: ProvisionMetadataFor<C>;
correlationVector?: string; // MS-CV to relay onto later phases (telemetry)
}

interface StartResult<C extends StateAwareContainmentBackend> {
Expand Down Expand Up @@ -664,7 +663,6 @@ State-aware-only fields:
| Field | Type | Required | Description |
|---|---|---|---|
| `phase` | `Phase` member | Yes | Discriminator. Absence means a one-shot request. |
| `correlationVector` | string | No. Relayed by the client onto non-`provision` phases; absent on `provision` (seeded by the executor). Rejected as a parse error on one-shot requests. | Microsoft Correlation Vector (MS-CV) seeded at `provision` and returned in its result; the client relays it verbatim into later phases so the lifecycle shares a telemetry base prefix (emitted under `__TlgCV__`). Each non-`provision` phase validates the relayed value and *spins* a fresh child element off a mutable base (keeping repeat invocations distinct), passes an already-frozen vector through unchanged, and reseeds a new base if it is absent or malformed. Ignored unless experimental telemetry is enabled. See [telemetry docs](../telemetry/telemetry.md#correlating-a-lifecycle). |
| `process` | `ProcessConfig` | Required for `exec`; absent otherwise. | Cross-backend execution fields. |

Cross-cutting fields available to state-aware (state-aware-only at top level — backends
Expand Down Expand Up @@ -773,7 +771,7 @@ type NonExecResponseEnvelope<TResult> = { result: TResult } | { error: ErrorEnve

| Phase | `TResult` shape |
|---|---|
| `provision` | `{ sandboxId: SandboxId<C>; metadata?: object; correlationVector?: string }` |
| `provision` | `{ sandboxId: SandboxId<C>; metadata?: object }` |
| `start` | `{ metadata?: object }` |
| `stop` | `{ metadata?: object }` |
| `deprovision` | `{ metadata?: object }` |
Expand Down
161 changes: 161 additions & 0 deletions docs/telemetry/telemetry-administrative-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# MXC administrative telemetry policy

Audience: developers embedding MXC in a product that ships to Windows devices.

MXC supports a single administrative policy that lets an organization prevent
MXC from collecting diagnostic data on a device, regardless of what the user
chooses. It is a **ceiling, never a grant** — see
[Why policy cannot substitute for consent](#why-policy-cannot-substitute-for-consent).

The policy is **Windows-only**, because [MXC only ever collects telemetry on
Windows](telemetry.md). On Linux and macOS there is nothing to restrict.

## The setting

| | |
|---|---|
| Key | `HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Mxc` |
| Value name | `AllowTelemetry` |
| Type | `REG_DWORD` |
| Scope | Machine (all users on the device) |

`HKLM\SOFTWARE\Policies\...` is an administrator-controlled machine-level registry location. MXC deliberately does not honor a per-user (`HKCU`) equivalent.

### Values

The values mirror the Windows diagnostic-data scale so administrators do not
have to learn a second one:

| Value | Windows name | Effect on MXC |
|-------|--------------|---------------|
| *(value absent)* | — | **Unrestricted.** The user's own choice decides. |
| `0` | Security / Off | **Blocked.** MXC collects nothing. |
| `1` | Required (Basic) | **Blocked.** MXC collects nothing. |
| `3` | Optional (Full) | **Allowed.** MXC may collect *if the user has also consented.* |
| anything else | — | **Blocked** (fail closed). |

`1` blocks MXC because everything MXC emits is classified as
*product-and-service-usage* data — optional diagnostic data in Windows'
taxonomy. MXC emits no required diagnostic data, so there is nothing left to
send at level `1`. Value `2` is not a defined level on modern Windows and is
therefore treated as unrecognized.

Any value MXC cannot read or cannot parse — a wrong type, a corrupt value, a
registry error — is treated as `Blocked`. Telemetry collection is never the
outcome of a failure.

## Deploying it

### Registry deployment

Use any deployment mechanism that writes
HKLM\SOFTWARE\Policies\Mxc\AllowTelemetry directly. For example:

- A startup/admin script:

```powershell
$key = 'HKLM:\SOFTWARE\Policies\Mxc'
New-Item -Path $key -Force | Out-Null
Set-ItemProperty -Path $key -Name 'AllowTelemetry' -Value 0 -Type DWord
```

- Any installer or configuration package that writes the same value.

### Verifying

Whatever consent-management/status surface ships must report the user's
recorded choice separately from the administrative ceiling.

For example, if a user previously granted consent and an administrator later
sets `AllowTelemetry=0`, the status must still make both facts visible:

- the stored user choice remains **granted**
- the administrative policy is **blocked**
- effective collection is therefore **off**
- no prompt is needed while the policy blocks

Keeping those states separate lets hosts explain why telemetry is currently
disabled without losing the user's prior choice.

## How the policy interacts with user consent

MXC collects diagnostic data only when **every** gate is open:

```
collect = policy_permits AND user_consented AND build_has_telemetry_enabled
```

Concretely:

| Policy | User consent | Result |
|--------|--------------|--------|
| unrestricted | granted | collects |
| unrestricted | denied / undetermined | **no collection** |
| allowed (`3`) | granted | collects |
| allowed (`3`) | denied / undetermined | **no collection** |
| blocked (`0`/`1`/other) | *anything* | **no collection** |

Two consequences worth calling out:

1. **A blocking policy suppresses the first-run consent prompt.** Asking a user
to permit something the administrator has already refused is a question with
no meaning. `needsPrompt` reports `false` while the policy blocks.
2. **A blocking policy does not erase the user's recorded choice.** If a user
had already consented and an administrator later blocks telemetry,
collection stops immediately but the recorded consent is preserved. If the
policy is later relaxed, the user's own prior decision takes effect again
rather than the user being re-prompted.

### Why policy cannot substitute for consent

An administrator setting `AllowTelemetry=3` does **not** cause MXC to start
collecting. It only removes MXC's administrative restriction; the user is still
asked, and still decides.

In particular, **if the user has opted out and the policy permits collection,
the result is opt-out.** A policy can only ever subtract. There is no policy
value, and no combination of policy and configuration, that causes MXC to
collect from a user who has not explicitly granted consent — including a user
who has never been asked.

This is a product rule MXC holds itself to, not merely a reading of external
guidance. It is also consistent with that guidance: Microsoft's privacy
direction for components classified as *apps* (rather than as parts of the
operating system) requires them to build their own notice-and-consent
experience and not to rely on the Windows diagnostic-data consent. An
administrative policy is an availability control, not an expression of a
user's informed choice, and no Microsoft guidance treats an admin "allow" as
consent on the user's behalf.

The implementation should enforce that rule in one place rather than
re-deriving it in each host surface.

## Relationship to the Windows `AllowTelemetry` policy

MXC reads **only** its own key. It does not read, and is not affected by:

- `HKLM\SOFTWARE\Policies\Microsoft\Windows\DataCollection\AllowTelemetry`
- `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection\AllowTelemetry`
- the Windows Settings → Diagnostics & feedback choice
- the `System/AllowTelemetry` Policy CSP node

Two reasons:

1. **Microsoft documents that it doesn't apply.** The Policy CSP documentation
for `System/AllowTelemetry` states that it "impacts the operating system and
apps that are considered part of Windows and doesn't apply to any additional
apps installed by your organization." MXC is such an app.
2. **Reading it would leak the user's Windows choice into MXC.** The supported
OS APIs for evaluating that policy deliberately combine the administrative
setting with the user's own Settings-app selection. Consuming them would
make MXC's behaviour depend on Windows consent state, which MXC's design
forbids.

The dominant pattern among Microsoft first-party applications — Office,
Visual Studio, Visual Studio Code, WinGet, PowerToys — is likewise an
application-specific policy under `SOFTWARE\Policies\Microsoft\<app>`.

## See also

- [Telemetry overview](telemetry.md)
- [Telemetry consent design](telemetry-consent-design.md)
Loading
Loading