Resolves#46005
Implement flow for ad-hoc distributed query campaign streamed over the
/api/v1/fleet/results/websocket endpoint, the same way the Fleet UI and
fleetctl run live queries.
https://github.com/fleetdm/fleet/actions/runs/28218912241/job/83595668272
`cmd/fleetctl/fleetctl TestGitOpsAndroidCertificatesAdd`
`cmd/fleetctl/fleetctl TestGitOpsAndroidCertificatesChange`
`cmd/fleetctl/fleetctl TestGitOpsAndroidCertificatesDeleteOne`
Panic triggered due to missing mock
```
created by net/http.(*Server).Serve in goroutine 1296276
/opt/hostedtoolcache/go/1.26.4/x64/src/net/http/server.go:3464 +0x88a
gitops_test.go:6099:
Error Trace: /home/runner/work/fleet/fleet/cmd/fleetctl/fleetctl/gitops_test.go:6099
Error: Received unexpected error:
applying Android certificates: POST /api/latest/fleet/spec/certificates: do request: Post "http://127.0.0.1:39447/api/latest/fleet/spec/certificates": EOF (API time: 4ms)
Test: TestGitOpsAndroidCertificatesDeleteOne
```
## 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
* **Tests**
* Updated the test mocks used for GitOps and fleetctl scenarios to
support certificate template variable updates.
* Prevents failures when certificate template variable setting is
invoked during test runs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Adds a comprehensive article explaining Apple's Managed Migration
Assistant in macOS 26.4, covering how it transforms Mac-to-Mac migration
from an uncontrolled user choice into declarative organizational policy.
Discusses governance, compliance, operational benefits, and how Fleet
can operationalize migration policies through version-controlled YAML.
Automated ingestion of latest Fleet-maintained app data.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Refreshed installer metadata for multiple Windows and macOS apps to
newer releases, including version checks, download links, and package
checksums.
* Updated several app entries such as Chrome, Cursor, Postman,
Bitwarden, Calibre, Zulip, and others to help keep install and upgrade
detection accurate.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
Fixes#46641
When Fleet runs under a subpath, server_url already includes that
subpath, so appending url_prefix again produced a doubled ACS callback
path (e.g. https://host/subpath/subpath/api/v1/fleet/sso/callback),
breaking SAML authentication for both login and MDM end user
authentication.
Drop url_prefix from the callback URL construction so the path is
appended directly to server_url, which is the full external base URL.
Fixes the same flaw in all five ACS-construction sites: login SSO
initiate and callback, and MDM SSO initiate plus both callback branches.
Fixes#46642
When Fleet is deployed under a subpath, server_url already carries that
subpath, so the email link base was being built as server_url +
url_prefix, duplicating the path (e.g.
https://host/subpath/subpath/login/reset) and producing 404 links.
Use server_url directly as the link base, matching how the rest of the
codebase already treats server_url as the full external base URL.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves #
Fix tagging of hostnames on returned MDM command results so all returned
results have a hostname
# 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
* **Bug Fixes**
* Fixed an issue where some MDM command results could return without
hostnames.
* Improved result visibility so only hosts the caller is allowed to see
are included.
* Ensured team-scoped users see only their permitted results, while
global admins continue to see all available results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Closes#45627
Part 2 of #45553 -- see there for the full behavioral contract and
Oracle.
## Changes
- Integrated the shared `orbit/pkg/backoff` package (shipped in #45624)
into orbit's `ExecuteConfigReceivers` loop
- On error (5xx, network failure): polling interval doubles each failure
(30s, 60s, 120s, ...) capped at 5 minutes
- On success: resets immediately to normal 30s polling
- The inner `retry.Do` in `GetConfig` (transient retry within a single
tick) is unchanged
## Manual testing
### Automated tests
```
go test ./orbit/pkg/backoff/ -race -count=1 # 17 tests, 0 failures
go test ./client/ -count=1 -short # client tests pass
```
### Build verification
```
go build ./orbit/cmd/orbit/ # compiles clean
go build ./orbit/cmd/desktop/ # compiles clean
```
### Dev environment testing
Built orbit from this branch and swapped it into a local dev setup
(`/opt/orbit/bin/orbit/macos/stable/orbit`). Server-side logs confirmed
that after the restart with the new binary, `/api/fleet/orbit/config`
requests stopped arriving at the fixed 30s cadence (old behavior),
consistent with backoff engaging on error responses. The `device_token`
endpoint (not covered by this PR) continued at its normal interval,
confirming the backoff is scoped to the config polling loop only.
Full end-to-end verification of the log messages (`backing off`,
`next_retry`, `exiting backoff`) should be done by QA with `sudo tail -f
/var/log/orbit/orbit.stderr.log`.
### QA manual test plan (cc @xpkoala)
**Setup:** Local Fleet server + orbit built from this branch (see build
steps above). Orbit logs are at `/var/log/orbit/orbit.stderr.log`
(requires `sudo`).
**Test 1 -- Backoff on server failure:**
1. Start Fleet server, verify orbit connects (config requests every ~30s
in server log)
2. Stop the Fleet server (`kill` the process or `docker stop` the
container)
3. Watch orbit logs: `sudo tail -f /var/log/orbit/orbit.stderr.log`
4. **Expected:** Log lines with `"running config receivers, backing
off"` and `next_retry` values increasing: ~60s, ~120s, ~240s, then
capping at ~5m (values include up to 10% random jitter)
**Test 2 -- Recovery resets to normal:**
1. While orbit is in backoff (from Test 1), restart the Fleet server
2. Wait for the next backoff tick to fire
3. **Expected:** Log line `"config receivers succeeded, exiting
backoff"` with `backoff_duration` showing how long the backoff lasted,
then polling resumes at normal 30s
**Test 3 -- Normal operation unchanged:**
1. With both server and orbit running healthy, watch orbit logs for ~2
minutes
2. **Expected:** No backoff-related log lines. Config polling stays at
30s intervals.
---
# Checklist for submitter
- [x] Changes file added for user-visible changes in `orbit/changes/`.
- [x] Input data is properly validated, no SQL changes, no JS changes.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops (backoff caps at 5 min).
- [x] Added/updated automated tests (existing backoff package tests
cover the mechanism).
- [ ] QA'd all new/changed functionality manually.
## fleetd/orbit/Fleet Desktop
- [x] If the change applies to only one platform, confirmed that
`runtime.GOOS` is used as needed to isolate changes (backoff is
platform-agnostic).
- [ ] Verified that fleetd runs on macOS, Linux and Windows.
- [ ] Verified auto-update works from the released version of component
to the new version.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Improvements**
* Config polling now implements exponential backoff on network/server
failures, gradually increasing retry intervals up to a 5-minute maximum
instead of fixed intervals.
* After a successful config poll, the retry schedule automatically
resets back to the normal update interval.
* **Tests**
* Added unit tests to verify backoff increases after repeated failures
and resets promptly after recovery.
<!-- 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#48192
- Deleted `refetchOnWindowFocus: false` so that users get fresh data if
they navigate away and come back to the report results page (IMHO this
should be the behavior across all Fleet's UI).
- Set a refetch interval of 5s when no report results are available.
^ is gated to the report bringing back results (i.e. `discard_data =
false` and `logging = snapshot`).
# 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] QA'd all new/changed functionality manually
https://github.com/user-attachments/assets/13513f37-8634-4c22-95cc-c0b2e9128058https://github.com/user-attachments/assets/ae30640a-d0cb-4d93-a0f3-058650895959https://github.com/user-attachments/assets/54a46634-fbca-4a7a-a75e-36b73370c9a0
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Report results now refresh automatically when you return to the
browser window.
* Empty report results are checked again every 5 seconds until data
appears.
* **Bug Fixes**
* Improved handling of report caching settings so refresh behavior is
skipped when caching is disabled.
* The empty-state view now stays in sync with whether report caching is
available.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
fix the typo of appropriate
<!-- 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))
Relates to #38670
Fix padding issue around automation icons and
add missing automation icons.
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
Related to: https://github.com/fleetdm/fleet/issues/48052
Changes:
- Added a JSON FAQ to the security and control pages header
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added FAQ structured data (JSON-LD) to the “Security and control” page
to enhance search engine understanding and visibility.
* The page layout now conditionally renders the FAQ JSON-LD script in
the document head when available.
<!-- 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:** #23242
Backend changes for Apple BYOD (personal) MDM enrollment.
- Adds a `byod` enrollment path that distinguishes personal devices from
organization-owned devices.
- Persists per-host Apple MDM enrollment access rights in a new
`host_mdm_apple_enrollment_permissions` table so SCEP/ACME renewal
honours Apple's monotonic-narrowing invariant (permissions can never be
widened on profile replacement).
- Surfaces wipe/lock/clear-passcode allowed flags on host details for
manually-enrolled Apple hosts.
- Renames the personal enrollment status label to `On (manual -
personal)`.
# 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] 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
### Test plan
- Manual (profile) enrollment, company-owned: device receives full
access rights; wipe/lock/clear-passcode allowed.
- Manual (profile) enrollment, personal (BYOD via `byod=1`): device
receives narrowed access rights (no device lock/erase); host details
show wipe/lock/clear-passcode disabled.
- SCEP/ACME renewal for each of the above: renewed profile preserves the
original ServerURL (incl. `byod=1`) and the stored (narrowed) access
rights; Apple does not reject the replacement.
- Renewal batching: multiple company-owned hosts collapse into a single
InstallProfile command; a BYOD host gets its own command.
- Account-Driven User Enrollment (ADUE): enroll a personal device via
ADUE and confirm it is inherently restricted (Apple `UserEnrollment`
mode — no device lock/erase regardless of AccessRights), and that its
SCEP renewal succeeds and preserves the account-driven enrollment
profile.
- Deleted-then-returned device: delete a still-enrolled BYOD host in
Fleet, let it check back in, and confirm a subsequent SCEP renewal still
uses the narrowed permissions.
## 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
* **New Features**
* Added personal (BYOD) Apple MDM enrollment support across manual
profiles, OTA enrollments, and SCEP/ACME certificate renewals, with
access rights generated appropriately.
* Apple host details now surface per-device permission flags for wipe,
lock, and clear passcode when available.
* Enrollment status text now shows personal manual enrollments as “On
(manual - personal)”.
* **Bug Fixes**
* Enforced remote wipe/lock (and clear passcode) permissions correctly
for personal devices, including persistence across renewals.
* Host deletion cleanup now removes newly tracked enrollment permission
data.
<!-- 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#44153
- Adds mdm enabled and configured checks for the update fleet endpoint
- Adds activity creation for the update fleet endpoint + gitops apply
# 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.
- [ ] 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
- [ ] 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
- [ ] 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)
- [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)
- [ ] Verified that any relevant UI is disabled when GitOps mode is
enabled
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary by CodeRabbit
* **New Features**
* Added activity logs when the managed local account setting is enabled
or disabled.
* Managed local account updates now work consistently through both the
Update Fleet endpoint and GitOps.
* **Bug Fixes**
* Prevented enabling managed local account unless macOS MDM is enabled
and configured.
* No activity is created when the setting is saved without any actual
change.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#36681, #48042
# 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.
## Testing
- [x] Added/updated automated tests
- [ ] 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
* **New Features**
* Certificate templates and managed Android app configurations now keep
track of referenced variables.
* Variable changes can now trigger automatic re-sending of affected
profiles and app availability updates.
* **Bug Fixes**
* Resend behavior now refreshes certificate templates when related
variable values change.
* Android managed app configurations are re-queued when their variables
are updated.
* **Database**
* Added support for variable tracking on certificate templates and
Android app configurations.
<!-- 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
* **Bug Fixes**
* Updated package metadata for several managed apps to newer releases,
including Firefox, LibreOffice, Arc, Bitwarden, Adobe Acrobat Reader,
Citrix Workspace, GitHub Desktop, Webex, Claude, Copilot Money, IINA,
Granola, Modern CSV, Workflowy, Codex, and A Better Finder Rename.
* Refreshed installer links and checksums so installs and updates match
the latest available versions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`.
- [x] Input data is properly validated (authorization policy change
only).
## Testing
- [x] Added/updated automated tests — the role matrix in
`TestConditionalAccessGetIdPSigningCertAuth` and
`TestConditionalAccessGetIdPAppleProfileAuth` now asserts observer and
observer+ are denied; `go test ./server/authz/` confirms the policy
compiles.
- [x] QA'd all new/changed functionality manually — covered by the
automated role-matrix tests for this authz-only change.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Tightened access to conditional access identity provider assets so
only higher-privilege roles can read them.
* Users with observer and observer+ roles can no longer access these
endpoints.
* Updated validation coverage to reflect the revised access behavior.
<!-- 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#44325 (follow-up to #47861 and #48009)
## Summary
Follow-up to #47861 and #48009 (both merged) for #44325. Those left
several GitOps-mode "Manage in YAML" tooltips still misaligned. This
makes the wrapper hug its content so the tooltip centers on the disabled
control instead of drifting to the full form width.
# Checklist for submitter
## Testing
- [x] QA'd all new/changed functionality manually
<img width="1280" height="860" alt="1_bootstrap_advanced"
src="https://github.com/user-attachments/assets/403cabb4-3d24-4ece-91f5-4887efd0da05"
/>
<img width="1280" height="860" alt="2_install_software"
src="https://github.com/user-attachments/assets/2f9b2130-0fd6-4744-9603-1a31aebd773e"
/>
<img width="1280" height="860" alt="3_fleet_action_rename"
src="https://github.com/user-attachments/assets/180f3e8d-1dee-404c-b13d-14124bc3509b"
/>
<img width="1280" height="860" alt="4_fleet_action_enroll"
src="https://github.com/user-attachments/assets/9378b6fb-5b1e-45e0-80e5-61d4996b49e0"
/>
<img width="1280" height="860" alt="5_fleet_checkbox"
src="https://github.com/user-attachments/assets/dcec8992-5407-452a-8b4c-5d4e8dc27d10"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved tooltip positioning and width behavior in setup forms so
tooltips align more consistently with the visible control.
* Input and dropdown fields now keep their full-width behavior, while
other controls are centered more naturally.
* Updated the macOS and Windows software requirement options to show
tooltips beside the control for better readability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
# Checklist for submitter
- [x] Changes file added for user-visible changes in `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.
## Summary
Fixes a regression from #47860 where `PerformRequiredPasswordReset`
cleared **all** sessions (including the one the user was actively
using), causing an error after completing the forced password reset.
**Issue:** #47860 changed `setNewPassword(ctx, user, password, false)`
to `true`, which calls `DestroyAllSessionsForUser`. This broke the
first-login flow for new users: they'd complete the password reset
successfully but then get a 401 because their own session was destroyed.
**Fix:** Revert to `clearSessions=false`, then selectively destroy all
sessions except the current one using `ListSessionsForUser` +
`DestroySession`. This preserves the user's active session while still
invalidating any other sessions.
## Reproduction
1. Create a new user (admin_forced_password_reset defaults to true)
2. Log in as the new user in an incognito window
3. Complete the required password reset
4. **Before fix:** 401 error, user is logged out
5. **After fix:** User lands on the home screen normally
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
- [x] Confirmed that the fix is not expected to adversely impact load
test results
### QA results
**Test 1: Security scenario (original #47860 goal)**
| Step | Result |
|------|--------|
| Admin flags user for required password reset | Sessions cleared,
`force_password_reset=true` |
| Attacker logs in with old password | Gets restricted session (401 on
`/hosts`) |
| Real user performs required password reset | Succeeds,
`force_password_reset=false` |
| Attacker session invalidated | **PASS** (401 on `/me`) |
| Real user session preserved | **PASS** (200 on `/me`) |
| New password works | **PASS** |
| Old password rejected | **PASS** |
**Test 2: Regression fix (Lucas's repro)**
| Step | Result |
|------|--------|
| Create new user (forced reset defaults to true) |
`force_password_reset=true` |
| Log in as new user | Token received |
| Complete required password reset | Succeeds,
`force_password_reset=false` |
| User session still works after reset | **PASS** (200 on `/me`) |
Automated ingestion of latest Fleet-maintained app data.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Updated macOS app metadata for several maintained apps to reflect
newer releases.
* Included version bumps for Clop, Cursor, NordVPN, NotchNook, OpenCode
Desktop, Postman, Rive, Shapr3D, Webex, and WhatsApp.
* **Bug Fixes**
* Installer checks now point to the latest available downloads and
matching integrity hashes.
* Version detection logic was refreshed so supported installs are
recognized correctly.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
<!-- 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.
- [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
* **Bug Fixes**
* Scheduled batch script execution now re-checks host team membership at
execution time, skipping any hosts moved to a different team before the
batch runs.
* Added a clear “team mismatch” incompatibility outcome and ensured
incompatible hosts are not queued for execution.
* **Tests**
* Expanded script scheduling tests to cover host-to-team transfers
between scheduling and execution, including updated incompatibility
counts and per-host expectations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
**Related issue:** N/A (internal security hardening)
## Summary
The SCEP certificate renewal flow accepted a CSR with any CommonName as
long as the requester proved possession of the old certificate's private
key. This allowed a host to obtain a certificate for a different host's
identity during renewal.
## Reproduction
Code-level verification (no running server required):
1. Read `ee/server/service/hostidentity/scep.go` `renewalMiddleware`
(lines 142-216).
2. Confirmed that after PoP signature verification (line 191), the CSR
is passed directly to `next.SignCSRContext(ctx, m)` (line 198) with no
comparison of `m.CSR.Subject.CommonName` against
`oldCertData.CommonName`.
3. Confirmed that `UpdateHostIdentityCertHostIDBySerial` (line 205) then
binds the new cert's serial to the old cert's `host_id`, completing the
identity takeover.
## Fix
Added a CN equality check after signature verification: if the CSR's CN
does not match the original certificate's CN, the renewal is rejected
with an error.
## Testing
### Unit tests (`ee/server/service/hostidentity/scep_test.go`)
Exercises `renewalMiddleware` directly with a mock datastore:
- `mismatched CN is rejected` -- constructs a renewal CSR with
`CN=attacker-identity` against an original cert with
`CN=original-host-identity`. Verifies the middleware returns an error
containing "common name does not match" and the next signer is never
called.
- `matching CN is accepted` -- constructs a renewal CSR with the same CN
as the original cert. Verifies the middleware passes through to the next
signer successfully.
### Integration tests (local, real MySQL)
Ran `TestHostIdentity` against a local MySQL 8.0.44 instance
(`MYSQL_TEST=1 REDIS_TEST=1`). All 28 subtests pass, including:
- **Certificate renewal flows** (ECC P256 orbit, ECC P384 orbit, ECC
P384 osquery) -- renewed certs preserve the original CN, host_id
binding, and work for authenticated requests.
- **Renewal replay protection** -- reusing a revoked cert's serial for
renewal is rejected.
- **Wrong cert authentication** -- cross-host cert usage is rejected (9
subtests).
- **Real SecureHW + SCEP** -- full TPM-simulated renewal flow succeeds.
- **Failure cases** -- empty/wrong challenge, oversized CN, non-ECC
algorithm all correctly rejected.
Linter passes (`make lint-go-incremental` -- 0 issues).
# 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
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Tightened certificate renewal checks so renewal requests now fail if
the new certificate request uses a different common name than the
existing certificate.
* Renewal requests with matching common names continue to work as
expected.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- Documents the new ability to combine `labels_exclude_any` with either
`labels_include_all` or `labels_include_any` on configuration profiles,
giving IT admins more granular control over profile targeting without
complex label queries.
- Adds documentation for the new `added_label_to_host` and
`removed_label_from_host` activity log entries.
- Includes GitOps YAML examples showing combined label targeting.
**Related issue:** Closes#32073
---
Built for [Mel
Pike](https://fleetdm.slack.com/archives/D0AKX7DJFCN/p1778016679163449?thread_ts=1777299502.461149&cid=D0AKX7DJFCN)
by [Kilo for Slack](https://kilo.ai/slack)
---------
Co-authored-by: Rachael Shaw <r@rachael.wtf>
Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Co-authored-by: melpike <79950145+melpike@users.noreply.github.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#38986
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a new convenience redirect route for `GET
/learn-more-about/configuration-profile-assets`, sending users to the
related configuration profile assets article section.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#47543
# 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
* **Refactor**
* Updated Android app availability to use staggered batch jobs instead
of processing everything at once, improving throughput and smoothing
workload.
* **New Features**
* Added batched handling that can perform per-host managed configuration
substitution when variables are present, including scheduling “pending
apply config” updates when required.
* **Configuration**
* Reduced the default Android batch size (`mdm.android_batch_size`) to
100.
* **Bug Fixes / Tests**
* Updated unit and integration tests to verify batching, staggering
timing, full host coverage, and order-independent policy application
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated the packaged app and generated target builds to use the latest
version across supported platforms.
* Kept release automation in sync for macOS, Linux, and Windows build
outputs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The APAC CSE role didn’t include an `onTargetEarnings` property, so it
was displaying on our website as $48k-$480k.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an explicit on-target earnings range to the Customer Support
Engineer (APAC) job posting, making compensation details clearer for
candidates.
<!-- 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
* **Chores**
* Updated maintained app definitions to reflect newer releases for
Alcove, Brave Browser, Cursor, Fastmail, Google Gemini, Node.js,
Postman, TablePlus, and Termius.
* Installation and patch detection now recognize the latest available
versions, improving upgrade checks and package availability across macOS
and Windows.
* Refreshed download details and checksums to match the newer installers
where applicable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
Permanent exclusion required to release fleetd (encrypted keys stored in
a USB stick)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Updated Mac exclusion coverage so an additional host is no longer
assigned the read-only external storage profile.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** N/A
# 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
- [x] Reproduced the issue and verified the fix
- [x] QA'd all new/changed functionality manually
## Summary
- Introduced a more granular authorization action for team membership
management
- Updated OPA policy and service-layer authorization accordingly
- Added comprehensive authorization test coverage
## Reproduction
Verified that with the previous authorization check, an API-only user
with team-scoped write access could call `PATCH
/api/latest/fleet/teams/{id}/users` to modify team membership without
restriction. After the fix, the operation correctly returns a 403
Forbidden for non-admin roles. Admin users retain full access to manage
team membership.
**Test**: `TestGitOpsCannotManageTeamMembers` in
`server/service/teams_test.go` explicitly exercises this scenario and
confirms the fix.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Tightened team member management so adding/removing team users now
requires a dedicated team-membership write permission (global admins and
team admins only, scoped appropriately).
* Prevented GitOps users from modifying team membership, including
self-promotion to admin.
* Updated enterprise integration expectations to return **403
Forbidden** for blocked membership change attempts.
* **Tests**
* Expanded authorization test coverage for team member write access
across roles and team scopes.
* Added coverage ensuring GitOps cannot manage team members, while valid
team admins can.
<!-- 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 #
# 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
* **Bug Fixes**
* Improved validation for batch script execution requests.
* Added an extra authorization check before a batch script can be
scheduled, helping ensure only permitted actions proceed.
* Expanded test coverage for role-based access during batch script
execution.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fleet added automatic renewal for SCEP certificates that are not proxied
through Fleet:
- https://github.com/fleetdm/fleet/issues/40639
I think the Okta conditional access certificate is one of these.
Update maintained app metadata and frontend mapping to reflect RealVNC
rebrand and package changes. Renamed app entries for macOS and Windows,
bumped macOS version to 8.4.2, updated bundle identifier checks and
patch queries to account for both legacy and new bundle IDs, and
replaced installer URL, checksums, and install/uninstall script refs.
Marked the Homebrew input as frozen. Also updated frontend icon mappings
to include the new "realvnc connect viewer" name (and kept a mapping for
the legacy name).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Updated the app label to **RealVNC Connect Viewer** across supported
platforms, including catalog/manifest entries.
* Added/updated icon mappings for **RealVNC Connect Viewer** and
**RealVNC Viewer**.
* **Bug Fixes**
* Updated the macOS viewer deployment to **version 8.4.2**.
* Improved upgrade/uninstall behavior to replace the legacy viewer,
relaunch the updated app, and clean up previous remnants.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## What & why
The [role-based access
guide](https://fleetdm.com/guides/role-based-access) listed
custom-variables permissions that don't match what Fleet actually
enforces in `server/authz/policy.rego` (the "Secret variables" rules):
- **Write** (create/edit/delete) is allowed for global **Admin,
Maintainer, and GitOps** only — the guide incorrectly granted it to
**Observer, Observer+, and Technician**, and omitted **GitOps**.
- **Read** (view) is allowed for **all global roles, including GitOps**
— the guide omitted GitOps.
This updates the two rows in the global permissions table so they match
enforcement (and mirror the existing "queries" rows, which share the
same role logic).
### Source of truth
`server/authz/policy.rego` — Secret variables:
```rego
# Global admins, maintainers, and gitops can write secret variables.
subject.global_role == [admin, maintainer, gitops][_] # action == write
# Any global user can read secret variables.
subject.global_role == [admin, maintainer, gitops, technician, observer_plus, observer][_] # action == read
```
### Notes
- Found during a QA chaos-engineering review (originally reported
2026-03-25): the docs implied read-only roles like Observer could
create/edit/delete custom variables, which the UI/API don't allow.
- The separate "the RBAC guide calls the Reports page the Query page"
terminology cleanup is **not** included here — it overlaps the in-flight
Query → Report rename (#41419) and is better handled there.
- Docs/article-only change; no `changes/` entry needed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Automated ingestion of latest Fleet-maintained app data.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated app metadata for MACE and Slicer on macOS to reflect newer
released versions.
* Refreshed download links and installer checksums so the latest
installers are referenced correctly.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
Automated ingestion of latest Fleet-maintained app data.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated package metadata for several maintained macOS apps, including
Acorn, BetterTouchTool, Brave Browser, Insomnia, opencode desktop,
Processing, and Signal.
* These updates point installers to the latest available versions and
refresh download checksums for safer installs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
Extracts the `/api/` request timeout/body-size override middleware out
of `runServeCmd` and into `apiTimeoutOverrideHandler` in a new
`cmd/fleet/http_middleware.go`. Same pattern as the prior extractions on
this issue (#44929, #45343, #45583, #46166, #46421, #46517, #46742,
#46830, #46893, #47151, #47562). `runServeCmd` drops from ~1000 to ~900
lines, and `serve.go` from 1475 to 1373.
The middleware is the `~100`-line `rootMux.HandleFunc("/api/", ...)`
closure that applies per-route read/write deadline overrides for
endpoints that legitimately run long — synchronous script runs, large
software-installer and bootstrap-package uploads, the Android enterprise
signup SSE stream, and large MDM profile batch operations — and, for
package-upload routes, caps the request body and threads the configured
max installer size through the request context.
Behavior is preserved — the handler is moved verbatim and wired into
`rootMux` via a single `apiTimeoutOverrideHandler(apiHandler, config,
logger)` call, so the same routes get the same overrides and every
request still falls through to `apiHandler.ServeHTTP`. The now-unused
`scripts` and `installersize` imports drop out of `serve.go`.
On test scope: `TestAPITimeoutOverrideHandler` verifies the real
decision in this middleware — that package-upload paths thread the
configured max installer size into the request context (and non-upload
requests keep the default) — and that the wrapped API handler is always
invoked. The deadline overrides themselves go through
`http.ResponseController`, which a unit-test `ResponseRecorder` doesn't
support (the handler logs and proceeds, as in production), so those are
exercised by booting the server rather than asserted in a unit test.
**Related issue:** Refs #33370
# Checklist for submitter
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually (verified via local
server boot)
- Changes file: not applicable — internal refactor with no user-visible
behavior change
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Improved timeout handling for long-running operations across the API.
Script execution, file uploads, Server-Sent Event streams, and batch
operations now have optimized request timeouts and body size limits.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->