This pull request improves the reliability and efficiency of the Winget
ingester by introducing robust retry logic for fetching manifest files
and directory contents, switching to CDN-backed raw file downloads, and
updating tests to cover these changes. The main focus is on handling
transient errors (like rate limits and server errors) gracefully,
preventing ingestion failures due to temporary issues with GitHub's API
or file servers.
**Reliability improvements for manifest fetching:**
* Added `getRawManifestFile` method to fetch manifest files directly
from `raw.githubusercontent.com` (or a testable override), avoiding
GitHub API rate limits and using CDN-backed downloads. This method
implements retry logic for transient HTTP errors (e.g., 429, 5xx), with
exponential backoff, and returns a specific error for missing files.
(`ee/maintained-apps/ingesters/winget/ingester.go`)
* Introduced `getRepoDirContents` method to list repository directories
via the GitHub API with retry logic for transient errors, improving
resilience against API throttling.
(`ee/maintained-apps/ingesters/winget/ingester.go`)
**Ingestion logic updates:**
* Updated `ingestOne` to use the new retry-enabled methods for both
directory listing and manifest file fetching, ensuring that only true
missing files are skipped and transient errors cause a controlled
failure, not silent downgrades.
(`ee/maintained-apps/ingesters/winget/ingester.go`)
[[1]](diffhunk://#diff-eb6c4ae7be41e61a2292c4240de750809d40c0686fb01f80f52df056ebc9c2a8L143-R270)
[[2]](diffhunk://#diff-eb6c4ae7be41e61a2292c4240de750809d40c0686fb01f80f52df056ebc9c2a8L182-R324)
**Test enhancements:**
* Modified test server and test cases to simulate the new raw file
fetching logic, including scenarios for retries, maximum attempts, and
handling of 404 errors. Added comprehensive tests for both
`getRawManifestFile` and `getRepoDirContents` retry behavior.
(`ee/maintained-apps/ingesters/winget/ingester_test.go`)
[[1]](diffhunk://#diff-c68f0564df3c6e38ad333d4ca6e1040305eb079eb0d168d29c95b1b250463055L509-R512)
[[2]](diffhunk://#diff-c68f0564df3c6e38ad333d4ca6e1040305eb079eb0d168d29c95b1b250463055L529-R678)
* Improved test reliability by reducing retry intervals for faster test
execution and using assertions for YAML marshaling and writing.
(`ee/maintained-apps/ingesters/winget/ingester_test.go`)
**Dependency and setup changes:**
* Added necessary imports for new functionality (`io`, `net/http`,
`net/url`, `time`, and `github.com/fleetdm/fleet/v4/pkg/retry`) and
updated struct initialization to support the new fields.
(`ee/maintained-apps/ingesters/winget/ingester.go`,
`ee/maintained-apps/ingesters/winget/ingester_test.go`)
[[1]](diffhunk://#diff-eb6c4ae7be41e61a2292c4240de750809d40c0686fb01f80f52df056ebc9c2a8R7-R25)
[[2]](diffhunk://#diff-eb6c4ae7be41e61a2292c4240de750809d40c0686fb01f80f52df056ebc9c2a8R52-R53)
[[3]](diffhunk://#diff-c68f0564df3c6e38ad333d4ca6e1040305eb079eb0d168d29c95b1b250463055R474-R475)
These changes make the Winget ingestion process more robust against
transient infrastructure issues and provide better test coverage for
error handling and retry logic.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved app ingestion resilience when GitHub returns transient
rate-limit or server errors, so a single failure no longer stops the
full import run.
* Added clearer handling for missing installer data: only genuine “not
found” responses now fall back to an older version, while other errors
are surfaced properly.
* **Tests**
* Added coverage for version fallback behavior and transient error
handling during ingestion.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Resolves#46461.
- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
---
Verification command (checks how many times /proc/stat is read):
```
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_openat
/str(args->filename) == "/proc/stat" || str(args->filename) == "/proc/uptime"/
{ @[comm, str(args->filename)] = count(); }
interval:s:60 { exit(); }'
```
1.57.0 outputs:
```
@[orbit, /proc/stat]: 1084
```
fleetd built with changes in this PR (and I had to trigger a restart,
otherwise it's 0):
```
@[orbit, /proc/stat]: 3
[...]
@[fleet-desktop, /proc/stat]: 6
```
## Testing
- [X] QA'd all new/changed functionality manually
## fleetd/orbit/Fleet Desktop
- [x] Verified compatibility with the latest released version of Fleet
(see [Must
rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md))
- [X] If the change applies to only one platform, confirmed that
`runtime.GOOS` is used as needed to isolate changes
- [X] Verified that fleetd runs on macOS, Linux and Windows
- [X] Verified auto-update works from the released version of component
to the new version (see [tools/tuf/test](../tools/tuf/test/README.md))
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved process listing performance on Linux by reducing repeated
system boot-time reads.
* Prevented unnecessary refreshes during frequent process checks,
helping watchdog-style polling run more efficiently.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#48418
Fixes the missing download button for custom software packages on the
software details page by gating the button on whether the package has a
downloadable installer file, rather than on the package's source URL
(which is empty for directly-uploaded custom packages).
# Checklist for submitter
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<img width="1400" height="1000" alt="FIXED-custom-package-receipts"
src="https://github.com/user-attachments/assets/7be76a27-3f2f-463e-8cdd-481e6058be53"
/>
<img width="1400" height="1000" alt="FIXED-fma-010editor"
src="https://github.com/user-attachments/assets/5ba0aaa9-c15c-4e4a-bd5a-342e100d164e"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Updated library item download visibility to rely on an explicit
download permission, so the download button now appears only when
downloading is allowed.
* Aligned software page rows and stories with the new download behavior
across active library items.
* Refined related test coverage and examples to match the updated
download-button logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#41056
Docs: https://github.com/fleetdm/fleet/pull/48735/changes
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## Testing
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary
* **Bug Fixes**
* Removed the obsolete Windows MDM authentication (unauthenticated STS)
endpoint; it now returns **HTTP 404**.
* Streamlined the Windows enrollment flow so only the supported
Microsoft MDM endpoints are exposed.
* **Testing**
* Added an integration test to confirm the removed endpoint remains
inaccessible.
* Removed now-irrelevant unit tests and helpers related to the deleted
authentication behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Surface the existing "Certificates" card on the host details page for
Windows hosts, with parity to macOS. Requires osquery 5.23.1 or higher.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#31294
Demo video: https://www.youtube.com/watch?v=kGRp-YtnnJc
Docs: https://github.com/fleetdm/fleet/pull/48493/changes
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [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
## 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.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary by CodeRabbit
* **New Features**
* Windows host certificates now display on the host details page (gated
by minimum agent/osquery version), including scope (**System** vs
**User**) and improved scope-aware certificates list details.
* **Bug Fixes**
* Certificate table labeling and help text are now platform-appropriate
(with “Keychain” renamed to “Scope”).
* Windows certificate reconciliation is more resilient, preserving
certificates for scopes not observed during a collection run and
preventing row collapsing when ids repeat across scopes.
* **Tests**
* Expanded coverage for Windows/malformed DN parsing and scope-aware
reconciliation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#48530
Fixes wrong platform-title capitalization in the "Filtered" tag tooltip
on the Hosts and Vulnerabilities dashboard charts.
# Checklist for submitter
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] 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 chart tooltip text for host/platform filters, ensuring
branded platform names keep correct capitalization and combined lists
use correct punctuation.
* Refined chart tooltip/platform display mapping to avoid incorrect
capitalization variants.
* **New Features**
* Updated browser chart category labeling to show “Browsers” with
consistent capitalization.
* **Tests**
* Expanded ChartCard tests to validate platform tooltip line formatting
for single and multiple selections.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Moves opening context paragraphs in several articles to follow the key
takeaways section for a more consistent structure. Also refines a few
takeaway phrases for clarity and updates calls to action, including
linking the Managed Migration Assistant article to the setup guide and
simplifying the closing CTA in the config-as-code article.
Fixes data race detected in
https://github.com/fleetdm/fleet/actions/runs/28769705097/job/85300822820.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved reliability of log delivery by ensuring buffered log data is
copied before being sent, preventing intermittent issues when batches
are processed.
* Reduced the risk of log entries being corrupted or lost during
transmission.
<!-- 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#45650
# 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] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary by CodeRabbit
* **Bug Fixes**
* Improved MySQL migration handling for MDM command results by safely
removing an outdated foreign key when present, preventing issues during
upgrade and re-run scenarios.
* Updated the database schema definition to keep related response
foreign key behavior consistent.
* **Chores**
* Added the latest migration version to the migration status seed data
to ensure version tracking stays in sync.
<!-- 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.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Documentation**
* Added a new customer testimonial highlighting Fleet’s device
management experience, including the customer quote, role, and profile
link.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Eric <eashaw@sailsjs.com>
- [x] QA'd all new/changed functionality manually
- Enrollment methods: ADE, profile-based manual, Managed Apple Account
- Also, update Controls > Setup experience copy. "Automatically" only
applies to macOS:
<img width="505" height="168" alt="Screenshot 2026-07-02 at 9 41 17 AM"
src="https://github.com/user-attachments/assets/ff46682f-e87b-4d2e-9889-7d0382b0d3d5"
/>
- Every other platform:
<img width="517" height="174" alt="Screenshot 2026-07-02 at 9 41 31 AM"
src="https://github.com/user-attachments/assets/0ab115fb-76fb-4080-afb4-52edcf4900b7"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Updated the setup guidance text for platform-specific enrollment so
macOS now shows “automatically enroll to Fleet.”
* Other platforms continue to show “enroll to Fleet,” improving clarity
in the install experience.
* **Tests**
* Adjusted the Android empty-state test to match the updated enrollment
wording.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** NA
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] QA'd all new/changed functionality manually
---
Brings `articles/control-apple-beta-programs-with-ddm.md` up to the
current article format:
- Moved the "Key takeaways" section and CTA button directly under the
dek, ahead of the intro, so the full argument sits at the top of the
page.
- Reworded two takeaways ("Beta control is no longer all-or-nothing" and
the token-fetching bullet) that echoed body sentences nearly verbatim —
takeaways now preview the body instead of repeating it.
No changes to metadata, links, or the substance of the article.
@headmin can you give this a review? The intention was not to rewrite
your article but to have it follow the new article format.
---
Reframes the opening to focus on operational cost and team dependency
tradeoffs, adds a new "Key takeaways" section, and inserts an early CTA
link. Also normalizes capitalization in the closing demo bullet for
consistency.
Fixes:
https://github.com/fleetdm/fleet/actions/runs/28775213423/job/85317520154.
New run: https://github.com/fleetdm/fleet/actions/runs/28779783653.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Added vulnerability status information for a known issue affecting
`fleetctl`, clarifying that it is not impacted by the reported problem.
* Included a note explaining why the affected code path is not reached
in typical use.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#45710
# Checklist for submitter
- [x] Changes file added (`changes/45710-zorin-os-support`).
- [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 —
`server/vulnerabilities/oval/oval_platform_test.go` extended with Zorin
→ Ubuntu LTS mapping cases (16/17/18) plus an unknown-version case
(`Zorin OS 99` → `zorin_99`, which `IsSupported()` rejects).
- [x] QA'd all new/changed functionality manually — Zorin OS 17.0 and
18.1 hosts enrolled against a patched Fleet server, host details show
`platform=zorin`, software inventory populates, and OVAL CVE matching
produces results against the corresponding `ubuntu_2204` / `ubuntu_2404`
feeds.
## Database migrations
- N/A. No schema changes.
## New Fleet configuration settings
- N/A. No new settings.
## fleetd/orbit/Fleet Desktop
- N/A. Server + frontend only; no fleetd/orbit changes.
---
## Summary
Fleet previously logged `unrecognized platform` for Zorin OS hosts
(osquery reports `platform=zorin` from `/etc/os-release` `ID=zorin`).
The common workaround was running osquery with
`--force_platform=ubuntu`, which masquerades the host. This change adds
`zorin` as a first-class Linux platform alongside Ubuntu:
- **`server/fleet/hosts.go`** — register `zorin` in `HostLinuxOSs` and
`HostDebPackageOSs`
- **`server/datastore/mysql/linux_mdm.go`** — include Zorin in the Linux
disk-encryption summary query
- **`server/vulnerabilities/oval/oval_platform.go`** — map Zorin major
version to the underlying Ubuntu LTS OVAL feed (16 → 20.04, 17 → 22.04,
18 → 24.04). Unknown future versions fall through to an unsupported
`zorin_<major>` identifier so vulnerability scanning is skipped rather
than served stale data from an aging LTS feed.
- **frontend** — add `zorin` to `HOST_LINUX_PLATFORMS`, the
disk-encryption support list and type guard, the label platform
dropdown, and the icon mapping (Ubuntu icon, since no Zorin-specific
asset exists in the repo).
No new dependency, schema migration, or config setting. Reuses existing
Ubuntu OVAL feeds and the existing Ubuntu icon.
Diff is ~30 lines net across 9 files (8 patched + 1 `changes/` file).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added Zorin OS as a supported Linux platform.
* Zorin hosts included in Linux disk-encryption summaries and treated as
disk-encryption capable.
* Zorin OS available as a selectable/filterable platform label and
considered DEB-install compatible.
* Vulnerability scanning enabled for Zorin 16→Ubuntu 20.04, 17→22.04,
18→24.04; unknown/future Zorin versions are marked unsupported and
skipped for CVE matching.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45712?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Reworks the article opening with a stronger headline, intro framing, and
a new key takeaways section plus CTA. It also tightens product language
(agent/query-based verification, Premium benchmark availability),
simplifies the “what changes” section into a clearer narrative, and
updates metadata by moving the category from `security` to `articles`.
**Related issue:** N/A
New article: "Take control of Apple beta programs with declarative
device management."
Covers the `com.apple.configuration.softwareupdate.settings` DDM
declaration for controlling Apple beta program enrollment, automating
AppleSeed for IT token retrieval from Apple Business Manager using the
Microsoft/HCS `betaTokens.sh` script, and deploying the declaration
through Fleet's custom OS settings (UI upload or GitOps) with
label-based scoping.
Follows the Fleet article format: dek, key takeaways above the fold,
post-takeaways CTA button, and closing "See it live" block.
Notes for reviewers:
- Verified `com.apple.configuration.softwareupdate.settings` is not in
Fleet's `ForbiddenDeclTypes` (`server/fleet/apple_mdm.go`), so the
"deploy with Fleet" section is accurate.
- CTA routes (`/try-fleet`, `/gitops-workshop`,
`/guides/custom-os-settings`) verified against
`website/config/routes.js`.
- Please click-check the Apple developer docs link for the
`SoftwareUpdateSettings` schema.
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Article-only change; no changes file, tests, migrations, or config
changes needed.
---------
Co-authored-by: Harrison Ravazzolo <38767391+harrisonravazzolo@users.noreply.github.com>
Adds WinDirStat to maintained apps for Windows by introducing the winget
input metadata, generated app output entries, and installer/uninstaller
version data. Also adds the WinDirStat icon asset and wires it into the
SoftwarePage icon map so the app displays with the correct branding in
the UI.
- Clarified the absence of a Refetch button for Android hosts
- Removed "Sync policies" header because the term policies could be
confusing. After that, just decided to remove the headers because the
article is short.
- Piece of the following request:
https://github.com/fleetdm/fleet/issues/42755
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 the Windows release metadata for Cursor to version 3.10.11,
including the download link and checksum.
* Updated the Windows release metadata for DBeaver Community to version
26.1.2, including the download link and checksum.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
**Related issue:** Resolves#46235
# 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: Pending if possible
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed DEP sync so progress is only saved after device data is written
successfully, preventing missed enrollment events during interrupted
syncs.
* Improved handling of sync errors so the next run can safely replay
affected devices instead of skipping them.
* Added end-to-end and scenario coverage to verify cursor behavior after
successful syncs, errors, and expired cursors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#48277
## What & why
Running a live report/query (or live policy) on some machines throws a
full error page once results start streaming in:
```
NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
```
**Root cause:** Chrome's built-in auto-translate (Google Translate)
wraps text nodes in `<font>` elements, detaching the original DOM nodes
React holds references to. As live results stream in over the websocket,
table cells (and the responded-count heading) unmount rapidly; React
then calls `parentNode.removeChild(node)` on a node Translate has
already moved, throwing `NotFoundError`. The app's error boundary
catches it and renders the error page (facebook/react#11538).
This is why it's machine-dependent: it only reproduces when Chrome is
translating the page. It surfaces on live results specifically because
that's one of the few surfaces that unmounts DOM rapidly while
displaying translatable text.
**Fix:** Exclude the live-results subtrees from translation via the
`notranslate` class on the top-level containers of `QueryResults` (live
report/query) and `PolicyResults` (live policy). These wrappers cover
the `LiveResultsHeading` counts, the results table, and (policy) the
errors table. Translation stays enabled everywhere else in the app.
## How to reproduce / QA
1. In Chrome, enable translation of the live results page (right-click →
Translate to English, or set a non-English preferred language so the
Translate banner activates and choose "Always translate").
2. Run a live query/report or live policy targeting several hosts so
results stream in.
3. Before the fix: error page appears after a few results. After the
fix: results render normally.
# Checklist for submitter
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] QA'd all new/changed functionality manually
For unreleased bug fixes in a release candidate, one of:
- [x] Confirmed that the fix is not expected to adversely impact load
test results
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Prevented browser auto-translation from modifying live results areas
in the policy and query editors.
* Reduces the chance of display errors during live streaming/remounting
of results.
* Addressed a related Google Translate browser extension issue that
could lead to incorrect live-run behavior.
* **Chores**
* Added a changelog entry for the live results translation fix.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Fully resolves
https://github.com/fleetdm/fleet/issues/34591.
## Testing
- [X] QA'd all new/changed functionality manually.
<img width="533" height="454" alt="Screenshot 2026-07-03 at 10 40 37 AM"
src="https://github.com/user-attachments/assets/892fb548-21c6-467c-b270-65f1c9338fdc"
/>
<img width="1287" height="259" alt="Screenshot 2026-07-03 at 10 41
55 AM"
src="https://github.com/user-attachments/assets/d3528b0c-0d05-4ace-8512-ab363241b97c"
/>
<img width="1077" height="123" alt="Screenshot 2026-07-03 at 10 41
46 AM"
src="https://github.com/user-attachments/assets/249e80de-320c-48f3-962a-59c98c736c54"
/>
<img width="725" height="208" alt="Screenshot 2026-07-03 at 10 41 32 AM"
src="https://github.com/user-attachments/assets/361764cf-26fc-4a44-b5d6-489d883a392b"
/>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added CachyOS Linux to rolling-release OS detection and reporting.
* Added a CachyOS fleetd package/image variant and a new CachyOS fleetd
service for local testing.
* **Bug Fixes**
* Improved rolling-release OS version labeling for host “Vitals”
display.
* Updated OS inventory normalization so CachyOS is aggregated with Arch
Linux, including correct “rolling” version handling.
* **Tests**
* Expanded OS version ingest test coverage for rolling-release and
CachyOS scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#39323
Missed updating [the case of a
word](https://github.com/fleetdm/fleet/issues/39323#issuecomment-4890263095)
in #47603.
# Checklist for submitter
## Testing
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Style**
* Updated the query description field help text to use consistent
capitalization (“optional” instead of “Optional”).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Related to: #39962
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added pre-install checks to prevent several fleet-managed app installs
from starting while the apps are already running (including Slack and
Zoom, plus others).
* Enabled automatic update installation with continuous automations for
a broad set of macOS and Windows apps, including Chrome, 1Password,
Slack, Zoom, and Visual Studio Code.
* **Bug Fixes**
* Updated update guidance to direct users to Self-service for the latest
versions, reducing conflicting “built-in update” instructions when apps
are already running.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Allen Houchins <allenhouchins@mac.com>
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 release metadata for several apps to their latest
versions, including DBeaver Community, DockDoor, Marked, OnlySwitch,
OpenRCT2, Spokenly, and Tunnelblick.
* Refreshes download links and checksums so installers point to the
newest available releases.
* **Bug Fixes**
* Improved patch detection logic to match the updated app versions,
helping keep upgrade checks accurate.
<!-- 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
* **Bug Fixes**
* Updated the macOS app entries for Clop and Stats to the latest
available versions.
* Refreshed download links and checksums so installs point to the
correct release artifacts.
<!-- 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 release metadata for several maintained apps to newer
versions, including BetterMouse, Beyond Compare, Clop, CodexBar,
DaisyDisk, and Kiro.
* Refreshed installer links and checksums so the latest available
packages are detected and installed correctly.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
Replace the hardcoded FLEET_MYSQL_MAX_OPEN_CONNS=10 in the loadtest
terraform (both the root ecs.tf stack and the infra/ stack) with a
mysql_max_open_conns variable, applied to both the writer and
read-replica pools.
Also document per-tier connection pool sizing in the AWS reference
architecture: 20 for R-class instances (25k+ hosts), 10 for the smaller
T-class instances (5k/10k hosts) whose low default max_connections
(~90/135) leaves little headroom.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#44802
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a configurable setting for MySQL connection limits in the load
testing environment.
* Connection settings now use a shared input value instead of fixed
defaults, making it easier to tune database load behavior across
container types.
<!-- 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**
* Refreshed release metadata for multiple maintained apps across macOS
and Windows by updating versions, installer download links, and
integrity checks so the latest installers are recognized.
* **New Features**
* Added an Egnyte Windows installer script that runs the MSI with
detailed logging and treats reboot-required outcomes as successful,
ensuring required follow-up behavior occurs on the next reboot.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: allenhouchins <32207388+allenhouchins@users.noreply.github.com>
Co-authored-by: Allen Houchins <allenhouchins@mac.com>
Related to: https://github.com/fleetdm/fleet/issues/48052
Changes:
- Added a JSON `pageFaqForSeo` to the device management page's view
action
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added schema.org FAQ structured data to the device management page to
improve search visibility and enable richer search results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#48697
## Summary
The hourly `UpdateQueryAggregatedStats` cron job currently walks **every
query ID** in the `queries` table and runs 5 expensive
percentile-calculation queries per query against
`scheduled_query_stats`, plus 1 INSERT/UPDATE to store results. Most
queries have no execution data at all (they are saved queries,
live-only, or de-scheduled), so this work is pure waste.
This PR changes the cron to only process queries that actually have
execution data, by querying `scheduled_query_stats` directly instead of
the `queries` table. The now-unused `walkIdsInTable` helper function is
also removed.
### How the calculations work
`CalculateAggregatedPerfStatsPercentiles` computes performance
statistics for each query that has been scheduled and executed by hosts.
For each qualifying query ID, it runs these operations against the read
replica:
1. **P50 user_time** -- Calculates the median (50th percentile) of
per-host average user-mode CPU time. The query groups
`scheduled_query_stats` rows by `host_id`, computes `SUM(user_time) /
SUM(executions)` per host, sorts them, then picks the row at position
`FLOOR(total_rows * 0.5) + 1` using a `@rownum` session variable.
2. **P95 user_time** -- Same calculation but picks the 95th percentile
row (`FLOOR(total_rows * 0.95) + 1`).
3. **P50 system_time** -- Same percentile calculation for kernel/system
CPU time.
4. **P95 system_time** -- 95th percentile of system CPU time.
5. **Total executions** -- `SELECT COALESCE(SUM(executions), 0) FROM
scheduled_query_stats WHERE scheduled_query_id = ?`
6. **INSERT/UPDATE** -- Writes the JSON result (`user_time_p50`,
`user_time_p95`, `system_time_p50`, `system_time_p95`,
`total_executions`) into the `aggregated_stats` table via `INSERT ... ON
DUPLICATE KEY UPDATE`.
### What changed
**Before:** `SELECT id FROM queries` -- walks every query (200-400+ in a
typical deployment).
**After:** `SELECT DISTINCT scheduled_query_id FROM
scheduled_query_stats WHERE executions > 0` -- walks only queries that
have actual execution data (typically 10-20).
### Benchmark results (MySQL 8.0, 300 queries seeded, only 15 with
stats)
| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| Avg time per cron run | 3.36s | 0.28s | **12.2x faster** |
| DB operations per run | 1,800 | 90 | **95% fewer** |
| DB operations per day | 43,200 | 2,160 | **41,040 eliminated** |
| `aggregated_stats` rows written | 300 (285 empty) | 15 (all
meaningful) | Less table bloat |
| Correctness | baseline | byte-identical JSON | **Zero regression** |
At 500+ queries the current approach **drops MySQL connections**
(`unexpected EOF` / `invalid connection`) because the cursor is held
open across thousands of heavy serial queries. The optimized version
handles any scale trivially.
### Impact analysis
Verified safe across all consumers: all query endpoints use `LEFT JOIN
aggregated_stats` (NULL-safe for missing rows), the frontend explicitly
handles null stats as "Undetermined", live query stats
(`service_campaigns.go`) call `CalculateAggregatedPerfStatsPercentiles`
directly and are unaffected, and query deletion already cleans up both
`scheduled_query_stats` and `aggregated_stats` rows.
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [x] Added/updated automated tests
- [x] Confirmed that the fix is not expected to adversely impact load
test results
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolves#47241.
- [X] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
- [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**
* Better host policy results by automatically cleaning up out-of-scope
`policy_membership` records.
* Refreshes host failing-policy counts after cleanup, including when
distributed writes report “no policies in scope.”
* Preserves existing safeguards by skipping this cleanup during
setup/initial configuration to prevent premature updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes the `device_mapping` ordering flake in
`TestIntegrations/TestListHostsByLabel` and
`TestIntegrations/TestHostsReportDownload`, seen across integration-core
jobs on `main` since July 1 (e.g. [this
run](https://github.com/fleetdm/fleet/actions/runs/28567132474)).
#48488 replaced the derived-table `GROUP_CONCAT` join in `ListHosts`
with a correlated subquery, but the `GROUP_CONCAT` has no `ORDER BY`, so
MySQL returns `device_mapping` entries in arbitrary order. The old plan
happened to read `idx_host_emails_host_id_email` in index order, which
masked this; the new access path doesn't, so the order now varies
between endpoints and runs — the tests compare `GET /hosts` output
against `GET /labels/{id}/hosts` (and CSV report) output for the same
host and intermittently see `[b@b.c, a@b.c]` vs `[a@b.c, b@b.c]`.
This adds `ORDER BY he.email, he.source` inside the `GROUP_CONCAT`,
matching the ordering of the single-host `listHostDeviceMappingDB`
query. The sort applies only within each host's few email rows, so it
doesn't affect the perf improvement from #48488.
No changes file: #48488 is unreleased (not in any RC branch), so this is
a fix to an unreleased change.
# Checklist for submitter
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
Covered by existing tests: `TestIntegrations/TestListHostsByLabel` and
`TestIntegrations/TestHostsReportDownload` assert the (now
deterministic) ordering. Ran both 4× locally with `MYSQL_TEST=1
REDIS_TEST=1`, plus the `TestHosts` device-mapping/ListHosts datastore
tests — all green.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved consistency of host device mapping results by making the
ordering deterministic.
* Fixed an issue where device mapping entries could appear in different
orders between requests.
* **Tests**
* Added coverage to verify the device mapping order remains stable and
predictable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#25574
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), 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] QA'd all new/changed functionality manually
---
## Summary
- Adds a new `splunk` log plugin that sends osquery logs directly to
Splunk's HTTP Event Collector (HEC) endpoint
- Eliminates the need for middleware like AWS Firehose when using Splunk
as a log destination
- Follows the same pattern as existing log destinations (Firehose, Kafka
REST, NATS, etc.)
- Includes `insecure_skip_verify` option for environments with
self-signed TLS certs
## UI changes
Follows the same pattern as the NATS log destination PR (#36527) --
adding "Splunk" to the display name, tooltip, and TypeScript type union.
No new components, pages, or styles.
### Manage automations modal -- "Log destination: Splunk"
<img width="822" height="527" alt="image"
src="https://github.com/user-attachments/assets/2533207f-fa95-4364-8ee0-3c39cd3e8e4d"
/>
### Query details page -- "Log destination: Splunk"
<img width="1905" height="662" alt="image"
src="https://github.com/user-attachments/assets/069a5005-f95c-4562-a819-fd8bdcc349f7"
/>
### Tooltip on hover
<img width="639" height="348" alt="image"
src="https://github.com/user-attachments/assets/809a47a6-b82a-4f45-b731-77b2d2c87947"
/>
### Edit query form -- "sent to your log destination: Splunk"
<img width="451" height="814" alt="image"
src="https://github.com/user-attachments/assets/b78b9a57-1f0c-4413-8b7c-654de1fd40a2"
/>
### Save new query modal -- "sent to your log destination: Splunk"
<img width="536" height="698" alt="image"
src="https://github.com/user-attachments/assets/d0a0ab01-66fe-4d63-9190-9c5e840e456d"
/>
---
### How it works
The Splunk writer (`server/logging/splunk.go`) implements the
`fleet.JSONLogger` interface. On startup it performs a health check
against the HEC `/services/collector/health` endpoint. On each `Write()`
call, it wraps each log entry in Splunk's HEC event format (adding
`time`, `index`, `source`, `sourcetype`), batches them up to 1 MB, and
POSTs to `/services/collector/event` with the `Authorization: Splunk
<token>` header. If a batch exceeds 1 MB it flushes and starts a new
one. Events over 1 MB are dropped with a log warning. Transient errors
(HTTP 503) are retried with exponential backoff (up to 8 retries).
### Configuration
```yaml
osquery:
status_log_plugin: splunk
result_log_plugin: splunk
splunk:
url: https://splunk.example.com:8088
token: <HEC token>
index: main
source: fleet
source_type: fleet:json
insecure_skip_verify: false # set true for self-signed certs
```
Or via environment variables:
```
FLEET_OSQUERY_STATUS_LOG_PLUGIN=splunk
FLEET_OSQUERY_RESULT_LOG_PLUGIN=splunk
FLEET_SPLUNK_URL=https://splunk.example.com:8088
FLEET_SPLUNK_TOKEN=<HEC token>
FLEET_SPLUNK_INDEX=main
FLEET_SPLUNK_SOURCE=fleet
FLEET_SPLUNK_SOURCE_TYPE=fleet:json
```
### Files changed
- `server/logging/splunk.go` -- Splunk HEC log writer with batching,
retry, and health check
- `server/logging/splunk_test.go` -- 9 unit tests
- `server/logging/splunk_integration_test.go` -- 3 integration tests
against real Splunk (gated by env var)
- `server/logging/logging.go` -- Added `SplunkConfig` and `case
"splunk"` to factory
- `server/config/config.go` -- Added `SplunkConfig` struct and config
flags
- `cmd/fleet/logging.go` -- Wired Splunk config into logging builder
- `server/fleet/app.go` -- Added `SplunkConfig` type for API responses
(excludes token)
- `server/service/service_appconfig.go` -- Added `case "splunk"` to
logging plugin validation
- `frontend/interfaces/config.ts` -- Added `"splunk"` to LogDestination
type
-
`frontend/components/LogDestinationIndicator/LogDestinationIndicator.tsx`
-- Added Splunk display name and tooltip
- `docs/Configuration/fleet-server-configuration.md` -- Splunk config
documentation
- `docs/Get started/FAQ.md` -- Updated plugin list
- `articles/log-destinations.md` -- Updated Splunk section with native
HEC docs
- `changes/25574-splunk-log-destination` -- Change file
## Test plan
### Unit tests (9 tests)
- [x] `TestSplunkWrite` -- sends 3 events, verifies HEC format, auth
header, index/source/sourcetype
- [x] `TestSplunkWriteEmpty` -- empty logs don't trigger HTTP request
- [x] `TestSplunkServerError` -- HEC 403 propagates as error
- [x] `TestSplunkHealthCheckFailure` -- constructor fails on bad health
- [x] `TestSplunkRecordTooBig` -- oversized events (>1MB) are dropped,
normal events still sent
- [x] `TestSplunkSplitBatchBySize` -- logs exceeding 1MB batch limit are
split into multiple requests
- [x] `TestSplunkRetryOnServiceUnavailable` -- 503 retried with backoff,
succeeds on 3rd attempt
- [x] `TestSplunkRetryExhausted` -- after 9 attempts (1 + 8 retries)
returns error
- [x] `TestSplunkMissingConfig` -- empty URL/token returns descriptive
error
### Integration tests (3 tests, gated by `SPLUNK_INTEGRATION_TEST=1`)
- [x] `TestSplunkIntegration` -- 3 events sent via writer, queried back
from Splunk REST API
- [x] `TestSplunkIntegrationBatch` -- 100 events in one Write(), all
confirmed indexed
- [x] `TestSplunkIntegrationBadToken` -- bad token Write() returns 403
### End-to-end test (macOS ARM64, real osquery agent)
1. Started Splunk Enterprise, MySQL, Redis via Docker
2. Built Fleet server from this branch with
`--osquery_status_log_plugin=splunk`
3. Set up Fleet, enrolled a real osquery 5.23.0 agent on this MacBook
4. **83 real osquery status log events indexed in Splunk** with correct
source/sourcetype/index
5. Each event contained full osquery data (`hostIdentifier`,
`host_uuid`, `calendarTime`, `severity`, `message`, `decorations`)
### Splunk showing real osquery events from Fleet
<img width="1910" height="861" alt="image"
src="https://github.com/user-attachments/assets/192490bf-d594-4424-a3e3-a18306892873"
/>
Generated with [Claude Code](https://claude.ai/code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added native Splunk HEC logging destination for status, result, and
audit logs.
* Updated the log destination UI to display **Splunk** with a dedicated
tooltip.
* Added Splunk HEC configuration (URL/token/index/source/source type)
including TLS verification control.
* **Bug Fixes**
* Improved log delivery with batching, retries for temporary HTTP
failures, and safeguards for oversized events.
* **Tests**
* Added unit tests and optional integration tests covering routing,
batching, retries, and error scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Changes
- Deleted 52 anonymous case study article files from the `articles/`
directory
- Removed all anonymous case study sections (financial services,
technology & SaaS, security/IT/healthcare/other) from
`handbook/marketing/fleet-social-proof.md`
- Removed 21 redirect entries from `website/config/routes.js` that
pointed to these removed case studies
The named customer stories (Stripe, Foursquare, Faire, Thumbtack,
Deputy, Fastly) and customer testimonials are preserved.
---
Built for [Irena
Reedy](https://fleetdm.slack.com/archives/D0APYC9R9SL/p1783033337222849?thread_ts=1775761161.561979&cid=D0APYC9R9SL)
by [Kilo for Slack](https://kilo.ai/slack)
---------
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Co-authored-by: Irena Reedy <irena@fleetdm.com>
Co-authored-by: Eric <eashaw@sailsjs.com>
Fixes `TestGitOpsFullGlobal`, which has been failing the `fleetctl` test
bundle on every `main` run since #48467 merged (bisected to a90eab6f62,
e.g. [this
run](https://github.com/fleetdm/fleet/actions/runs/28665588825)).
#48467 changed `BatchSetMDMProfiles` so that `assume_enabled` is only
honored on dry runs; real runs now validate Windows profiles against the
app config persisted in the datastore. That's correct in production,
because the GitOps run persists `windows_enabled_and_configured: true`
via `ModifyAppConfig` before the profiles batch call. But this test's
`AppConfigFunc` mock always returned a fixed app config with Windows MDM
disabled, never reflecting what `SaveAppConfigFunc` stored — so the
real-run profiles batch now fails with 422 "Windows MDM isn't turned
on".
The fix makes the mock behave like the real datastore: once
`SaveAppConfig` is called, `AppConfigFunc` returns the saved config.
Test-only change, no product code touched.
# Checklist for submitter
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
## Testing
- [x] Added/updated automated tests
`go test -run TestGitOps ./cmd/fleetctl/fleetctl/` passes locally (it
fails on `main` without this change).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Improved GitOps test coverage to better match real persistence
behavior during an apply run.
* Updated test setup so saved app configuration is read back correctly
after changes are applied.
* Reset test state between subtests to keep each scenario isolated and
reliable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->