mirror of
https://github.com/fleetdm/fleet
synced 2026-05-15 04:58:25 +00:00
#24385 Some docs change here: https://github.com/fleetdm/fleet/pull/25026. - [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/Committing-Changes.md#changes-files) for more information. - [X] Added/updated tests - [X] Manual QA for all new/changed functionality
116 lines
4.2 KiB
Go
116 lines
4.2 KiB
Go
// Package automatic_policy generates "trigger policies" from metadata of software packages.
|
|
package automatic_policy
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// PolicyData contains generated data for a policy to trigger installation of a software package.
|
|
type PolicyData struct {
|
|
// Name is the generated name of the policy.
|
|
Name string
|
|
// Query is the generated SQL/sqlite of the policy.
|
|
Query string
|
|
// Description is the generated description for the policy.
|
|
Description string
|
|
// Platform is the target platform for the policy.
|
|
Platform string
|
|
}
|
|
|
|
// InstallerMetadata contains the metadata of a software package used to generate the policies.
|
|
type InstallerMetadata struct {
|
|
// Title is the software title extracted from a software package.
|
|
Title string
|
|
// Extension is the extension of the software package.
|
|
Extension string
|
|
// BundleIdentifier contains the bundle identifier for 'pkg' packages.
|
|
BundleIdentifier string
|
|
// PackageIDs contains the product code for 'msi' packages.
|
|
PackageIDs []string
|
|
}
|
|
|
|
var (
|
|
// ErrExtensionNotSupported is returned if the extension is not supported to generate automatic policies.
|
|
ErrExtensionNotSupported = errors.New("extension not supported")
|
|
// ErrMissingBundleIdentifier is returned if the software extension is "pkg" and a bundle identifier was not extracted from the installer.
|
|
ErrMissingBundleIdentifier = errors.New("missing bundle identifier")
|
|
// ErrMissingProductCode is returned if the software extension is "msi" and a product code was not extracted from the installer.
|
|
ErrMissingProductCode = errors.New("missing product code")
|
|
// ErrMissingTitle is returned if a title was not extracted from the installer.
|
|
ErrMissingTitle = errors.New("missing title")
|
|
)
|
|
|
|
// Generate generates the "trigger policy" from the metadata of a software package.
|
|
func Generate(metadata InstallerMetadata) (*PolicyData, error) {
|
|
switch {
|
|
case metadata.Title == "":
|
|
return nil, ErrMissingTitle
|
|
case metadata.Extension != "pkg" && metadata.Extension != "msi" && metadata.Extension != "deb" && metadata.Extension != "rpm":
|
|
return nil, ErrExtensionNotSupported
|
|
case metadata.Extension == "pkg" && metadata.BundleIdentifier == "":
|
|
return nil, ErrMissingBundleIdentifier
|
|
case metadata.Extension == "msi" && (len(metadata.PackageIDs) == 0 || metadata.PackageIDs[0] == ""):
|
|
return nil, ErrMissingProductCode
|
|
}
|
|
|
|
name := fmt.Sprintf("[Install software] %s (%s)", metadata.Title, metadata.Extension)
|
|
|
|
description := fmt.Sprintf("Policy triggers automatic install of %s on each host that's missing this software.", metadata.Title)
|
|
if metadata.Extension == "deb" || metadata.Extension == "rpm" {
|
|
basedPrefix := "RPM"
|
|
if metadata.Extension == "rpm" {
|
|
basedPrefix = "Debian"
|
|
}
|
|
description += fmt.Sprintf(
|
|
"\nSoftware won't be installed on Linux hosts with %s-based distributions because this policy's query is written to always pass on these hosts.",
|
|
basedPrefix,
|
|
)
|
|
}
|
|
|
|
switch metadata.Extension {
|
|
case "pkg":
|
|
return &PolicyData{
|
|
Name: name,
|
|
Query: fmt.Sprintf("SELECT 1 FROM apps WHERE bundle_identifier = '%s';", metadata.BundleIdentifier),
|
|
Platform: "darwin",
|
|
Description: description,
|
|
}, nil
|
|
case "msi":
|
|
return &PolicyData{
|
|
Name: name,
|
|
Query: fmt.Sprintf("SELECT 1 FROM programs WHERE identifying_number = '%s';", metadata.PackageIDs[0]),
|
|
Platform: "windows",
|
|
Description: description,
|
|
}, nil
|
|
case "deb":
|
|
return &PolicyData{
|
|
Name: name,
|
|
Query: fmt.Sprintf(
|
|
// First inner SELECT will mark the policies as successful on non-DEB-based hosts.
|
|
`SELECT 1 WHERE EXISTS (
|
|
SELECT 1 WHERE (SELECT COUNT(*) FROM deb_packages) = 0
|
|
) OR EXISTS (
|
|
SELECT 1 FROM deb_packages WHERE name = '%s'
|
|
);`, metadata.Title,
|
|
),
|
|
Platform: "linux",
|
|
Description: description,
|
|
}, nil
|
|
case "rpm":
|
|
return &PolicyData{
|
|
Name: name,
|
|
Query: fmt.Sprintf(
|
|
// First inner SELECT will mark the policies as successful on non-RPM-based hosts.
|
|
`SELECT 1 WHERE EXISTS (
|
|
SELECT 1 WHERE (SELECT COUNT(*) FROM rpm_packages) = 0
|
|
) OR EXISTS (
|
|
SELECT 1 FROM rpm_packages WHERE name = '%s'
|
|
);`, metadata.Title),
|
|
Platform: "linux",
|
|
Description: description,
|
|
}, nil
|
|
default:
|
|
return nil, ErrExtensionNotSupported
|
|
}
|
|
}
|