fleet/server/datastore/mysql/setup_experience.go

913 lines
30 KiB
Go
Raw Normal View History

package mysql
import (
"context"
"database/sql"
"errors"
2024-10-08 20:41:57 +00:00
"fmt"
"slices"
"strings"
Don't run setup experience on host that was previously enrolled (#38318) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35717 # Details This PR adds a check before enqueuing setup experience items, so that if the specified host has already been enrolled for > 24 hours we skip the setup experience. This handles the edge case where an enrolled host upgrades from an Orbit version that didn't support setup experience to one that does. # 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 - [X] QA'd all new/changed functionality manually I didn't go through the process of getting a 1.48.1 fleetd installation on my VM, but I tested in this way: 1. Installed fleetd on a host to a team with no setup experience items 2. Manually adjusted the `last_enrolled_at` date of that host's db record to be > 24 hours in the past. 3. After enrollment, added setup experience items to that team. No setup window popped up (expected). 4. Deleted the `setup_experience.json` file on that host and restarted Orbit. 5. On `main` branch, the setup experience window popped up. When repeating these steps on this branch, no window popped up. 6. Also verified that for a new enrollment wiht `last_enrolled_at` in the last 24 hours, the setup experience window popped up as expected.
2026-01-28 14:44:42 +00:00
"time"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
Don't run setup experience on host that was previously enrolled (#38318) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35717 # Details This PR adds a check before enqueuing setup experience items, so that if the specified host has already been enrolled for > 24 hours we skip the setup experience. This handles the edge case where an enrolled host upgrades from an Orbit version that didn't support setup experience to one that does. # 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 - [X] QA'd all new/changed functionality manually I didn't go through the process of getting a 1.48.1 fleetd installation on my VM, but I tested in this way: 1. Installed fleetd on a host to a team with no setup experience items 2. Manually adjusted the `last_enrolled_at` date of that host's db record to be > 24 hours in the past. 3. After enrollment, added setup experience items to that team. No setup window popped up (expected). 4. Deleted the `setup_experience.json` file on that host and restarted Orbit. 5. On `main` branch, the setup experience window popped up. When repeating these steps on this branch, no window popped up. 6. Also verified that for a new enrollment wiht `last_enrolled_at` in the last 24 hours, the setup experience window popped up as expected.
2026-01-28 14:44:42 +00:00
"github.com/go-kit/log/level"
"github.com/jmoiron/sqlx"
)
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
func (ds *Datastore) EnqueueSetupExperienceItems(ctx context.Context, hostPlatformLike string, hostUUID string, teamID uint) (bool, error) {
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
return ds.enqueueSetupExperienceItems(ctx, hostPlatformLike, hostUUID, teamID, false)
}
func (ds *Datastore) ResetSetupExperienceItemsAfterFailure(ctx context.Context, hostPlatformLike string, hostUUID string, teamID uint) (bool, error) {
return ds.enqueueSetupExperienceItems(ctx, hostPlatformLike, hostUUID, teamID, true)
}
func (ds *Datastore) enqueueSetupExperienceItems(ctx context.Context, hostPlatformLike string, hostUUID string, teamID uint, resetFailedSetupSteps bool) (bool, error) {
Don't run setup experience on host that was previously enrolled (#38318) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35717 # Details This PR adds a check before enqueuing setup experience items, so that if the specified host has already been enrolled for > 24 hours we skip the setup experience. This handles the edge case where an enrolled host upgrades from an Orbit version that didn't support setup experience to one that does. # 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 - [X] QA'd all new/changed functionality manually I didn't go through the process of getting a 1.48.1 fleetd installation on my VM, but I tested in this way: 1. Installed fleetd on a host to a team with no setup experience items 2. Manually adjusted the `last_enrolled_at` date of that host's db record to be > 24 hours in the past. 3. After enrollment, added setup experience items to that team. No setup window popped up (expected). 4. Deleted the `setup_experience.json` file on that host and restarted Orbit. 5. On `main` branch, the setup experience window popped up. When repeating these steps on this branch, no window popped up. 6. Also verified that for a new enrollment wiht `last_enrolled_at` in the last 24 hours, the setup experience window popped up as expected.
2026-01-28 14:44:42 +00:00
// Find the host with the given UUID and platform. If it's already been enrolled for > the cutoff,
// don't enqueue any items. This handles the edge case where an enrolled host upgrades from an
// Orbit version that didn't support setup experience to one that does.
// See https://github.com/fleetdm/fleet/issues/35717
stmtHost := `
SELECT
last_enrolled_at
FROM
hosts
WHERE uuid = ? AND platform = ?
`
var lastEnrolledAt sql.NullTime
if err := sqlx.GetContext(ctx, ds.reader(ctx), &lastEnrolledAt, stmtHost, hostUUID, hostPlatformLike); err != nil {
if errors.Is(err, sql.ErrNoRows) {
// This shouldn't happen but we don't check for it elsewhere,
// so we'll log a warning and continue.
level.Warn(ds.logger).Log("msg", "Host not found while enqueueing setup experience items", "host_uuid", hostUUID, "platform_like", hostPlatformLike)
} else {
return false, ctxerr.Wrap(ctx, err, "finding host for enqueueing setup experience items")
}
}
// If the host was enrolled more than 24 hours ago, don't enqueue any items.
// Note: if the last enroll date is our "zero date" (1/1/2000), treat it as if it's never enrolled.
if lastEnrolledAt.Valid && lastEnrolledAt.Time.Before(time.Now().Add(-24*time.Hour)) && lastEnrolledAt.Time.After(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)) {
level.Debug(ds.logger).Log("msg", "Host enrolled more than 24 hours ago, skipping enqueueing setup experience items", "host_uuid", hostUUID, "platform_like", hostPlatformLike, "last_enrolled_at", lastEnrolledAt.Time)
return false, nil
}
// NOTE: currently, the Android platform does not use the "enqueue setup experience items" flow as it
// doesn't support any on-device UI (such as the screen showing setup progress) nor any
// ordering of installs - all software to install is provided as part of the Android policy
// when the host enrolls in Fleet.
// See https://github.com/fleetdm/fleet/issues/33761#issuecomment-3548996114
stmtClearSetupStatus := `
DELETE FROM setup_experience_status_results
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
WHERE host_uuid = ? AND %s`
if resetFailedSetupSteps {
stmtClearSetupStatus = fmt.Sprintf(stmtClearSetupStatus, "status != 'success'")
} else {
stmtClearSetupStatus = fmt.Sprintf(stmtClearSetupStatus, "TRUE")
}
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
// stmtSoftwareInstallers query currently supports installers for macOS and Linux.
stmtSoftwareInstallers := `
INSERT INTO setup_experience_status_results (
host_uuid,
name,
status,
software_installer_id
) SELECT
?,
st.name,
'pending',
si.id
FROM software_installers si
INNER JOIN software_titles st
ON si.title_id = st.id
WHERE install_during_setup = true
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
AND global_or_team_id = ?
AND (
-- installer platform matches the host's fleet platform (darwin, linux or windows)
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
si.platform = ?
AND
(
-- platform is 'darwin' or 'windows', so nothing else to check.
(si.platform = 'darwin' OR si.platform = 'windows')
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
-- platform is 'linux', so we must check if the installer is compatible with the linux distribution.
OR
(
-- tar.gz and sh can be installed on any Linux distribution
(si.extension = 'tar.gz' OR si.extension = 'sh')
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
OR
(
-- deb packages can only be installed on Debian-based hosts.
(si.extension = 'deb' AND ? = 'debian')
OR
-- rpm packages can only be installed on RHEL-based hosts.
(si.extension = 'rpm' AND ? = 'rhel')
)
)
)
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
)
AND %s ORDER BY st.name ASC
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 resetFailedSetupSteps {
stmtSoftwareInstallers = fmt.Sprintf(stmtSoftwareInstallers, "si.id NOT IN (SELECT software_installer_id FROM setup_experience_status_results WHERE host_uuid = ? AND status = 'success' AND software_installer_id IS NOT NULL)")
} else {
stmtSoftwareInstallers = fmt.Sprintf(stmtSoftwareInstallers, "TRUE")
}
stmtVPPApps := `
INSERT INTO setup_experience_status_results (
host_uuid,
name,
status,
vpp_app_team_id
) SELECT
?,
st.name,
'pending',
vat.id
FROM vpp_apps va
INNER JOIN vpp_apps_teams vat
ON vat.adam_id = va.adam_id
AND vat.platform = va.platform
INNER JOIN software_titles st
ON va.title_id = st.id
WHERE vat.install_during_setup = true
AND vat.global_or_team_id = ?
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
AND va.platform = ?
AND %s
ORDER BY st.name ASC
`
if resetFailedSetupSteps {
stmtVPPApps = fmt.Sprintf(stmtVPPApps, "vat.id NOT IN (SELECT vpp_app_team_id FROM setup_experience_status_results WHERE host_uuid = ? AND status = 'success' AND vpp_app_team_id IS NOT NULL)")
} else {
stmtVPPApps = fmt.Sprintf(stmtVPPApps, "TRUE")
}
stmtSetupScripts := `
INSERT INTO setup_experience_status_results (
host_uuid,
name,
status,
setup_experience_script_id
) SELECT
?,
name,
'pending',
id
FROM setup_experience_scripts
WHERE global_or_team_id = ?`
var totalInsertions uint
if err := ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
totalInsertions = 0 // reset for each attempt
// Clean out old statuses for the host
if _, err := tx.ExecContext(ctx, stmtClearSetupStatus, hostUUID); err != nil {
return ctxerr.Wrap(ctx, err, "removing stale setup experience entries")
}
// Software installers
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
fleetPlatform := fleet.PlatformFromHost(hostPlatformLike)
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
args := []any{hostUUID, teamID, fleetPlatform, hostPlatformLike, hostPlatformLike}
if resetFailedSetupSteps {
args = append(args, hostUUID)
}
if fleetPlatform != "ios" && fleetPlatform != "ipados" {
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
res, err := tx.ExecContext(ctx, stmtSoftwareInstallers, args...)
if err != nil {
return ctxerr.Wrap(ctx, err, "inserting setup experience software installers")
}
inserts, err := res.RowsAffected()
if err != nil {
return ctxerr.Wrap(ctx, err, "retrieving number of inserted software installers")
}
totalInsertions += uint(inserts) // nolint: gosec
}
// VPP apps
if fleetPlatform == "darwin" || fleetPlatform == "ios" || fleetPlatform == "ipados" {
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
args := []any{hostUUID, teamID, fleetPlatform}
if resetFailedSetupSteps {
args = append(args, hostUUID)
}
res, err := tx.ExecContext(ctx, stmtVPPApps, args...)
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if err != nil {
return ctxerr.Wrap(ctx, err, "inserting setup experience vpp apps")
}
inserts, err := res.RowsAffected()
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if err != nil {
return ctxerr.Wrap(ctx, err, "retrieving number of inserted vpp apps")
}
totalInsertions += uint(inserts) // nolint: gosec
}
// Scripts
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if fleetPlatform == "darwin" {
res, err := tx.ExecContext(ctx, stmtSetupScripts, hostUUID, teamID)
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if err != nil {
return ctxerr.Wrap(ctx, err, "inserting setup experience scripts")
}
inserts, err := res.RowsAffected()
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if err != nil {
return ctxerr.Wrap(ctx, err, "retrieving number of inserted setup experience scripts")
}
totalInsertions += uint(inserts) // nolint: gosec
}
// Set setup experience on Apple hosts only if they have something configured.
if fleetPlatform == "darwin" || fleetPlatform == "ios" || fleetPlatform == "ipados" {
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if totalInsertions > 0 {
if err := setHostAwaitingConfiguration(ctx, tx, hostUUID, true); err != nil {
return ctxerr.Wrap(ctx, err, "setting host awaiting configuration to true")
}
}
}
return nil
}); err != nil {
return false, ctxerr.Wrap(ctx, err, "enqueue setup experience")
}
return totalInsertions > 0, nil
}
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
func (ds *Datastore) SetSetupExperienceSoftwareTitles(ctx context.Context, platform string, teamID uint, titleIDs []uint) error {
switch platform {
case string(fleet.MacOSPlatform),
string(fleet.IOSPlatform),
string(fleet.IPadOSPlatform),
string(fleet.AndroidPlatform),
"windows",
"linux":
// ok, valid platform
default:
return ctxerr.Errorf(ctx, "platform %q is not supported, only %q, %q, %q, %q, \"windows\", or \"linux\" platforms are supported",
platform, fleet.MacOSPlatform, fleet.IOSPlatform, fleet.IPadOSPlatform, fleet.AndroidPlatform)
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
}
2024-10-08 20:41:57 +00:00
titleIDQuestionMarks := strings.Join(slices.Repeat([]string{"?"}, len(titleIDs)), ",")
stmtSelectInstallersIDs := fmt.Sprintf(`
SELECT
st.id AS title_id,
si.id,
st.name,
si.platform
FROM
software_titles st
LEFT JOIN
software_installers si
ON st.id = si.title_id
WHERE
si.global_or_team_id = ?
AND
st.id IN (%s)
`, titleIDQuestionMarks)
stmtSelectVPPAppsTeamsID := fmt.Sprintf(`
SELECT
st.id AS title_id,
vat.id,
st.name,
vat.platform
FROM
software_titles st
LEFT JOIN
vpp_apps va
ON st.id = va.title_id
LEFT JOIN
vpp_apps_teams vat
ON va.adam_id = vat.adam_id AND va.platform = vat.platform
2024-10-08 20:41:57 +00:00
WHERE
vat.global_or_team_id = ?
AND
st.id IN (%s)
AND va.platform IN ('darwin', 'ios', 'ipados', 'android')
2024-10-08 20:41:57 +00:00
`, titleIDQuestionMarks)
stmtUnsetInstallers := `
UPDATE software_installers
SET install_during_setup = false
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
WHERE platform = ? AND global_or_team_id = ?`
2024-10-08 20:41:57 +00:00
stmtUnsetVPPAppsTeams := `
UPDATE vpp_apps_teams vat
SET install_during_setup = false
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
WHERE platform = ? AND global_or_team_id = ?`
2024-10-08 20:41:57 +00:00
stmtSetInstallers := `
UPDATE software_installers
SET install_during_setup = true
WHERE id IN (%s)`
stmtSetVPPAppsTeams := `
UPDATE vpp_apps_teams
SET install_during_setup = true
WHERE id IN (%s)`
if err := ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
var softwareIDPlatforms []idPlatformTuple
var softwareIDs []any
var vppIDPlatforms []idPlatformTuple
var vppAppTeamIDs []any
// List of title IDs that were sent but aren't in the
// database. We add everything and then remove them
// from the list when we validate them below
2024-10-08 20:41:57 +00:00
missingTitleIDs := make(map[uint]struct{})
// Arguments used for queries that select vpp apps/installers
2024-10-08 20:41:57 +00:00
titleIDAndTeam := []any{teamID}
for _, id := range titleIDs {
missingTitleIDs[id] = struct{}{}
titleIDAndTeam = append(titleIDAndTeam, id)
}
// Select requested software installers
if platform != string(fleet.IOSPlatform) && platform != string(fleet.IPadOSPlatform) && platform != string(fleet.AndroidPlatform) {
if len(titleIDs) > 0 {
if err := sqlx.SelectContext(ctx, tx, &softwareIDPlatforms, stmtSelectInstallersIDs, titleIDAndTeam...); err != nil {
return ctxerr.Wrap(ctx, err, "selecting software IDs using title IDs")
}
}
2024-10-08 20:41:57 +00:00
// Validate software titles match the expected platform.
for _, tuple := range softwareIDPlatforms {
delete(missingTitleIDs, tuple.TitleID)
if tuple.Platform != platform {
return ctxerr.Wrap(ctx, &fleet.BadRequestError{
Message: fmt.Sprintf("invalid platform for requested software installer: %d (%s, %s), vs. expected %s", tuple.ID, tuple.Name, tuple.Platform, platform),
})
}
softwareIDs = append(softwareIDs, tuple.ID)
2024-10-08 20:41:57 +00:00
}
}
// Select requested VPP apps
if platform == string(fleet.MacOSPlatform) || platform == string(fleet.IOSPlatform) || platform == string(fleet.IPadOSPlatform) ||
platform == string(fleet.AndroidPlatform) {
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if len(titleIDs) > 0 {
if err := sqlx.SelectContext(ctx, tx, &vppIDPlatforms, stmtSelectVPPAppsTeamsID, titleIDAndTeam...); err != nil {
return ctxerr.Wrap(ctx, err, "selecting vpp app team IDs using title IDs")
}
}
2024-10-08 20:41:57 +00:00
// Validate VPP app platforms
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
for _, tuple := range vppIDPlatforms {
delete(missingTitleIDs, tuple.TitleID)
if tuple.Platform != platform {
return ctxerr.Wrap(ctx, &fleet.BadRequestError{
Message: fmt.Sprintf("invalid platform for requested AppStoreApp title: %d (%s, %s), vs. expected %s", tuple.ID, tuple.Name, tuple.Platform, platform),
})
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
}
vppAppTeamIDs = append(vppAppTeamIDs, tuple.ID)
2024-10-08 20:41:57 +00:00
}
}
// If we have any missing titles, return error
2024-10-08 20:41:57 +00:00
if len(missingTitleIDs) > 0 {
var keys []string
for k := range missingTitleIDs {
keys = append(keys, fmt.Sprintf("%d", k))
}
err := &fleet.BadRequestError{
Message: "at least one selected software title does not exist or is not available for setup experience",
}
return ctxerr.Wrapf(ctx, err, "title IDs not available: %s", strings.Join(keys, ","))
2024-10-08 20:41:57 +00:00
}
// Unset all installers
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if _, err := tx.ExecContext(ctx, stmtUnsetInstallers, platform, teamID); err != nil {
2024-10-08 20:41:57 +00:00
return ctxerr.Wrap(ctx, err, "unsetting software installers")
}
// Unset all vpp apps
if platform == string(fleet.MacOSPlatform) || platform == string(fleet.IOSPlatform) ||
platform == string(fleet.IPadOSPlatform) || platform == string(fleet.AndroidPlatform) {
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
if _, err := tx.ExecContext(ctx, stmtUnsetVPPAppsTeams, platform, teamID); err != nil {
return ctxerr.Wrap(ctx, err, "unsetting vpp app teams")
}
2024-10-08 20:41:57 +00:00
}
if len(softwareIDs) > 0 {
stmtSetInstallersLoop := fmt.Sprintf(stmtSetInstallers, questionMarks(len(softwareIDs)))
if _, err := tx.ExecContext(ctx, stmtSetInstallersLoop, softwareIDs...); err != nil {
return ctxerr.Wrap(ctx, err, "setting software installers")
}
}
if (platform == string(fleet.MacOSPlatform) || platform == string(fleet.IOSPlatform) ||
platform == string(fleet.IPadOSPlatform) || platform == string(fleet.AndroidPlatform)) && len(vppAppTeamIDs) > 0 {
2024-10-08 20:41:57 +00:00
stmtSetVPPAppsTeamsLoop := fmt.Sprintf(stmtSetVPPAppsTeams, questionMarks(len(vppAppTeamIDs)))
if _, err := tx.ExecContext(ctx, stmtSetVPPAppsTeamsLoop, vppAppTeamIDs...); err != nil {
return ctxerr.Wrap(ctx, err, "setting vpp app teams")
}
}
return nil
}); err != nil {
return ctxerr.Wrap(ctx, err, "setting setup experience software")
}
return nil
}
func (ds *Datastore) GetSetupExperienceCount(ctx context.Context, platform string, teamID *uint) (*fleet.SetupExperienceCount, error) {
stmt := `
SELECT
(
SELECT COUNT(*)
FROM software_installers
WHERE team_id = ?
AND install_during_setup = 1
AND platform = ?
) AS installers,
(
SELECT COUNT(*)
FROM vpp_apps_teams
WHERE team_id = ?
AND platform = ?
AND install_during_setup = 1
) AS vpp,
(
SELECT COUNT(*)
FROM setup_experience_scripts
WHERE team_id = ?
) AS scripts`
sec := &fleet.SetupExperienceCount{}
if err := sqlx.GetContext(
ctx, ds.reader(ctx), sec, stmt,
teamID, platform,
teamID, platform,
teamID,
); err != nil {
return nil, ctxerr.Wrap(ctx, err, "selecting setup experience counts")
}
// Only macOS supports scripts during setup experience currently
if platform != string(fleet.MacOSPlatform) {
sec.Scripts = 0
}
return sec, nil
}
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
func (ds *Datastore) ListSetupExperienceSoftwareTitles(ctx context.Context, platform string, teamID uint, opts fleet.ListOptions) ([]fleet.SoftwareTitleListResult, int, *fleet.PaginationMetadata, error) {
// I believe this can be removed, as the platforms are validated before this function
for p := range strings.SplitSeq(strings.ReplaceAll(platform, "macos", "darwin"), ",") {
switch p {
case string(fleet.MacOSPlatform),
string(fleet.IOSPlatform),
string(fleet.IPadOSPlatform),
string(fleet.AndroidPlatform),
"windows",
"linux":
// ok, valid platform
default:
return nil, 0, nil, ctxerr.Errorf(ctx, "platform %q is not supported, only %q, %q, %q, %q, \"windows\", or \"linux\" platforms are supported",
p, fleet.MacOSPlatform, fleet.IOSPlatform, fleet.AndroidPlatform, fleet.IPadOSPlatform)
}
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
}
2024-10-08 20:41:57 +00:00
opts.IncludeMetadata = true
opts.After = ""
titles, count, meta, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
TeamID: &teamID,
ListOptions: opts,
API endpoints for Linux setup experience (#32493) For #32040. --- Backend changes to unblock the development of the orbit and frontend changes. New GET and PUT APIs for setting/getting software for Linux Setup Experience: ``` curl -k -X GET -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software?team_id=8&per_page=3000 curl -k -X PUT -H "Authorization: Bearer $TEST_TOKEN" https://localhost:8080/api/latest/fleet/setup_experience/linux/software -d '{"team_id":8,"software_title_ids":[3000, 3001, 3007]}' ``` New setup_experience/init API called by orbit to trigger the Linux setup experience on the device: ``` curl -v -k -X POST -H "Content-Type: application/json" "https://localhost:8080/api/fleet/orbit/setup_experience/init" -d '{"orbit_node_key": "ynYEtFsvv9xZ7rX619UE8of1I28H+GCj"}' ``` Get status API to call on "My device": ``` curl -v -k -X POST "https://localhost:8080/api/latest/fleet/device/7d940b6e-130a-493b-b58a-2b6e9f9f8bfc/setup_experience/status" ``` --- - [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 - [X] 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 ## New Fleet configuration settings - [X] Verified that the setting is exported via `fleetctl generate-gitops` - [X] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [X] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Added Linux support for Setup Experience alongside macOS. - Introduced platform-specific admin APIs to configure and retrieve Setup Experience software (macOS/Linux). - Added device API to report Setup Experience status and an Orbit API to initialize Setup Experience on non-macOS devices. - Setup Experience now gates policy queries on Linux until setup is complete. - New activity log entry when Setup Experience software is edited (includes platform and team). - Documentation - Updated audit logs reference to include the new “edited setup experience software” event. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-09-04 15:58:47 +00:00
Platform: platform,
AvailableForInstall: true,
ForSetupExperience: true,
2024-10-08 20:41:57 +00:00
}, fleet.TeamFilter{
IncludeObserver: true,
TeamID: &teamID,
})
if err != nil {
return nil, 0, nil, ctxerr.Wrap(ctx, err, "calling list software titles")
}
return titles, count, meta, nil
}
type idPlatformTuple struct {
ID uint `db:"id"`
TitleID uint `db:"title_id"`
Name string `db:"name"`
Platform string `db:"platform"`
}
func questionMarks(number int) string {
return strings.Join(slices.Repeat([]string{"?"}, number), ",")
}
func (ds *Datastore) ListSetupExperienceResultsByHostUUID(ctx context.Context, hostUUID string) ([]*fleet.SetupExperienceStatusResult, error) {
const stmt = `
2024-10-08 20:41:57 +00:00
SELECT
sesr.id,
sesr.host_uuid,
sesr.name,
sesr.status,
sesr.software_installer_id,
sesr.host_software_installs_execution_id,
2024-10-08 20:41:57 +00:00
sesr.vpp_app_team_id,
sesr.nano_command_uuid,
sesr.setup_experience_script_id,
sesr.script_execution_id,
NULLIF(va.adam_id, '') AS vpp_app_adam_id,
NULLIF(va.platform, '') AS vpp_app_platform,
ses.script_content_id,
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
COALESCE(si.title_id, COALESCE(va.title_id, NULL)) AS software_title_id,
COALESCE(
(SELECT source FROM software_titles WHERE id = si.title_id),
(SELECT source FROM software_titles WHERE id = va.title_id)
) AS source,
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
CASE
WHEN hsi.execution_status = 'failed_install' THEN
CASE
WHEN post_install_script_exit_code IS NOT NULL AND post_install_script_exit_code != 0 THEN COALESCE(post_install_script_output, 'Unknown error in post-install script')
WHEN install_script_exit_code IS NOT NULL AND install_script_exit_code != 0 THEN COALESCE(install_script_output, 'Unknown error in install script')
WHEN pre_install_query_output IS NULL OR pre_install_query_output = '' THEN 'Pre-install query failed'
ELSE 'Installation failed'
END
WHEN hsr.exit_code IS NOT NULL AND hsr.exit_code != 0 THEN COALESCE(hsr.output, 'Unknown error in script')
ELSE sesr.error
END AS error
FROM setup_experience_status_results sesr
LEFT JOIN setup_experience_scripts ses ON ses.id = sesr.setup_experience_script_id
LEFT JOIN software_installers si ON si.id = sesr.software_installer_id
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
LEFT JOIN host_software_installs hsi ON hsi.execution_id = sesr.host_software_installs_execution_id
LEFT JOIN host_script_results hsr ON hsr.execution_id = sesr.script_execution_id
LEFT JOIN vpp_apps_teams vat ON vat.id = sesr.vpp_app_team_id
LEFT JOIN vpp_apps va ON vat.adam_id = va.adam_id AND vat.platform = va.platform
WHERE host_uuid = ?
`
var results []*fleet.SetupExperienceStatusResult
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &results, stmt, hostUUID); err != nil {
return nil, ctxerr.Wrap(ctx, err, "select setup experience status results by host uuid")
}
titleIDs := make([]uint, 0, len(results))
byTitleID := make(map[uint]*fleet.SetupExperienceStatusResult, len(results))
for _, res := range results {
if res.SoftwareTitleID != nil {
titleIDs = append(titleIDs, *res.SoftwareTitleID)
byTitleID[*res.SoftwareTitleID] = res
}
}
// load custom display name and custom icon for the software installers, if any
if len(titleIDs) > 0 {
// NOTE: as documented in fleet.HostUUIDForSetupExperience, the setup experience "host_uuid"
// is NOT always the host.uuid (on Windows and Linux, specifically). So if the host's team is
// not found, we simply don't load the icons and display names, anyway we only need those
// on macOS currently as it's the only place where the setup experience UI is shown.
// we need the host's team to load the custom icons and display names
const hostTeam = `SELECT team_id FROM hosts WHERE uuid = ? LIMIT 1`
var hostTeamID sql.Null[uint]
if err := sqlx.GetContext(ctx, ds.reader(ctx), &hostTeamID, hostTeam, hostUUID); err != nil {
if errors.Is(err, sql.ErrNoRows) {
// host not found, skip loading icons and display names
return results, nil
}
return nil, ctxerr.Wrap(ctx, err, "get host team ID for setup experience results")
}
icons, err := ds.GetSoftwareIconsByTeamAndTitleIds(ctx, hostTeamID.V, titleIDs)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "get software icons by team and title IDs")
}
displayNames, err := ds.getDisplayNamesByTeamAndTitleIds(ctx, hostTeamID.V, titleIDs)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "get software display names by team and title IDs")
}
for titleID, icon := range icons {
if res := byTitleID[titleID]; res != nil {
res.IconURL = icon.IconUrl()
}
}
for titleID, name := range displayNames {
if res := byTitleID[titleID]; res != nil {
res.DisplayName = name
}
}
}
return results, nil
}
func (ds *Datastore) UpdateSetupExperienceStatusResult(ctx context.Context, status *fleet.SetupExperienceStatusResult) error {
const stmt = `
UPDATE setup_experience_status_results
SET
host_uuid = ?,
name = ?,
status = ?,
software_installer_id = ?,
host_software_installs_execution_id = ?,
vpp_app_team_id = ?,
nano_command_uuid = ?,
setup_experience_script_id = ?,
script_execution_id = ?,
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
error = LEFT(?, 255)
WHERE id = ?
`
if err := status.IsValid(); err != nil {
return ctxerr.Wrap(ctx, err, "invalid status update")
}
if _, err := ds.writer(ctx).ExecContext(
ctx,
stmt,
status.HostUUID,
status.Name,
status.Status,
status.SoftwareInstallerID,
status.HostSoftwareInstallsExecutionID,
status.VPPAppTeamID,
status.NanoCommandUUID,
status.SetupExperienceScriptID,
status.ScriptExecutionID,
status.Error,
status.ID,
); err != nil {
return ctxerr.Wrap(ctx, err, "updating setup experience status result")
}
return nil
}
func (ds *Datastore) GetSetupExperienceScript(ctx context.Context, teamID *uint) (*fleet.Script, error) {
Add PUT endpoint for setup experience script (#35651) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35309 Related doc update #35736 Adds a PUT endpoint for setting setup experience scripts, as opposed to the current POST implementation(which errors if the script is already set, which is why gitops calls DELETE first every time). If the contents change, the new endpoint has the same effect as DELETE then POST today, however if the contents are unchanged no changes occur, allowing gitops runs to avoid cancelling script executions. Also switched gitops over to the new PUT endpoint and removed the DELETE in the "set" path. # 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) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] 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) - [ ] QA'd all new/changed functionality manually
2025-11-14 15:22:36 +00:00
return ds.getSetupExperienceScript(ctx, ds.reader(ctx), teamID)
}
func (ds *Datastore) getSetupExperienceScript(ctx context.Context, q sqlx.QueryerContext, teamID *uint) (*fleet.Script, error) {
query := `
SELECT
id,
team_id,
name,
script_content_id,
created_at,
updated_at
FROM
setup_experience_scripts
WHERE
global_or_team_id = ?
`
var globalOrTeamID uint
if teamID != nil {
globalOrTeamID = *teamID
}
var script fleet.Script
Add PUT endpoint for setup experience script (#35651) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35309 Related doc update #35736 Adds a PUT endpoint for setting setup experience scripts, as opposed to the current POST implementation(which errors if the script is already set, which is why gitops calls DELETE first every time). If the contents change, the new endpoint has the same effect as DELETE then POST today, however if the contents are unchanged no changes occur, allowing gitops runs to avoid cancelling script executions. Also switched gitops over to the new PUT endpoint and removed the DELETE in the "set" path. # 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) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] 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) - [ ] QA'd all new/changed functionality manually
2025-11-14 15:22:36 +00:00
if err := sqlx.GetContext(ctx, q, &script, query, globalOrTeamID); err != nil {
if err == sql.ErrNoRows {
return nil, ctxerr.Wrap(ctx, notFound("SetupExperienceScript"), "get setup experience script")
}
return nil, ctxerr.Wrap(ctx, err, "get setup experience script")
}
return &script, nil
}
func (ds *Datastore) GetSetupExperienceScriptByID(ctx context.Context, scriptID uint) (*fleet.Script, error) {
query := `
SELECT
id,
team_id,
name,
script_content_id,
created_at,
updated_at
FROM
setup_experience_scripts
WHERE
id = ?
`
var script fleet.Script
if err := sqlx.GetContext(ctx, ds.reader(ctx), &script, query, scriptID); err != nil {
if err == sql.ErrNoRows {
return nil, ctxerr.Wrap(ctx, notFound("SetupExperienceScript"), "get setup experience script by id")
}
return nil, ctxerr.Wrap(ctx, err, "get setup experience script by id")
}
return &script, nil
}
func (ds *Datastore) SetSetupExperienceScript(ctx context.Context, script *fleet.Script) error {
err := ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
var err error
// first insert script contents
scRes, err := insertScriptContents(ctx, tx, script.ScriptContents)
if err != nil {
return err
}
id, _ := scRes.LastInsertId()
// This clause allows for PUT semantics. The basic idea is:
Add PUT endpoint for setup experience script (#35651) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35309 Related doc update #35736 Adds a PUT endpoint for setting setup experience scripts, as opposed to the current POST implementation(which errors if the script is already set, which is why gitops calls DELETE first every time). If the contents change, the new endpoint has the same effect as DELETE then POST today, however if the contents are unchanged no changes occur, allowing gitops runs to avoid cancelling script executions. Also switched gitops over to the new PUT endpoint and removed the DELETE in the "set" path. # 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) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] 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) - [ ] QA'd all new/changed functionality manually
2025-11-14 15:22:36 +00:00
// - no existing setup script -> go through the usual insert logic
// - existing setup script with different content -> delete(with all side effects) and re-insert
// - existing setup script with same content -> no-op
gotSetupExperienceScript, err := ds.getSetupExperienceScript(ctx, tx, script.TeamID)
if err != nil && !fleet.IsNotFound(err) {
return err
}
// We will fall through on a notFound err - nothing to do here
if err == nil {
if gotSetupExperienceScript.ScriptContentID != uint(id) { // nolint:gosec // dismiss G115 - low risk here
err = ds.deleteSetupExperienceScript(ctx, tx, script.TeamID)
if err != nil {
return err
Add PUT endpoint for setup experience script (#35651) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35309 Related doc update #35736 Adds a PUT endpoint for setting setup experience scripts, as opposed to the current POST implementation(which errors if the script is already set, which is why gitops calls DELETE first every time). If the contents change, the new endpoint has the same effect as DELETE then POST today, however if the contents are unchanged no changes occur, allowing gitops runs to avoid cancelling script executions. Also switched gitops over to the new PUT endpoint and removed the DELETE in the "set" path. # 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) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] 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) - [ ] QA'd all new/changed functionality manually
2025-11-14 15:22:36 +00:00
}
} else {
// no change
return nil
Add PUT endpoint for setup experience script (#35651) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35309 Related doc update #35736 Adds a PUT endpoint for setting setup experience scripts, as opposed to the current POST implementation(which errors if the script is already set, which is why gitops calls DELETE first every time). If the contents change, the new endpoint has the same effect as DELETE then POST today, however if the contents are unchanged no changes occur, allowing gitops runs to avoid cancelling script executions. Also switched gitops over to the new PUT endpoint and removed the DELETE in the "set" path. # 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) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] 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) - [ ] QA'd all new/changed functionality manually
2025-11-14 15:22:36 +00:00
}
}
// then create the script entity
_, err = insertSetupExperienceScript(ctx, tx, script, uint(id)) // nolint: gosec
return err
})
return err
}
func insertSetupExperienceScript(ctx context.Context, tx sqlx.ExtContext, script *fleet.Script, scriptContentsID uint) (sql.Result, error) {
const insertStmt = `
INSERT INTO
setup_experience_scripts (
team_id, global_or_team_id, name, script_content_id
)
VALUES
(?, ?, ?, ?)
`
var globalOrTeamID uint
if script.TeamID != nil {
globalOrTeamID = *script.TeamID
}
res, err := tx.ExecContext(ctx, insertStmt,
script.TeamID, globalOrTeamID, script.Name, scriptContentsID)
if err != nil {
if IsDuplicate(err) {
// already exists for this team/no team
err = &existsError{ResourceType: "SetupExperienceScript", TeamID: &globalOrTeamID}
} else if isChildForeignKeyError(err) {
// team does not exist
err = foreignKey("setup_experience_scripts", fmt.Sprintf("team_id=%v", script.TeamID))
}
return nil, ctxerr.Wrap(ctx, err, "insert setup experience script")
}
return res, nil
}
func (ds *Datastore) DeleteSetupExperienceScript(ctx context.Context, teamID *uint) error {
Add PUT endpoint for setup experience script (#35651) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35309 Related doc update #35736 Adds a PUT endpoint for setting setup experience scripts, as opposed to the current POST implementation(which errors if the script is already set, which is why gitops calls DELETE first every time). If the contents change, the new endpoint has the same effect as DELETE then POST today, however if the contents are unchanged no changes occur, allowing gitops runs to avoid cancelling script executions. Also switched gitops over to the new PUT endpoint and removed the DELETE in the "set" path. # 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) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] 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) - [ ] QA'd all new/changed functionality manually
2025-11-14 15:22:36 +00:00
return ds.deleteSetupExperienceScript(ctx, ds.writer(ctx), teamID)
}
func (ds *Datastore) deleteSetupExperienceScript(ctx context.Context, tx sqlx.ExtContext, teamID *uint) error {
var globalOrTeamID uint
if teamID != nil {
globalOrTeamID = *teamID
}
Add PUT endpoint for setup experience script (#35651) <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35309 Related doc update #35736 Adds a PUT endpoint for setting setup experience scripts, as opposed to the current POST implementation(which errors if the script is already set, which is why gitops calls DELETE first every time). If the contents change, the new endpoint has the same effect as DELETE then POST today, however if the contents are unchanged no changes occur, allowing gitops runs to avoid cancelling script executions. Also switched gitops over to the new PUT endpoint and removed the DELETE in the "set" path. # 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) - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] 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) - [ ] QA'd all new/changed functionality manually
2025-11-14 15:22:36 +00:00
_, err := tx.ExecContext(ctx, `DELETE FROM setup_experience_scripts WHERE global_or_team_id = ?`, globalOrTeamID)
if err != nil {
return ctxerr.Wrap(ctx, err, "delete setup experience script")
}
// NOTE: CleanupUnusedScriptContents is responsible for removing any orphaned script_contents
// for setup experience scripts.
return nil
}
func (ds *Datastore) SetHostAwaitingConfiguration(ctx context.Context, hostUUID string, awaitingConfiguration bool) error {
return ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
return setHostAwaitingConfiguration(ctx, tx, hostUUID, awaitingConfiguration)
})
}
func setHostAwaitingConfiguration(ctx context.Context, tx sqlx.ExtContext, hostUUID string, awaitingConfiguration bool) error {
const stmt = `
INSERT INTO host_mdm_apple_awaiting_configuration (host_uuid, awaiting_configuration)
VALUES (?, ?)
ON DUPLICATE KEY UPDATE
awaiting_configuration = VALUES(awaiting_configuration)
`
_, err := tx.ExecContext(ctx, stmt, hostUUID, awaitingConfiguration)
if err != nil {
return ctxerr.Wrap(ctx, err, "setting host awaiting configuration")
}
return nil
}
func (ds *Datastore) GetHostAwaitingConfiguration(ctx context.Context, hostUUID string) (bool, error) {
const stmt = `
SELECT
awaiting_configuration
FROM host_mdm_apple_awaiting_configuration
WHERE host_uuid = ?
`
var awaitingConfiguration bool
if err := sqlx.GetContext(ctx, ds.reader(ctx), &awaitingConfiguration, stmt, hostUUID); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return false, notFound("HostAwaitingConfiguration")
}
return false, ctxerr.Wrap(ctx, err, "getting host awaiting configuration")
}
return awaitingConfiguration, nil
}
func (ds *Datastore) MaybeUpdateSetupExperienceVPPStatus(ctx context.Context, hostUUID string, nanoCommandUUID string, status fleet.SetupExperienceStatusResultStatus) (bool, error) {
selectStmt := "SELECT id FROM setup_experience_status_results WHERE host_uuid = ? AND nano_command_uuid = ?"
updateStmt := "UPDATE setup_experience_status_results SET status = ? WHERE id = ?"
var id uint
if err := ds.writer(ctx).GetContext(ctx, &id, selectStmt, hostUUID, nanoCommandUUID); err != nil {
// TODO: maybe we can use the reader instead for this query
if errors.Is(err, sql.ErrNoRows) {
// return early if no results found
return false, nil
}
return false, err
}
res, err := ds.writer(ctx).ExecContext(ctx, updateStmt, status, id)
if err != nil {
return false, err
}
n, _ := res.RowsAffected()
return n > 0, nil
}
func (ds *Datastore) MaybeUpdateSetupExperienceSoftwareInstallStatus(ctx context.Context, hostUUID string, executionID string, status fleet.SetupExperienceStatusResultStatus) (bool, error) {
selectStmt := "SELECT id FROM setup_experience_status_results WHERE host_uuid = ? AND host_software_installs_execution_id = ?"
updateStmt := "UPDATE setup_experience_status_results SET status = ? WHERE id = ?"
var id uint
if err := ds.writer(ctx).GetContext(ctx, &id, selectStmt, hostUUID, executionID); err != nil {
// TODO: maybe we can use the reader instead for this query
if errors.Is(err, sql.ErrNoRows) {
// return early if no results found
return false, nil
}
return false, err
}
res, err := ds.writer(ctx).ExecContext(ctx, updateStmt, status, id)
if err != nil {
return false, err
}
n, _ := res.RowsAffected()
return n > 0, nil
}
func (ds *Datastore) MaybeUpdateSetupExperienceScriptStatus(ctx context.Context, hostUUID string, executionID string, status fleet.SetupExperienceStatusResultStatus) (bool, error) {
selectStmt := "SELECT id FROM setup_experience_status_results WHERE host_uuid = ? AND script_execution_id = ?"
updateStmt := "UPDATE setup_experience_status_results SET status = ? WHERE id = ?"
var id uint
if err := ds.writer(ctx).GetContext(ctx, &id, selectStmt, hostUUID, executionID); err != nil {
// TODO: maybe we can use the reader instead for this query
if errors.Is(err, sql.ErrNoRows) {
// return early if no results found
return false, nil
}
return false, err
}
res, err := ds.writer(ctx).ExecContext(ctx, updateStmt, status, id)
if err != nil {
return false, err
}
n, _ := res.RowsAffected()
return n > 0, 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
func (ds *Datastore) CancelPendingSetupExperienceSteps(ctx context.Context, hostUUID string) error {
cancelStmt := "UPDATE setup_experience_status_results SET status = ? WHERE host_uuid = ? AND status NOT IN (?, ?)"
err := ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
_, err := tx.ExecContext(ctx, cancelStmt, fleet.SetupExperienceStatusCancelled, hostUUID, fleet.SetupExperienceStatusSuccess, fleet.SetupExperienceStatusFailure)
return err
})
if err != nil {
return ctxerr.Wrap(ctx, err, "cancelling pending setup experience steps")
}
return nil
}