Add multiple macOS FMAs (#37069)

This pull request adds support for several new macOS applications to the
maintained apps system. It introduces new input definitions, output
metadata, and installation/uninstallation scripts for each app, enabling
automated management and categorization. The changes primarily focus on
expanding the catalog with productivity, developer, and communication
tools.

**New App Integrations:**

* Added input definitions and output metadata for the following apps:
- Inkscape (vector graphics editor)
[[1]](diffhunk://#diff-7ce5d431eb69c5546afaa12ada343d8584e835e855ecebf4adc13801ab3eab78R1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R697-R703)
[[3]](diffhunk://#diff-00054bf967e9164fbd87bfc1518f6332cbee50e85936c7e9617a0bfefe405fa4R1-R21)
- Jabra Direct (headset management)
[[1]](diffhunk://#diff-78c52106d0314ec88decc1b6e6490ea8519a45170df466789414c8eac90825f9R1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R739-R745)
[[3]](diffhunk://#diff-cd97d46bd199c6376c16fe81366404c1a3010d3f75b8b8b9a611d354a9edc2cbR1-R21)
- Keeper Password Manager (password manager)
[[1]](diffhunk://#diff-a973ebde05953000c62f2492b17c079a9e552fd3bbab3b678ee2aa0757dafeadR1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R767-R787)
[[3]](diffhunk://#diff-5b88b8712d6bf670a34dd05a496fa7a036b9f53dda262bea1f57deb9a10f6f6eR1-R21)
- Keka (file archiver)
[[1]](diffhunk://#diff-2c462b137233fc73d72dd6f42b4bc07e58d6396e6b178741d496536822f4e732R1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R767-R787)
- Lens (Kubernetes IDE)
[[1]](diffhunk://#diff-51e6db269aa8b8fc295f8573eb1582adbb28bcf1f1fd040fe92f8e0e95c816b2R1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R767-R787)
- Maccy (clipboard manager)
[[1]](diffhunk://#diff-a497d9aa8763fd1b331ce6d454994c1fc955e9fec54d996dae5134c2c64d5e2cR1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R830-R843)
- Mattermost (open-source chat)
[[1]](diffhunk://#diff-7286f40f757bf5322974f664bb55fd6ef89ca486aacba5e524e3e4a7055f24bcR1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R830-R843)
- MongoDB Compass (database GUI)
[[1]](diffhunk://#diff-c03bf76b1aa1a8a9a857a235e2eaa46a35c5d0a8b8331d5990251eadf1855568R1-R8)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R921-R927)

**Installer and Uninstaller Scripts:**

* Added custom install and uninstall shell scripts for Inkscape, Jabra
Direct, and Keeper Password Manager to handle application lifecycle
tasks, including quitting running apps and cleaning up user data.
[[1]](diffhunk://#diff-00054bf967e9164fbd87bfc1518f6332cbee50e85936c7e9617a0bfefe405fa4R1-R21)
[[2]](diffhunk://#diff-cd97d46bd199c6376c16fe81366404c1a3010d3f75b8b8b9a611d354a9edc2cbR1-R21)
[[3]](diffhunk://#diff-5b88b8712d6bf670a34dd05a496fa7a036b9f53dda262bea1f57deb9a10f6f6eR1-R21)

**App Categorization:**

* Assigned appropriate default categories (e.g., Productivity, Developer
tools, Communication) to each new app for better organization and
filtering in the catalog.
[[1]](diffhunk://#diff-7ce5d431eb69c5546afaa12ada343d8584e835e855ecebf4adc13801ab3eab78R1-R8)
[[2]](diffhunk://#diff-78c52106d0314ec88decc1b6e6490ea8519a45170df466789414c8eac90825f9R1-R8)
[[3]](diffhunk://#diff-a973ebde05953000c62f2492b17c079a9e552fd3bbab3b678ee2aa0757dafeadR1-R8)
[[4]](diffhunk://#diff-2c462b137233fc73d72dd6f42b4bc07e58d6396e6b178741d496536822f4e732R1-R8)
[[5]](diffhunk://#diff-51e6db269aa8b8fc295f8573eb1582adbb28bcf1f1fd040fe92f8e0e95c816b2R1-R8)
[[6]](diffhunk://#diff-a497d9aa8763fd1b331ce6d454994c1fc955e9fec54d996dae5134c2c64d5e2cR1-R8)
[[7]](diffhunk://#diff-7286f40f757bf5322974f664bb55fd6ef89ca486aacba5e524e3e4a7055f24bcR1-R8)
[[8]](diffhunk://#diff-c03bf76b1aa1a8a9a857a235e2eaa46a35c5d0a8b8331d5990251eadf1855568R1-R8)

**Metadata and Version Tracking:**

* Introduced detailed metadata and version tracking for each app,
including installer URLs, bundle identifiers, SHA256 checksums, and SQL
queries for existence checks.
[[1]](diffhunk://#diff-00054bf967e9164fbd87bfc1518f6332cbee50e85936c7e9617a0bfefe405fa4R1-R21)
[[2]](diffhunk://#diff-cd97d46bd199c6376c16fe81366404c1a3010d3f75b8b8b9a611d354a9edc2cbR1-R21)
[[3]](diffhunk://#diff-5b88b8712d6bf670a34dd05a496fa7a036b9f53dda262bea1f57deb9a10f6f6eR1-R21)

**Catalog Expansion:**

* Updated the main `apps.json` output to include all new apps with
descriptions and platform information, ensuring visibility in the
maintained apps catalog.
[[1]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R697-R703)
[[2]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R739-R745)
[[3]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R767-R787)
[[4]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R830-R843)
[[5]](diffhunk://#diff-4c1446cfc02c6bb0bda874481e333c65b84e184fcea52f656b49a6489f73c9c2R921-R927)
This commit is contained in:
Allen Houchins
2025-12-10 17:14:01 -06:00
committed by GitHub
parent 7efdb67401
commit bee28a9e86
35 changed files with 502 additions and 12 deletions
+86 -12
View File
@@ -93,6 +93,90 @@ func forceLaunchServicesRefresh(appPath string) error {
return nil
}
// normalizeVersion removes common suffixes from version strings
func normalizeVersion(v string) string {
suffixes := []string{"-latest", "-beta", "-alpha", "-rc", "-pre"}
normalized := v
for _, suffix := range suffixes {
normalized = strings.TrimSuffix(normalized, suffix)
}
return normalized
}
// checkVersionMatch checks if the expected version matches any of the found versions
// using various matching strategies: exact match, normalization, concatenation, and prefix matching
func checkVersionMatch(expectedVersion, foundVersion, foundBundledVersion string) bool {
// Check exact matches first (no normalization needed)
if expectedVersion == foundVersion || expectedVersion == foundBundledVersion {
return true
}
// Only normalize if exact match failed (lazy normalization)
normalizedExpected := normalizeVersion(expectedVersion)
normalizedFound := normalizeVersion(foundVersion)
normalizedBundled := normalizeVersion(foundBundledVersion)
// Check normalized exact matches
if normalizedExpected == normalizedFound || normalizedExpected == normalizedBundled {
return true
}
// Check if expected version is a concatenation of short version + bundled version
// This handles cases like "1.4.230579" = "1.4.2" + "30579" or "1.4.2.30579" = "1.4.2" + "." + "30579"
// Only check concatenation if the expected version is longer than the short version alone,
// which indicates it might be a concatenation (avoids false positives)
if foundVersion != "" && foundBundledVersion != "" && len(expectedVersion) > len(foundVersion) {
// Try direct concatenation (no separator)
concatenated := foundVersion + foundBundledVersion
if expectedVersion == concatenated {
return true
}
// Check normalized concatenation
normalizedConcatenated := normalizedFound + normalizedBundled
if normalizedExpected == normalizedConcatenated {
return true
}
// Try concatenation with dot separator
concatenatedWithDot := foundVersion + "." + foundBundledVersion
if expectedVersion == concatenatedWithDot {
return true
}
normalizedConcatenatedWithDot := normalizedFound + "." + normalizedBundled
if normalizedExpected == normalizedConcatenatedWithDot {
return true
}
}
// Check if found version starts with expected version (handles suffixes like ".CE")
// This handles cases where the app version is "8.0.44.CE" but expected is "8.0.44"
if strings.HasPrefix(foundVersion, expectedVersion+".") ||
strings.HasPrefix(foundBundledVersion, expectedVersion+".") {
return true
}
if strings.HasPrefix(normalizedFound, normalizedExpected+".") ||
strings.HasPrefix(normalizedBundled, normalizedExpected+".") {
return true
}
// Check if expected version starts with found version (handles cases where osquery reports shorter version)
// This handles cases where expected is "2025.2.1.8" but osquery reports "2025.2"
if strings.HasPrefix(expectedVersion, foundVersion+".") {
return true
}
if strings.HasPrefix(normalizedExpected, normalizedFound+".") {
return true
}
// Also check bundled version for prefix matches
if strings.HasPrefix(expectedVersion, foundBundledVersion+".") {
return true
}
if strings.HasPrefix(normalizedExpected, normalizedBundled+".") {
return true
}
return false
}
func appExists(ctx context.Context, logger kitlog.Logger, appName, uniqueAppIdentifier, appVersion, appPath string) (bool, error) {
execTimeout, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
@@ -169,18 +253,8 @@ func appExists(ctx context.Context, logger kitlog.Logger, appName, uniqueAppIden
return true, nil
}
// Check exact match first
if result.Version == appVersion || result.BundledVersion == appVersion {
return true, nil
}
// Check if found version starts with expected version (handles suffixes like ".CE")
// This handles cases where the app version is "8.0.44.CE" but expected is "8.0.44"
if strings.HasPrefix(result.Version, appVersion+".") || strings.HasPrefix(result.BundledVersion, appVersion+".") {
return true, nil
}
// Check if expected version starts with found version (handles cases where osquery reports shorter version)
// This handles cases where expected is "2025.2.1.8" but osquery reports "2025.2"
if strings.HasPrefix(appVersion, result.Version+".") {
// Check various version matching strategies
if checkVersionMatch(appVersion, result.Version, result.BundledVersion) {
return true, nil
}
}