Files
fleet/server/vulnerabilities/oval/oval_platform.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

177 lines
4.8 KiB
Go

package oval
import (
"fmt"
"regexp"
"strings"
"time"
oval_parsed "github.com/fleetdm/fleet/v4/server/vulnerabilities/oval/parsed"
)
type Platform string
// OvalFilePrefix is the file prefix used when saving an OVAL artifact.
const (
OvalFilePrefix = "fleet_oval"
GovalDictionaryFilePrefix = "fleet_goval_dictionary"
)
// SupportedSoftwareSources are the software sources for which we are using OVAL or goval-dictionary for vulnerability detection.
var SupportedSoftwareSources = []string{"deb_packages", "rpm_packages"}
var SupportedGovalPlatforms = []string{
"amzn_01",
"amzn_02",
"amzn_2022",
"amzn_2023",
"rhel_07",
"rhel_08",
"rhel_09",
}
// GovalKernelOnlyPlatforms are platforms where goval-dictionary is used only for kernel vulnerability scanning.
// These platforms use the regular OVAL scanning for non-kernel packages.
var GovalKernelOnlyPlatforms = []string{
"rhel_07",
"rhel_08",
"rhel_09",
}
// getMajorMinorVer returns the major and minor version of an 'os_version'.
// ex: 'Ubuntu 20.4.0' => '(20, 04)'
func getMajorMinorVer(osVersion string) (string, string) {
re := regexp.MustCompile(` (?P<major>\d+)\.?(?P<minor>\d+)?`)
m := re.FindStringSubmatch(osVersion)
if len(m) < 2 {
return "", ""
}
maIdx := re.SubexpIndex("major")
miIdx := re.SubexpIndex("minor")
if maIdx > 0 && miIdx > 0 {
major := m[maIdx]
if len(major) < 2 {
major = fmt.Sprintf("0%s", major)
}
minor := m[miIdx]
if len(minor) < 2 {
minor = fmt.Sprintf("0%s", minor)
}
return major, minor
}
return "", ""
}
func format(platform string, major string, minor string) string {
if platform == "zorin" {
// Zorin OS is Ubuntu-based; map to the underlying Ubuntu LTS OVAL feed.
// Unknown future versions fall through to "zorin_<major>", which
// IsSupported() rejects so vuln scanning is skipped rather than served
// stale data from an aging LTS feed.
switch major {
case "16":
return "ubuntu_2004"
case "17":
return "ubuntu_2204"
case "18":
return "ubuntu_2404"
}
}
if platform == "ubuntu" {
return fmt.Sprintf("%s_%s%s", platform, major, minor)
}
// RHEL based platforms only use the major version for their OVAL definitions
return fmt.Sprintf("%s_%s", platform, major)
}
// NewPlatform combines the host platform and os version into a string used to match OVAL
// definitions.
// Examples:
// ('ubuntu', 'Ubuntu 20.4.0') => 'ubuntu_2004'.
// ('rhel', 'CentOS Linux 7.9.2009') => 'rhel_07'.
func NewPlatform(hostPlatform, hostOsVersion string) Platform {
nPlatform := strings.Trim(strings.ToLower(hostPlatform), " ")
hostOsVersion = oval_parsed.ReplaceFedoraOSVersion(hostOsVersion)
major, minor := getMajorMinorVer(strings.Trim(hostOsVersion, " "))
return Platform(format(nPlatform, major, minor))
}
// ToFilename combines 'date' with the contents of 'platform' to produce a 'standard' filename.
func (op Platform) ToFilename(date time.Time, extension string) string {
return fmt.Sprintf("%s_%s-%d_%02d_%02d.%s", OvalFilePrefix, op, date.Year(), date.Month(), date.Day(), extension)
}
func (op Platform) ToGovalDictionaryFilename() string {
return fmt.Sprintf("%s_%s.sqlite3", GovalDictionaryFilePrefix, op)
}
// ToGovalDatabaseFilename returns the filename of the sqlite3 files downloaded using
// the goval-dictionary fetch method in the vulnerabilities generate-cve.yml workflow
func (op Platform) ToGovalDatabaseFilename() string {
return fmt.Sprintf("%s.sqlite3", op)
}
// IsSupported returns whether the given platform is currently supported.
func (op Platform) IsSupported() bool {
supported := []string{
"ubuntu_1404",
"ubuntu_1604",
"ubuntu_1804",
"ubuntu_1910",
"ubuntu_2004",
"ubuntu_2104",
"ubuntu_2110",
"ubuntu_2204",
"ubuntu_2210",
"ubuntu_2304",
"ubuntu_2310",
"ubuntu_2404",
"ubuntu_2410",
"ubuntu_2504",
"rhel_05",
"rhel_06",
"rhel_07",
"rhel_08",
"rhel_09",
}
for _, p := range supported {
if strings.HasPrefix(string(op), p) {
return true
}
}
return false
}
func (op Platform) IsGovalDictionarySupported() bool {
for _, p := range SupportedGovalPlatforms {
if strings.HasPrefix(string(op), p) {
return true
}
}
return false
}
// IsGovalDictionaryKernelOnly returns true if this platform uses goval-dictionary
// only for kernel vulnerability scanning (non-kernel packages use regular OVAL).
func (op Platform) IsGovalDictionaryKernelOnly() bool {
for _, p := range GovalKernelOnlyPlatforms {
if strings.HasPrefix(string(op), p) {
return true
}
}
return false
}
// IsUbuntu checks whether the current Platform targets Ubuntu.
func (op Platform) IsUbuntu() bool {
return strings.HasPrefix(string(op), "ubuntu")
}
// IsRedHat checks whether the current Platform targets Redhat based systems.
func (op Platform) IsRedHat() bool {
return strings.HasPrefix(string(op), "rhel") || strings.HasPrefix(string(op), "amzn")
}