fleet/orbit/pkg/setup_experience/setup_experience.go

690 lines
22 KiB
Go
Raw Normal View History

package setupexperience
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
28434 Setup experience reliability (#28931) For #28434 This ticket is largely changing the options we invoke Swift Dialog with so that it is more reliable. The only small divergence from the ticket is that the command to exit was changed to command+shift+x due to limitations in Swift Dialog(no way to require control + key) # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Make sure fleetd is compatible with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/fleetd-development-and-release-strategy.md)). - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2025-05-08 18:05:31 +00:00
"time"
"github.com/fleetdm/fleet/v4/orbit/pkg/constant"
"github.com/fleetdm/fleet/v4/orbit/pkg/swiftdialog"
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
"github.com/fleetdm/fleet/v4/orbit/pkg/token"
"github.com/fleetdm/fleet/v4/orbit/pkg/update"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/ptr"
"github.com/rs/zerolog/log"
)
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
// OrbitClient is the minimal interface needed to communicate with the Fleet server.
type OrbitClient interface {
Stop setup experience on software install failure (#34173) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #33173 **Related issue:** Resolves #33111 # Details This is the remaining work to implement the "Stop the setup experience when required software fails to install" feature. This didn't turn out to be quite as straightforward as expected so I ended up doing a bit of design-by-code and expect some feedback on the approach. I tried to make it as low-touch as possible. The general design is: 1. In the `maybeUpdateSetupExperienceStatus` function which is called in various places when a setup experience step is marked as completed, call a new `maybeCancelPendingSetupExperienceSteps` function if the setup step was marked as failed. Similarly call `maybeCancelPendingSetupExperienceSteps` if a VPP app install fails to enqueue. 2. In `maybeCancelPendingSetupExperienceSteps`, check whether the specified host is MacOS and whether the "RequireAllSoftwareMacOS" flag is set in the team (or global) config. If so, mark the remaining setup experience items as canceled and cancel any upcoming activities related to those steps. 3. On the front-end, if the `require_all_software_macos` is set and a software step is marked as failed, show a new failure page indicating that setup has failed and showing details of the failed software. 4. On the agent side, when checking setup experience status, send a `reset_after_failure` flag _only the first time_. If this flag is set, then the code in the `/orbit/setup_experience/status` handler will clear and re-queue any failed setup experience steps (but leave successful steps to avoid re-installing already-installed software). This facilitates re-starting the setup experience when the host is rebooted. I also updated the way that software (packages and VPP) is queued up for the setup experience to be ordered alphabetically, to make it easier to test _and_ because this is a desired outcome for a future story. Since the order is not deterministic now, this update shouldn't cause any problems (aside from a couple of test updates), but I'm ok taking it out if desired. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [X] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [X] Added/updated automated tests * Added a new integration test for software packages, testing that a failed software package causes the rest of the setup experience to be marked as failed when `require_all_software_macos` is set, and testing that the "reset after failure" code works. * Added a new integration test for VPP packages, testing that a failed VPP enqueue causes the same halting of the setup experience. I _don't_ have test for a failure _during_ a VPP install. It should go through the same code path as the software package failure, so it's not a huge gap. - [ ] QA'd all new/changed functionality manually Working on it ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [X] Verified that fleetd runs on macOS, Linux and Windows <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Configurable option to halt macOS device setup if any software install fails. - Device setup page now shows a clear “Device setup failed” state with expandable error details when all software is required on macOS. - Improvements - Setup status now includes per-step error messages for better troubleshooting. - Pending setup steps are automatically canceled after a failure when applicable, with support to reset and retry the setup flow as configured. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ian Littman <iansltx@gmail.com>
2025-10-17 13:38:53 +00:00
GetSetupExperienceStatus(resetFailedSetupSteps bool) (*fleet.SetupExperienceStatusPayload, error)
}
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
// DeviceClient is the minimal interface needed to get the device's browser URL.
type DeviceClient interface {
BrowserDeviceURL(token string) string
}
// SetupExperiencer is the type that manages the Fleet setup experience flow during macOS Setup
// Assistant. It uses swiftDialog as a UI for showing the status of software installations and
// script execution that are configured to run before the user has full access to the device.
// If the setup experience is supposed to run, it will launch a single swiftDialog instance and then
// update that instance based on the results from the /orbit/setup_experience/status endpoint.
type SetupExperiencer struct {
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
OrbitClient OrbitClient
DeviceClient DeviceClient
closeChan chan struct{}
rootDirPath string
// Note: this object is not safe for concurrent use. Since the SetupExperiencer is a singleton,
// its Run method is called within a WaitGroup,
// and no other parts of Orbit need access to this field (or any other parts of the
// SetupExperiencer), it's OK to not protect this with a lock.
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
sd *swiftdialog.SwiftDialog
started bool
trw *token.ReadWriter
stopTokenRotation func()
Add macos web setup experience capability check (#34582) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #34596 # Details This PR adds back the "legacy" macOS setup experience, and a new `CapabilityMacOSWebSetupExperience` capability check. The legacy experience will be shown whenever the `CapabilityMacOSWebSetupExperience` capability is _not_ detected in the Fleet server response. The majority of the code is just copying the `Run` and `startSwiftDialog` from the [4.75.1 patch release](https://github.com/fleetdm/fleet/blob/rc-patch-fleet-v4.75.1/orbit/pkg/setup_experience/setup_experience.go) and adding them back as `RunLegacy` and `startSwiftDialogLegacy`, then adding the little bit of plumbing to have `Run()` call `RunLegacy()` when the new capability is not detected. # Checklist for submitter If some of the following don't apply, delete the relevant line. ## Testing - [ ] Added/updated automated tests - [ ] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [X] QA'd all new/changed functionality manually Tested on a VM that the setup experience starts in "legacy" mode if `CapabilityMacOSWebSetupExperience` is not set in the server, and that it starts in the new web view if the capability _is_ set. For unreleased bug fixes in a release candidate, one of: - [X] Confirmed that the fix is not expected to adversely impact load test results - [ ] Alerted the release DRI if additional load testing is needed ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [ ] Verified that fleetd runs on macOS, Linux and Windows I have not re-verified this, but the changes will only run on macOS - [ ] Verified auto-update works from the released version of component to the new version (see [tools/tuf/test](../tools/tuf/test/README.md)) This should not be affected.
2025-10-21 17:32:16 +00:00
uiSteps map[string]swiftdialog.ListItem // For legacy swiftDialog UI to track current steps
UseLegacyUI bool
}
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
func NewSetupExperiencer(orbitClient OrbitClient, deviceClient DeviceClient, rootDirPath string, trw *token.ReadWriter) *SetupExperiencer {
return &SetupExperiencer{
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
OrbitClient: orbitClient,
DeviceClient: deviceClient,
closeChan: make(chan struct{}),
rootDirPath: rootDirPath,
trw: trw,
Add macos web setup experience capability check (#34582) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #34596 # Details This PR adds back the "legacy" macOS setup experience, and a new `CapabilityMacOSWebSetupExperience` capability check. The legacy experience will be shown whenever the `CapabilityMacOSWebSetupExperience` capability is _not_ detected in the Fleet server response. The majority of the code is just copying the `Run` and `startSwiftDialog` from the [4.75.1 patch release](https://github.com/fleetdm/fleet/blob/rc-patch-fleet-v4.75.1/orbit/pkg/setup_experience/setup_experience.go) and adding them back as `RunLegacy` and `startSwiftDialogLegacy`, then adding the little bit of plumbing to have `Run()` call `RunLegacy()` when the new capability is not detected. # Checklist for submitter If some of the following don't apply, delete the relevant line. ## Testing - [ ] Added/updated automated tests - [ ] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [X] QA'd all new/changed functionality manually Tested on a VM that the setup experience starts in "legacy" mode if `CapabilityMacOSWebSetupExperience` is not set in the server, and that it starts in the new web view if the capability _is_ set. For unreleased bug fixes in a release candidate, one of: - [X] Confirmed that the fix is not expected to adversely impact load test results - [ ] Alerted the release DRI if additional load testing is needed ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [ ] Verified that fleetd runs on macOS, Linux and Windows I have not re-verified this, but the changes will only run on macOS - [ ] Verified auto-update works from the released version of component to the new version (see [tools/tuf/test](../tools/tuf/test/README.md)) This should not be affected.
2025-10-21 17:32:16 +00:00
uiSteps: make(map[string]swiftdialog.ListItem),
}
}
func (s *SetupExperiencer) Run(oc *fleet.OrbitConfig) error {
if !oc.Notifications.RunSetupExperience {
log.Debug().Msg("skipping setup experience: notification flag is not set")
return nil
}
Add macos web setup experience capability check (#34582) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #34596 # Details This PR adds back the "legacy" macOS setup experience, and a new `CapabilityMacOSWebSetupExperience` capability check. The legacy experience will be shown whenever the `CapabilityMacOSWebSetupExperience` capability is _not_ detected in the Fleet server response. The majority of the code is just copying the `Run` and `startSwiftDialog` from the [4.75.1 patch release](https://github.com/fleetdm/fleet/blob/rc-patch-fleet-v4.75.1/orbit/pkg/setup_experience/setup_experience.go) and adding them back as `RunLegacy` and `startSwiftDialogLegacy`, then adding the little bit of plumbing to have `Run()` call `RunLegacy()` when the new capability is not detected. # Checklist for submitter If some of the following don't apply, delete the relevant line. ## Testing - [ ] Added/updated automated tests - [ ] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [X] QA'd all new/changed functionality manually Tested on a VM that the setup experience starts in "legacy" mode if `CapabilityMacOSWebSetupExperience` is not set in the server, and that it starts in the new web view if the capability _is_ set. For unreleased bug fixes in a release candidate, one of: - [X] Confirmed that the fix is not expected to adversely impact load test results - [ ] Alerted the release DRI if additional load testing is needed ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [ ] Verified that fleetd runs on macOS, Linux and Windows I have not re-verified this, but the changes will only run on macOS - [ ] Verified auto-update works from the released version of component to the new version (see [tools/tuf/test](../tools/tuf/test/README.md)) This should not be affected.
2025-10-21 17:32:16 +00:00
// If using the legacy UI, then call that method.
if s.UseLegacyUI {
return s.RunLegacy(oc)
}
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
// Ensure that the token rotation checker is started, so that we have a valid token
// when we need to show or refresh the My Device URL in the webview.
if s.stopTokenRotation == nil {
s.stopTokenRotation = s.trw.StartRotation()
}
_, binaryPath, _ := update.LocalTargetPaths(
s.rootDirPath,
"swiftDialog",
update.SwiftDialogMacOSTarget,
)
if _, err := os.Stat(binaryPath); err != nil {
log.Info().Msg("skipping setup experience: swiftDialog is not installed")
return nil
}
log.Info().Msg("checking setup experience status")
// Poll the status endpoint. This also releases the device if we're done.
Stop setup experience on software install failure (#34173) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #33173 **Related issue:** Resolves #33111 # Details This is the remaining work to implement the "Stop the setup experience when required software fails to install" feature. This didn't turn out to be quite as straightforward as expected so I ended up doing a bit of design-by-code and expect some feedback on the approach. I tried to make it as low-touch as possible. The general design is: 1. In the `maybeUpdateSetupExperienceStatus` function which is called in various places when a setup experience step is marked as completed, call a new `maybeCancelPendingSetupExperienceSteps` function if the setup step was marked as failed. Similarly call `maybeCancelPendingSetupExperienceSteps` if a VPP app install fails to enqueue. 2. In `maybeCancelPendingSetupExperienceSteps`, check whether the specified host is MacOS and whether the "RequireAllSoftwareMacOS" flag is set in the team (or global) config. If so, mark the remaining setup experience items as canceled and cancel any upcoming activities related to those steps. 3. On the front-end, if the `require_all_software_macos` is set and a software step is marked as failed, show a new failure page indicating that setup has failed and showing details of the failed software. 4. On the agent side, when checking setup experience status, send a `reset_after_failure` flag _only the first time_. If this flag is set, then the code in the `/orbit/setup_experience/status` handler will clear and re-queue any failed setup experience steps (but leave successful steps to avoid re-installing already-installed software). This facilitates re-starting the setup experience when the host is rebooted. I also updated the way that software (packages and VPP) is queued up for the setup experience to be ordered alphabetically, to make it easier to test _and_ because this is a desired outcome for a future story. Since the order is not deterministic now, this update shouldn't cause any problems (aside from a couple of test updates), but I'm ok taking it out if desired. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [X] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [X] Added/updated automated tests * Added a new integration test for software packages, testing that a failed software package causes the rest of the setup experience to be marked as failed when `require_all_software_macos` is set, and testing that the "reset after failure" code works. * Added a new integration test for VPP packages, testing that a failed VPP enqueue causes the same halting of the setup experience. I _don't_ have test for a failure _during_ a VPP install. It should go through the same code path as the software package failure, so it's not a huge gap. - [ ] QA'd all new/changed functionality manually Working on it ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [X] Verified that fleetd runs on macOS, Linux and Windows <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Configurable option to halt macOS device setup if any software install fails. - Device setup page now shows a clear “Device setup failed” state with expandable error details when all software is required on macOS. - Improvements - Setup status now includes per-step error messages for better troubleshooting. - Pending setup steps are automatically canceled after a failure when applicable, with support to reset and retry the setup flow as configured. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ian Littman <iansltx@gmail.com>
2025-10-17 13:38:53 +00:00
payload, err := s.OrbitClient.GetSetupExperienceStatus(!s.started)
if err != nil {
return err
}
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
// Marshall the payload for logging
payloadBytes, err := json.Marshal(payload)
if err != nil {
log.Error().Err(err).Msg("marshalling setup experience payload for logging")
} else {
log.Debug().Msgf("setup experience payload: %s", string(payloadBytes))
}
// If swiftDialog isn't up yet, then launch it
orgLogo := payload.OrgLogoURL
if orgLogo == "" {
orgLogo = "https://fleetdm.com/images/permanent/fleet-mark-color-40x40@4x.png"
}
if err := s.startSwiftDialog(binaryPath, orgLogo); err != nil {
return err
}
// Defer this so that s.started is only false the first time this function runs.
defer func() { s.started = true }()
select {
case <-s.closeChan:
log.Info().Str("receiver", "setup_experiencer").Msg("swiftDialog closed")
return nil
default:
// ok
}
// We're rendering the initial loading UI (shown while there are still profiles, bootstrap package,
// and account configuration to verify) right off the bat, so we can just no-op if any of those
// are not terminal
log.Info().Msg("setup experience: checking for pending statuses")
if payload.BootstrapPackage != nil {
if payload.BootstrapPackage.Status != fleet.MDMBootstrapPackageFailed && payload.BootstrapPackage.Status != fleet.MDMBootstrapPackageInstalled {
log.Info().Msg("setup experience: bootstrap package pending")
return nil
}
}
if isPending, name := anyProfilePending(payload.ConfigurationProfiles); isPending {
log.Info().Msg(fmt.Sprintf("setup experience: profile pending: %s", name))
return nil
}
if payload.AccountConfiguration != nil {
if payload.AccountConfiguration.Status != fleet.MDMAppleStatusAcknowledged &&
payload.AccountConfiguration.Status != fleet.MDMAppleStatusError &&
payload.AccountConfiguration.Status != fleet.MDMAppleStatusCommandFormatError {
log.Info().Msg("setup experience: account config pending")
return nil
}
}
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
// If we got this far, then we can hand the UI over to the webview.
// Clear the dialog message.
if err := s.sd.HideMessage(); err != nil {
log.Error().Err(err).Msg("clearing message in setup experience UI")
}
// Remove the icon.
if err := s.sd.HideIcon(); err != nil {
log.Error().Err(err).Msg("clearing icon in setup experience UI")
}
// Hide the title.
if err := s.sd.HideTitle(); err != nil {
log.Error().Err(err).Msg("hiding title in setup experience UI")
}
// Hide the progress.
if err := s.sd.HideProgress(); err != nil {
log.Error().Err(err).Msg("hiding progress in setup experience UI")
}
// Get the device token.
token, err := s.trw.Read()
if err != nil {
return fmt.Errorf("getting device token: %w", err)
}
// Get the My Device URL.
browserURL := s.DeviceClient.BrowserDeviceURL(token)
// log out the url
log.Debug().Msgf("setup experience: opening web content URL: %s", browserURL)
// Set the web content URL.
if err := s.sd.SetWebContent(browserURL + "?setup_only=1"); err != nil {
log.Error().Err(err).Msg("setting web content URL in setup experience UI")
return nil
}
Fixed setup experience UI hanging when a step is removed from the payload (#29385) This is one facet of https://github.com/fleetdm/fleet/issues/28664 When you run gitops or otherwise just do something to remove a software installer from the setup experience list while it is running and then delete that software installer, setup experience fails to proceed past the "steps" screen because it is expecting all software in the initial payload to complete installation even if those installers were not in the current payload. This now tracks the status of items in the current payload and as a small enhancement deletes the items that disappear from the payload, which seemed like the best thing to do # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Make sure fleetd is compatible with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)). - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2025-05-22 18:58:17 +00:00
// Note that we are setting this based on the current payload only just in case something
// was removed from the payload that was there earlier(e.g. a deleted software title).
allStepsDone := true
// Now render the UI for the software and script.
if len(payload.Software) > 0 || payload.Script != nil {
log.Info().Msg("setup experience: rendering software and script UI")
if len(payload.Software) > 0 {
Stop setup experience on software install failure (#34173) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #33173 **Related issue:** Resolves #33111 # Details This is the remaining work to implement the "Stop the setup experience when required software fails to install" feature. This didn't turn out to be quite as straightforward as expected so I ended up doing a bit of design-by-code and expect some feedback on the approach. I tried to make it as low-touch as possible. The general design is: 1. In the `maybeUpdateSetupExperienceStatus` function which is called in various places when a setup experience step is marked as completed, call a new `maybeCancelPendingSetupExperienceSteps` function if the setup step was marked as failed. Similarly call `maybeCancelPendingSetupExperienceSteps` if a VPP app install fails to enqueue. 2. In `maybeCancelPendingSetupExperienceSteps`, check whether the specified host is MacOS and whether the "RequireAllSoftwareMacOS" flag is set in the team (or global) config. If so, mark the remaining setup experience items as canceled and cancel any upcoming activities related to those steps. 3. On the front-end, if the `require_all_software_macos` is set and a software step is marked as failed, show a new failure page indicating that setup has failed and showing details of the failed software. 4. On the agent side, when checking setup experience status, send a `reset_after_failure` flag _only the first time_. If this flag is set, then the code in the `/orbit/setup_experience/status` handler will clear and re-queue any failed setup experience steps (but leave successful steps to avoid re-installing already-installed software). This facilitates re-starting the setup experience when the host is rebooted. I also updated the way that software (packages and VPP) is queued up for the setup experience to be ordered alphabetically, to make it easier to test _and_ because this is a desired outcome for a future story. Since the order is not deterministic now, this update shouldn't cause any problems (aside from a couple of test updates), but I'm ok taking it out if desired. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [X] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [X] Added/updated automated tests * Added a new integration test for software packages, testing that a failed software package causes the rest of the setup experience to be marked as failed when `require_all_software_macos` is set, and testing that the "reset after failure" code works. * Added a new integration test for VPP packages, testing that a failed VPP enqueue causes the same halting of the setup experience. I _don't_ have test for a failure _during_ a VPP install. It should go through the same code path as the software package failure, so it's not a huge gap. - [ ] QA'd all new/changed functionality manually Working on it ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [X] Verified that fleetd runs on macOS, Linux and Windows <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Configurable option to halt macOS device setup if any software install fails. - Device setup page now shows a clear “Device setup failed” state with expandable error details when all software is required on macOS. - Improvements - Setup status now includes per-step error messages for better troubleshooting. - Pending setup steps are automatically canceled after a failure when applicable, with support to reset and retry the setup flow as configured. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ian Littman <iansltx@gmail.com>
2025-10-17 13:38:53 +00:00
for _, step := range payload.Software {
// If any step is not in a terminal state, then we're not done.
if (step.Status != fleet.SetupExperienceStatusFailure && step.Status != fleet.SetupExperienceStatusSuccess) ||
// If any software failed, and we're requiring all software to succeed, then we'll block completion.
(step.Status == fleet.SetupExperienceStatusFailure && payload.RequireAllSoftware) {
allStepsDone = false
}
}
}
Stop setup experience on software install failure (#34173) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #33173 **Related issue:** Resolves #33111 # Details This is the remaining work to implement the "Stop the setup experience when required software fails to install" feature. This didn't turn out to be quite as straightforward as expected so I ended up doing a bit of design-by-code and expect some feedback on the approach. I tried to make it as low-touch as possible. The general design is: 1. In the `maybeUpdateSetupExperienceStatus` function which is called in various places when a setup experience step is marked as completed, call a new `maybeCancelPendingSetupExperienceSteps` function if the setup step was marked as failed. Similarly call `maybeCancelPendingSetupExperienceSteps` if a VPP app install fails to enqueue. 2. In `maybeCancelPendingSetupExperienceSteps`, check whether the specified host is MacOS and whether the "RequireAllSoftwareMacOS" flag is set in the team (or global) config. If so, mark the remaining setup experience items as canceled and cancel any upcoming activities related to those steps. 3. On the front-end, if the `require_all_software_macos` is set and a software step is marked as failed, show a new failure page indicating that setup has failed and showing details of the failed software. 4. On the agent side, when checking setup experience status, send a `reset_after_failure` flag _only the first time_. If this flag is set, then the code in the `/orbit/setup_experience/status` handler will clear and re-queue any failed setup experience steps (but leave successful steps to avoid re-installing already-installed software). This facilitates re-starting the setup experience when the host is rebooted. I also updated the way that software (packages and VPP) is queued up for the setup experience to be ordered alphabetically, to make it easier to test _and_ because this is a desired outcome for a future story. Since the order is not deterministic now, this update shouldn't cause any problems (aside from a couple of test updates), but I'm ok taking it out if desired. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [X] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [X] Added/updated automated tests * Added a new integration test for software packages, testing that a failed software package causes the rest of the setup experience to be marked as failed when `require_all_software_macos` is set, and testing that the "reset after failure" code works. * Added a new integration test for VPP packages, testing that a failed VPP enqueue causes the same halting of the setup experience. I _don't_ have test for a failure _during_ a VPP install. It should go through the same code path as the software package failure, so it's not a huge gap. - [ ] QA'd all new/changed functionality manually Working on it ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [X] Verified that fleetd runs on macOS, Linux and Windows <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Configurable option to halt macOS device setup if any software install fails. - Device setup page now shows a clear “Device setup failed” state with expandable error details when all software is required on macOS. - Improvements - Setup status now includes per-step error messages for better troubleshooting. - Pending setup steps are automatically canceled after a failure when applicable, with support to reset and retry the setup flow as configured. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ian Littman <iansltx@gmail.com>
2025-10-17 13:38:53 +00:00
// If a script is still running, then we're not done.
if payload.Script != nil && payload.Script.Status != fleet.SetupExperienceStatusFailure && payload.Script.Status != fleet.SetupExperienceStatusSuccess {
allStepsDone = false
}
}
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
// If we get here, we can close the webview.
// It will likely already be displaying a "done" message.
Fixed setup experience UI hanging when a step is removed from the payload (#29385) This is one facet of https://github.com/fleetdm/fleet/issues/28664 When you run gitops or otherwise just do something to remove a software installer from the setup experience list while it is running and then delete that software installer, setup experience fails to proceed past the "steps" screen because it is expecting all software in the initial payload to complete installation even if those installers were not in the current payload. This now tracks the status of items in the current payload and as a small enhancement deletes the items that disappear from the payload, which seemed like the best thing to do # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Make sure fleetd is compatible with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)). - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [x] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2025-05-22 18:58:17 +00:00
if allStepsDone {
if err := s.sd.EnableButton1(true); err != nil {
log.Info().Err(err).Msg("enabling close button in setup experience UI")
}
28434 Setup experience reliability (#28931) For #28434 This ticket is largely changing the options we invoke Swift Dialog with so that it is more reliable. The only small divergence from the ticket is that the command to exit was changed to command+shift+x due to limitations in Swift Dialog(no way to require control + key) # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Make sure fleetd is compatible with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/fleetd-development-and-release-strategy.md)). - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2025-05-08 18:05:31 +00:00
// Sleep for a few seconds to let the user see the done message before closing
// the UI
time.Sleep(3 * time.Second)
if err := s.sd.Quit(); err != nil {
log.Info().Err(err).Msg("quitting setup experience UI on completion")
}
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
// Stop the token rotation checker since we're done with the setup experience.
s.stopTokenRotation()
}
return nil
}
func anyProfilePending(profiles []*fleet.SetupExperienceConfigurationProfileResult) (bool, string) {
for _, p := range profiles {
if p.Status == fleet.MDMDeliveryPending {
return true, p.Name
}
}
return false, ""
}
func (s *SetupExperiencer) startSwiftDialog(binaryPath, orgLogo string) error {
if s.started {
log.Info().Msg("swiftDialog started")
return nil
}
log.Info().Msg("creating swiftDialog instance")
created := make(chan struct{})
swiftDialog, err := swiftdialog.Create(context.Background(), binaryPath)
if err != nil {
return errors.New("creating swiftDialog instance: %w")
}
s.sd = swiftDialog
iconSize, err := swiftdialog.GetIconSize(orgLogo)
if err != nil {
log.Error().Err(err).Msg("setup experience: getting icon size")
iconSize = swiftdialog.DefaultIconSize
}
go func() {
initOpts := &swiftdialog.SwiftDialogOptions{
Title: "none",
Message: "### Setting up your Mac...\n\nYour Mac is being configured by your organization using Fleet. This process may take some time to complete. Please don't attempt to restart or shut down the computer unless prompted to do so.",
Icon: orgLogo,
MessageAlignment: swiftdialog.AlignmentCenter,
CentreIcon: true,
Height: "625",
Big: true,
ProgressText: "Configuring your device...",
Button1Text: "Close",
Button1Disabled: true,
28434 Setup experience reliability (#28931) For #28434 This ticket is largely changing the options we invoke Swift Dialog with so that it is more reliable. The only small divergence from the ticket is that the command to exit was changed to command+shift+x due to limitations in Swift Dialog(no way to require control + key) # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Make sure fleetd is compatible with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/fleetd-development-and-release-strategy.md)). - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2025-05-08 18:05:31 +00:00
BlurScreen: true,
OnTop: true,
QuitKey: "X", // Capital X to require command+shift+x
}
28434 Setup experience reliability (#28931) For #28434 This ticket is largely changing the options we invoke Swift Dialog with so that it is more reliable. The only small divergence from the ticket is that the command to exit was changed to command+shift+x due to limitations in Swift Dialog(no way to require control + key) # Checklist for submitter If some of the following don't apply, delete the relevant line. <!-- Note that API documentation changes are now addressed by the product design team. --> - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [x] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality - For Orbit and Fleet Desktop changes: - [x] Make sure fleetd is compatible with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/fleetd-development-and-release-strategy.md)). - [x] Orbit runs on macOS, Linux and Windows. Check if the orbit feature/bugfix should only apply to one platform (`runtime.GOOS`). - [x] Manual QA must be performed in the three main OSs, macOS, Windows and Linux. - [ ] Auto-update manual QA, from released version of component to new version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2025-05-08 18:05:31 +00:00
if err := s.sd.Start(context.Background(), initOpts, true); err != nil {
log.Error().Err(err).Msg("starting swiftDialog instance")
}
if err = s.sd.ShowProgress(); err != nil {
log.Error().Err(err).Msg("setting initial setup experience progress")
}
if err := s.sd.SetIconSize(iconSize); err != nil {
log.Error().Err(err).Msg("setting initial setup experience icon size")
}
log.Debug().Msg("swiftDialog process started")
created <- struct{}{}
if _, err = s.sd.Wait(); err != nil {
log.Error().Err(err).Msg("swiftdialog.Wait failed")
}
s.closeChan <- struct{}{}
}()
<-created
return nil
}
// LinuxSetupExperiencer runs the setup experience on Linux hosts.
type LinuxSetupExperiencer struct {
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
orbitClient OrbitClient
rootDir string
}
// NewLinuxSetupExperiencer creates a config receiver to run the setup experience on Linux hosts.
Use webview in MacOS setup experience (#33884) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** For #33111 # Details This PR updates the setup experience for MacOS to use a web view pointed at the device's "Setting up your device" page rather than using native MacOS UI elements, bringing it more in line with Linux and Windows setup experiences. This covers only the new web UI for the setup experience progress, _not_ the UI for the new case of blocking the device when a piece of software fails to install. I'll add that in a separate PR. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests Added tests for the updates to the token rotation code. - [X] QA'd all new/changed functionality manually A new tool is provided to allow testing this code against a virtual machine if a separate host that you can wipe and run setup on is not available. See https://github.com/fleetdm/fleet/blob/sgress454/new-setup-experience/tools/mdm/apple/setupexperience/README.md for details. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - macOS setup experience moved to a new web-based UI. - Automatic device token rotation during setup to keep sessions valid. - Bug Fixes - More reliable setup flow with improved dialog lifecycle and cleaner handoff to web content. - Dialog elements hidden/cleared appropriately when transitioning to the browser. - Documentation - Added guide and tool to simulate the macOS setup experience on a VM, with prerequisites and usage steps. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-10-08 16:51:26 +00:00
func NewLinuxSetupExperiencer(client OrbitClient, rootDir string) *LinuxSetupExperiencer {
return &LinuxSetupExperiencer{
orbitClient: client,
rootDir: rootDir,
}
}
// Run implements fleet.OrbitConfigReceiver.
//
// Currently the fleet.OrbitConfig is ununsed but might be used in the future.
func (s *LinuxSetupExperiencer) Run(_ *fleet.OrbitConfig) error {
info, err := ReadSetupExperienceStatusFile(s.rootDir)
if err != nil {
return fmt.Errorf("read setup experience file: %w", err)
}
if info == nil || info.TimeFinished != nil {
// nothing to do.
return nil
}
Stop setup experience on software install failure (#34173) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #33173 **Related issue:** Resolves #33111 # Details This is the remaining work to implement the "Stop the setup experience when required software fails to install" feature. This didn't turn out to be quite as straightforward as expected so I ended up doing a bit of design-by-code and expect some feedback on the approach. I tried to make it as low-touch as possible. The general design is: 1. In the `maybeUpdateSetupExperienceStatus` function which is called in various places when a setup experience step is marked as completed, call a new `maybeCancelPendingSetupExperienceSteps` function if the setup step was marked as failed. Similarly call `maybeCancelPendingSetupExperienceSteps` if a VPP app install fails to enqueue. 2. In `maybeCancelPendingSetupExperienceSteps`, check whether the specified host is MacOS and whether the "RequireAllSoftwareMacOS" flag is set in the team (or global) config. If so, mark the remaining setup experience items as canceled and cancel any upcoming activities related to those steps. 3. On the front-end, if the `require_all_software_macos` is set and a software step is marked as failed, show a new failure page indicating that setup has failed and showing details of the failed software. 4. On the agent side, when checking setup experience status, send a `reset_after_failure` flag _only the first time_. If this flag is set, then the code in the `/orbit/setup_experience/status` handler will clear and re-queue any failed setup experience steps (but leave successful steps to avoid re-installing already-installed software). This facilitates re-starting the setup experience when the host is rebooted. I also updated the way that software (packages and VPP) is queued up for the setup experience to be ordered alphabetically, to make it easier to test _and_ because this is a desired outcome for a future story. Since the order is not deterministic now, this update shouldn't cause any problems (aside from a couple of test updates), but I'm ok taking it out if desired. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [X] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) ## Testing - [X] Added/updated automated tests * Added a new integration test for software packages, testing that a failed software package causes the rest of the setup experience to be marked as failed when `require_all_software_macos` is set, and testing that the "reset after failure" code works. * Added a new integration test for VPP packages, testing that a failed VPP enqueue causes the same halting of the setup experience. I _don't_ have test for a failure _during_ a VPP install. It should go through the same code path as the software package failure, so it's not a huge gap. - [ ] QA'd all new/changed functionality manually Working on it ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [X] Verified that fleetd runs on macOS, Linux and Windows <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Configurable option to halt macOS device setup if any software install fails. - Device setup page now shows a clear “Device setup failed” state with expandable error details when all software is required on macOS. - Improvements - Setup status now includes per-step error messages for better troubleshooting. - Pending setup steps are automatically canceled after a failure when applicable, with support to reset and retry the setup flow as configured. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ian Littman <iansltx@gmail.com>
2025-10-17 13:38:53 +00:00
payload, err := s.orbitClient.GetSetupExperienceStatus(false)
if err != nil {
return err
}
if setupExperienceDone(payload) {
info.TimeFinished = ptr.Time(time.Now())
if err := WriteSetupExperienceStatusFile(s.rootDir, info); err != nil {
log.Error().Err(err).Msg("write setup experience status file")
}
}
return nil
}
func setupExperienceDone(payload *fleet.SetupExperienceStatusPayload) bool {
for _, software := range payload.Software {
if software != nil && (software.Status == fleet.SetupExperienceStatusPending || software.Status == fleet.SetupExperienceStatusRunning) {
return false
}
}
return true
}
// SetupExperienceInfo holds information of the state of the setup experience for a host.
type SetupExperienceInfo struct {
// TimeInitiated is the time the setup experience was attempted during setup/installation.
TimeInitiated time.Time `json:"time_initiated"`
// Enabled is true if the setup experience was enabled during setup/installation.
Enabled bool `json:"enabled"`
// TimeFinished is the time the setup experience was finished by the host.
TimeFinished *time.Time `json:"time_finished,omitempty"`
}
// ReadSetupExperienceStatusFile reads the setup experience state from a known file in the rootDir.
func ReadSetupExperienceStatusFile(rootDir string) (*SetupExperienceInfo, error) {
infoPath := filepath.Join(rootDir, constant.SetupExperienceFilename)
f, err := os.Open(infoPath)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("read setup experience file: %w", err)
}
defer f.Close()
var exp SetupExperienceInfo
if err := json.NewDecoder(f).Decode(&exp); err != nil {
return nil, fmt.Errorf("decoding setup experience file: %w", err)
}
return &exp, nil
}
// WriteSetupExperienceStatusFile writes the setup experience state to a file under rootDir.
func WriteSetupExperienceStatusFile(rootDir string, exp *SetupExperienceInfo) error {
infoPath := filepath.Join(rootDir, constant.SetupExperienceFilename)
f, err := os.OpenFile(infoPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, constant.DefaultFileMode)
if err != nil {
return fmt.Errorf("create setup experience completed file: %w", err)
}
defer f.Close()
if err := json.NewEncoder(f).Encode(exp); err != nil {
return fmt.Errorf("write setup experience completed file: %w", err)
}
return nil
}
Add macos web setup experience capability check (#34582) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #34596 # Details This PR adds back the "legacy" macOS setup experience, and a new `CapabilityMacOSWebSetupExperience` capability check. The legacy experience will be shown whenever the `CapabilityMacOSWebSetupExperience` capability is _not_ detected in the Fleet server response. The majority of the code is just copying the `Run` and `startSwiftDialog` from the [4.75.1 patch release](https://github.com/fleetdm/fleet/blob/rc-patch-fleet-v4.75.1/orbit/pkg/setup_experience/setup_experience.go) and adding them back as `RunLegacy` and `startSwiftDialogLegacy`, then adding the little bit of plumbing to have `Run()` call `RunLegacy()` when the new capability is not detected. # Checklist for submitter If some of the following don't apply, delete the relevant line. ## Testing - [ ] Added/updated automated tests - [ ] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [X] QA'd all new/changed functionality manually Tested on a VM that the setup experience starts in "legacy" mode if `CapabilityMacOSWebSetupExperience` is not set in the server, and that it starts in the new web view if the capability _is_ set. For unreleased bug fixes in a release candidate, one of: - [X] Confirmed that the fix is not expected to adversely impact load test results - [ ] Alerted the release DRI if additional load testing is needed ## fleetd/orbit/Fleet Desktop - [X] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [X] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [ ] Verified that fleetd runs on macOS, Linux and Windows I have not re-verified this, but the changes will only run on macOS - [ ] Verified auto-update works from the released version of component to the new version (see [tools/tuf/test](../tools/tuf/test/README.md)) This should not be affected.
2025-10-21 17:32:16 +00:00
func (s *SetupExperiencer) RunLegacy(oc *fleet.OrbitConfig) error {
const doneMessage = `### Setup is complete\n\nPlease contact your IT Administrator if there were any errors.`
if !oc.Notifications.RunSetupExperience {
log.Debug().Msg("skipping setup experience: notification flag is not set")
return nil
}
_, binaryPath, _ := update.LocalTargetPaths(
s.rootDirPath,
"swiftDialog",
update.SwiftDialogMacOSTarget,
)
if _, err := os.Stat(binaryPath); err != nil {
log.Info().Msg("skipping setup experience: swiftDialog is not installed")
return nil
}
log.Info().Msg("checking setup experience status")
// Poll the status endpoint. This also releases the device if we're done.
payload, err := s.OrbitClient.GetSetupExperienceStatus(false)
if err != nil {
return err
}
// If swiftDialog isn't up yet, then launch it
orgLogo := payload.OrgLogoURL
if orgLogo == "" {
orgLogo = "https://fleetdm.com/images/permanent/fleet-mark-color-40x40@4x.png"
}
if err := s.startSwiftDialogLegacy(binaryPath, orgLogo); err != nil {
return err
}
// Defer this so that s.started is only false the first time this function runs.
defer func() { s.started = true }()
select {
case <-s.closeChan:
log.Info().Str("receiver", "setup_experiencer").Msg("swiftDialog closed")
return nil
default:
// ok
}
// We're rendering the initial loading UI (shown while there are still profiles, bootstrap package,
// and account configuration to verify) right off the bat, so we can just no-op if any of those
// are not terminal
log.Info().Msg("setup experience: checking for pending statuses")
if payload.BootstrapPackage != nil {
if payload.BootstrapPackage.Status != fleet.MDMBootstrapPackageFailed && payload.BootstrapPackage.Status != fleet.MDMBootstrapPackageInstalled {
log.Info().Msg("setup experience: bootstrap package pending")
return nil
}
}
if isPending, name := anyProfilePending(payload.ConfigurationProfiles); isPending {
log.Info().Msg(fmt.Sprintf("setup experience: profile pending: %s", name))
return nil
}
if payload.AccountConfiguration != nil {
if payload.AccountConfiguration.Status != fleet.MDMAppleStatusAcknowledged &&
payload.AccountConfiguration.Status != fleet.MDMAppleStatusError &&
payload.AccountConfiguration.Status != fleet.MDMAppleStatusCommandFormatError {
log.Info().Msg("setup experience: account config pending")
return nil
}
}
// Note that we are setting this based on the current payload only just in case something
// was removed from the payload that was there earlier(e.g. a deleted software title).
allStepsDone := true
// Log the payload JSON
log.Debug().Msgf("setup experience: payload: %+v", payload)
// Now render the UI for the software and script.
if len(payload.Software) > 0 || payload.Script != nil {
log.Info().Msg("setup experience: rendering software and script UI")
var stepsDone int
var prog uint
var steps []*fleet.SetupExperienceStatusResult
if len(payload.Software) > 0 {
steps = payload.Software
}
if payload.Script != nil {
steps = append(steps, payload.Script)
}
// Check for any items that were in the payload that are no longer there. This can happen
// if a software title was deleted, for instance
for uiStepName, uiStep := range s.uiSteps {
uiStepExistsInPayload := false
for _, step := range steps {
if uiStep.Title == step.Name {
uiStepExistsInPayload = true
break
}
}
if !uiStepExistsInPayload {
log.Info().Msgf("Setup Experience: list item %s removed from payload", uiStep.Title)
err = s.sd.DeleteListItemByTitle(uiStep.Title)
if err != nil {
log.Info().Err(err).Msg("deleting list item removed from payload from setup experience UI")
}
delete(s.uiSteps, uiStepName)
}
}
for _, step := range steps {
currentStepState := resultToListItem(step)
if priorStepState, ok := s.uiSteps[step.Name]; ok {
if currentStepState != priorStepState {
// We only want to resend on change so we're not unnecessarily scrolling the UI
err = s.sd.UpdateListItemByTitle(currentStepState.Title, currentStepState.StatusText, currentStepState.Status)
if err != nil {
log.Info().Err(err).Msg("updating list item in setup experience UI")
}
} else {
log.Info().Msgf("setup experience: no change in status for %s", step.Name)
}
} else {
err = s.sd.AddListItem(currentStepState)
if err != nil {
log.Info().Err(err).Msg("adding list item in setup experience UI")
}
s.uiSteps[step.Name] = currentStepState
}
if step.Status == fleet.SetupExperienceStatusFailure || step.Status == fleet.SetupExperienceStatusSuccess {
stepsDone++
// The swiftDialog progress bar is out of 100
for range int(float32(1) / float32(len(steps)) * 100) {
prog++
}
} else {
allStepsDone = false
}
}
if err = s.sd.UpdateProgress(prog); err != nil {
log.Info().Err(err).Msg("updating progress bar in setup experience UI")
}
if err := s.sd.ShowList(); err != nil {
log.Info().Err(err).Msg("showing progress bar in setup experience UI")
}
if err := s.sd.UpdateProgressText(fmt.Sprintf("%.0f%%", float32(stepsDone)/float32(len(steps))*100)); err != nil {
log.Info().Err(err).Msg("updating progress text in setup experience UI")
}
}
// If we get here, we can render the "done" UI.
if allStepsDone {
if err := s.sd.SetMessage(doneMessage); err != nil {
log.Info().Err(err).Msg("setting message in setup experience UI")
}
if err := s.sd.CompleteProgress(); err != nil {
log.Info().Err(err).Msg("completing progress bar in setup experience UI")
}
if len(payload.Software) > 0 || payload.Script != nil {
// need to call this because SetMessage removes the list from the view for some reason :(
if err := s.sd.ShowList(); err != nil {
log.Info().Err(err).Msg("showing list in setup experience UI")
}
}
if err := s.sd.UpdateProgressText("100%"); err != nil {
log.Info().Err(err).Msg("updating progress text in setup experience UI")
}
if err := s.sd.EnableButton1(true); err != nil {
log.Info().Err(err).Msg("enabling close button in setup experience UI")
}
// Sleep for a few seconds to let the user see the done message before closing
// the UI
time.Sleep(3 * time.Second)
if err := s.sd.Quit(); err != nil {
log.Info().Err(err).Msg("quitting setup experience UI on completion")
}
}
return nil
}
func (s *SetupExperiencer) startSwiftDialogLegacy(binaryPath, orgLogo string) error {
if s.started {
log.Info().Msg("swiftDialog started")
return nil
}
log.Info().Msg("creating swiftDialog instance")
created := make(chan struct{})
swiftDialog, err := swiftdialog.Create(context.Background(), binaryPath)
if err != nil {
return errors.New("creating swiftDialog instance: %w")
}
s.sd = swiftDialog
iconSize, err := swiftdialog.GetIconSize(orgLogo)
if err != nil {
log.Error().Err(err).Msg("setup experience: getting icon size")
iconSize = swiftdialog.DefaultIconSize
}
go func() {
initOpts := &swiftdialog.SwiftDialogOptions{
Title: "none",
Message: "### Setting up your Mac...\n\nYour Mac is being configured by your organization using Fleet. This process may take some time to complete. Please don't attempt to restart or shut down the computer unless prompted to do so.",
Icon: orgLogo,
MessageAlignment: swiftdialog.AlignmentCenter,
CentreIcon: true,
Height: "625",
Big: true,
ProgressText: "Configuring your device...",
Button1Text: "Close",
Button1Disabled: true,
BlurScreen: true,
OnTop: true,
QuitKey: "X", // Capital X to require command+shift+x
}
if err := s.sd.Start(context.Background(), initOpts, true); err != nil {
log.Error().Err(err).Msg("starting swiftDialog instance")
}
if err = s.sd.ShowProgress(); err != nil {
log.Error().Err(err).Msg("setting initial setup experience progress")
}
if err := s.sd.SetIconSize(iconSize); err != nil {
log.Error().Err(err).Msg("setting initial setup experience icon size")
}
log.Debug().Msg("swiftDialog process started")
created <- struct{}{}
if _, err = s.sd.Wait(); err != nil {
log.Error().Err(err).Msg("swiftdialog.Wait failed")
}
s.closeChan <- struct{}{}
}()
<-created
return nil
}
func resultToListItem(result *fleet.SetupExperienceStatusResult) swiftdialog.ListItem {
statusText := "Pending"
status := swiftdialog.StatusWait
switch result.Status {
case fleet.SetupExperienceStatusFailure:
status = swiftdialog.StatusFail
statusText = "Failed"
case fleet.SetupExperienceStatusSuccess:
status = swiftdialog.StatusSuccess
statusText = "Installed"
if result.IsForScript() {
statusText = "Ran"
}
}
return swiftdialog.ListItem{
Title: result.Name,
Status: status,
StatusText: statusText,
}
}