Managed mode

Zero-touch deployment for MDM-managed fleets. When the configuration profile sets shft.deploymentMode = managed, shft hides its setup wizard entirely and runs the migration from profile values.

Scope

  • Skip the entire wizard (Welcome → Role → Discovery → Pairing → User Mapping → Manifest → Preflight → Progress → Complete).
  • Validate required profile keys at launch; surface missing ones as a clear "Contact IT" UI rather than crashing.
  • Local self-attestation when requireManagedSource = true — a destination demanding the source be MDM-enrolled has to be enrolled itself.
  • Drive ConnectionManager programmatically through discovery → peer selection → pairing.
  • Derive a UserMapping from userPrincipal (no user prompt).
  • Apply migrationCategories to the data picker, then run the engine.
  • Post a JSON telemetry envelope to telemetryEndpoint on every lifecycle transition.

Profile keys

See Configuration profile reference for the canonical key table. The keys this feature reads:

KeyRequired when managedNotes
shft.deploymentModemanaged activates this whole flow
shft.deploymentRoledestination (default) or source
shft.userPrincipalyesMDM variable, typically $EMAIL
shft.migrationSourceauto / bonjour / thunderbolt
shft.migrationCategoriesSubset of category IDs
shft.requireManagedSourceBoolean; gates on local self-attestation
shft.telemetryEndpointURL for managed-mode events
shft.prefRestoreModeSee Staged pref restore
shft.brandingNameSurfaced as "Managed by …"

Missing shft.userPrincipal (the only required-when-managed key) puts the coordinator into a missingKeys state. The UI shows Contact IT and the lifecycle event managed.missing_keys POSTs to the telemetry endpoint.

State machine

ManagedModeCoordinator.State:

validating
  ↓
  ├─ missingKeys([String])        → UI: Contact IT, telemetry: managed.missing_keys
  ├─ attestationFailed(reason)    → UI: Contact IT, telemetry: managed.attestation_failed
  │
  ↓ (validation + attestation pass)
awaitingPeer                      → telemetry: managed.awaiting_peer
  ↓
pairing(peerName)
  │   ├─ failed(reason)           → telemetry: managed.pairing_failed
  ↓
ready(peerName)                   → telemetry: managed.ready
  ↓
transferring                      → telemetry: managed.transfer_start
  ↓
  ├─ complete                     → telemetry: managed.complete
  └─ failed(reason)               → telemetry: managed.failed

ManagedStatusView reflects each state with a self-explanatory label and never shows a control beyond "Quit shft" (on completion) or "Contact IT" (hard errors). By design the user never clicks anything.

Source attestation

SourceAttestation.attestLocalDevice() checks two MDM signals:

  1. /Library/Managed Preferences/ populated — the strongest signal. MDM provisions a per-user subdirectory the moment a profile is installed; an empty or missing directory is a "not managed" tell.

  2. /usr/bin/profiles status -type enrollment — catches devices where the user-scoped preferences haven't been delivered yet but the device record is good. Matches a line like MDM enrollment: Yes ….

When requireManagedSource = true, the coordinator runs this check on the destination before doing anything else. A device that can't prove its own enrollment can't credibly require it of a peer.

Telemetry envelope

TelemetryClient POSTs a JSON body for every event:

{
  "timestamp": "2026-05-20T00:57:00Z",
  "event": "managed.complete",
  "device": "mac-1234",
  "principal": "alice@example.com",
  "appVersion": "1.0.0",
  "details": {
    "files": "12847",
    "bytes": "53483392"
  }
}

Failures log a warning and are dropped — point the endpoint at a webhook or logging collector that owns durability. No retry queue, no local buffering: the migration never blocks on the telemetry path.

Example: minimal managed profile

<key>shft.deploymentMode</key>
<string>managed</string>
<key>shft.userPrincipal</key>
<string>$EMAIL</string>
<key>shft.migrationCategories</key>
<array>
    <string>userFiles</string>
    <string>applicationData</string>
    <string>browserData</string>
</array>
<key>shft.requireManagedSource</key>
<true/>
<key>shft.telemetryEndpoint</key>
<string>https://webhook.acme.example/shft</string>
<key>shft.brandingName</key>
<string>Acme</string>

$EMAIL is the standard MDM variable for the enrolled user's email/UPN — Jamf, Kandji, Mosyle, and Intune all resolve it per-device.