<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49750
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [ ] 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. (Already a part of something else, this is just
further solidifying the current behaviour)
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [ ] Timeouts are implemented and retries are limited to avoid infinite
loops
- [ ] 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] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Added coverage to verify the command sequence during Apple device
enrollment.
* Ensures the fleet management agent installation happens first,
followed by the bootstrap package, and then configuration profile and
management commands.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves
https://fleetdm.slack.com/archives/C02A8BRABB5/p1784765147322239?thread_ts=1784727509.435919&cid=C02A8BRABB5https://github.com/user-attachments/assets/e6bdeeb9-9ec3-4ba6-9669-6ea18ec8362d
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [ ] 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.
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [ ] Timeouts are implemented and retries are limited to avoid infinite
loops
- [ ] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes
## Testing
- [ ] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a danger variant for checkboxes, with red styling for default,
hover, and active states.
* Updated release and wipe confirmation checkboxes to clearly indicate
destructive actions.
* Added Storybook controls for checkbox values and variants.
* **Bug Fixes**
* Standardized checkbox values to use boolean states only.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#48340
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Enabled enhanced database performance monitoring for load-testing
environments.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#48340
Windows only. The fix is to use a rollup status table instead of
recalculating the host profile summary on demand.
Verified the fix in load test with 100k Windows MDM hosts. Note that
this does not improve the host details page filtered by OS settings,
which will be handled by the follow up
https://github.com/fleetdm/fleet/issues/48996
# 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] Timeouts are implemented and retries are limited to avoid infinite
loops
## 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
## Database migrations
- [x] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [x] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.
- [x] Ensured the correct collation is explicitly set for character
columns (`COLLATE utf8mb4_unicode_ci`).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved Windows fleet configuration profile status summaries to avoid
timeouts on large fleets.
* Kept per-host Windows profile statuses accurate after profile updates,
resends, certificate changes, cleanup, unenrollment, and host deletion.
* Added automatic reconciliation to correct stale or orphaned status
data.
* **Data Integrity**
* Improved Windows profile status reporting, including profile and
BitLocker summaries, for more reliable results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#49682
Mozilla Firefox and Firefox ESR are distinct Fleet-maintained apps that
share the macOS bundle identifier `org.mozilla.firefox`, so they resolve
to one software title. Adding both to a fleet previously gave a generic
conflict error (or no error at all). This adds a clear message — "Only
one of Mozilla Firefox or Mozilla Firefox ESR can be added to the same
fleet." — on both the single-add and GitOps/batch paths. The check is
general (any two FMAs sharing a bundle identifier), with the app names
filled in dynamically.
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`.
- [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
- [ ] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Prevented adding both Mozilla Firefox and Firefox ESR to the same
fleet when they share a bundle identifier.
- Updated the UI to show a specific conflict message explaining that
only one of the two can be added.
- Ensured existing workflows still work for adding new versions of the
already-selected app.
- **Tests**
- Added backend and frontend test coverage for the new conflict
detection and error-message formatting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
# 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), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes
## Summary
Enforced API-only endpoint restrictions on chart endpoints, matching the
pattern already used by the activity bounded context. Also added
`RouteTemplateRequestFunc` to chart route server options so the
middleware can read the matched mux route template from context.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
### Reproduction
Created an API-only user with a restrictive endpoint allow-list (only
`GET /api/v1/fleet/hosts`). Confirmed that:
- Allowed endpoint (`/api/latest/fleet/hosts`) returns 200
- Non-allowed cataloged endpoint (`/api/latest/fleet/users`) returns 403
- Chart endpoint (`/api/latest/fleet/charts/uptime`) returned 200 before
the fix (the bug)
- After the fix, chart endpoint correctly returns 403
### Unit test
Added a test case in `server/service/middleware/auth/api_only_test.go`
that verifies an API-only user with endpoint restrictions is denied
access to chart endpoints not in their allow-list. The chart endpoint is
included in the test catalog (matching production), so the test
exercises the allow-list rejection path.
All 17 tests in the auth middleware package pass.
### Local verification
1. Confirmed the chart middleware in `cmd/fleet/serve.go` previously
called `auth.AuthenticatedUser(svc, next)` without
`APIOnlyEndpointCheck` wrapping
2. Verified the activity bounded context (same file) already uses
`auth.APIOnlyEndpointCheck(next)` as the correct pattern
3. Applied the same wrapping to the chart middleware
4. Added `RouteTemplateRequestFunc` to
`server/chart/internal/service/endpoint_utils.go` so the route template
is available in context (required by `APIOnlyEndpointCheck`)
5. Ran `go test ./server/service/middleware/auth/ -v` with all 17 tests
passing
6. Ran `make lint-go-incremental` with 0 issues
Resolves#16770
The MFA login token redemption path (`POST /api/latest/fleet/sessions`)
read the one-time verification token with a non-locking `SELECT` on the
read replica, then created a session and deleted the token in a
*separate* transaction without verifying the token was still present.
Concurrent requests carrying the same token each passed the `SELECT` and
each minted a distinct session, breaking the single-use guarantee.
`SessionByMFAToken` now consumes the token and creates the session
inside a single transaction:
- The token row is locked with `SELECT ... FOR UPDATE`, then deleted,
and the delete's rows-affected count is confirmed non-zero before the
session is created.
- Concurrent redemptions serialize on the row lock; the loser re-reads
after the winner commits the delete, finds no row, and aborts before
creating a session.
- The user is still loaded *before* the transaction, so a
concurrently-deleted user or a transient read error leaves the token
intact for retry (preserving the pre-fix atomicity behavior).
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Juan Fernandez <juan@fleetdm.com>
**Related issue:** Resolves#49276
**New features**
- Added new "Secondary" (bordered, off-white fill) and "Subdued"
(borderless, low-emphasis) button variants to match the Figma spec,
alongside the existing Primary style.
- Allowed rows to be selected in Controls > OS updates.
**Cleanup**
- Once nothing referenced the old styles anymore, fully removed the old
`text-icon`, `brand-inverse-icon`, `inverse-alert`, `inverse`, and
`icon` button variants (type, styles, and Storybook entries) from the
shared `Button` component.
- Removed the `iconStroke` prop, which had become a no-op once the old
variants it supported were gone.
- Renamed `ActionsDropdown`'s variants
(`button`/`brand-button`/`small-button`) to
`subdued`/`primary`/`secondary` to match the same naming used everywhere
else.
- Replaced a one-off dropdown implementation on the Software title page
with the shared `ActionsDropdown` component, instead of maintaining
duplicate styling logic.
- Changed the button name on Host details > Reports > Report details
from "View data for all hosts" to "View report for all hosts" (to match
the previous page's Actions drop-down options).
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<img width="1475" height="241" alt="Screenshot 2026-07-21 at 06 35 49"
src="https://github.com/user-attachments/assets/7cfbd444-7837-40e8-854e-bc5989d57d85"
/>
<img width="661" height="306" alt="Screenshot 2026-07-21 at 06 37 18"
src="https://github.com/user-attachments/assets/5d0c4873-8179-4089-b115-7e8cd3a53b4d"
/>
<img width="1427" height="423" alt="Screenshot 2026-07-21 at 06 37 30"
src="https://github.com/user-attachments/assets/a4850a60-f44a-4902-b45e-0094f23a52f8"
/>
<img width="1427" height="640" alt="Screenshot 2026-07-21 at 06 37 46"
src="https://github.com/user-attachments/assets/738a4a7f-cd7d-4162-b659-6f649c32204d"
/>
<img width="1445" height="479" alt="Screenshot 2026-07-22 at 07 03 22"
src="https://github.com/user-attachments/assets/4f672dc0-5c6d-4eb8-8465-ed5233fcd1b2"
/>
<img width="811" height="871" alt="Screenshot 2026-07-21 at 06 41 20"
src="https://github.com/user-attachments/assets/5421c96e-2dab-492a-af26-be0e5a7791ca"
/>
Make failed logins for MFA-enabled accounts return a consistent response
and timing regardless of the cause, in line with authentication best
practices. Guidance for CLI users whose client can't complete email
verification is now surfaced by fleetctl on any login failure.
Added a `user_mfa_requested` activity, recorded when valid credentials
are submitted for an MFA-enabled account and a verification email is
sent.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49368
Video:
https://github.com/user-attachments/assets/d73a2146-be13-4bfd-802a-f02eb5681b69
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [ ] 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. **Part of backend PR**
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [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] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added “Release from Apple Business” to eligible host actions,
including a confirmation modal with success and error handling.
* Added Apple Business release entries to the activity feed.
* **Bug Fixes**
* Improved user-facing Apple Business error and “Learn more” messaging,
including clearer output when Apple Business device status isn’t
accessible.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** N/A
# Checklist for submitter
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Summary
Moves the `POST
/api/v1/fleet/device/{token}/software/install/{software_title_id}`
("Install self-service software") endpoint out of the contributor-only
API reference (`docs/Contributing/reference/api-for-contributors.md`)
and into the public REST API docs (`docs/REST API/rest-api.md`), nested
under the existing `## Software` section.
- Added `### Install self-service software` to `docs/REST
API/rest-api.md`, right after `### Uninstall software`, with a TOC entry
and a note that it uses the device's authentication token instead of the
usual Fleet API token.
- Removed the TOC entry and body section for this endpoint from
`docs/Contributing/reference/api-for-contributors.md`. Sibling
device-authenticated self-service endpoints were left in place there
since only this one endpoint was moved.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an API route allowing Fleet Desktop users to initiate
self-service software installations using a device token and software
title.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Rachael Shaw <r@rachael.wtf>
## Summary
Documentation-only update to the SSO deployment guide
(`docs/Deploy/single-sign-on-sso.md`) to improve clarity and consistency
across the supported identity providers. No code changes.
## Changes
- **Okta**: Rewrote the setup section into clear numbered steps — app
naming/logo, SAML settings, attribute statements (including the
`displayname` expression and JIT group-to-role mapping example), and
copying the
metadata URL.
- **Consistent callback URLs**: Standardized how each IdP documents the
two callback URLs, making the distinction explicit everywhere:
- **Fleet users** → `https://<your_fleet_url>/api/v1/fleet/sso/callback`
- **End users** (MDM/end user authentication) →
`https://<your_fleet_url>/api/v1/fleet/mdm/sso/callback`
- **Google Workspace, Entra, authentik, Other IdPs**: Updated each to
use the same "depends on which connection you're configuring" callback
URL pattern, and aligned Entity ID wording.
- Cleaned up formatting/indentation and removed redundant/duplicated
instructions.
- Added a new screenshot: `docs/images/okta-sso-step-1.png`.
## Checklist for submitter
- [x] QA'd all new/changed functionality manually (previewed rendered
Markdown and images)
---------
Co-authored-by: Rachael Shaw <r@rachael.wtf>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49736
Adds **Airtable** (`Formagrid.Airtable`) as a Fleet-maintained app for
Windows, grouped with the existing macOS Airtable FMA under the shared
name `Airtable`.
## What changed
- `ee/maintained-apps/inputs/winget/airtable.json` — winget input
(`neutral` arch, `exe`, `user` scope).
- `ee/maintained-apps/inputs/winget/scripts/airtable_install.ps1` —
install script.
- `ee/maintained-apps/inputs/winget/scripts/airtable_uninstall.ps1` —
uninstall script.
- `ee/maintained-apps/outputs/airtable/windows.json` — generated output.
- `ee/maintained-apps/outputs/apps.json` — catalog entry + description.
## Reviewer notes
- **Identity verified against the real installer, not the catalog.**
Downloaded `AirtableSetup1.4.5.exe` (SHA256 matched the winget manifest
exactly) and extracted the embedded Squirrel nuspec:
`<title>Airtable</title>` → registry DisplayName `Airtable`
(`unique_identifier`); `<authors>Airtable</authors>` → registry
Publisher `Airtable`. Publisher matches the winget locale, so no
`program_publisher` override is needed. exists query: `... WHERE name =
'Airtable' AND publisher = 'Airtable'`.
- **Per-user Squirrel installer.** Manifest is `InstallerType: exe`,
`Scope: user`, `Silent: --silent` (Squirrel signature). Run directly as
Local System it would install into the SYSTEM profile and lock its own
`.exe`, so the install uses the **Figma/Postman scheduled-task pattern**
— it runs `--silent` in the logged-on user's session. Uninstall does a
defensive HKLM+HKCU registry lookup and runs Squirrel's `Update.exe
--silent`.
- `installer_arch: neutral` matches the manifest (Dynalist precedent).
The binary is x86; it runs on x64 and ARM64 via emulation and routes to
`windows-latest`.
- Installer URL is version-pinned (`AirtableSetup1.4.5.exe`), not a
"latest" redirect, so the pinned SHA won't silently drift.
- Icon already exists (frontend `airtable` key + website PNG). No shared
Go code changed; no validator rebuild needed.
# Checklist for submitter
- [x] QA'd all new/changed functionality manually (winget manifest +
installer identity verified; output regenerated via `go run
cmd/maintained-apps/main.go --slug="airtable/windows"`; `apps.json`
valid JSON, additions-only diff)
<!-- FMA-only content change: no changes/ entry, DB migration, config
setting, or fleetd change. -->
**Related issue:** Resolves#49737
Adds **Podman Desktop** (`RedHat.Podman-Desktop`, v1.28.3) as a Windows
Fleet-maintained app. It pairs with the existing `podman-desktop/darwin`
FMA under the same catalog name, so the two group together in the FMA
library and share the existing icon.
## What changed
- `ee/maintained-apps/inputs/winget/podman-desktop.json` — input
manifest (x64, machine scope, `exe`/NSIS)
- `ee/maintained-apps/inputs/winget/scripts/podman-desktop_install.ps1`
/ `_uninstall.ps1` — custom install/uninstall scripts
- `ee/maintained-apps/outputs/podman-desktop/windows.json` — generated
output
- `ee/maintained-apps/outputs/apps.json` — new Windows catalog entry;
also reworded the existing macOS description to the standard "`<App>` is
a(n)…" format for consistency
## Identity verification (verified, not guessed)
Podman Desktop ships as an **electron-builder NSIS** installer, and the
winget metadata does **not** match what osquery sees on a host. I
decompressed the NSIS header and traced electron-builder's source to
confirm the registry identity:
- **DisplayName** = `Podman Desktop 1.28.3` → `unique_identifier:
"Podman Desktop"` with `fuzzy_match_name` (matches the version-suffixed
name).
- **Publisher** = `Podman Desktop` — derived from the package's
`author.name` (`COMPANY_NAME` → registry `Publisher`), **not** the
winget locale's `RedHat`. Using "RedHat" would have made the exists
query silently never match on real hosts.
- **SHA256** matches the winget manifest exactly; version `1.28.3`
equals the registry `DisplayVersion`, so the patch policy reconciles
cleanly.
Silent install uses `/S /ALLUSERS`; uninstall does a registry lookup
with the defensive three-shape UninstallString parser and mirrors `/S
/ALLUSERS`, following the proven `another-redis-desktop-manager`
electron-builder machine-scope pattern.
## Reviewer notes
- **x64 only.** The winget manifest also has an arm64 installer, but the
repo has no arm64 FMA inputs yet (x64 is the established convention). A
separate arm64 slug can be added later.
- Installer URL is a **pinned GitHub release** asset (not a "latest"
redirect), so the SHA is stable until the FMA auto-updater bumps the
version.
- No shared Go code changed — only FMA input/output data.
## Checklist for submitter
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] Generated the output via `go run cmd/maintained-apps/main.go
--slug="podman-desktop/windows" --debug`; verified exists/patched
queries, pinned SHA matches the winget manifest, and `apps.json` is
valid JSON.
- [ ] QA'd install/uninstall on a Windows host (will be exercised by the
FMA validator).
Changes:
- Updated the error logged in `register-one-fleet-instance-using-vpp`
action when a Fleet license key cannot be verified to include the
error's message.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved error reporting when Fleet license verification fails,
providing more specific details to support troubleshooting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#49738
Adds **Box Tools** as a Fleet-maintained app for **Windows** (winget
`Box.BoxTools`) and **macOS** (Homebrew cask `box-tools`).
## Windows details (verified against the real installer)
- Installer: `BoxToolsInstaller-AdminInstall.msi` (machine-wide admin
MSI, `ALLUSERS=1`), x64.
- MSI Property table verified with msitools: `ProductName` = `Box
Tools`, `Manufacturer` = `Box`, `ProductVersion` = `4.32.0.1324` — all
match the winget manifest, so `unique_identifier: "Box Tools"` and the
generated exists query (`name = 'Box Tools' AND publisher = 'Box'`)
match what osquery reports from the registry. No `program_publisher`
override needed.
- The winget manifest has no `Scope`, so `installer_scope: "machine"` is
set in the input (confirmed by `ALLUSERS=1`).
- ProductCode/UpgradeCode match the manifest; standard auto-generated
machine-MSI install + upgrade-code uninstall scripts.
- Downloaded SHA256 matches the manifest SHA (`9f5958...c5066`).
- No sibling-name collision with the existing Box Drive FMA (its
DisplayName is `Box`; matching is exact).
## macOS details
Box Tools on macOS is **per-user only**: the cask installs the app
bundles to `~/Library/Application Support/Box/Box Edit/`, Box's admin
`.pkg` forbids the local system domain (`enable_localSystem="false"`),
and [Box's large-scale deployment
docs](https://support.box.com/hc/en-us/articles/360043695834-Large-Scale-Deployments-Box-Tools)
instruct running the installer as the console user (multi-user Macs are
not a supported configuration).
Because the install location is outside osquery's `apps` directory scan
paths, detection relies on osquery's LaunchServices enumeration
(`_LSCopyAllApplicationURLs` in `genApps`), which surfaces the bundles
regardless of location — verified against a live install where all four
Box Tools bundles are LaunchServices-registered at the per-user path and
appear in the `apps` table.
- `unique_identifier: com.Box.Box-Edit` (verified `CFBundleIdentifier`
of `Box Edit.app` in the DMG).
- **Custom install script** (the cask's app artifacts are all
`target:`-style, which the script generator skips, so the auto-generated
script would be a no-op): resolves the console user (falling back to
`lastUserName` when run while logged out), quits the Box apps, copies
the four app bundles from the DMG's `Install Box
Tools.app/Contents/Resources/` into the user's `~/Library/Application
Support/Box/Box Edit/` (replicating the cask/pkg payload exactly),
chowns them, and registers them with LaunchServices in both root and
user contexts so inventory and box.com pick them up without a first
manual launch.
- **Custom uninstall script**: quits/kills the Box Tools processes and
removes `Box Edit` from every local user's home. The parent `Box`
directory is shared with Box Drive, so it is only removed if left empty.
- The cask uses `sha256 :no_check` (rolling `currentrelease` URL) — the
established FMA convention for such casks (same as Google Chrome/VS Code
darwin); the server pins the hash of what it downloads at add time.
- Cask version is `4.32` while `CFBundleShortVersionString` is `4.32.0`;
the validator's prefix matching and the patched query's
`version_compare` both treat these as consistent.
## Shared caveat
⚠️ Both installer URLs are rolling `currentrelease` links. On Windows
the pinned SHA will drift when Box ships a new build until the FMA
auto-update ingests the new manifest; macOS uses `no_check` per the
cask.
## Icon
Generated from the official 512×512 Box Tools icon shipped inside the
vendor DMG via `tools/software/icons/generate-icons.sh` (frontend
`BoxTools.tsx` + map entry, website `app-icon-box-tools-60x60@2x.png`).
Both platforms share the icon via the common `name`/slug.
# Checklist for submitter
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] Verified installer identity fields (MSI Property table, Info.plist
bundle identifiers/versions) with msitools/PlistBuddy against the live
installers; Windows output SHA matches the winget manifest.
- [x] Verified on a live macOS install that the per-user Box Tools
bundles are LaunchServices-registered and visible to osquery's `apps`
table.
- [ ] FMA validation CI (Windows + macOS runners) to confirm
install/uninstall/detection.
- [ ] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added Box Tools support for both Windows and macOS.
* Added Box Tools install, upgrade, and uninstall handling for the
maintained app catalog.
* Published Box Tools metadata to the software catalog (including
platform-specific entries and version targeting).
* Added a Box Tools icon to the software interface for improved name
matching.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#46644
Demo video: https://www.youtube.com/watch?v=svCaA-820yc
Docs: https://github.com/fleetdm/fleet/pull/49713/changes
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
## 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
- Did not verify macOS.
- [x] Verified auto-update works from the released version of component
to the new version (see [tools/tuf/test](../tools/tuf/test/README.md))
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added `--bypass-end-user-auth` to `fleetctl package` and Orbit.
* Generated Linux and Windows installers can skip the end-user
authentication prompt during enrollment.
* Added `ORBIT_BYPASS_END_USER_AUTH` for environment-based
configuration.
* End-user authentication remains enabled when a supported EUA token is
provided.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This enforces NTP on macOS devices.
The "Set date and time automatically" toggle can be verified with
`systemsetup - getusingnetworktime` (you can write a script to put the
output of that into a file, then use the `file_lines` table in a
policy), and set with `systemsetup - setusingnetworktime on` (which
could be a script automation that kicks off if a device fails the
policy).
If you want to prevent users from changing it, you can use the attached
config profile. Note that it requires setting the NTP server, but this
is most likely just the default Apple server. The `setusingnetworktime`
will work even with the Ul locked.
<img width="1458" height="320" alt="Screenshot 2026-05-14 at 08 19 28"
src="https://github.com/user-attachments/assets/22064715-1548-490c-b3e0-bde51dd26f12"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a macOS configuration profile that automatically configures
devices to use Apple’s time server.
* Included a human-readable profile name and standard configuration
metadata for easier deployment.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** N/A — part of the ongoing Windows Fleet-maintained
apps (FMA) parity workstream (letter H).
## What this does
Adds **5** Windows Fleet-maintained apps for the letter-H batch, each
with a winget-sourced input, generated output manifest, and a
first-party catalog icon.
- **HashTools** — Inno Setup, machine, x64. File-checksum utility
(Binary Fortress). Has an evergreen WebView2 dependency (present on
virtually all fleets; core hashing works without it).
- **HeidiSQL** — Inno Setup, machine, x64. Custom install passes
`/ALLUSERS` for machine scope (the ingester doesn't forward manifest
`Custom` switches).
- **HWMonitor** — Inno Setup, machine, x86. ARP DisplayName is `CPUID
HWMonitor`; installs a kernel driver removed by its uninstaller.
- **HP Prime Virtual Calculator** — WiX burn bundle, machine, x64. Uses
a name-only exists query (the ARP publisher is MORAVIA Consulting, not
the manifest's "HP").
- **Huddle** — InstallShield exe (`/exenoui /quiet`), machine, x86.
Uninstall via the MSI UpgradeCode (`uninstall_type: msi`); `ignore_hash`
for the non-versioned installer URL.
## Dropped from this batch (recorded in the workstream tracker)
- **HandBrake** — the GUI declares an unbundled
`Microsoft.DotNet.DesktopRuntime.10` dependency (won't run without it);
the CLI is a portable zip with no Add/Remove Programs entry to detect.
- **HiPIN** (`KPN.HIPIN`) — unbundled VCRedist + WebView2 dependencies,
a non-versioned "latest" URL, and no ARP DisplayName/ProductCode. The
`binbat.whipinto` candidate is an unrelated WebRTC tool (mismatch).
## Notes
- **Huddle** uses a non-versioned `HuddleSetup.exe` URL — if the vendor
ships past 4.8.0.0, osquery version detection may drift (same pattern
that failed GoodSync in letter G). Flagging for the validator; will drop
if it can't match.
- Verification (winget manifest identity, installer type/scope/arch,
ProductCode/UpgradeCode, silent switches, dependencies, URL stability)
was done per the `new-fma` skill against the winget-pkgs manifests.
## Testing
- [ ] FMA CI validator (install → detect → uninstall) on the
SYSTEM-context Windows runner — pending.
- Generated outputs verified locally: all 5 produce valid manifests;
exists/patched queries reviewed; Huddle's MSI UpgradeCode uninstall
auto-generated correctly.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49756
# Checklist for submitter
- [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] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary by CodeRabbit
* **Bug Fixes**
* Custom SCEP proxy challenges can again include characters such as
underscores.
* Apple device enrollment works again with these challenges.
* Removed the overly strict printable-character validation from the
Custom SCEP configuration form.
* The Challenge field now only enforces the required-value rule and no
longer shows printable-character validation errors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49367
# 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), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [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)
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added “Release from Apple Business” for eligible Apple hosts,
including per-device success/failure reporting and activity logging.
* Added a new API endpoint to trigger the action and return results for
each selected host with clear error details.
* Introduced authorization rules for global admins and team admins to
release only within allowed scope.
* **Bug Fixes**
* Improved validation and error handling: rejects oversized selections,
reports unknown/ineligible hosts and DEP-related failures per device,
and treats assignment-cleanup failures as non-blocking.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves #
Super small change to make it easier to correlate bootstrap and fleetd
`InstallEnterpriseApplication` command UUID with log statements
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
## Testing
- [ ] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved logging for Apple MDM command delivery by including the
associated command identifier when application and bootstrap package
installation commands are sent.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- Product Designers will have their own unpacking and during this call
will pull up their respective product group board. Thus, PDs don't need
to add requests that contribute to product maturity back to the drafting
board by adding the `:product` label.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#48003
# 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), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [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] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Fixed MDM SSO configuration handling to automatically remove leading
and trailing whitespace from provider fields.
- GitOps-applied MDM SSO settings are now normalized before validation,
preventing otherwise invalid configurations caused by extra spaces.
- Required-field and URL validation now operate on the cleaned values.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** NA
## What changed
Adds a new blog article,
`articles/build-your-own-linux-self-service-with-script-only-packages.md`,
published under the `articles` category.
The article is a how-to piece showing how Fleet 4.89.0's new support for
**uninstall script, pre-install query, and post-install script on
script-only packages** turns `apt-get install` / `dnf install` into a
GitOps-managed, self-service Linux software catalog, with no
`.deb`/`.rpm` to host. It ends with a small generator that emits the
install script, uninstall script, and YAML block from just a package
name.
## Why
Script-only packages became a full install/uninstall/verify lifecycle in
4.89.0. This article documents a practical pattern built on top of that
capability for teams managing Linux with Fleet.
## Notes for reviewers
- Content-only change: one new markdown file, no code.
- Technical claims were verified against the 4.89.0 `CHANGELOG.md` and
`docs/Configuration/yaml-files.md` / the deploy-software-packages guide.
In particular, script-only packages support `uninstall_script`,
`post_install_script`, and `pre_install_query` (they still do **not**
support `install_script` or automatic install via policy).
- All links point to real destinations (`fleetdm.com` routes and GitHub
paths) that were checked against `website/config/routes.js` and the
docs.
- Followed the `fleet-article-formatting` house style (dek, key
takeaways, post-takeaways CTA button, "See it live" endmatter) and
`content-style` rules.
# Checklist for submitter
- [x] QA'd all new/changed functionality manually (proofread; verified
links and technical claims against repo docs/changelog).
<sub>This change is a documentation/content-only addition; the code,
testing, database, configuration, and fleetd sections of the standard
template do not apply.</sub>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49751
A customer's egress proxy (an Envoy sidecar bound to loopback) was
getting blocked by Fleet's SSRF network-blocking check, since the check
applies to whatever address the HTTP transport dials, including the
proxy hop itself, not just the ultimate destination. There was no
supported way to disable this in production (the existing full-bypass
mode was dev-only), leaving no path forward for environments where
egress is already constrained by external infrastructure.
# Checklist for submitter
- [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] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a production server setting to bypass outbound network blocking
for integration requests when external egress controls are already in
place.
* The setting is disabled by default and can be configured through the
server configuration.
* **Documentation**
* Clarified that bypassing network blocking disables SSRF protections
for all outbound integration requests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#41787
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a new redirect for the “Learn more about MDM enrollment” page,
sending visitors to the Windows MDM setup guide’s manual enrollment
section.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Updated the article to improve clarity and fix minor grammatical issues
throughout the text, including prerequisites, policy creation, and
script instructions.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves #
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [ ] 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.
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [ ] Timeouts are implemented and retries are limited to avoid infinite
loops
- [ ] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes
## Testing
- [ ] Added/updated automated tests
- [ ] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)
- [ ] QA'd all new/changed functionality manually
For unreleased bug fixes in a release candidate, one of:
- [ ] Confirmed that the fix is not expected to adversely impact load
test results
- [ ] Alerted the release DRI if additional load testing is needed
## Database migrations
- [ ] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [ ] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.
- [ ] Ensured the correct collation is explicitly set for character
columns (`COLLATE utf8mb4_unicode_ci`).
## New Fleet configuration settings
- [ ] Setting(s) is/are explicitly excluded from GitOps
If you didn't check the box above, follow this checklist for
GitOps-enabled settings:
- [ ] Verified that the setting is exported via `fleetctl
generate-gitops`
- [ ] 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)
- [ ] 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)
- [ ] Verified that any relevant UI is disabled when GitOps mode is
enabled
## fleetd/orbit/Fleet Desktop
- [ ] 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))
- [ ] If the change applies to only one platform, confirmed that
`runtime.GOOS` is used as needed to isolate changes
- [ ] Verified that fleetd runs on macOS, Linux and Windows
- [ ] Verified auto-update works from the released version of component
to the new version (see [tools/tuf/test](../tools/tuf/test/README.md))
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Related to #45524
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes
## Testing
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary
* **New Features**
* Added `fleet://install_all` and `fleet://install-all` deep links with
optional `category_id` to open the scoped self-service page and guide
the install-all confirmation flow.
* **Bug Fixes**
* Improved macOS single-instance behavior by forwarding deep links and
relaunch/reopen events to the already-running window.
* Hardened SSO/auth navigation and external-link handling to prevent
expired flows and stranded pages.
* Improved download filename safety and ensured recovery back to the
home view.
* Strengthened configuration and device token validation; refined
install/badge update timing.
* **Chores**
* Bumped version to 1.4.0, enforced single-instance in the app bundle,
and parallelized Intel/Apple Silicon builds.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Allen Houchins <allenhouchins@mac.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49707
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Improved API endpoint search with relevance-based ranking across
endpoint names and paths.
* Search results now prioritize exact, prefix, whole-word, and partial
matches.
* Added path-based matching and clearer empty-state behavior.
* Removed pagination in favor of the existing results scrollbar.
* **Bug Fixes**
* Preserved relevance ordering instead of applying an incorrect default
sort.
* Excluded already-selected endpoints from search results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Automated ingestion of latest Fleet-maintained app data.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added support for the latest releases of numerous desktop applications
across macOS and Windows, including Amazon Corretto, Claude, Kiro,
Postman, Tableau, Thunderbird, and others.
* Updated installer downloads and integrity checks for newly available
versions.
* **Bug Fixes**
* Improved app removal by quitting running applications before cleanup
for select apps.
* Updated uninstall cleanup paths for newer application versions.
* **Maintenance**
* Refreshed version detection and upgrade checks across the maintained
application catalog.
* Updated Telegram’s download source for improved installation
reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
Added a comprehensive guide on detecting and removing unwanted software
installed by peripherals using Fleet policies and scripts. This includes
instructions for creating detection policies, removal scripts, and
connecting them with automation.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves
https://github.com/fleetdm/confidential/issues/16880
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary by CodeRabbit
* **Bug Fixes**
* Secured the Windows MDM Terms of Service endpoint against reflected
cross-site scripting.
* Strengthened validation for the `redirect_uri` used in Terms of
Service rendering, allowing only approved `https` and `ms-appx-web`
schemes.
* Unsafe, malformed, or non-allowlisted redirect values are now rejected
and not displayed.
* **Tests**
* Added integration and unit coverage to verify unsafe redirects are
blocked while valid ones continue to work.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Sharon Katz <121527325+sharon-fdm@users.noreply.github.com>
**Related issue:** Resolves#47963
# Checklist for submitter
- [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), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] Added/updated automated tests
- [ ] QA'd all new/changed functionality manually
## Summary
Fixes a 500 seen via monitoring during `POST /api/mdm/apple/enroll`:
```
checking os updates settings serial [redacted]: getting team id for host: sql: no rows in result set
```
### Root cause
During DEP enrollment, `CheckMDMAppleEnrollmentWithMinimumOSVersion` →
`shouldOSUpdateForDEPEnrollment` calls
`GetMDMAppleOSUpdatesSettingsByHostSerial`, which joins `hosts` to
`host_dep_assignments` by serial. When no matching row exists yet — e.g.
the enrollment request arrives before the host / DEP assignment row is
created or replicated (replica lag / ordering) — `sqlx.GetContext`
returns `sql.ErrNoRows`.
The service layer already handles this case gracefully (skip the
OS-update check, allow enrollment to proceed) via
`fleet.IsNotFound(err)`. But the datastore wrapped the raw
`sql.ErrNoRows` with a plain `ctxerr.Wrap`, which does not implement the
`IsNotFound()` interface, so the graceful path never triggered and the
request 500'd.
### Fix
Convert `sql.ErrNoRows` into a proper `notFound` error in the datastore
method, matching the existing pattern used throughout `apple_mdm.go`.
This lets the existing service-layer graceful-skip path take over so
enrollment proceeds.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed Apple MDM enrollment to continue gracefully when OS update
settings are missing because a host’s DEP assignment hasn’t been created
yet or hasn’t replicated.
* Prevented enrollment from failing with an unexpected 500 error by
returning a clear “not found” outcome instead.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->