**Related issue:** Resolves #45710 # Checklist for submitter - [x] Changes file added (`changes/45710-zorin-os-support`). - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops. - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes. ## Testing - [x] Added/updated automated tests — `server/vulnerabilities/oval/oval_platform_test.go` extended with Zorin → Ubuntu LTS mapping cases (16/17/18) plus an unknown-version case (`Zorin OS 99` → `zorin_99`, which `IsSupported()` rejects). - [x] QA'd all new/changed functionality manually — Zorin OS 17.0 and 18.1 hosts enrolled against a patched Fleet server, host details show `platform=zorin`, software inventory populates, and OVAL CVE matching produces results against the corresponding `ubuntu_2204` / `ubuntu_2404` feeds. ## Database migrations - N/A. No schema changes. ## New Fleet configuration settings - N/A. No new settings. ## fleetd/orbit/Fleet Desktop - N/A. Server + frontend only; no fleetd/orbit changes. --- ## Summary Fleet previously logged `unrecognized platform` for Zorin OS hosts (osquery reports `platform=zorin` from `/etc/os-release` `ID=zorin`). The common workaround was running osquery with `--force_platform=ubuntu`, which masquerades the host. This change adds `zorin` as a first-class Linux platform alongside Ubuntu: - **`server/fleet/hosts.go`** — register `zorin` in `HostLinuxOSs` and `HostDebPackageOSs` - **`server/datastore/mysql/linux_mdm.go`** — include Zorin in the Linux disk-encryption summary query - **`server/vulnerabilities/oval/oval_platform.go`** — map Zorin major version to the underlying Ubuntu LTS OVAL feed (16 → 20.04, 17 → 22.04, 18 → 24.04). Unknown future versions fall through to an unsupported `zorin_<major>` identifier so vulnerability scanning is skipped rather than served stale data from an aging LTS feed. - **frontend** — add `zorin` to `HOST_LINUX_PLATFORMS`, the disk-encryption support list and type guard, the label platform dropdown, and the icon mapping (Ubuntu icon, since no Zorin-specific asset exists in the repo). No new dependency, schema migration, or config setting. Reuses existing Ubuntu OVAL feeds and the existing Ubuntu icon. Diff is ~30 lines net across 9 files (8 patched + 1 `changes/` file). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Zorin OS as a supported Linux platform. * Zorin hosts included in Linux disk-encryption summaries and treated as disk-encryption capable. * Zorin OS available as a selectable/filterable platform label and considered DEB-install compatible. * Vulnerability scanning enabled for Zorin 16→Ubuntu 20.04, 17→22.04, 18→24.04; unknown/future Zorin versions are marked unsupported and skipped for CVE matching. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45712?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
105 lines
2.6 KiB
Go
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`
|
|
}
|