Files
fleet/server/datastore/mysql/linux_mdm.go
T
fletcher-rudra dfc8c272d3 Add Zorin OS as a recognized Linux platform (#45712)
**Related issue:** Resolves #45710

# Checklist for submitter

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

## Testing

- [x] Added/updated automated tests —
`server/vulnerabilities/oval/oval_platform_test.go` extended with Zorin
→ Ubuntu LTS mapping cases (16/17/18) plus an unknown-version case
(`Zorin OS 99` → `zorin_99`, which `IsSupported()` rejects).
- [x] QA'd all new/changed functionality manually — Zorin OS 17.0 and
18.1 hosts enrolled against a patched Fleet server, host details show
`platform=zorin`, software inventory populates, and OVAL CVE matching
produces results against the corresponding `ubuntu_2204` / `ubuntu_2404`
feeds.

## Database migrations

- N/A. No schema changes.

## New Fleet configuration settings

- N/A. No new settings.

## fleetd/orbit/Fleet Desktop

- N/A. Server + frontend only; no fleetd/orbit changes.

---

## Summary

Fleet previously logged `unrecognized platform` for Zorin OS hosts
(osquery reports `platform=zorin` from `/etc/os-release` `ID=zorin`).
The common workaround was running osquery with
`--force_platform=ubuntu`, which masquerades the host. This change adds
`zorin` as a first-class Linux platform alongside Ubuntu:

- **`server/fleet/hosts.go`** — register `zorin` in `HostLinuxOSs` and
`HostDebPackageOSs`
- **`server/datastore/mysql/linux_mdm.go`** — include Zorin in the Linux
disk-encryption summary query
- **`server/vulnerabilities/oval/oval_platform.go`** — map Zorin major
version to the underlying Ubuntu LTS OVAL feed (16 → 20.04, 17 → 22.04,
18 → 24.04). Unknown future versions fall through to an unsupported
`zorin_<major>` identifier so vulnerability scanning is skipped rather
than served stale data from an aging LTS feed.
- **frontend** — add `zorin` to `HOST_LINUX_PLATFORMS`, the
disk-encryption support list and type guard, the label platform
dropdown, and the icon mapping (Ubuntu icon, since no Zorin-specific
asset exists in the repo).

No new dependency, schema migration, or config setting. Reuses existing
Ubuntu OVAL feeds and the existing Ubuntu icon.

Diff is ~30 lines net across 9 files (8 patched + 1 `changes/` file).

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

* **New Features**
  * Added Zorin OS as a supported Linux platform.
* Zorin hosts included in Linux disk-encryption summaries and treated as
disk-encryption capable.
* Zorin OS available as a selectable/filterable platform label and
considered DEB-install compatible.
* Vulnerability scanning enabled for Zorin 16→Ubuntu 20.04, 17→22.04,
18→24.04; unknown/future Zorin versions are marked unsupported and
skipped for CVE matching.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45712?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-06 13:00:10 -03:00

105 lines
2.6 KiB
Go

package mysql
import (
"context"
"fmt"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/jmoiron/sqlx"
)
func (ds *Datastore) GetLinuxDiskEncryptionSummary(ctx context.Context, teamID *uint) (fleet.MDMLinuxDiskEncryptionSummary, error) {
var args []interface{}
var teamFilter string
if teamID != nil {
teamFilter = "AND h.team_id = ?"
args = append(args, *teamID)
} else {
teamFilter = "AND h.team_id IS NULL"
}
stmt := fmt.Sprintf(`SELECT
CASE WHEN hdek.base64_encrypted IS NOT NULL
AND hdek.base64_encrypted != ''
AND hdek.client_error = '' THEN
'verified'
WHEN hdek.client_error IS NOT NULL
AND hdek.client_error != '' THEN
'failed'
WHEN hdek.base64_encrypted IS NULL
OR (hdek.base64_encrypted = ''
AND hdek.client_error = '') THEN
'action_required'
END AS status,
COUNT(h.id) AS host_count
FROM
hosts h
LEFT JOIN host_disk_encryption_keys hdek ON h.id = hdek.host_id
WHERE
(h.os_version LIKE '%%fedora%%'
OR h.platform LIKE 'ubuntu'
OR h.platform LIKE 'zorin')
%s
GROUP BY
status`, teamFilter)
type countRow struct {
Status string `db:"status"`
HostCount uint `db:"host_count"`
}
var counts []countRow
summary := fleet.MDMLinuxDiskEncryptionSummary{}
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &counts, stmt, args...); err != nil {
return summary, err
}
for _, count := range counts {
switch count.Status {
case "verified":
summary.Verified = count.HostCount
case "action_required":
summary.ActionRequired = count.HostCount
case "failed":
summary.Failed = count.HostCount
}
}
return summary, nil
}
func sqlCaseLinuxOSSettingsStatus() string {
return `
CASE WHEN
hdek.base64_encrypted IS NOT NULL
AND hdek.base64_encrypted != ''
AND hdek.client_error = '' THEN
'` + string(fleet.OSSettingsVerified) + `'
WHEN hdek.client_error IS NOT NULL
AND hdek.client_error != '' THEN
'` + string(fleet.OSSettingsFailed) + `'
WHEN hdek.base64_encrypted IS NULL
OR (hdek.base64_encrypted = ''
AND hdek.client_error = '') THEN
'` + string(fleet.OSSettingsPending) + `'
END`
}
func sqlCaseLinuxDiskEncryptionStatus() string {
return `
CASE WHEN
hdek.base64_encrypted IS NOT NULL
AND hdek.base64_encrypted != ''
AND hdek.client_error = '' THEN
'` + string(fleet.DiskEncryptionVerified) + `'
WHEN hdek.client_error IS NOT NULL
AND hdek.client_error != '' THEN
'` + string(fleet.DiskEncryptionFailed) + `'
WHEN hdek.base64_encrypted IS NULL
OR (hdek.base64_encrypted = ''
AND hdek.client_error = '') THEN
'` + string(fleet.DiskEncryptionActionRequired) + `'
END`
}