<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#47535
## Description
`DeleteMDMAppleDeclaration` re-ran the upload-time validator
(`ValidateUserProvided`) on the delete path. That validator enforces
*upload-admission* rules — forbidden declaration types
(`ForbiddenDeclTypes`) and the `AllowAllDeclarations` config flag — so
any declaration that was accepted at upload time became **undeletable**
through the API once the accepted set later shrank. Two ways this
happens in practice:
- A server config flag that had been enabled at upload time is later
disabled (the original customer report, prod 4.86.1).
- A declaration type is added to `ForbiddenDeclTypes` in a later
release, after declarations of that type were already uploaded.
In both cases the UI showed "Couldn't delete. Please try again." and the
API returned `400` with an upload-validation message on a *delete*
request.
Whether a declaration is Fleet-managed (and therefore protected from
deletion through this endpoint) is already determined by the Fleet
reserved-name check that runs immediately above the offending block.
This PR removes the upload-time validation from the delete path and
relies solely on that reserved-name check, so:
- A user can delete any declaration they previously uploaded, regardless
of whether the current validator config would still accept it on upload.
- Fleet-managed declarations (reserved names) remain protected from
deletion.
The `AllowAllDeclarations` flag and `ValidateUserProvided` are unchanged
on the **add/upload** path — admission control still happens where it
belongs.
## Testing
Extended `TestMDMConfigProfileCRUD` (replacing the pre-existing `//
TODO: Add tests for create/delete forbidden declaration types?`) with
two cases:
- A declaration whose type is in `ForbiddenDeclTypes` can be deleted
(regression guard — fails before this change, passes after).
- A declaration with a Fleet-reserved name remains protected from
deletion (guards the reserved-name check that is now the sole
Fleet-managed gate — a boundary that was previously untested).
Manually verified end-to-end in the UI: reproduced the stuck declaration
(upload a forbidden type with `FLEET_MDM_ALLOW_ALL_DECLARATIONS=true`,
restart without the flag), confirmed the pre-fix `400`, then confirmed
deletion succeeds after the fix with the flag off.
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved Apple MDM declaration deletion to avoid re-running
upload-time validation during the delete flow.
* Declaration deletion checks now rely on Fleet management status and
reserved naming, preserving protection for Fleet-managed declarations.
* Added/adjusted deletion behavior for restricted and Fleet-reserved
declaration types.
* **Tests**
* Added regression coverage for Apple declaration profile deletion via
the configuration profile delete endpoint, including strict-mode
scenarios and cleanup behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49705
Verified fix with 100k host Windows load test.
# Checklist for submitter
## 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] Alerted the release DRI if additional load testing is needed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Summary by CodeRabbit
* **Bug Fixes**
* Improved host certificate deduplication and automated self-healing
when duplicate certificate records are ingested.
* Updated source reconciliation to only change what’s stale, preventing
unnecessary rewrites of unchanged source entries.
* Ensured certificate sources consistently associate to the newest
canonical certificate record for each certificate hash.
* Improved certificate listing accuracy by returning a deduplicated set
of certificate/source pairs with correct usernames.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49750
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information. (Already a part of something else, this is just
further solidifying the current behaviour)
- [ ] 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
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Added coverage to verify the command sequence during Apple device
enrollment.
* Ensures the fleet management agent installation happens first,
followed by the bootstrap package, and then configuration profile and
management commands.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#48340
Windows only. The fix is to use a rollup status table instead of
recalculating the host profile summary on demand.
Verified the fix in load test with 100k Windows MDM hosts. Note that
this does not improve the host details page filtered by OS settings,
which will be handled by the follow up
https://github.com/fleetdm/fleet/issues/48996
# 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] Timeouts are implemented and retries are limited to avoid infinite
loops
## Testing
- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)
- [x] QA'd all new/changed functionality manually
## 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
* **Bug Fixes**
* Improved Windows fleet configuration profile status summaries to avoid
timeouts on large fleets.
* Kept per-host Windows profile statuses accurate after profile updates,
resends, certificate changes, cleanup, unenrollment, and host deletion.
* Added automatic reconciliation to correct stale or orphaned status
data.
* **Data Integrity**
* Improved Windows profile status reporting, including profile and
BitLocker summaries, for more reliable results.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#49682
Mozilla Firefox and Firefox ESR are distinct Fleet-maintained apps that
share the macOS bundle identifier `org.mozilla.firefox`, so they resolve
to one software title. Adding both to a fleet previously gave a generic
conflict error (or no error at all). This adds a clear message — "Only
one of Mozilla Firefox or Mozilla Firefox ESR can be added to the same
fleet." — on both the single-add and GitOps/batch paths. The check is
general (any two FMAs sharing a bundle identifier), with the app names
filled in dynamically.
# 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
- [ ] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Prevented adding both Mozilla Firefox and Firefox ESR to the same
fleet when they share a bundle identifier.
- Updated the UI to show a specific conflict message explaining that
only one of the two can be added.
- Ensured existing workflows still work for adding new versions of the
already-selected app.
- **Tests**
- Added backend and frontend test coverage for the new conflict
detection and error-message formatting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
# 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
## Summary
Enforced API-only endpoint restrictions on chart endpoints, matching the
pattern already used by the activity bounded context. Also added
`RouteTemplateRequestFunc` to chart route server options so the
middleware can read the matched mux route template from context.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
### Reproduction
Created an API-only user with a restrictive endpoint allow-list (only
`GET /api/v1/fleet/hosts`). Confirmed that:
- Allowed endpoint (`/api/latest/fleet/hosts`) returns 200
- Non-allowed cataloged endpoint (`/api/latest/fleet/users`) returns 403
- Chart endpoint (`/api/latest/fleet/charts/uptime`) returned 200 before
the fix (the bug)
- After the fix, chart endpoint correctly returns 403
### Unit test
Added a test case in `server/service/middleware/auth/api_only_test.go`
that verifies an API-only user with endpoint restrictions is denied
access to chart endpoints not in their allow-list. The chart endpoint is
included in the test catalog (matching production), so the test
exercises the allow-list rejection path.
All 17 tests in the auth middleware package pass.
### Local verification
1. Confirmed the chart middleware in `cmd/fleet/serve.go` previously
called `auth.AuthenticatedUser(svc, next)` without
`APIOnlyEndpointCheck` wrapping
2. Verified the activity bounded context (same file) already uses
`auth.APIOnlyEndpointCheck(next)` as the correct pattern
3. Applied the same wrapping to the chart middleware
4. Added `RouteTemplateRequestFunc` to
`server/chart/internal/service/endpoint_utils.go` so the route template
is available in context (required by `APIOnlyEndpointCheck`)
5. Ran `go test ./server/service/middleware/auth/ -v` with all 17 tests
passing
6. Ran `make lint-go-incremental` with 0 issues
Resolves#16770
The MFA login token redemption path (`POST /api/latest/fleet/sessions`)
read the one-time verification token with a non-locking `SELECT` on the
read replica, then created a session and deleted the token in a
*separate* transaction without verifying the token was still present.
Concurrent requests carrying the same token each passed the `SELECT` and
each minted a distinct session, breaking the single-use guarantee.
`SessionByMFAToken` now consumes the token and creates the session
inside a single transaction:
- The token row is locked with `SELECT ... FOR UPDATE`, then deleted,
and the delete's rows-affected count is confirmed non-zero before the
session is created.
- Concurrent redemptions serialize on the row lock; the loser re-reads
after the winner commits the delete, finds no row, and aborts before
creating a session.
- The user is still loaded *before* the transaction, so a
concurrently-deleted user or a transient read error leaves the token
intact for retry (preserving the pre-fix atomicity behavior).
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Juan Fernandez <juan@fleetdm.com>
Make failed logins for MFA-enabled accounts return a consistent response
and timing regardless of the cause, in line with authentication best
practices. Guidance for CLI users whose client can't complete email
verification is now surfaced by fleetctl on any login failure.
Added a `user_mfa_requested` activity, recorded when valid credentials
are submitted for an MFA-enabled account and a verification email is
sent.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** N/A
# Checklist for submitter
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Summary
Moves the `POST
/api/v1/fleet/device/{token}/software/install/{software_title_id}`
("Install self-service software") endpoint out of the contributor-only
API reference (`docs/Contributing/reference/api-for-contributors.md`)
and into the public REST API docs (`docs/REST API/rest-api.md`), nested
under the existing `## Software` section.
- Added `### Install self-service software` to `docs/REST
API/rest-api.md`, right after `### Uninstall software`, with a TOC entry
and a note that it uses the device's authentication token instead of the
usual Fleet API token.
- Removed the TOC entry and body section for this endpoint from
`docs/Contributing/reference/api-for-contributors.md`. Sibling
device-authenticated self-service endpoints were left in place there
since only this one endpoint was moved.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an API route allowing Fleet Desktop users to initiate
self-service software installations using a device token and software
title.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Rachael Shaw <r@rachael.wtf>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49367
# 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
* **New Features**
* Added “Release from Apple Business” for eligible Apple hosts,
including per-device success/failure reporting and activity logging.
* Added a new API endpoint to trigger the action and return results for
each selected host with clear error details.
* Introduced authorization rules for global admins and team admins to
release only within allowed scope.
* **Bug Fixes**
* Improved validation and error handling: rejects oversized selections,
reports unknown/ineligible hosts and DEP-related failures per device,
and treats assignment-cleanup failures as non-blocking.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves #
Super small change to make it easier to correlate bootstrap and fleetd
`InstallEnterpriseApplication` command UUID with log statements
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
## Testing
- [ ] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved logging for Apple MDM command delivery by including the
associated command identifier when application and bootstrap package
installation commands are sent.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#48003
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Fixed MDM SSO configuration handling to automatically remove leading
and trailing whitespace from provider fields.
- GitOps-applied MDM SSO settings are now normalized before validation,
preventing otherwise invalid configurations caused by extra spaces.
- Required-field and URL validation now operate on the cleaned values.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49751
A customer's egress proxy (an Envoy sidecar bound to loopback) was
getting blocked by Fleet's SSRF network-blocking check, since the check
applies to whatever address the HTTP transport dials, including the
proxy hop itself, not just the ultimate destination. There was no
supported way to disable this in production (the existing full-bypass
mode was dev-only), leaving no path forward for environments where
egress is already constrained by external infrastructure.
# 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
* **New Features**
* Added a production server setting to bypass outbound network blocking
for integration requests when external egress controls are already in
place.
* The setting is disabled by default and can be configured through the
server configuration.
* **Documentation**
* Clarified that bypassing network blocking disables SSRF protections
for all outbound integration requests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves
https://github.com/fleetdm/confidential/issues/16880
# 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**
* Secured the Windows MDM Terms of Service endpoint against reflected
cross-site scripting.
* Strengthened validation for the `redirect_uri` used in Terms of
Service rendering, allowing only approved `https` and `ms-appx-web`
schemes.
* Unsafe, malformed, or non-allowlisted redirect values are now rejected
and not displayed.
* **Tests**
* Added integration and unit coverage to verify unsafe redirects are
blocked while valid ones continue to work.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Sharon Katz <121527325+sharon-fdm@users.noreply.github.com>
**Related issue:** Resolves#47963
# 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
- [ ] QA'd all new/changed functionality manually
## Summary
Fixes a 500 seen via monitoring during `POST /api/mdm/apple/enroll`:
```
checking os updates settings serial [redacted]: getting team id for host: sql: no rows in result set
```
### Root cause
During DEP enrollment, `CheckMDMAppleEnrollmentWithMinimumOSVersion` →
`shouldOSUpdateForDEPEnrollment` calls
`GetMDMAppleOSUpdatesSettingsByHostSerial`, which joins `hosts` to
`host_dep_assignments` by serial. When no matching row exists yet — e.g.
the enrollment request arrives before the host / DEP assignment row is
created or replicated (replica lag / ordering) — `sqlx.GetContext`
returns `sql.ErrNoRows`.
The service layer already handles this case gracefully (skip the
OS-update check, allow enrollment to proceed) via
`fleet.IsNotFound(err)`. But the datastore wrapped the raw
`sql.ErrNoRows` with a plain `ctxerr.Wrap`, which does not implement the
`IsNotFound()` interface, so the graceful path never triggered and the
request 500'd.
### Fix
Convert `sql.ErrNoRows` into a proper `notFound` error in the datastore
method, matching the existing pattern used throughout `apple_mdm.go`.
This lets the existing service-layer graceful-skip path take over so
enrollment proceeds.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed Apple MDM enrollment to continue gracefully when OS update
settings are missing because a host’s DEP assignment hasn’t been created
yet or hasn’t replicated.
* Prevented enrollment from failing with an unexpected 500 error by
returning a clear “not found” outcome instead.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves: N/A
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## 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**
* Updated host deletion behavior to return consistent “not found”
responses when the host doesn’t exist or isn’t visible to the requester.
* Prevented out-of-scope delete attempts from disclosing whether the
target host exists (now returns “not found” instead of “forbidden”).
* Preserved “forbidden” errors when the host is visible but the
requester lacks delete permission.
* **Tests**
* Added/updated authorization and deletion coverage to verify the new
response-masking behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49489
Custom host vitals were skipped when host name template enforcement
(#38806) shipped, since both features were in development at the same
time. This adds `$FLEET_HOST_VITAL_<id>` support to host name templates,
matching the existing secret-variable pattern (validation, per-host
resolution, resend on value change).
I also introduced a new `IsInvalidReferencedCustomHostVitalsError` call
after Copilot's comment below.
# 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
* **New Features**
* Added support for `$FLEET_HOST_VITAL_<id>` in Apple host name
templates.
* Device-name template reconciliation now expands referenced per-host
vital values and updates automatically when those values change.
* **Bug Fixes**
* Prevents deleting custom host vitals that are referenced by host name
templates.
* If a referenced vital has no value for a host, device-name delivery is
marked failed for that host (retryable).
* **Improved Error Handling**
* Refined validation behavior so unknown/malformed vital references
return user-facing invalid-argument errors, while infrastructure errors
propagate unchanged.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Resolves#48689
Adds a CPE translation so Firefox Developer Edition on macOS resolves to
the standard `mozilla:firefox` product. Without it, `CPEFromSoftware`
generates no CPE for the app, so it matches no Firefox CVEs and shows as
vulnerability-free — a silent false negative.
The root cause is that none of the standard matching paths fit Developer
Edition: its bundle identifier `org.mozilla.firefoxdeveloperedition`
splits to a product token (`firefoxdeveloperedition`) that has no NVD
entry, and the sanitized-name and full-text fallbacks don't resolve to
`firefox` either. Regular Firefox works only because its bundle
(`org.mozilla.firefox`) splits cleanly to `mozilla`/`firefox`. The fix
uses the same translation mechanism the existing Firefox ESR rule uses,
mapping the Developer Edition bundle to `product: firefox`, `vendor:
mozilla` — with no `sw_edition`, since Developer Edition tracks standard
Firefox advisories (ESR is the special case that needs the `esr`
edition).
Match is on the bundle identifier rather than the display name so it's
stable regardless of how the app name is ingested.
**Out of scope:** Firefox Nightly (`org.mozilla.nightly`) has the same
failure mode but uses pre-release version strings (e.g. `155.0a1`) that
don't line up with NVD's per-version Firefox CPEs, so mapping it to
`firefox` risks bad matches — it warrants separate handling. Firefox
Beta already works today (its bundle is `org.mozilla.firefox`), so it
needs no change.
**Testing.** Two layers, matching how the codebase already tests CPE
rules:
- An offline unit test (`TestFirefoxDeveloperEditionTranslation`) loads
the real shipped `cpe_translations.json` and asserts Developer Edition
translates to `mozilla:firefox` with no `sw_edition`. It needs no CPE
dictionary or network, so it runs in the fast suite.
- A case in the network-gated `TestCPEFromSoftwareIntegration`,
alongside the existing regular-Firefox case, asserts the full CPE string
against the live NVD dictionary in CI. It reuses the known-good
`105.0.1` Firefox entry. The downstream CPE→CVE step is unchanged and
already covered for `mozilla:firefox` by `TestTranslateCPEToCVE`, so no
new CVE-matching test is needed.
# 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 — ran
`TestFirefoxDeveloperEditionTranslation` locally against the shipped
rule (passes); the full software→CPE resolution against live NVD data is
exercised by the network-gated integration case in CI.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved recognition of Firefox Developer Edition on macOS so it maps
to the expected Firefox vulnerability data.
* Better handling of version matching for this app, helping scan results
stay accurate.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixed an issue where an SSO-only invitation could be accepted with a
password, creating a local password-authenticated account and
bypassing SSO enforcement. The authentication mode is now derived
solely from the invite. Derive the authentication mode from the invite
record instead of client input during invite acceptance.
**Related issue:** Resolvesfleetdm/confidential#16883
# 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
## Summary
Normalized LocURI target values before validation checks in Windows MDM
profile handling.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
- [x] Confirmed that the fix is not expected to adversely impact load
test results
### Reproduction
Wrote test cases that construct Windows SCEP profile XML with trailing
whitespace appended to LocURI paths (e.g., `/Install/SubjectName ` with
a trailing space). Before the fix, these profiles passed validation
without the required renewal-id marker because `strings.HasSuffix` did
not match the whitespace-suffixed path. The same bypass applied to
Challenge and ServerURL LocURIs.
### Unit tests added
7 new test cases across two test functions:
**`TestAdditionalNDESValidationForWindowsProfiles`** (3 new cases):
- SubjectName LocURI with trailing whitespace is still validated for
renewal id
- Challenge LocURI with trailing whitespace still validates correctly
- ServerURL LocURI with trailing whitespace still validates correctly
**`TestAdditionalCustomSCEPValidationForWindowsProfiles`** (new
function, 4 cases):
- Valid custom SCEP profile passes
- SubjectName missing renewal id is rejected
- SubjectName with trailing whitespace in LocURI is still validated for
renewal id
- SubjectName with internal whitespace (not trailing) is rejected
### Local verification
1. Wrote failing tests first, confirmed the whitespace bypass existed
(tests failed as expected before the fix)
2. Applied the fix (`strings.TrimSpace` on target before `HasSuffix`
checks)
3. Confirmed all new tests pass after the fix
4. Ran full test suite: `go test ./server/service/ -run
"TestAdditionalNDESValidation|TestAdditionalCustomSCEPValidation" -v`
with all 14 tests passing
5. Ran `make lint-go-incremental` with 0 issues
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#48845
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Apple MDM reconciliation no longer queues profiles for deleted or
non–MDM-enrolled hosts.
* Apple MDM reconciliation batching/snapshots now include only hosts
with confirmed active MDM enrollment, reducing incorrect or stale
reconciliation candidates.
* **Tests**
* Added MySQL datastore coverage to validate reconcile snapshot
selection and reconcile host lookup behavior.
* Improved Apple MDM and related test setups to explicitly ensure
required MDM server configuration exists before reconciliation
assertions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
prep work for #49367
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added support for disowning Apple DEP devices, returning per-device
results (successful, failed, and inaccessible).
* **Bug Fixes**
* Improved consistency of authentication-related requests by carrying
over the original `User-Agent` when it is set.
* **Chores**
* Updated the bundled upstream dependency to a newer commit.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#47698
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
## 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
* **New Features**
* Added support for marking ABM tokens as invalid with a new
default-enabled status field.
* Existing token records are now initialized with a valid default state
during the update.
* **Tests**
* Added coverage to verify the new token status field is created
correctly and backfilled for existing records.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Token redemption consumed the key via a non-atomic read-then-delete,
which allowed concurrent requests to redeem the same one-time token more
than once. Made consumption atomic so a token can only be used once,
even under concurrent access, and added coverage for the concurrent
path.
The ESP release wrote the user-scope ServerHasFinishedProvisioning
Replace and immediately committed awaiting_configuration=None. During
OOBE the device rejects user-scope writes with SyncML 405 until its user
MDM context initializes, so the Account setup phase never received its
completion signal and the device hung until the 3-hour timeout, while
Fleet believed the ESP had completed (and relaxed the DMClient poll,
crippling remediation).
The release path now stays Active until the device acks the user-scope
Replace with a 200: a new resend phase re-sends the Replace once per
session (bounded by the existing 3-hour timeout), and the Active->None
transition commits only on the 200.
Live-validated on Win11 26200 on both a fresh and a re-enrolled device:
the 405 reproduced at release time in both flows, and the retried
Replace acked 200 one session after the user context came up, releasing
the ESP.
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49134
# 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] 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
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Bug Fixes
- Fixed an issue where Windows Autopilot enrollment could intermittently
hang at **“Account setup”** on the Enrollment Status Page.
- Updated Enrollment Status Page release handling so enrollment **stays
active until the device acknowledges** the user-scope completion
command.
- When the user-scope completion is rejected or still unacknowledged, it
is **retried in subsequent management sessions** until successfully
acknowledged.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#44954
When a custom host vital referenced in a script or profile has no value
set for a host, the delivery failure detail didn't name the vital,
making it hard for admins to tell which one needed a value. The message
now includes both the vital's name and its `$FLEET_HOST_VITAL_<id>`
token.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Bug Fixes**
- Improved missing custom host vital error messages by including both
the vital name and its corresponding environment variable identifier.
- Updated the wording to be clearer about why values can’t be populated
when no value is set for the host.
- Kept singular vs. plural messaging correct when one or multiple vital
values are missing.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves #
Saw I missed these when doing the DDM assets backend
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
## Testing
- [x] 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
* **Tests**
* Expanded endpoint coverage for device management asset routes,
including listing, retrieving, deleting, and batch creation.
* Documented a remaining limitation affecting multipart asset uploads.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#48342
# Checklist for submitter
If some of the following don't apply, delete the relevant line.
- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added support for editing existing Apple, Windows, and Android
configuration profiles through the API.
* Supports updating profile content, names where applicable, label
targeting, and Fleet variable associations without replacing the profile
identity.
* Added support for editing Apple DDM declarations.
* Added activity tracking for configuration profile edits.
* **Bug Fixes**
* Added validation for unsupported edits, invalid labels, duplicate
names, missing profiles, and protected Fleet-managed profiles.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Jordan Montgomery <elijah.jordan.montgomery@gmail.com>
**Related issue:** Resolves#49455
Offer `.py` script-only packages on macOS hosts, matching `.sh`.
# Checklist for submitter
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
## Testing
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Python (`.py`) installer packages are now treated as compatible
alongside shell (`.sh`) installers on macOS and Linux.
* Python installers can now appear in software availability,
self-service installation, and setup experience selections.
* Windows behavior remains unchanged (Unix-script installers are
excluded).
* **Bug Fixes**
* Improved cross-platform compatibility matching for Unix-like hosts
when choosing the first eligible installer package.
* **Tests**
* Added and expanded unit/integration coverage for `.py` installer
compatibility across platforms and flows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#46399
When a label's query errors on a host (e.g. the extension socket is
unavailable) instead of returning zero rows, Fleet was recording that
error the same as a definitive "no match," clearing the host's existing
label membership. This could unintentionally remove configuration
profiles or other automations scoped to that label. The fix leaves
existing label membership untouched when a label query errors.
# 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
**Setup:** macOS VM enrolled as a Fleet host, with a dynamic label whose
query targets a real, always-present table but with a deliberately
invalid `WHERE` clause, so the query fails deterministically (a `no such
column` SQL error).
```sql
-- working version (label matches)
SELECT * FROM os_version;
-- broken version (query errors on every run)
SELECT * FROM os_version WHERE this_column_does_not_exist = 1;
```
### Before (bug reproduced on unpatched code)
1. Set the label's query to the working version and refetched the host —
confirmed it shows up under the host's Labels.
2. Edited the label's query to the broken version.
3. Clicked **Refetch** on the host.
4. **Result:** the label disappeared from the host's Labels list — a
query error incorrectly cleared existing membership.
### After (fix verified)
1. Reset the label's query to the working version and refetched —
confirmed membership was restored.
2. Edited the label's query to the broken version again.
3. Clicked **Refetch** on the host.
4. **Result:** the label remained on the host's Labels list — a query
error now correctly leaves existing membership untouched.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Preserved existing dynamic label memberships when label queries fail
or yield unknown results.
* Avoided treating unknown/failed evaluations as label removals.
* Ensured label updates/removals are applied only when a definite match
or non-match is returned.
* **Tests**
* Expanded coverage for label query errors across datastore, async
processing, and distributed execution to confirm memberships remain
unchanged.
* Updated expectations for queued async updates to skip errored labels.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#49495
Redirects queued Fleet-maintained app installs to the newly-active
installer (canceling already-dispatched ones) atomically when an
auto-update or pin change flips the active version, and re-resolves
install retries to the active installer, so a host no longer installs a
superseded cached version.
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## 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**
* Fleet-maintained app installs now consistently use the currently
active version after automatic promotions, preventing stale installer
targeting.
* Queued installs tied to an older promoted installer are redirected to
the newly active installer instead of being canceled.
* Install retry flows now re-resolve to the active installer at retry
time, avoiding stale retries after version changes.
* **Tests**
* Added datastore coverage for active-installer redirection and updated
retry tests to verify the correct installer ID is used.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49474
# 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
- Relied on integration test for testing changes made by the
`maintained_apps_auto_update` job
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed patch policies for Fleet-maintained apps not updating when the
active app version changes.
* Patch policy queries now refresh to match the currently active (or
pinned) installer version, including changes driven by pinning, cron,
and GitOps.
* Improved behavior when pins are cleared or switched, ensuring the
policy continues referencing the correct version-specific query.
* **Tests**
* Expanded integration coverage to verify version-pinned patch policy
queries across scenario updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#49475
Makes a non-zero install-script exit code a terminal failure so an
install that failed but whose post-install script exited 0 is no longer
reported as installed, in both the Go status computation and the
`host_software_installs` `status`/`execution_status` generated columns.
# Checklist for submitter
- [x] Changes file added for user-visible changes in `changes/`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
## 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. Redefining the
`status`/`execution_status` generated columns rebuilds the table, but
`ON UPDATE CURRENT_TIMESTAMP` is not triggered by `ALTER TABLE`, so
`updated_at` is preserved.
- [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
* **Bug Fixes**
* Installations that fail during the install script are now correctly
reported as failed, even if the post-install script succeeds.
* Install and execution status reporting is now consistent about which
script exit code takes precedence.
* Pending, successful, failed, canceled, and uninstall outcomes continue
to be reported correctly.
* **Tests**
* Added regression/unit test coverage for install-status and
execution-status precedence across mixed install/post-install exit code
scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Resolves#47699.
- [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**
* Microsoft Entra Conditional Access is now supported for self-hosted
Fleet Premium instances.
* Conditional Access is available only on the Fleet Premium license
tier.
* **Changes**
* Removed the Microsoft Compliance Partner API key configuration and
updated the proxy behavior accordingly.
* Removed the managed-cloud indicator from license/config responses and
adjusted related UI rendering and gating.
* **Tests / Maintenance**
* Updated fixtures and automated tests to reflect the new licensing
gates and API/proxy behavior (including updated failure codes).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
**Related issue:** Resolves#41470
Adds support for uploading Python (`.py`) script-only software packages
— accepted as script-only (the file contents become the install script;
advanced options and automatic install follow `.sh`/`.ps1`), assigned
the new `py_packages` source, and installable on macOS and Linux hosts
across the UI, REST API, and GitOps.
Feature branch combining the backend (#48942) and frontend (#48946)
sub-PRs.
# Checklist for submitter
- [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
* **New Features**
* Added support for Python (`.py`) script-only software packages across
UI uploads, API/self-service installs, and GitOps parsing.
* Python installers now derive metadata correctly and render the proper
Python icon, with install eligibility for macOS & Linux.
* **Bug Fixes**
* Improved installer-script validation and “supported file types” error
messages to include `.py` (and consistent handling of related script
fields/options).
* **Tests**
* Expanded unit, integration, and GitOps tests to cover Python package
parsing, metadata derivation, platform/host eligibility, and UI
rendering.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Relates to #38806
Extend host name templates beyond the three host-identity variables to
also accept the IdP end-user variables, and re-enqueue the rename when a
referenced variable's value changes.
Re-enqueue on value change:
- An IdP data change (SCIM user/group create/update/delete) re-queues
only the affected hosts whose template uses the changed IdP variable —
IdP values are per host, so the scope is the specific hosts mapped to
that user/group.
- A custom (secret) value change re-queues every eligible host in each
team / "No team" whose template references the changed secret — secret
values are global, so the scope is the whole team/No-team.
Built-in variables intentionally NOT supported:
- Certificate/CA variables — $FLEET_VAR_NDES_SCEP_CHALLENGE,
_NDES_SCEP_PROXY_URL, _CUSTOM_SCEP_CHALLENGE_*,
_CUSTOM_SCEP_PROXY_URL_*, _SMALLSTEP_SCEP_CHALLENGE_*,
_SMALLSTEP_SCEP_PROXY_URL_*, _DIGICERT_DATA_*, _DIGICERT_PASSWORD_*,
_SCEP_WINDOWS_CERTIFICATE_ID, _CERTIFICATE_RENEWAL_ID (and legacy
_SCEP_RENEWAL_ID), _PSSO_DEVICE_REGISTRATION_TOKEN. These resolve to
one-time SCEP challenges, proxy URLs, base64 PKCS12 cert data, or
Fleet-minted tokens — meaningless as a device name, and resolving them
has side effects (issuing certificates, consuming one-time challenges)
and would leak secrets into a name that's broadcast on-device, in
osquery, and in the UI.
- Legacy $FLEET_VAR_HOST_END_USER_EMAIL_IDP — deprecated ("avoid in new
replacements") and not a documented built-in variable, so it's excluded
in favor of the supported IDP_USERNAME variables.
Resolves#35075
- Added vulnerability (CVE) reporting for Android OS versions.
- Folded the Android security patch level into the host's OS version.
---------
Co-authored-by: Konstantin Sykulev <konst@sykulev.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49260
This fix is based on direct discussion with Apple and consultation of
the Apple docs. We are not currently sure if this is actually issue the
customer is running into but we have identified it as an issue with our
enrollment process.
As far as testing my iPad running 18.7 gets prompted to update every
time now when I enroll it with updates turned on. If I back up and don't
take the upgrade and try to enroll again I get an error but I believe
this is an Apple bug which we've been told was fixed in 26+
# 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 during Android Device Enrollment where devices assigned
a mandatory software update could incorrectly show a failure status.
* Resolved cases where the required software update was not displayed
correctly.
* Improved Apple device enrollment update details by reporting the
operating system version consistently.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#49329
## What & why
Fresh **Windows 11 25H2** (build 10.0.26200) devices failed Microsoft
Entra / Autopilot MDM auto-enrollment during OOBE with error
**80180006**. The device advertises an MS-MDE2 discovery
`RequestVersion` of `"9.0"`, and Fleet's `IsValidDiscoveryMsg()`
rejected it via an exact-match allow-list (`{"4.0","5.0","6.0","7.0"}`)
that could only be changed by rebuilding the server.
The discovery **response** already pins the protocol to
`EnrollmentVersionV4` (`"4.0"`) and the client negotiates down, so the
exact-match check was the only blocker. This PR implements the issue's
preferred fix: **accept any `RequestVersion >= 4.0`**, which is
forward-compatible with future Windows version bumps.
- `server/mdm/microsoft/syncml/syncml.go`: replaced the
`SupportedEnrollmentVersions` allow-list var with a
`MinSupportedEnrollmentVersion` constant.
- `server/fleet/microsoft_mdm.go`: added `enrollmentVersionAtLeast`
(numeric component-wise compare, so `"10.0" > "9.0"`) and changed
discovery validation to accept any version at or above the minimum.
# 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
- [ ] QA'd all new/changed functionality manually
For unreleased bug fixes in a release candidate, one of:
- [x] Confirmed that the fix is not expected to adversely impact load
test results
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed MDM enrollment failures on fresh Windows 11 25H2 and other
recent builds.
* Discovery requests now accept supported MDE2 `RequestVersion` values
at or above the minimum supported version (instead of requiring an exact
match).
* Invalid or outdated discovery versions now return more specific
validation errors.
* **Tests**
* Added unit test coverage for minimum, equal, newer, and invalid
enrollment version comparisons.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
<!-- Add the related story/sub-task/bug number, like Resolves#123, or
remove if NA -->
**Related issue:** Resolves#44954
# 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
* **New Features**
* Added Custom Host Vitals management (create/edit/delete, search) with
copyable variable tokens and per-host values.
* Show Custom Host Vitals on host details, including role-based editing.
* Enabled Custom Host Vitals in host-vitals labels and the activity
feed.
* Extended GitOps to manage global Custom Host Vitals declaratively
(including dry-run behavior).
* Split Controls → Variables into Global Variables and Custom Host
Vitals, including routing updates.
* **Bug Fixes**
* Improved validation and expansion of Custom Host Vital references
across scripts, profiles, installers, and deployments, with clearer
failures when values are missing or invalid.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->