Commit Graph
5241 Commits
Author SHA1 Message Date
Andrew Mellor 2abc49ba02 46235 dep profile assigner context cancelled (#48473)
**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 -->
2026-07-06 14:16:14 +01:00
Lucas Manuel Rodriguez 1c1fae8e93 Add CachyOS support (part 2/2) (#48688)
**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 -->
2026-07-06 09:12:15 -03:00
480847b7f5 v4.88.0 doc changes (#46357)
Documentation changes for 4.88.0

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

## Summary by CodeRabbit

* **New Features**
* Added a new chart data API endpoint for retrieving metric-based chart
information.
* **Tests**
* Updated test server setup so chart-related routes are included in
endpoint validation, improving coverage and consistency.

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

---------

Co-authored-by: Jordan Montgomery <elijah.jordan.montgomery@gmail.com>
Co-authored-by: Victor Lyuboslavsky <2685025+getvictor@users.noreply.github.com>
Co-authored-by: Marko Lisica <83164494+marko-lisica@users.noreply.github.com>
Co-authored-by: Mike Thomas <78363703+mike-j-thomas@users.noreply.github.com>
Co-authored-by: Scott Gress <scottmgress@gmail.com>
Co-authored-by: melpike <79950145+melpike@users.noreply.github.com>
2026-07-03 17:22:51 -05:00
Sharon KatzandClaude Opus 4.6 6ba04b0d20 Optimize query aggregated stats cron to skip queries without execution data (#48698)
**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>
2026-07-03 13:29:49 -04:00
Lucas Manuel Rodriguez 1ceca6ad8e Cleanup policy_membership stale entries in distributed/write (#48674)
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 -->
2026-07-03 14:12:08 -03:00
Lucas Manuel Rodriguez 171504dc18 Fix nondeterministic device_mapping order in ListHosts (#48696)
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 -->
2026-07-03 14:09:07 -03:00
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
George Karr dea65b824c Bump migration timestamps after 4.88 cherry-pick (#48617)
**Related issue:** Resolves NA (release hygiene — migration ordering)

## What & why

The `4.88.0` patch cherry-picked two migrations,
`20260624210253_AddHostMDMAppleEnrollmentPermissions` and
`20260624210311_RenamePersonalEnrollmentStatus`. Eight migrations on
`main` were **not** cherry-picked into 4.88 but had **earlier**
timestamps than those two:

| Old timestamp | Migration |
|---|---|
| 20260611202649 | AddWindowsMDMConfigProfilesPendingDelete |
| 20260615135619 | AddSetupExperienceSoftwareInstallers |
| 20260617172853 | CreateSoftwareTitleTeamPins |
| 20260617194413 | AddAndroidProfileVariableTracking |
| 20260622124714 | AddPolicyGateToSetupExperienceResults |
| 20260622124734 | AddBYODFleetAndADUEEnrollment |
| 20260623140135 | AddSupportSoftwareCategory |
| 20260624152755 | AddCertAndAndroidAppVariableTracking |

This violates the rule in
`docs/Contributing/workflows/releasing-fleet.md`:

> Any migrations that are not cherry-picked in a patch must have a
_later_ timestamp than migrations that were cherry-picked.

Left as-is, a customer on `4.88.0` (who applied migrations through
`20260624210311`) upgrading to `4.89.0` would hit these 8 as
out-of-order/missing migrations older than their highest-applied
version.

## Fix

Bumped the 8 non-cherry-picked migrations to new timestamps
(`20260702013055`–`20260702013102`) using `tools/bump-migration`,
**preserving their relative order**, so they now sort after the
cherry-picked migrations and
`20260626120000_CompressWindowsMDMResponsesColumn`. Regenerated
`schema.sql`.

Verified `20260626120000_CompressWindowsMDMResponsesColumn` (the only
other non-cherry-picked migration, already correctly ordered) touches
only `windows_mdm_responses` — none of the 8 moved migrations touch that
table, so no dependency inversion is introduced by the reorder. None of
these 10 migrations shipped in `4.87.1`, so no released database is
affected.

`rc-patch-fleet-v4.88.0` needs no change. This lands on `main` and
should be reflected on `rc-minor-fleet-v4.89.0`.

# Checklist for submitter

## Database migrations

- [x] Migration files renamed via `tools/bump-migration`; function names
updated to match new timestamps.
- [x] Regenerated `schema.sql` via `make dump-test-schema`; migrations
apply cleanly in the new order.
- [x] No schema/content changes to the migrations themselves — timestamp
renumber only.

## Testing

- [x] `go build ./server/datastore/mysql/migrations/...` and `go vet`
pass; schema regeneration ran all migrations successfully in order.

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

## Summary by CodeRabbit

* **New Features**
* Added support for additional device/profile tracking across Android,
Apple, Windows, certificates, and apps.
* Added new setup and software management records, including support
software categories and team pins.
  * Added a policy-gating flag for setup experience results.

* **Bug Fixes**
* Improved database consistency with stronger uniqueness and
cascade-delete behavior.
* Updated schema tracking so migrations apply cleanly with the latest
database state.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-02 12:00:56 -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 4afd59833d Fix installed_software status in policy automation activities
Relates to #38670

The policies/:id/automation_activities endpoint derived the top-level
status for installed_software activities from the live
host_software_installs.status generated column. That column becomes NULL
when the install row is marked removed=1 (e.g. after the installer
package is edited/updated or the software is re-installed), so a
historically-successful install was miscategorized as "error".

Derive the outcome from the activity's recorded details.status instead,
which reflects the install result at the time the activity was created.
The install output still comes from host_software_installs. This applies
to both the displayed status and the ?status=error|success filter.

Also fixed alignment with the info icon on the policy automations table.
2026-07-02 09:59:59 -04: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
Lucas Manuel Rodriguez c4a66e6303 Update osquery schema and flags to 5.23.1 (#48587)
osquery [5.23.1](https://github.com/osquery/osquery/releases/tag/5.23.1)
was released by osquery publicly today, this updates our schema with the
changes in it.

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

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

## Summary by CodeRabbit

* **New Features**
* Updated schema support for certificate `subject2` and `issuer2` fields
on Linux and macOS.
* Documentation generation and download tooling now target osquery
`5.23.1`.

* **Bug Fixes**
* Clarified the `process_open_handles` table behavior by removing
outdated default-process wording.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-01 19:34:00 -03: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
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
Jordan Montgomery 6223af892e Fix manual-personal enrollment for iOS/iPadOS (#48534)
<!-- 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.

Unreleased bug, no changes file

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

- [ ] 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
- [ ] 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**
* Personal enrollment status is now preserved and updated correctly when
MDM device records change.
* macOS MDM ingestion now keeps the BYOD/personal enrollment flag for
Fleet devices instead of defaulting it away.
* Incoming server URLs continue to have query parameters removed while
still retaining the enrollment status used for processing.

* **Tests**
* Added coverage for personal enrollment updates and macOS ingestion
scenarios, including BYOD and non-BYOD cases.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-01 09:59:55 -05: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
Victor Lyuboslavsky 5d531c10d9 Fix orbit nudge test mdm connection fidelity (#48423)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #44629

Test fix only. Test now distinguishes between being connected to Fleet
MDM and being connected but not osquery-enrolled.

[ ] QA'd all new/changed functionality manually

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

## Summary by CodeRabbit

* **Tests**
* Improved validation of host configuration nudge behavior by refining
how Fleet MDM connection states are simulated.
* Test scenarios now better cover: enrolled but not connected to Fleet
MDM, and connected to Fleet MDM without enrollment.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-30 21:32:10 +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
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
Juan Fernandez ed14c5385c Fix API endpoint validation for prefix-mounted SCIM routes
The SCIM endpoints are served by the elimity-com/scim library mounted as
a single prefix handler on the root ServeMux, so they are never
registered as individual gorilla/mux routes.

Since the routes can't be discovered, supply them to the validator
instead: add scim.RegisterValidationRoutes, a FeatureRouteFunc that
registers stub routes for the SCIM endpoints (handlers are never
invoked, only their path templates and methods are inspected). Wire it
into the three Validate call sites (production serve, test helper,
svctest).
2026-06-30 09:10:06 -04:00
Noah TalermanandRachael Shaw 2c3e38b737 Foreign vitals mapping: Update SCIM integration instructions (#48413)
- Update the best practice is to create an API-only user w/ the admin
role and access only to necessary SCIM API endpoints
- These doc updates require [this
bug](https://github.com/fleetdm/fleet/issues/48062) to be fixed because
the `/scim/*` API endpoints aren't exposed as API endpoints one can pick
when creating an API only user
- Document the `/scim/*` API endpoints


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

## Summary by CodeRabbit

* **New Features**
  * Added SCIM API endpoints for managing users and groups.
* Supported actions include listing, creating, viewing, replacing,
updating, and deleting SCIM users and groups.
* Added read-only endpoints for SCIM schemas, service provider
configuration, and resource types.

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

---------

Co-authored-by: Rachael Shaw <r@rachael.wtf>
2026-06-29 17:56:35 -05: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
Lucas Manuel Rodriguez ddc126ea8d Google Workspace IdP [4/6]: fleetctl generate-gitops support (#48167)
### 🥞 Stack (review/merge bottom-up)

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

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

---

## Summary

**PR 4 of 6.** **GitOps / fleetctl**: `fleetctl generate-gitops` support
for the Google Workspace integration, redacting `api_key_json` with a
TODO + secret warning, plus updated golden testdata.

> 🥞 **Stacked PR.** Base: `42915-gw-idp-vitals-3-statistics` (PR 3).

**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**
* GitOps now supports Google Workspace settings in organization
configuration output.

* **Bug Fixes**
* Free-tier accounts no longer include Google Workspace settings in
global GitOps output.
* Sensitive Google Workspace API key content is now replaced with a
placeholder in generated GitOps files, with a warning recorded.
* GitOps applies a clear state when Google Workspace settings are
omitted or left empty.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 13:20:11 -03: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 70b41063a4 Google Workspace IdP [3/6]: usage statistics (#48166)
### 🥞 Stack (review/merge bottom-up)

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

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

---

## Summary

**PR 3 of 6.** **Usage statistics**: report whether a Google Workspace
IdP integration is configured via the new `googleWorkspaceConfigured`
field (`server/fleet/statistics.go`,
`server/datastore/mysql/statistics.go`).

> 🥞 **Stacked PR.** Base: `42915-gw-idp-vitals-2-backend` (PR 2).

**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**
* Usage statistics now include whether Google Workspace is configured,
improving reporting accuracy.

* **Bug Fixes**
* Fixed statistics submissions so the Google Workspace configuration
status is included consistently in outgoing requests.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 12:34:06 -03: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
Lucas Manuel Rodriguez b1c3a31dac Google Workspace IdP [1/6]: activity types (frontend + backend) (#48164)
### 🥞 Stack (review/merge bottom-up)

1. **#48164 — Activity types (FE+BE) ⬅ this PR**
2. #48165 — Backend (cron + directory sync)
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 1 of 6** — splits the Google Workspace IdP host-vitals feature into
a reviewable stack.

Adds the **activity types** for the Google Workspace integration,
frontend and backend:
- Backend: `added_google_workspace_integration`,
`edited_google_workspace_integration`,
`deleted_google_workspace_integration` (`server/fleet/activities.go`).
- Frontend: activity-feed rendering for those three types (`activity.ts`
enum + display names + `domain` detail; `GlobalActivityItem.tsx`
templates).

> 🥞 **Stacked PR.** Base: `main`.

**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 support for new Google Workspace integration activity entries:
added, edited, and deleted.
  * Activity feeds now display the integration domain when available.
  * New filter labels were added for these activity types.

* **Bug Fixes**
* Activity details now render Google Workspace integration events
correctly in the dashboard feed.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-29 11:40:08 -03: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
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 b438893bc2 Do not block further wipe commands on inactive existing entry (#48358)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #45931

# Checklist for submitter

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

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

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

## Testing

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

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

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved device lock handling so only active pending lock commands are
treated as valid.
* Fixed stale lock state cases where an old lock reference no longer
blocks a new lock request.
* When a prior lock command is no longer deliverable, a new lock command
is now issued and tracked correctly.
* Updated coverage to verify lock status transitions and replacement
behavior in these edge cases.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-26 15:58:42 -04: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
Carlo ce1f85b9b8 Use active custom script if available (#48350)
**Related issue:** Resolves #48301

When the auto-update cron downloads a new Fleet-maintained app version,
it now carries forward the previously-active install/uninstall scripts
when they were customized (e.g. via GitOps), instead of overwriting them
with the manifest defaults. Customization is detected per-script by
comparing the active scripts against the manifest (the uninstall script
is compared against the manifest template substituted with the active
version's package IDs, since it's version-specific). When the active
scripts match the manifest, the new version's manifest scripts are used
as before.

  # 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
2026-06-26 14:38:42 -04:00
Carlo d5afa45efd Pin-cleanup on FMA delete (#48333)
**Related issue:** Resolves #48309

Deleting a Fleet-maintained app from a team now also deletes its
`software_title_team_pins` row. Previously the pin survived the delete
(the FK cascades only on title deletion, and the title row outlives the
installer rows), so re-adding the app resurfaced a stale pin pointing at
a version no longer cached.

  # 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
2026-06-26 13:18:50 -04:00
Carlo 0b6f8066db Return per-version filename in fleet_maintained_versions (#48335)
**Related issue:** Resolves #48334

The software title response now returns a per-version `filename` in
`fleet_maintained_versions`, and the Library version rows render each
version's own filename instead of the active installer's. Previously,
every cached-version row showed the active installer's filename because
the array didn't include one.

  # 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
2026-06-26 12:44:55 -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