<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#41484
Unreleased bug.
# 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`.
## 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
* **License Enforcement Updates**
* Team-scoped Mobile Device Management operations now require a premium
license. Free-tier users will receive an error when attempting to create
or manage team-level MDM declarations and profiles.
<!-- 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#42405
Demo video: https://www.youtube.com/watch?v=F3nfFvwdj-c
# 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`.
## 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**
* Android Wi‑Fi configuration profiles that reference client
certificates are withheld until the certificate is installed or reaches
a terminal state.
* Host OS settings now show the specific pending reason in the detail
column when Android profiles are waiting on certificate installation.
<!-- 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#42368
# 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. For the overall story
- [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
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#42103
# 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**
* Improved profile removal handling: Fleet now successfully removes host
OS setting entries even when the removal command encounters a "profile
not found" error from the device.
<!-- 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#42991
# 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.
- [ ] 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
**Related issue:** Resolves#42881
- Added user_api_endpoints table to track per user API endpoint
permissions.
- Added service/api_endpoints, used to handle service/api_endpoints.yml
artifact.
- Added check on server start that makes sure that
service/apin_endpoints.yml is a subset of router routes.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#36643
# 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
**Related issue:** Resolves#40076
This clears out the enrollment from migration status from the
`nano_enrollment` table if the device is going through a fresh
enrollment (aka not from an mdm migration)
# Checklist for submitter
- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
- [x] Added/updated automated tests
- [ ] QA'd all new/changed functionality manually
---------
Co-authored-by: Magnus Jensen <magnus@fleetdm.com>
Resolves#42979
- [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
Tested UI flow described in issue with:
- Global admin.
- Global maintainer.
- Team admin of one team.
- Team admin of two teams (where bug manifests).
- Team maintainer of two teams.
- Team admin of one team, maintainer of another team.
- Team admin of one team, technician of another team.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#42853
This PR simply adds the `require_all_software_windows` config option. It
doesn't use it. The logic to use it will be hooked up in subsequent PRs.
The fleetctl TestIntegrationsPreview test is expected to fail since it
builds the server against main and doesn't know about our new config
option.
# 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`.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
## New Fleet configuration settings
- [x] Verified that the setting is exported via `fleetctl
generate-gitops`
- Not exported. generate-gitops does not export
require_all_software_windows (or require_all_software_macos either). The
generateControls function (generate_gitops.go) outputs a "TODO: update
with your setup_experience configuration" placeholder when any setup
experience config exists, rather than exporting individual field values.
This is a pre-existing limitation that applies equally to both fields -
not something introduced by our PR.
- [x] Verified the setting is documented in a separate PR to [the GitOps
documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485)
- Yes. PR #42046 adds require_all_software_windows to both docs/REST
API/rest-api.md and docs/Configuration/yaml-files.md.
- [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)
- Yes, it gets cleared to false - both when setup_experience: is present
without the field, and when setup_experience: is omitted entirely. This
is the same behavior as the existing require_all_software_macos field
- [x] Verified that any relevant UI is disabled when GitOps mode is
enabled
- Covered by #42854 (frontend subtask). The existing macOS checkbox in
InstallSoftwareForm.tsx:271 already checks gitOpsModeEnabled to disable
itself. The Windows checkbox to be added in #42854 will follow the same
pattern.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a Windows setup experience software requirement setting. When
enabled, Windows devices will cancel the Autopilot setup if any required
software installation fails.
* **Tests**
* Added test coverage for the new Windows software requirement
configuration.
<!-- 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#41741
# 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
- [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**
* Software setup items are now ordered using custom display names when
available.
* **Bug Fixes**
* Software installations now process sequentially for improved
reliability and predictability.
* Enhanced handling of missing installation tracking data to prevent
failures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Ian Littman <iansltx@gmail.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#38988
# 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.
- [ ] 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)
- [ ] QA'd all new/changed functionality manually
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#42836
This is another hot path optimization.
## Before
When a host submits policy results via `SubmitDistributedQueryResults`,
the system needed to determine which policies "flipped" (changed from
passing to failing or vice versa). Each consumer computed this
independently:
```
SubmitDistributedQueryResults(policyResults)
|
+-- processScriptsForNewlyFailingPolicies
| filter to failing policies with scripts
| BUILD SUBSET of results
| CALL FlippingPoliciesForHost(subset) <-- DB query #1
| convert result to set, filter, queue scripts
|
+-- processSoftwareForNewlyFailingPolicies
| filter to failing policies with installers
| BUILD SUBSET of results
| CALL FlippingPoliciesForHost(subset) <-- DB query #2
| convert result to set, filter, queue installs
|
+-- processVPPForNewlyFailingPolicies
| filter to failing policies with VPP apps
| BUILD SUBSET of results
| CALL FlippingPoliciesForHost(subset) <-- DB query #3
| convert result to set, filter, queue VPP
|
+-- webhook filtering
| filter to webhook-enabled policies
| CALL FlippingPoliciesForHost(subset) <-- DB query #4
| register flipped policies in Redis
|
+-- RecordPolicyQueryExecutions
CALL FlippingPoliciesForHost(all results) <-- DB query #5
reset attempt counters for newly passing
INSERT/UPDATE policy_membership
```
Each `FlippingPoliciesForHost` call runs `SELECT policy_id, passes FROM
policy_membership WHERE host_id = ? AND policy_id IN (?)`. All 5 queries
hit the same table for the same host before `policy_membership` is
updated, so they all see identical state.
Each consumer also built intermediate maps to narrow down to its subset
before calling `FlippingPoliciesForHost`, then converted the result into
yet another set for filtering. This meant 3-4 temporary maps per
consumer.
## After
```
SubmitDistributedQueryResults(policyResults)
|
CALL FlippingPoliciesForHost(all results) <-- single DB query
build newFailingSet, normalize newPassing
|
+-- processScriptsForNewlyFailingPolicies
| filter to failing policies with scripts
| CHECK newFailingSet (in-memory map lookup)
| queue scripts
|
+-- processSoftwareForNewlyFailingPolicies
| filter to failing policies with installers
| CHECK newFailingSet (in-memory map lookup)
| queue installs
|
+-- processVPPForNewlyFailingPolicies
| filter to failing policies with VPP apps
| CHECK newFailingSet (in-memory map lookup)
| queue VPP
|
+-- webhook filtering
| filter to webhook-enabled policies
| FILTER newFailing/newPassing by policy IDs (in-memory)
| register flipped policies in Redis
|
+-- RecordPolicyQueryExecutions
USE pre-computed newPassing (skip DB query)
reset attempt counters for newly passing
INSERT/UPDATE policy_membership
```
The intermediate subset maps and per-consumer set conversions are
removed. Each process function goes directly from "policies with
associated automation" to "is this policy in newFailingSet?" in a single
map lookup.
# 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`.
## 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
* **Performance Improvements**
* Reduced redundant database queries during policy result submissions by
computing flipping policies once per host check-in instead of multiple
times.
<!-- 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#40015
# Details
Activates deprecation warnings for old API params and CLI args, updates
tests that would generate warnings (except for tests explicitly designed
to generate warnings).
The expectation from here on is that Fleet UI usage should not generate
any deprecation warnings in the server logs, nor should the output from
`generate-gitops` generate any warnings when fed into `gitops`.
# 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
- [ ] QA'd all new/changed functionality manually
- [X] clicked around in an mdm-enabled instance, turned setup experience
features on and off, saw no server warnings
- [X] did `fleetctl generate-gitops` on mdm-enabled instance, saw no
server or cli warnings
- [X] did `fleetctl gitops` on mdm-enabled instance, saw no server or
cli warnings
This would have helped some troubleshooting on customer workflows
failing due to long response times.
(We had a long running `spec/fleets` API request for customer-numa.)
Sample of logging after I added a `300s` sleep to
`/api/latest/fleet/config`:
```
[+] would've applied EULA
[+] would've applied certificate authorities
Error: applying fleet config: PATCH /api/latest/fleet/config: do request: Patch "https://localhost:8080/api/latest/fleet/config?dry_run=true&overwrite=true": stream error: stream ID 49; INTERNAL_ERROR; received from peer (API time: 1m40.002s)
```
Another sample error after bringing Fleet down during a GitOps run:
```
[+] would've applied 4 software packages for fleet Conditional access FTW
Error: applying software installers for fleet "Conditional access FTW": GET /api/latest/fleet/software/batch/395942cc-69c9-49f9-93d3-f1120e0b9e34: do request: Get "https://localhost:8080/api/latest/fleet/software/batch/395942cc-69c9-49f9-93d3-f1120e0b9e34?dry_run=true&fleet_name=Conditional+access+test+team&overwrite=true": dial tcp [::1]:8080: connect: connection refused (API time: 2ms)
```
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#43034
## Before (correlated subqueries):
The old query scans the policies table and for each policy row, MySQL
executes up to 3 separate subqueries against policy_labels +
label_membership:
```sql
-- For EACH policy row p:
-- Subquery 1: Does this policy have any include labels?
NOT EXISTS (
SELECT 1 FROM policy_labels pl
WHERE pl.policy_id = p.id AND pl.exclude = 0
)
-- Subquery 2: Is the host in at least one include label?
OR EXISTS (
SELECT 1 FROM policy_labels pl
INNER JOIN label_membership lm ON (lm.host_id = ? AND lm.label_id = pl.label_id)
WHERE pl.policy_id = p.id AND pl.exclude = 0
)
-- Subquery 3: Is the host in any exclude label?
AND NOT EXISTS (
SELECT 1 FROM policy_labels pl
INNER JOIN label_membership lm ON (lm.host_id = ? AND lm.label_id = pl.label_id)
WHERE pl.policy_id = p.id AND pl.exclude = 1
)
```
With 200 policies, MySQL executes up to 600 subquery probes into policy_labels and label_membership.
## After (single aggregated LEFT JOIN):
The new query first builds one aggregated result set from policy_labels + label_membership for this host, grouped by policy_id, then joins it once:
```sql
LEFT JOIN (
SELECT pl.policy_id,
MAX(CASE WHEN pl.exclude = 0 THEN 1 ELSE 0 END) AS has_include_labels,
MAX(CASE WHEN pl.exclude = 0 AND lm.host_id IS NOT NULL THEN 1 ELSE 0
END) AS host_in_include,
MAX(CASE WHEN pl.exclude = 1 AND lm.host_id IS NOT NULL THEN 1 ELSE 0
END) AS host_in_exclude
FROM policy_labels pl
LEFT JOIN label_membership lm ON lm.label_id = pl.label_id AND
lm.host_id = ?
GROUP BY pl.policy_id
) pl_agg ON pl_agg.policy_id = p.id
```
The subquery scans policy_labels once, LEFT JOINs to label_membership for the specific host, and aggregates per policy. Each policy gets three booleans:
- has_include_labels: 1 if any policy_labels row with exclude=0 exists
- host_in_include: 1 if any include label row matched a label_membership row for this host
- host_in_exclude: 1 if any exclude label row matched a label_membership row for this host
Then the WHERE clause uses these:
```sql
(COALESCE(pl_agg.has_include_labels, 0) = 0 OR pl_agg.host_in_include =
1)
AND COALESCE(pl_agg.host_in_exclude, 0) = 0
```
The COALESCE handles policies with no policy_labels rows at all (the LEFT JOIN produces NULL).
# 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`.
## Testing
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
## Release Notes
* **Refactor**
* Optimized database query efficiency for policy operations, delivering approximately 77% faster query execution at scale while improving support for label-based policy scoping.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#40057
# 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
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* OSV (Open Source Vulnerabilities) added as an optional Ubuntu
vulnerability data source and enabled by default.
* **Features**
* Integrated OSV into the vulnerability scanning pipeline, artifact
sync/refresh, detection, and cleanup flows.
* Improved Ubuntu package/kernel version matching for more accurate OSV
detections.
* **Chores**
* Added configuration flag and updated expected config fixtures.
* **Tests**
* Added extensive tests for OSV sync, artifact handling, analyzer logic,
and cleanup behaviors.
<!-- 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#41409
# Details
This PR updates the `ApplyStarterLibrary` method and functionality to
rely on the same templates and mechanisms as `fleetctl new`. The end
result is that running `fleetctl new` and `fleetctl gitops` on a new
instance should be a no-op; no changes should be made. Similarly,
changing the templates in a Fleet release will automatically affect
`fleetctl new` and `ApplyStarterLibrary` in the same exact way for that
release.
> Note that this moves the template files out of `fleetctl` and into
their own shared package. This move comprises the majority of the file
changes in the PR.
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## Testing
- [X] Added/updated automated tests
Note that
<img width="668" height="44" alt="image"
src="https://github.com/user-attachments/assets/066cd566-f91d-4661-84fc-2aabbfce2ef9"
/>
will fail until the 4.83 Fleet docker image is published, since it's
trying to push 4.83 config (including `exceptions`) to a 4.82 server.
- [X] QA'd all new/changed functionality manually
- [X] Created a new instance and validated that the fleets, policies and
labels created matched the ones created by `fleetctl new`
- [X] Ran `fleetctl new` and verified that it created the expected
folders and files
- [X] Ran `fleetctl gitops` with the files created by `fleetctl new` and
verified that the instance was unchanged.
- [X] Ran `fleetctl preview` successfully using a dev build of the Fleet
server image (since it won't work against the latest published build,
which doesn't support `exceptions`). Verified it shows the expected
teams, policies and labels
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#42808
This is another hot path optimization recommended by Claude Code. I QA'd
it with a local osquery perf run.
# 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`.
## Testing
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Enhanced performance of the distributed read endpoint by optimizing
lock contention management during jitter table access operations. This
change reduces latency and improves system responsiveness when handling
distributed read requests, particularly benefiting high-concurrency
scenarios. The optimization maintains all existing functionality while
providing better performance characteristics for read-heavy workloads.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes#40841
## Summary
The root cause of the URL mismatch described in the issue is unknown. We
couldn't reproduce it and couldn't find a deterministic code path that
explains it.
What we fix in this PR is a code defect that turns an unknown transient
condition into a hard failure. When a policy has both a URL and a hash
(which is always the case for `package_path` references), and the URL
lookup fails for any reason, a continue statement prevented the
hash-based fallback from ever running.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** The entire ACME feature branch merge
# 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
## 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
---------
Co-authored-by: Jordan Montgomery <elijah.jordan.montgomery@gmail.com>
Co-authored-by: Martin Angers <martin.n.angers@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Gabriel Hernandez <ghernandez345@gmail.com>
Co-authored-by: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#42600
# 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`.
## 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 an issue where Android device certificate template records were
not properly cleared during unenrollment, which previously resulted in
stale certificate statuses after re-enrollment.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes#40785
## Summary
When a GitOps run includes a `volume_purchasing_program` config that
references a team that doesn't exist yet, the code temporarily removes
the entire VPP config from the global AppConfig, clearing ALL VPP
token-to-team assignments on the server. However, the code only deferred
`app_store_apps` for the missing teams, not for existing teams that also
lost their VPP assignments. Those existing teams then failed with "No
available VPP Token" when their `app_store_apps` were applied.
The fix widens the deferral scope to match the clearing scope. When VPP
assignments are temporarily cleared, `app_store_apps` are now deferred
for all teams in the VPP config, not just the missing ones.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#41484
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
## Testing
- [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 a server crash that occurred when uploading a Windows MDM
profile to a team on a free license.
<!-- 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#42799
When a macOS device acknowledges a lock command it can immediately send
a trailing Idle check-in. CleanAppleMDMLock now requires that unlock_ref
to be set at least 5 minutes ago before clearing the lock state,
preventing that trailing Idle to prematurely clearing the MDM lock
state.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#34950
I changed from the original spec of 100 old commands to 3 due to load
test results. Admittedly my load test meant a very large number of hosts
all checked in and triggered deletion at once but at 100 per host and
per command the load was too high. 3 still results in cleanup over time
and doesn't seem to cause load issues.
# 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)
- [x] QA'd all new/changed functionality manually
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Resolves#40164
Manually verified:
<img width="785" height="187" alt="image"
src="https://github.com/user-attachments/assets/c2b91fd4-3592-4760-8241-c33a89e162c0"
/>
Adds a "Learn more" link to the [End-user
Authentication](https://fleetdm.com/guides/setup-experience#end-user-authentication)
documentation on the `/settings/integrations/sso/end-users` page, making
it easier for customers to reference docs while configuring SSO
settings.
- **`EndUserAuthSection.tsx`**: Appended a `Learn more` anchor (opens in
new tab) after the description text in the end-user auth settings card.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a "Learn more" link in the end user authentication setup
section, providing quick access to comprehensive setup guidance and
documentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: getvictor <2685025+getvictor@users.noreply.github.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#40117
Fix:
<img width="1033" height="320" alt="image"
src="https://github.com/user-attachments/assets/a6a642ef-d174-4ca7-b89b-8bb127c5c961"
/>
# 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`.
## Testing
- [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 incorrect platform detection for SQL queries that use table
aliases (e.g., `FROM mounts m`).
<!-- 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#37546
Docs: https://github.com/fleetdm/fleet/pull/42780
Demo: https://www.youtube.com/watch?v=K44wRg9_79M
# 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
## Database migrations
- [x] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Automatic retry for Android certificate installations: failed installs
are retried up to 3 times before marked terminal.
* Installation activities recorded: install/failed-install events (with
details) are logged for better visibility and troubleshooting.
* Resend/reset actions now reset retry state so retries behave
predictably after manual resend.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- [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] QA'd all new/changed functionality manually
Server log when SCIM ingestion receives a deactivation event for the
last admin:
```log
ts=2026-04-01T15:23:01Z level=error msg="failed to delete fleet user on deactivation" component=SCIM err="cannot delete last global admin"
```
Server response when attempting to demote last admin:
```json
{
"message": "Validation Failed",
"errors": [
{
"name": "global_role",
"reason": "cannot demote the last global admin"
}
],
"uuid": "1d110f56-25ac-47b8-bc96-982354474a87"
}
```
Server response when attempting to delete last admin:
```json
{
"message": "Validation Failed",
"errors": [
{
"name": "id",
"reason": "cannot delete the last global admin"
}
],
"uuid": "1448c2da-30e2-4652-a9a8-a01fc4f9b9c1"
}
```
---
## Original AI Summary
- Fixes a TOCTOU race condition where two concurrent admin operations
could bypass the last-global-admin guard, leaving zero admins and
permanently locking out the Fleet instance (fleetdm/confidential#14827)
- Introduces two new atomic datastore methods
(`DeleteUserIfNotLastAdmin`, `SaveUserIfNotLastAdmin`) that wrap the
admin count check and the write in a single MySQL transaction with
`SELECT ... FOR UPDATE`
- Fixes all four vulnerable code paths: service `DeleteUser`, service
`ModifyUser` (two demotion paths), and SCIM user deletion
## Test plan
- [X] Manual verification: single admin cannot be deleted or demoted
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#37546
Noah approved design here:
https://fleetdm.slack.com/archives/C09HG9VMRSS/p1774895365069069?thread_ts=1774647818.613419&cid=C09HG9VMRSS
Docs: https://github.com/fleetdm/fleet/pull/42609
# 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`.
## Testing
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Certificate installation activity logging for Android hosts (success &
failure)
* "Installed certificate" activity type displayed in host activity feed
with status
* Host activity card enabled on Android host details page to show
installs
* Detailed install modal with error detail reveal when failures occur
* Upcoming activities tab disabled for Android hosts where unsupported
<!-- 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#40317
# 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
- [ ] Added/updated automated tests
With the current router we have in place, we can't really test `<Link>`
elements, so our ability to make useful automated tests is pretty
limited here. I extracted the fleet name sorting code into an exported
function and added some tests for that.
- [X] QA'd all new/changed functionality manually
- [X] verified that when All Fleets is selected in dropdown, navigating
to Controls switches to Workstations
- [X] verified that when another fleet is selected in dropdown,
navigating to Controls maintains that selection
- [X] verified that when a fleet is selected in dropdown, navigating to
the dashboard changes to All Fleets
- [X] verified that when "Unassigned" is present in the fleets dropdown,
it is at the bottom
- [X] verified that when using a permalink to the dashboard with a fleet
selected (e.g. `?fleet_id=1`), the correct fleet shows as selected
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#39190https://www.loom.com/share/3c1828f03c584756b7ed8f3ba75a1038
<img width="1840" height="1196" alt="Screenshot 2026-03-30 at 1 08
32 PM"
src="https://github.com/user-attachments/assets/592c9396-65b4-4723-99e7-63f9ee0264c1"
/>
- [x] Changes file added for user-visible changes in `changes/`
- [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**
* Resolved host filtering by software version when the version is not
available on the selected team; now returns software information instead
of an error.
* Fixed a related UI issue caused by the original filtering 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#41710
Updates (only) macOS software title names on FMA catalog sync.
Updates software title names on installer upload for Windows FMAs with
an upgrade code.
# 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.
- [ ] 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.
- [ ] 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
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#36751
# 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
- [X] Verified that `fleetctl generate-gitops` correctly outputs
policies with `install_software.fleet_maintained_app_slug` populated
when the policies have FMA automation
- [X] Verified that running `fleetctl gitops` using files with
`install_software.fleet_maintained_app_slug` creates/updates FMA policy
automation correctly
- [X] Verified no changes to the above for custom packages or VPP apps
- [X] Verified that when software is excepted from GitOps, FMA policy
automations still work (correctly validates FMAs exist before applying)
## 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:
- [X] 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)
checking on this
- [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)
- [X] Verified that any relevant UI is disabled when GitOps mode is
enabled