**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 -->
177 lines
4.8 KiB
Go
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")
|
|
}
|