Commit Graph
4508 Commits
Author SHA1 Message Date
Sharon KatzandClaude Opus 4.6 b36be84e85 Add native Splunk HEC log destination (#48455)
**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>
2026-07-03 12:14:24 -04:00
Lucas Manuel Rodriguez 34af79e98a Fix performance regression in software_macos query (#48649)
Resolves #47894

- [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

---

Performance results on my macOS host (between the old an new query):

Clean, dramatic result. Subtracting the ~0.23 s / ~27.5 MB osqueryd
startup baseline to isolate the query cost:
```
┌─────────────────────┬───────────┬──────────┬──────────────────────────┐
│                     │ Wall time │ Peak RSS │ Query-attributable work¹ │
├─────────────────────┼───────────┼──────────┼──────────────────────────┤
│ Baseline (SELECT 1) │ 0.23 s    │ 27.5 MB  │ —                        │
├─────────────────────┼───────────┼──────────┼──────────────────────────┤
│ OLD (recursive %%)  │ ~1.46 s   │ 128 MB   │ +1.23 s, +100 MB         │
├─────────────────────┼───────────┼──────────┼──────────────────────────┤
│ NEW (bounded 2+3)   │ 0.24 s    │ 27.8 MB  │ +0.01 s, +0.3 MB         │
└─────────────────────┴───────────┴──────────┴──────────────────────────┘

¹ over baseline
```

Takeaways:
- Memory: ~128 MB → ~28 MB peak (–100 MB). The recursive walk alone
added ~100 MB; the bounded version adds essentially nothing.
- Time: ~1.46 s → ~0.24 s (~6× faster wall clock; the query-attributable
work dropped ~1.23 s → ~0.01 s, effectively free).
- System time tells the story: OLD spends 0.88–0.97 s in sys (the
readdir/stat syscalls from walking the tree); NEW spends ~0.00 s.

And this is with only 6 casks, dominated by gcloud-cli's ~98k-entry SDK
tree (walked twice via the latest → version symlink, plus following the
app back-symlinks into /Applications bundles). The recursive query hit
128 MB peak from a single well-stocked host — already within striking
distance of osquery's 200 MB watchdog limit. On hosts with more or
larger casks (or the /Library//Applications patterns from the issue),
that's exactly what tips it over and kills the worker. The bounded
version is flat regardless.
2026-07-03 11:04:30 -03:00
plop28andplop28 292fe61301 Add CachyOS support (#47757)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Should Resolve #34591

# Checklist for submitter
- [x] Changes file added 

## User Story
CachyOS lacks from vitals information such as :
* disk encryption status
* disk space
* IP & MAC Addresses
* Installed packages


## Summary
  - Add CachyOS as a recognized Linux platform

## Tests
  - [x] Enroll a CachyOS host and verify it appears as Linux in Fleet
  - [x] Verify disk encryption status displays correctly
- [x] Verify pacman packages are queryable via `fleetd_pacman_packages`
table
  - [x] Disk space, mac address, Public/Private IP are well reported
  - [x] Script are well executed
- [x] No more errors in fleet service logs (level=error
msg="unrecognized platform" hostID=169 platform=cachyos)
  - [ ]  QA'd all new/changed functionality manually


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **New Features**
* CachyOS (Arch-based Linux distribution) is now recognized as a
supported platform, including disk encryption detection and LUKS
support.
* **Bug Fixes**
* Updated host vitals disk-encryption tooltip messaging so CachyOS uses
the correct Linux-specific copy.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: plop28 <plop28@noreply.com>
2026-07-03 10:28:08 -03:00
Jonathan Katz 8b1e806754 Fix GitOps creating duplicate software titles (#48664)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #48054 
Changes:
- Changes batch add installer path to reuse
`getOrGenerateSoftwareInstallerTitleID`
- Adds migration to retroactively fix duplicate titles created by this
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`.
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

## 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.
- The tables will actually be updated, so it makes sense for that to
change if it happens

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Resolved a case where GitOps uploads of Windows software could create
duplicate software titles when a host had already reported the same
program.
* Improved deduplication and reassociation so related records
(installers and icons) are merged into the retained title, preserving
the correct upgrade code.
* **Tests**
* Added regression coverage for the duplicate-title scenario to prevent
future repeats.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-02 19:16:28 -04:00
e95a8dfb8e Better error message: Configuration profiles has characters that need escaping (#40073)
- @noahtalerman: For the following quick win:
  - #40074

---------

Co-authored-by: Kilo Code <kilo@fleetdm.com>
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-07-02 14:32:49 -05:00
Lucas Manuel Rodriguez ad0a39e067 Fix panic in GetClientConfig with null agent options config (#47388) (#48584)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #47388

I'll be doing some separate research on how agent options ends up as
`null` in the first place.
Obviously you can set `config:` in the agent options and hit `Save` and
the issue is reproduced but seems unlikely (one theory is GitOps doing
some overriding).

# 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.

## Summary

`GetClientConfig` (`server/service/osquery.go`) panicked with
`assignment to entry in nil map` (returning 5XX on
`/api/v1/osquery/config`) when a host's resolved agent options had a
null `config`.

Root cause: `config` is initialized as an empty map, but
`json.Unmarshal([]byte("null"), &config)` silently sets the map to `nil`
(no error). When the host also had packs or scheduled queries, the later
`config["packs"] = ...` assignment panicked.

This adds a nil-guard that re-initializes the map after the unmarshal.

## Testing

- [x] Added/updated automated tests

Added `TestGetClientConfigNullConfig`, which sets `{"config":null}`
agent options plus a pack and asserts no panic/error and that `packs`
still serialize correctly.

- [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 could occur when generating osquery
configuration for hosts with a null agent config.
* Improved config handling so hosts with packs and scheduled queries now
receive their configuration reliably, even when the base config is
empty.
  * Added regression coverage to help prevent this issue from returning.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-02 11:17:04 -03:00
Juan Fernandez 7023c5be9a Fix cron jobs stuck in "expired" when a run is interrupted mid-flight
Fixes #48497

When a cron run's context was cancelled mid-flight (e.g. the instance
received SIGTERM during graceful shutdown), the stats row was left
"pending" because the terminal-status write failed on the cancelled
context. CleanupCronStats would later reap it to "expired", hiding the
fact that the run was interrupted and discarding the captured job
errors.

Record the terminal status on a context detached from cancellation
(context.WithoutCancel with a bounded timeout) so an interrupted run
persists its outcome. The run is marked "canceled" only when the context
was cancelled AND a job actually reported an error, so a run whose jobs
all finished cleanly is still "completed" even if cancellation merely
raced the end of the run.
2026-07-02 07:38:11 -04:00
Juan Fernandez 013718aacb Fix Redis MOVED errors from query results counts in cluster mode
Fixes #47303

GetQueryResultsCounts and IncrQueryResultsCounts pipelined commands
across multiple query_results_count:<id> keys on a single connection.
These keys have no hash tag, so in a Redis Cluster they scatter across
hash slots. A pipelined connection binds to the first key's slot, so
every other key returned a MOVED redirect, producing recurring error log
noise on host check-ins. IncrQueryResultsCounts additionally used
ConfigureDoer, whose RetryConn does not support Send, so increments
failed entirely in cluster mode.

Group the keys by hash slot with redis.SplitKeysBySlot and run one
pipeline per slot group, mirroring the existing QueriesForHost and
CleanupInactiveQueries patterns in the same file. The write path uses a
plain pooled connection (not ConfigureDoer) since all keys in a slot
group share a slot and no redirect handling is needed.
2026-07-02 07:37:42 -04:00
George Karr 80b883a2e7 Adding in check to disable recovery lock on personal macos since it doesn't have the required permissions (#48598)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #48594

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually

For unreleased bug fixes in a release candidate, one of:

- [x] Confirmed that the fix is not expected to adversely impact load
test results
- [x] Alerted the release DRI if additional load testing is needed

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Recovery-lock password checks now skip personally owned (BYOD) Apple
devices, avoiding failures on eligible hosts.
* Recovery-lock clear actions are no longer applied to personally owned
enrollments.

* **Tests**
* Added coverage to verify BYOD devices are excluded from both
recovery-lock enforcement and clear workflows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-01 16:20:50 -05:00
Steven PalmesanoandCopilot Autofix powered by AI c7ea006a4d Rename "Create" buttons and links to "Add" across the Fleet UI (#48284)
**Related issue:** Resolves #48177

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.


## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Style**
* Standardized action wording across the UI from “Create” to “Add” for
fleets, packs, users, and reports.
* Updated related labels in command palette items, empty states,
buttons, links, and modal titles to match the new terminology.

* **Tests**
* Updated UI tests to assert the revised button and link text in
affected fleet, host, and report flows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-01 15:04:12 -05:00
Victor Lyuboslavsky 7e8b03cd1c Reject unsupported OnPremise Windows MDM enrollment with an actionable message (#46387) (#48300) 2026-07-01 19:21:02 +01:00
Juan Fernandez e8f26ec4ef Fix S3 file carve cleanup hang and rework reconciliation
Relates to #48549

The S3 carve cleanup (server/datastore/s3, run by the
cleanups_then_aggregation cron) advanced ListObjectsV2 pagination using
the response's ContinuationToken — an echo of the request token —
instead of NextContinuationToken. On any bucket with more than one page
of objects this looped forever, hanging the entire serial cleanup cron
and stalling every cleanup/aggregation job ordered after it.

Replace the bucket-listing reconciliation with a direct HeadObject probe
per carve, which is exact and independent of listing order or object
counts:

- Only carves older than 24h with a completed upload are reconciled
(mirrors the MySQL carve store's floor; skips in-flight multipart
uploads). A carve is expired only on a definitive not-found; transient
or other probe errors leave it for a future run, so a carve whose object
still exists is never expired.
- Probes run with bounded concurrency; expirations are written in one
batched, retryable UPDATE (new ExpireCarves datastore method) rather
than one per carve.
- The number of carves reconciled per run is capped so a large backlog
drains across runs without any single run making unbounded S3 requests.

Add S3-carve-store-only server settings (the MySQL carve store is
unaffected):
- s3.carves_cleanup_disabled       — skip reconciliation entirely
- s3.carves_cleanup_max_per_run    — per-run cap (default 1000)
- s3.carves_cleanup_concurrency    — concurrent probes (default 32)

Also log the expired count per run and fix the test bucket cleanup
helper to paginate. Adds unit tests (transient-error safety, partial
failure, concurrency) and a MySQL integration test for ExpireCarves.
2026-07-01 14:00:59 -04:00
Lucas Manuel RodriguezandCopilot Autofix powered by AI 2d70a7b500 Associate all matching hosts with a SCIM/IdP user (not just the first) (#48351)
Resolves https://github.com/fleetdm/fleet/issues/48378 (issue found
while working on the Google Workspace IdP integration).

## Summary

Fixes a bug where an IdP user associated with **multiple hosts** only
had IdP host vitals populated on **one** of them.

`maybeAssociateScimUserWithHostMDMIdP` (called when a SCIM/IdP user is
created) matched all hosts whose MDM IdP account corresponds to the
user, but then deliberately linked only `hostIDs[0]` (with a `// TODO:
confirm desired behavior` / "just use the first one"). So when a user is
created *after* the hosts already enrolled — e.g. a directory sync
creating users for people who each have a laptop and a desktop — only
the first host got a `host_scim_user` row, and therefore only that host
received the user's IdP host vitals and profile-variable resends.

The fix links **every** matching host. `associateHostWithScimUser` is
keyed on `host_id` (`INSERT … ON DUPLICATE KEY UPDATE`) and triggers its
own per-host profile resend, so calling it once per host is safe and
idempotent.

This is shared SCIM linking code, so the fix benefits all IdP sources
(Okta/Entra SCIM as well as the Google Workspace directory sync that
surfaced it). Deletes and updates already handled multiple hosts
correctly; only the initial reverse-link was capped.

## Testing

Added `testScimUserCreateAssociatesAllMatchingHosts`
(`server/datastore/mysql/scim_test.go`): two hosts share one MDM IdP
account, then a SCIM user is created — both hosts must resolve to it via
`ScimUserByHostID`. Fails before the fix (host #2 unlinked), passes
after.

**Related issue:** Resolves #48378

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements).

## Testing

- [x] Added/updated automated tests
- [X] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* SCIM/IdP user provisioning now associates a new SCIM user with **all**
matching hosts, not just the first match.
* Host end-user details (including IdP username/full name) are now
populated consistently on every associated host.
* **Tests**
* Added SCIM integration and datastore regression coverage to ensure
multiple hosts linked to the same IdP account are all associated during
user creation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-01 10:40:31 -03:00
Lucas Manuel Rodriguez bec3b0dc2a Reduce MySQL reader load on GET /hosts with device_mapping + search query (#47722) (#48488)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #47722

The issue was from a customer running `GET
/api/v1/fleet/hosts?device_mapping=true&page=1&per_page=100&query=<ADDRESS>%40example.com`
on a script in a for loop. This change reduces the impact of the API on
such workflows.

Results from my local load test:

EXPLAIN ANALYZE:
```
┌───────────────────────────────────┬────────────────┬─────────────┬─────────────────────────────────────────────┐
│                                   │ optimizer cost │ actual time │         device_mapping aggregation          │
├───────────────────────────────────┼────────────────┼─────────────┼─────────────────────────────────────────────┤
│ Old (derived-table GROUP BY join) │ ~23,179        │ ~73 ms      │ materialized dm derived table, cost ~7,125  │
├───────────────────────────────────┼────────────────┼─────────────┼─────────────────────────────────────────────┤
│ New (correlated subquery)         │ ~1,260         │ ~25 ms      │ Aggregate … loops=1 (only the returned row) │
└───────────────────────────────────┴────────────────┴─────────────┴─────────────────────────────────────────────┘
```
Tests with 10k hosts:
```
┌───────────────────────────────────┬────────────┬───────────────┬───────┐
│              dataset              │ OLD (main) │ NEW (this PR) │ ratio │
├───────────────────────────────────┼────────────┼───────────────┼───────┤
│ 10k hosts × 3 emails (30k rows)   │ 4.6s       │ 1.1s          │ ~4×   │
├───────────────────────────────────┼────────────┼───────────────┼───────┤
│ 10k hosts × 30 emails (300k rows) │ 35.9s      │ 1.2s          │ ~30×  │
└───────────────────────────────────┴────────────┴───────────────┴───────┘
```

# 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

## What & why

`GET
/api/v1/fleet/hosts?device_mapping=true&page=1&per_page=100&query=<email>`
caused high MySQL **reader** load on instances with ~10k hosts. Each
page load ran an expensive aggregation over the entire `host_emails`
table even though only ~100 rows are returned.

**Root cause:** with `device_mapping=true`, `applyHostFilters` added a
`LEFT JOIN` on a derived table with `GROUP BY host_id` over
`host_emails`. Because of the `GROUP BY`, MySQL must fully materialize
that derived table (aggregating every row for all hosts) before the
outer `WHERE`/`LIMIT 100` can be applied, so the full cost is paid on
every page request regardless of result size. `CountHosts` reused the
same options, materializing the aggregation a **second** time per page
load.

**Fixes (both in `server/datastore/mysql/hosts.go`):**

1. Replaced the derived-table join with a correlated subquery in the
`SELECT` list (only when `opt.DeviceMapping`), so it is evaluated only
for the rows actually returned, each as an indexed lookup on
`idx_host_emails_host_id_email`. This matches the existing
`host_additional` pattern in the same query.
2. Set `opt.DeviceMapping = false` in `CountHosts` — the column is never
selected for counting — mirroring the existing `opt.DisableIssues`
handling.

## Notes

- The composite index `idx_host_emails_host_id_email (host_id, email)`
already exists, so the correlated subquery resolves via an indexed
lookup per returned row.
- `TestHosts` (full suite) passes, including `HostDeviceMapping`,
`CustomHostDeviceMapping`, and `IDPHostDeviceMapping` (the last two
verify the `custom_*` → `custom` and `idp` → `mdm_idp_accounts` source
translation still works through the new subquery).
- Recommend validating with `EXPLAIN ANALYZE` on a ~10k-host dataset
before/after, per the issue. I did not have access to such a dataset.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Performance**
* Improved host list responsiveness when using search filters alongside
device mapping.
* Reduced database load during host listing by retrieving device mapping
more efficiently per host.
* Improved host counting speed by avoiding device-mapping evaluation for
count queries.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-01 10:28:30 -03:00
Victor Lyuboslavsky a90eab6f62 Improved GitOps consistency for Windows BatchSetMDMProfiles (#48467)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves
https://github.com/fleetdm/confidential/issues/16293

Test failures are not related to this change. They are currently failing
on main.

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **Bug Fixes**
* Improved consistency when applying Windows configuration profiles in
batch by validating against the latest server MDM state.
* Fixed an issue where a temporary “assume enabled” setting could affect
real configuration updates; it now applies only to dry runs.
* Ensured team profile validation uses the freshly persisted server
state during the same GitOps execution.
* Added a regression test covering Windows MDM “assume enabled” behavior
for dry-run vs real runs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-30 21:33:07 +01:00
Steven PalmesanoandLucas Manuel Rodriguez fe46e41a52 Add public IP address to host search (#46809)
**Related issue:** Resolves #4842

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.


## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* IP-based host searches now match both private and public IP addresses.
* Updated the host search box placeholder and tooltip to refer to “IP
address” (instead of “private IP”).
* **Tests**
* Expanded backend coverage to verify matching (and non-matching)
results for both private and public IPs when listing and searching
hosts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
2026-06-30 16:20:37 -03:00
Lucas Manuel RodriguezandCopilot Autofix powered by AI 36f73885d8 Bump Render blueprint MySQL to 8.0.44 (#47488) (#48481)
**Related issue:** Resolves #47488

Smoke tested a Render blueprint deploy using this branch:

<img width="655" height="216" alt="Screenshot 2026-06-30 at 12 11 25 PM"
src="https://github.com/user-attachments/assets/7f5b6e76-1aa6-4ae6-b96c-9757f7cf2baf"
/>

## What & why

The Render deployment blueprint provisioned its MySQL service from the
external
[`render-examples/mysql`](https://github.com/render-examples/mysql)
repo, whose Dockerfile pins `mysql/mysql-server:8.0.24`. MySQL 8.0.24
does not support nesting a `UNION` inside the right-hand operand of
another `UNION`, so host-detail queries fail with:

> Error 1235 (42000): This version of MySQL doesn't yet support 'nesting
of unions at the right-hand side'

This surfaced via the Vanta integration hitting `GET
/api/latest/fleet/hosts/:id` on a Render deployment.

This PR switches the `fleet-mysql` service to pull the official
`mysql:8.0.44` image directly (`runtime: image`), removing the
dependency on the external repo. 8.0.44 is Fleet's documented minimum
supported MySQL version and is what `docker-compose.yml` already uses
for dev/CI. The official image honors the same `MYSQL_DATABASE` /
`MYSQL_USER` / `MYSQL_PASSWORD` / `MYSQL_ROOT_PASSWORD` env contract, so
the rest of the blueprint is unchanged.

`8.0.44` (latest 8.0) was chosen over `8.4` so existing deployments
upgrade in place from their current 8.0.24 data volume without a
cross-major manual step.

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`.

## Testing

- [x] QA'd all new/changed functionality manually

Verified locally (Docker) that the failing query shape behaves as
expected across versions:

| Query shape | MySQL 8.0.24 | MySQL 8.0.44 |
|---|---|---|
| `SELECT 1 UNION (SELECT 2)` | works | works |
| `SELECT 1 UNION (SELECT 2 UNION SELECT 3)` | **ERROR 1235** | works |
| `(SELECT 1 UNION SELECT 2) UNION (SELECT 3 UNION SELECT 4)` | **ERROR
1235** | works |

`docker-compose.yml` already runs `mysql:8.0.44` with the same env
contract, so the image swap is a drop-in. Remaining validation on a real
Render Blueprint instance: fresh provision health (`/healthz`, `fleet
prepare db`, `hostport` resolution) and in-place upgrade from an
existing 8.0.24 volume.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Updated the database deployment target to a newer MySQL version,
resolving a Render deployment error related to union nesting.
* Switched the managed database service to use an explicit MySQL 8.0.44
image for more reliable deployments.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-30 12:26:57 -03:00
Nico 40d286cbb4 Add Cache-Control to static assets served under /assets/ (#48409)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #45682

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

#### Before

<img width="1252" height="1027" alt="Screenshot 2026-06-29 at 10 33
15 AM"
src="https://github.com/user-attachments/assets/847ee011-7d2c-4cd2-9882-1508ed77bbd7"
/>
<img width="1248" height="1008" alt="Screenshot 2026-06-29 at 10 33
21 AM"
src="https://github.com/user-attachments/assets/859c2860-5fdb-43f2-8323-af8fc0665ff8"
/>


#### After

<img width="1198" height="819" alt="Screenshot 2026-06-29 at 10 29
25 AM"
src="https://github.com/user-attachments/assets/b96a134a-1271-40f5-99ca-802c7a1fbe10"
/>
<img width="1201" height="804" alt="Screenshot 2026-06-29 at 10 29
29 AM"
src="https://github.com/user-attachments/assets/37c4c262-95ce-4a77-8979-49944e7f2b75"
/>




<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Content-hashed static assets under `/assets/` (e.g., hashed JS/CSS,
images, fonts) now use long-lived, immutable `Cache-Control` to improve
repeat page loads.
* **Bug Fixes**
* `Cache-Control` is now applied consistently for successful responses
and `304 Not Modified`.
* Non-hashed assets and non-success/error responses correctly avoid
caching via `Cache-Control: no-cache`.
* **Documentation**
* Added a release note explaining the new `Cache-Control` behavior for
hashed assets.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-30 10:13:07 -03:00
Nico 2544c17c36 Fix IdP name overflowing button in login page (#48426)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #42473

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

With image URL set:
<img width="598" height="476" alt="Screenshot 2026-06-29 at 1 48 45 PM"
src="https://github.com/user-attachments/assets/9e10c92d-57ce-448e-94c8-01cf852550a9"
/>

Without image:
<img width="598" height="507" alt="Screenshot 2026-06-29 at 1 49 13 PM"
src="https://github.com/user-attachments/assets/782324e9-ffd3-459f-85ea-6bece16b8ce5"
/>



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Prevented SSO sign-in button text from overflowing by standardizing
the visible label to **“Sign in with SSO”**.
* Show the configured identity provider name in a **hover tooltip**,
instead of altering the button label.
* Improved SSO button/tooltip layout and spacing, including refined icon
spacing and better button sizing within the tooltip.
* **Tests**
* Updated LoginForm focus assertions to match the revised SSO button
labeling and accessibility name.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-30 08:55:03 -03:00
Tim Lee 2ce30968f8 Detect Citrix Workspace LTSR cumulative updates (#41790) (#47591) 2026-06-29 14:45:06 -06:00
Tim Lee c15844c87b Fix CPE generation for Citrix Workspace without YYMM suffix (#46811) (#47545) 2026-06-29 14:44:47 -06:00
Victor Lyuboslavsky af2d4dbbbd Optimize IsHostConnectedToFleetMDM on the orbit check-in hot path (#44629) (#48375)
**Related issue:** Resolves #44629

This folds the connected-to-Fleet check into `GetHostMDM` via a
`connected_to_fleet` column that mirrors the existing
`IsHostConnectedToFleetMDM` and `hostMDMSelect` conditions, and derives
the value in `GetOrbitConfig` from the `host_mdm` data it already
fetches. Result: **2 queries → 1** on the orbit check-in hot path, with
no semantic change.

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.

## Testing

- [x] Added/updated automated tests
- [x] 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

* **Performance Improvements**
* Orbit check-ins now determine MDM connection status from existing host
MDM data, reducing database work and improving response time.
* **Bug Fixes**
* Added platform-aware connection detection so Windows, Apple, and
Android devices report MDM connectivity more accurately.
* Updated related checks and tests to keep connection status consistent
across enrollment and unenrollment changes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 17:11:27 +01:00
Carlo 8cf1796a7d Support advanced options for script-only packages (#48315)
**Related issue:** Resolves #42797

Adds support for pre-install query, post-install script, and uninstall
script on script-only packages (`.sh` and `.ps1`) across the API, UI,
and GitOps; previously these were silently stripped. The install script
remains the uploaded file's contents (file-driven) and is shown
read-only. Automatic install stays unsupported for script-only packages.

- **API** (`POST`/`PATCH /software/package`): stop stripping the fields;
validate post-install and uninstall scripts for script packages
- **GitOps**: allow
`uninstall_script`/`post_install_script`/`pre_install_query` paths
inline in the team YAML for script-only packages
- **UI**: show advanced options for `.sh`/`.ps1`; install script shown
read-only

  # 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.

  ## 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**
* Script-only packages (`.sh`/`.ps1`) now expose advanced
options—pre-install query, post-install script, and uninstall
script—consistently across the UI, REST API, and GitOps.
* Script-only packages display advanced options in the UI, and the
“Install script” editor can be made read-only where appropriate.
* **Bug Fixes**
* Preserved advanced option values for script-only packages during
upload, edits, and synchronization (including replace-file scenarios).
* Improved YAML generation and validation so supported fields are
included while unsupported ones are correctly rejected/omitted.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 11:59:37 -04:00
Lucas Manuel Rodriguez ef0a051482 Google Workspace IdP [2/6]: backend (cron + directory sync) (#48165)
### 🥞 Stack (review/merge bottom-up)

1. #48164 — Activity types (FE+BE)
2. **#48165 — Backend (cron + directory sync) ⬅ this PR**
3. #48166 — Usage statistics
4. #48167 — fleetctl generate-gitops
5. #48168 — Settings UI

📄 Documentation is tracked separately in #48169 (targets
`docs-v4.89.0`).

---

## Summary

**PR 2 of 6.** Core **backend** for the Google Workspace IdP
integration:
- Directory sync client (`ee/server/googleworkspace/`) and cron job
(`server/cron/google_workspace_cron.go`) reusing the `scim_*` tables
(Google Workspace and SCIM are mutually exclusive).
- Config types + validation (`server/fleet/google_workspace.go`,
`app.go`, `integrations.go`), appconfig handling + activity emission
(`server/service/appconfig.go`), cron registration and schedule.
- SCIM is ignored while Google Workspace is configured
(`ee/server/scim/scim.go`).

> 🥞 **Stacked PR.** Base: `42915-gw-idp-vitals-1-activities` (PR 1) —
review/merge that first.

**Related issue:** Resolves #42915

# Checklist for submitter

- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements).
- [ ] Timeouts are implemented and retries are limited to avoid infinite
loops.

## Testing

- [ ] Added/updated automated tests
- [ ] QA'd all new/changed functionality manually


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added Google Workspace integration support for syncing users, groups,
and host-related identity data.
* Added a scheduled sync that keeps directory data up to date
automatically.
* Added support for configuring Google Workspace in app settings, with
validation and masking of sensitive credentials.

* **Bug Fixes**
* Prevented SCIM provisioning from overwriting data when Google
Workspace sync is configured.
* Preserved existing Google Workspace credentials when an update omits
masked API key values.
* Added handling for deleted users and group membership changes during
sync.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 12:28:10 -03:00
7f8e800003 Add private network IP blocking for outbound HTTP requests (#46463)
**Related issue:** N/A (security hardening)

# 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
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Summary

Added network-level validation for outbound HTTP requests made by Fleet
integrations (webhooks, SSO, Jira, Zendesk, certificate authorities,
etc.) to prevent requests to unintended destinations. Includes a
configuration option for environments that require connectivity to
private network addresses.

Also fixes a pre-existing nil pointer panic in Jira retry logic and
ensures all HTTP clients use the validated transport.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

Unit and integration tests cover validation logic, boundary conditions,
and multiple configuration modes.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-29 10:41:16 -04:00
Jonathan Katz ba814f4965 Fix gitops leaving temporary url for script-only package in datastore (#48370)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #47947 

# 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

## 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)
- [ ] Verified that the setting is cleared on the server if it is not
supplied in a YAML file (or that it is documented as being optional)
- [ ] Verified that any relevant UI is disabled when GitOps mode is
enabled


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed GitOps generation for script-only packages added by path so it
no longer creates invalid output files.
* Script package entries now use cleaner comments, while regular
packages still show version details.
* Placeholder `script://` installer URLs are now cleared properly and
won’t remain stored after processing.
* **Tests**
* Added coverage for script package comment formatting and for clearing
placeholder installer URLs during GitOps workflows.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 10:21:40 -04:00
Juan Fernandez bef74a6ff5 Add per-host reverse index for small-target live queries
Resolves #42441

Store queries that target at most
redis.live_query_small_target_threshold hosts (default 1000) in a
per-host reverse index instead instead of a per-query bitfield indexed
by host ID.

Setting the threshold to 0 disables the reverse index (no query has <= 0
targets), serving as the kill-switch.
2026-06-29 09:43:30 -04:00
Rahul Raghunathan 8b90422038 Update install software tooltip in setup experience (#48382)
**Related issue:** Resolves #48368

# Before / After
- Before: "Old tooltip for Windows/Linux"
<img width="591" height="278" alt="image"
src="https://github.com/user-attachments/assets/c413c8a0-4c3b-489c-a046-c65d03452c44"
/>


- After: "Updated tooltip for Windows/Linux"
<img width="629" height="283" alt="image"
src="https://github.com/user-attachments/assets/b9e99430-5d63-470d-801e-2d4c060c112d"
/>

- for Mac and Apple-related OS stays unchanged.
<img width="583" height="273" alt="Screenshot 2026-06-28 at 5 52 50 PM"
src="https://github.com/user-attachments/assets/cac7990d-6212-4b69-9467-73d6a3f7d733"
/>



# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **Bug Fixes**
* Updated the “installed during setup” tooltip to clarify installation
order rules.
  * The tooltip now specifies ordering by software name (0–9, then A–Z).
* Added clearer policy sequencing: software without an install policy is
installed before software with a policy.
  * Android setup messaging remains unchanged.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 14:08:53 +01:00
Victor Lyuboslavsky a019cfb8f4 Compress windows_mdm_responses envelopes on the Windows MDM hot path (#48320)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #44188 

# 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.
- [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

* **Bug Fixes**
* Windows MDM check-in response payloads are now stored gzip-compressed
in the database to reduce write pressure for large SyncML data.
* When fetching results, responses are automatically decompressed so the
original content is returned to clients.
* Empty payloads are preserved, and stored data is validated to ensure
only valid gzip content is accepted.
* **Database / Migration**
* Added a migration and backfill to move existing records from
uncompressed storage to the new compressed column format.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-26 22:03:01 +01:00
Jordan Montgomery a764e5d595 Parse both date formats while parsing macos profiles for verification (#48328)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #45947

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually

We do not know how to repro the customer issue and I spent about 6 hours
across a couple of days throwing everything I could at it so testing was
limited to macos profile verification smoke testing and unit tests to
confirm the time we see from customer logs and queries is now supported

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed an issue where macOS configuration profiles could get stuck in
“Verifying” when the reported install date uses a 12-hour time format.
* Improved parsing of locale-formatted install dates, including handling
of special spacing characters found on newer macOS versions.
* Enhanced validation so unsupported or empty install date formats
return clearer error messages.


<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-26 15:58:31 -04:00
George Karr 0f439f9593 Auto-update, pin, and rollback Fleet-maintained apps via UI and GitOps (#48293)
**Related issue:** Resolves #38504

  **Constituent PRs (merged into this feature branch):**

- #47682 — Fleet UI: APRF Software title details page Library/Inventory
layout
- #47808 — Extend update software installer API to support FMA version
pinning
  - #47944 — Fleet UI: APRF library item accordion component
  - #48081 — Versions modal, multi-row Library, pinned state
  - #48098 — Add `pinned_version` to `edited_software` activity
  - #48123 — Auto-update FMA cron
  - #48144 — Download a newly-published FMA version when pinned to it

  # Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or
`ee/fleetd-chrome/changes`. See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

  ## Testing

  - [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates
  to one hosts's records do not affect another)

  - [x] QA'd all new/changed functionality manually


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added Fleet-maintained app version pinning (Latest, exact, and major)
via a new Versions modal.
* Introduced premium auto-updates for maintained apps with pin-aware
promotion and rollback-safe caching.
  * Added expandable library version rows and a Policies modal.
* **Bug Fixes**
* Improved pin handling, cache/manifest hydration, and safer update
behavior on per-app failures and deduplication.
* **UI/UX**
* Refreshed the Software title details experience with new
accordion/list patterns, redesigned details widget/tooltips, and updated
installer presentation.
* **Documentation**
* Expanded Storybook component/page coverage and adjusted Storybook
canvas padding.
* **Tests**
* Added/updated unit and integration tests for pinning, auto-update
flows, and new modal/UI behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-26 14:42:23 -05:00
Luke Heath 2b50257de9 Bump golang.org/x/image to v0.42.0 (CVE-2026-33813) (#48345) 2026-06-26 11:24:16 -07:00
Andrew Mellor 5d58c5f5ff fix: remove as a custom MDM command text from MDM command list view (#48307)
**Related issue:** Resolves #48297

# 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

* **Bug Fixes**
* Corrected MDM command labeling in host details so only commands run
through the custom MDM command API appear as “custom MDM command.”
* Improved command details display for MDM items to show the appropriate
label instead of applying the custom label broadly.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-26 19:13:50 +01:00
Juan Fernandez cbe36a217a Fix policy selection resetting pagination to first page
Fixes #47246

On the host details policies tab and the device user self-service
policies page, clicking a policy while on any page other than the first
reset the list back to page 1. To fix this, Memoize the data set so its
reference stays stable across re-renders that don't change the policies.
2026-06-26 13:03:40 -04:00
Juan Fernandez 005bcdcf87 fleet-mcp: run multi-host live queries via ad-hoc campaign so observer_plus works
Resolves #46005 

Implement flow for ad-hoc distributed query campaign streamed over the
/api/v1/fleet/results/websocket endpoint, the same way the Fleet UI and
fleetctl run live queries.
2026-06-26 12:07:13 -04:00
Juan Fernandez 194f0cfb8f Fix SSO callback URLs doubling the subpath under a URL prefix
Fixes #46641

When Fleet runs under a subpath, server_url already includes that
subpath, so appending url_prefix again produced a doubled ACS callback
path (e.g. https://host/subpath/subpath/api/v1/fleet/sso/callback),
breaking SAML authentication for both login and MDM end user
authentication.

Drop url_prefix from the callback URL construction so the path is
appended directly to server_url, which is the full external base URL.
Fixes the same flaw in all five ACS-construction sites: login SSO
initiate and callback, and MDM SSO initiate plus both callback branches.
2026-06-26 10:40:55 -04:00
Juan Fernandez 8b737cc87c Fix duplicated URL prefix in transactional email links for subpath deployments
Fixes #46642

When Fleet is deployed under a subpath, server_url already carries that
subpath, so the email link base was being built as server_url +
url_prefix, duplicating the path (e.g.
https://host/subpath/subpath/login/reset) and producing 404 links.

Use server_url directly as the link base, matching how the rest of the
codebase already treats server_url as the full external base URL.
2026-06-26 10:40:26 -04:00
Jordan Montgomery 657ba985c3 Fix returned values on MDM command results endpoint (#48296)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #

Fix tagging of hostnames on returned MDM command results so all returned
results have a hostname

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Fixed an issue where some MDM command results could return without
hostnames.
* Improved result visibility so only hosts the caller is allowed to see
are included.
* Ensured team-scoped users see only their permitted results, while
global admins continue to see all available results.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-26 10:34:26 -04:00
Nico 040cefde93 Enable refetchOnWindowFocus and set refetchInterval to 5s when no report results are available (#48268)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #48192

- Deleted `refetchOnWindowFocus: false` so that users get fresh data if
they navigate away and come back to the report results page (IMHO this
should be the behavior across all Fleet's UI).
- Set a refetch interval of 5s when no report results are available.

^ is gated to the report bringing back results (i.e. `discard_data =
false` and `logging = snapshot`).

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] QA'd all new/changed functionality manually



https://github.com/user-attachments/assets/13513f37-8634-4c22-95cc-c0b2e9128058



https://github.com/user-attachments/assets/ae30640a-d0cb-4d93-a0f3-058650895959



https://github.com/user-attachments/assets/54a46634-fbca-4a7a-a75e-36b73370c9a0





<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Report results now refresh automatically when you return to the
browser window.
* Empty report results are checked again every 5 seconds until data
appears.

* **Bug Fixes**
* Improved handling of report caching settings so refresh behavior is
skipped when caching is disabled.
* The empty-state view now stays in sync with whether report caching is
available.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-26 09:51:29 -03:00
George Karr a2af2d97a0 Adding BYOD backend changes (#47716)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** #23242

Backend changes for Apple BYOD (personal) MDM enrollment.

- Adds a `byod` enrollment path that distinguishes personal devices from
organization-owned devices.
- Persists per-host Apple MDM enrollment access rights in a new
`host_mdm_apple_enrollment_permissions` table so SCEP/ACME renewal
honours Apple's monotonic-narrowing invariant (permissions can never be
widened on profile replacement).
- Surfaces wipe/lock/clear-passcode allowed flags on host details for
manually-enrolled Apple hosts.
- Renames the personal enrollment status label to `On (manual -
personal)`.

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [ ] QA'd all new/changed functionality manually

### Test plan

- Manual (profile) enrollment, company-owned: device receives full
access rights; wipe/lock/clear-passcode allowed.
- Manual (profile) enrollment, personal (BYOD via `byod=1`): device
receives narrowed access rights (no device lock/erase); host details
show wipe/lock/clear-passcode disabled.
- SCEP/ACME renewal for each of the above: renewed profile preserves the
original ServerURL (incl. `byod=1`) and the stored (narrowed) access
rights; Apple does not reject the replacement.
- Renewal batching: multiple company-owned hosts collapse into a single
InstallProfile command; a BYOD host gets its own command.
- Account-Driven User Enrollment (ADUE): enroll a personal device via
ADUE and confirm it is inherently restricted (Apple `UserEnrollment`
mode — no device lock/erase regardless of AccessRights), and that its
SCEP renewal succeeds and preserves the account-driven enrollment
profile.
- Deleted-then-returned device: delete a still-enrolled BYOD host in
Fleet, let it check back in, and confirm a subsequent SCEP renewal still
uses the narrowed permissions.

## Database migrations

- [x] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [x] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.
- [x] Ensured the correct collation is explicitly set for character
columns (`COLLATE utf8mb4_unicode_ci`).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added personal (BYOD) Apple MDM enrollment support across manual
profiles, OTA enrollments, and SCEP/ACME certificate renewals, with
access rights generated appropriately.
* Apple host details now surface per-device permission flags for wipe,
lock, and clear passcode when available.
* Enrollment status text now shows personal manual enrollments as “On
(manual - personal)”.
* **Bug Fixes**
* Enforced remote wipe/lock (and clear passcode) permissions correctly
for personal devices, including persistence across renewals.
* Host deletion cleanup now removes newly tracked enrollment permission
data.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 18:21:26 -05:00
RachelElysia 45bea9d17f Fleet UI: Activity feed outline only on keyboard focus (#48295) 2026-06-25 17:44:03 -04:00
Jonathan Katz d563ed21a1 Add activity and enable managed account fleets endpoint (#48273)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #44153
- Adds mdm enabled and configured checks for the update fleet endpoint
- Adds activity creation for the update fleet endpoint + gitops apply

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [ ] Timeouts are implemented and retries are limited to avoid infinite
loops
- [ ] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [ ] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually

## New Fleet configuration settings

- [ ] Setting(s) is/are explicitly excluded from GitOps

If you didn't check the box above, follow this checklist for
GitOps-enabled settings:

- [ ] Verified that the setting is exported via `fleetctl
generate-gitops`
- [ ] Verified the setting is documented in a separate PR to [the GitOps
documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485)
- [x] Verified that the setting is cleared on the server if it is not
supplied in a YAML file (or that it is documented as being optional)
- [ ] Verified that any relevant UI is disabled when GitOps mode is
enabled


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

* **New Features**
* Added activity logs when the managed local account setting is enabled
or disabled.
* Managed local account updates now work consistently through both the
Update Fleet endpoint and GitOps.

* **Bug Fixes**
* Prevented enabling managed local account unless macOS MDM is enabled
and configured.
* No activity is created when the setting is saved without any actual
change.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 17:29:33 -04:00
Konstantin Sykulev c226a3feab On var change resend Android certificate templates and managed app configs (#48278)
**Related issue:** Resolves #36681, #48042

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.

## Testing

- [x] Added/updated automated tests
- [ ] QA'd all new/changed functionality manually

## Database migrations

- [x] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [x] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.
- [x] Ensured the correct collation is explicitly set for character
columns (`COLLATE utf8mb4_unicode_ci`).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Certificate templates and managed Android app configurations now keep
track of referenced variables.
* Variable changes can now trigger automatic re-sending of affected
profiles and app availability updates.
* **Bug Fixes**
* Resend behavior now refreshes certificate templates when related
variable values change.
* Android managed app configurations are re-queued when their variables
are updated.
* **Database**
* Added support for variable tracking on certificate templates and
Android app configurations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 16:27:30 -05:00
Lucas Manuel Rodriguez 608bd2764c Restrict conditional access Okta IdP asset endpoints to privileged roles (#48294)
# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`.
- [x] Input data is properly validated (authorization policy change
only).

## Testing

- [x] Added/updated automated tests — the role matrix in
`TestConditionalAccessGetIdPSigningCertAuth` and
`TestConditionalAccessGetIdPAppleProfileAuth` now asserts observer and
observer+ are denied; `go test ./server/authz/` confirms the policy
compiles.
- [x] QA'd all new/changed functionality manually — covered by the
automated role-matrix tests for this authz-only change.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Tightened access to conditional access identity provider assets so
only higher-privilege roles can read them.
* Users with observer and observer+ roles can no longer access these
endpoints.
  * Updated validation coverage to reflect the revised access behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 15:57:25 -03:00
Carlo DiCelico 2f9147e685 merge main 2026-06-25 13:57:22 -04:00
Carlo DiCelico b0f2f19fbc add changes file 2026-06-25 13:13:13 -04:00
Jordan MontgomeryandCopilot Autofix powered by AI 07ebe1d836 Check if host is still on script's team before executing batch (#48244)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Scheduled batch script execution now re-checks host team membership at
execution time, skipping any hosts moved to a different team before the
batch runs.
* Added a clear “team mismatch” incompatibility outcome and ensured
incompatible hosts are not queued for execution.
* **Tests**
* Expanded script scheduling tests to cover host-to-team transfers
between scheduling and execution, including updated incompatibility
counts and per-host expectations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-25 12:04:34 -04:00
Sharon Katz 8756b2f86c Tighten certificate renewal validation in host identity SCEP service (#48270)
**Related issue:** N/A (internal security hardening)

## Summary

The SCEP certificate renewal flow accepted a CSR with any CommonName as
long as the requester proved possession of the old certificate's private
key. This allowed a host to obtain a certificate for a different host's
identity during renewal.

## Reproduction

Code-level verification (no running server required):

1. Read `ee/server/service/hostidentity/scep.go` `renewalMiddleware`
(lines 142-216).
2. Confirmed that after PoP signature verification (line 191), the CSR
is passed directly to `next.SignCSRContext(ctx, m)` (line 198) with no
comparison of `m.CSR.Subject.CommonName` against
`oldCertData.CommonName`.
3. Confirmed that `UpdateHostIdentityCertHostIDBySerial` (line 205) then
binds the new cert's serial to the old cert's `host_id`, completing the
identity takeover.

## Fix

Added a CN equality check after signature verification: if the CSR's CN
does not match the original certificate's CN, the renewal is rejected
with an error.

## Testing

### Unit tests (`ee/server/service/hostidentity/scep_test.go`)

Exercises `renewalMiddleware` directly with a mock datastore:
- `mismatched CN is rejected` -- constructs a renewal CSR with
`CN=attacker-identity` against an original cert with
`CN=original-host-identity`. Verifies the middleware returns an error
containing "common name does not match" and the next signer is never
called.
- `matching CN is accepted` -- constructs a renewal CSR with the same CN
as the original cert. Verifies the middleware passes through to the next
signer successfully.

### Integration tests (local, real MySQL)

Ran `TestHostIdentity` against a local MySQL 8.0.44 instance
(`MYSQL_TEST=1 REDIS_TEST=1`). All 28 subtests pass, including:
- **Certificate renewal flows** (ECC P256 orbit, ECC P384 orbit, ECC
P384 osquery) -- renewed certs preserve the original CN, host_id
binding, and work for authenticated requests.
- **Renewal replay protection** -- reusing a revoked cert's serial for
renewal is rejected.
- **Wrong cert authentication** -- cross-host cert usage is rejected (9
subtests).
- **Real SecureHW + SCEP** -- full TPM-simulated renewal flow succeeds.
- **Failure cases** -- empty/wrong challenge, oversized CN, non-ECC
algorithm all correctly rejected.

Linter passes (`make lint-go-incremental` -- 0 issues).

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Tightened certificate renewal checks so renewal requests now fail if
the new certificate request uses a different common name than the
existing certificate.
* Renewal requests with matching common names continue to work as
expected.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 12:02:15 -04:00
Konstantin Sykulev 214619d935 Refactor makeAndroidAppAvailable to use staggered job queuing (#47880)
**Related issue:** Resolves #47543

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Updated Android app availability to use staggered batch jobs instead
of processing everything at once, improving throughput and smoothing
workload.
* **New Features**
* Added batched handling that can perform per-host managed configuration
substitution when variables are present, including scheduling “pending
apply config” updates when required.
* **Configuration**
* Reduced the default Android batch size (`mdm.android_batch_size`) to
100.
* **Bug Fixes / Tests**
* Updated unit and integration tests to verify batching, staggering
timing, full host coverage, and order-independent policy application
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-25 10:31:38 -05:00
Dante Catalfamo 1b64b6104a Fix NDES not using the same retry clearing method as SmallStep for macos (#48105)
**Related issue:** Resolves #46291
2026-06-25 09:32:22 -04:00