From 93ce34ab1b307c5266f6ea8a4a80756fefe452f1 Mon Sep 17 00:00:00 2001 From: Erik Gomez Date: Wed, 10 Jul 2024 17:04:47 -0500 Subject: [PATCH] add major and minor SLAs for sofa --- CHANGELOG.md | 9 ++- .../Preferences/DefaultPreferencesNudge.swift | 36 +++++++--- Nudge/Preferences/PreferencesStructure.swift | 36 ++++++---- Nudge/UI/Main.swift | 26 ++++--- Schema/jamf/com.github.macadmins.Nudge.json | 69 +++++++++++++++++-- 5 files changed, 136 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0167dc45..4b7265ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,9 +21,12 @@ Requires macOS 12.0 and higher. Further releases and feature requests may make t - `latest-minor`: stay in the current major release and get the latest minor updates available - This requires utilizing the SOFA feed features to properly work, which is opt-out by default - Nudge will then utilize two date integers to automatically calculate the `requiredInstallationDate` - - `activelyExploitedCVEsInstallationSLA` under the `osVersionRequirement` key will default to 14 days - - `nonActivelyExploitedCVEsSLA` under the `osVersionRequirement` key will default to 21 days - - `standardInstallationSLA` under the `osVersionRequirement` key will default to 28 days + - `activelyExploitedCVEsMajorUpgradeSLA` under the `osVersionRequirement` key will default to 14 days + - `activelyExploitedCVEsMinorUpdateSLA` under the `osVersionRequirement` key will default to 14 days + - `nonActivelyExploitedCVEsMajorUpgradeSLA` under the `osVersionRequirement` key will default to 21 days + - `nonActivelyExploitedCVEsMinorUpdateSLA` under the `osVersionRequirement` key will default to 21 days + - `standardMajorUpgradeSLA` under the `osVersionRequirement` key will default to 28 days + - `standardMinorUpdateSLA` under the `osVersionRequirement` key will default to 28 days - These dates are calculated against the `ReleaseDate` key in the SOFA feed, which is UTC formatted. Local timezones will **not be supported** with the automatic sofa feed unless you use a custom feed and change this value yourself, following ISO-8601 date formats - To artificially delay the SOFA nudge events, see the details below for `nudgeEventLaunchDelay` - If you'd like to not have nudge events for releases without any known CVEs, please configure the `disableNudgeForStandardInstalls` key under `optionalFeatures` to true diff --git a/Nudge/Preferences/DefaultPreferencesNudge.swift b/Nudge/Preferences/DefaultPreferencesNudge.swift index 65798feb..d04b10ac 100644 --- a/Nudge/Preferences/DefaultPreferencesNudge.swift +++ b/Nudge/Preferences/DefaultPreferencesNudge.swift @@ -207,9 +207,15 @@ struct OSVersionRequirementVariables { "" } - static var activelyExploitedCVEsInstallationSLA: Int { - osVersionRequirementsProfile?.activelyExploitedCVEsInstallationSLA ?? - osVersionRequirementsJSON?.activelyExploitedCVEsInstallationSLA ?? + static var activelyExploitedCVEsMajorUpgradeSLA: Int { + osVersionRequirementsProfile?.activelyExploitedCVEsMajorUpgradeSLA ?? + osVersionRequirementsJSON?.activelyExploitedCVEsMajorUpgradeSLA ?? + 14 + } + + static var activelyExploitedCVEsMinorUpdateSLA: Int { + osVersionRequirementsProfile?.activelyExploitedCVEsMinorUpdateSLA ?? + osVersionRequirementsJSON?.activelyExploitedCVEsMinorUpdateSLA ?? 14 } @@ -219,9 +225,15 @@ struct OSVersionRequirementVariables { "" } - static var nonActivelyExploitedCVEsSLA: Int { - osVersionRequirementsProfile?.nonActivelyExploitedCVEsSLA ?? - osVersionRequirementsJSON?.nonActivelyExploitedCVEsSLA ?? + static var nonActivelyExploitedCVEsMajorUpgradeSLA: Int { + osVersionRequirementsProfile?.nonActivelyExploitedCVEsMajorUpgradeSLA ?? + osVersionRequirementsJSON?.nonActivelyExploitedCVEsMajorUpgradeSLA ?? + 21 + } + + static var nonActivelyExploitedCVEsMinorUpdateSLA: Int { + osVersionRequirementsProfile?.nonActivelyExploitedCVEsMinorUpdateSLA ?? + osVersionRequirementsJSON?.nonActivelyExploitedCVEsMinorUpdateSLA ?? 21 } @@ -233,9 +245,15 @@ struct OSVersionRequirementVariables { } } - static var standardInstallationSLA: Int { - osVersionRequirementsProfile?.standardInstallationSLA ?? - osVersionRequirementsJSON?.standardInstallationSLA ?? + static var standardMajorUpgradeSLA: Int { + osVersionRequirementsProfile?.standardMajorUpgradeSLA ?? + osVersionRequirementsJSON?.standardMajorUpgradeSLA ?? + 28 + } + + static var standardMinorUpdateSLA: Int { + osVersionRequirementsProfile?.standardMinorUpdateSLA ?? + osVersionRequirementsJSON?.standardMinorUpdateSLA ?? 28 } diff --git a/Nudge/Preferences/PreferencesStructure.swift b/Nudge/Preferences/PreferencesStructure.swift index bac9c632..bacfe162 100644 --- a/Nudge/Preferences/PreferencesStructure.swift +++ b/Nudge/Preferences/PreferencesStructure.swift @@ -148,12 +148,15 @@ struct OSVersionRequirement: Codable { var aboutUpdateURL: String? var aboutUpdateURLs: [AboutUpdateURL]? var actionButtonPath: String? - var activelyExploitedCVEsInstallationSLA: Int? + var activelyExploitedCVEsMajorUpgradeSLA: Int? + var activelyExploitedCVEsMinorUpdateSLA: Int? var majorUpgradeAppPath: String? - var nonActivelyExploitedCVEsSLA: Int? + var nonActivelyExploitedCVEsMajorUpgradeSLA: Int? + var nonActivelyExploitedCVEsMinorUpdateSLA: Int? var requiredInstallationDate: Date? var requiredMinimumOSVersion: String? - var standardInstallationSLA: Int? + var standardMajorUpgradeSLA: Int? + var standardMinorUpdateSLA: Int? var targetedOSVersionsRule: String? var unsupportedURL: String? var unsupportedURLs: [UnsupportedURL]? @@ -164,11 +167,14 @@ extension OSVersionRequirement { init(fromDictionary: [String: AnyObject]) { self.aboutUpdateURL = fromDictionary["aboutUpdateURL"] as? String self.actionButtonPath = fromDictionary["actionButtonPath"] as? String - self.activelyExploitedCVEsInstallationSLA = fromDictionary["activelyExploitedCVEsInstallationSLA"] as? Int + self.activelyExploitedCVEsMajorUpgradeSLA = fromDictionary["activelyExploitedCVEsMajorUpgradeSLA"] as? Int + self.activelyExploitedCVEsMinorUpdateSLA = fromDictionary["activelyExploitedCVEsMinorUpdateSLA"] as? Int self.majorUpgradeAppPath = fromDictionary["majorUpgradeAppPath"] as? String - self.nonActivelyExploitedCVEsSLA = fromDictionary["nonActivelyExploitedCVEsSLA"] as? Int + self.nonActivelyExploitedCVEsMajorUpgradeSLA = fromDictionary["nonActivelyExploitedCVEsMajorUpgradeSLA"] as? Int + self.nonActivelyExploitedCVEsMinorUpdateSLA = fromDictionary["nonActivelyExploitedCVEsMinorUpdateSLA"] as? Int self.requiredMinimumOSVersion = fromDictionary["requiredMinimumOSVersion"] as? String - self.standardInstallationSLA = fromDictionary["standardInstallationSLA"] as? Int + self.standardMajorUpgradeSLA = fromDictionary["standardMajorUpgradeSLA"] as? Int + self.standardMinorUpdateSLA = fromDictionary["standardMinorUpdateSLA"] as? Int self.targetedOSVersionsRule = fromDictionary["targetedOSVersionsRule"] as? String self.unsupportedURL = fromDictionary["unsupportedURL"] as? String @@ -239,12 +245,15 @@ extension OSVersionRequirement { aboutUpdateURL: String? = nil, aboutUpdateURLs: [AboutUpdateURL]? = nil, actionButtonPath: String? = nil, - activelyExploitedCVEsInstallationSLA: Int? = nil, + activelyExploitedCVEsMajorUpgradeSLA: Int? = nil, + activelyExploitedCVEsMinorUpdateSLA: Int? = nil, majorUpgradeAppPath: String? = nil, - nonActivelyExploitedCVEsSLA: Int? = nil, + nonActivelyExploitedCVEsMajorUpgradeSLA: Int? = nil, + nonActivelyExploitedCVEsMinorUpdateSLA: Int? = nil, requiredInstallationDate: Date? = nil, requiredMinimumOSVersion: String? = nil, - standardInstallationSLA: Int? = nil, + standardMajorUpgradeSLA: Int? = nil, + standardMinorUpdateSLA: Int? = nil, targetedOSVersionsRule: String? = nil, unsupportedURL: String? = nil, unsupportedURLs: [UnsupportedURL]? = nil @@ -253,12 +262,15 @@ extension OSVersionRequirement { aboutUpdateURL: aboutUpdateURL ?? self.aboutUpdateURL, aboutUpdateURLs: aboutUpdateURLs ?? self.aboutUpdateURLs, actionButtonPath: actionButtonPath ?? self.actionButtonPath, - activelyExploitedCVEsInstallationSLA: activelyExploitedCVEsInstallationSLA ?? self.activelyExploitedCVEsInstallationSLA, + activelyExploitedCVEsMajorUpgradeSLA: activelyExploitedCVEsMajorUpgradeSLA ?? self.activelyExploitedCVEsMajorUpgradeSLA, + activelyExploitedCVEsMinorUpdateSLA: activelyExploitedCVEsMinorUpdateSLA ?? self.activelyExploitedCVEsMinorUpdateSLA, majorUpgradeAppPath: majorUpgradeAppPath ?? self.majorUpgradeAppPath, - nonActivelyExploitedCVEsSLA: nonActivelyExploitedCVEsSLA ?? self.nonActivelyExploitedCVEsSLA, + nonActivelyExploitedCVEsMajorUpgradeSLA: nonActivelyExploitedCVEsMajorUpgradeSLA ?? self.nonActivelyExploitedCVEsMajorUpgradeSLA, + nonActivelyExploitedCVEsMinorUpdateSLA: nonActivelyExploitedCVEsMinorUpdateSLA ?? self.nonActivelyExploitedCVEsMinorUpdateSLA, requiredInstallationDate: requiredInstallationDate ?? self.requiredInstallationDate, requiredMinimumOSVersion: requiredMinimumOSVersion ?? self.requiredMinimumOSVersion, - standardInstallationSLA: standardInstallationSLA ?? self.standardInstallationSLA, + standardMajorUpgradeSLA: standardMajorUpgradeSLA ?? self.standardMajorUpgradeSLA, + standardMinorUpdateSLA: standardMinorUpdateSLA ?? self.standardMinorUpdateSLA, targetedOSVersionsRule: targetedOSVersionsRule ?? self.targetedOSVersionsRule, unsupportedURL: unsupportedURL ?? self.unsupportedURL, unsupportedURLs: unsupportedURLs ?? self.unsupportedURLs diff --git a/Nudge/UI/Main.swift b/Nudge/UI/Main.swift index 848176b9..4c704f41 100644 --- a/Nudge/UI/Main.swift +++ b/Nudge/UI/Main.swift @@ -207,15 +207,21 @@ class AppDelegate: NSObject, NSApplicationDelegate { let activelyExploitedCVEs = selectedOS!.activelyExploitedCVEs.count > 0 let presentCVEs = selectedOS!.cves.count > 0 let slaExtension: TimeInterval - switch (activelyExploitedCVEs, presentCVEs) { - case (false, true): - slaExtension = TimeInterval(OSVersionRequirementVariables.nonActivelyExploitedCVEsSLA * 86400) - case (true, true): - slaExtension = TimeInterval(OSVersionRequirementVariables.activelyExploitedCVEsInstallationSLA * 86400) - case (false, false): - slaExtension = TimeInterval(OSVersionRequirementVariables.standardInstallationSLA * 86400) - default: - slaExtension = TimeInterval(OSVersionRequirementVariables.standardInstallationSLA * 86400) + switch (activelyExploitedCVEs, presentCVEs, AppStateManager().requireMajorUpgrade()) { + case (false, true, true): + slaExtension = TimeInterval(OSVersionRequirementVariables.nonActivelyExploitedCVEsMajorUpgradeSLA * 86400) + case (false, true, false): + slaExtension = TimeInterval(OSVersionRequirementVariables.nonActivelyExploitedCVEsMinorUpdateSLA * 86400) + case (true, true, true): + slaExtension = TimeInterval(OSVersionRequirementVariables.activelyExploitedCVEsMajorUpgradeSLA * 86400) + case (true, true, false): + slaExtension = TimeInterval(OSVersionRequirementVariables.activelyExploitedCVEsMinorUpdateSLA * 86400) + case (false, false, true): + slaExtension = TimeInterval(OSVersionRequirementVariables.standardMajorUpgradeSLA * 86400) + case (false, false, false): + slaExtension = TimeInterval(OSVersionRequirementVariables.standardMinorUpdateSLA * 86400) + default: // If we get here, something is wrong, use 90 days as a safety + slaExtension = TimeInterval(90 * 86400) } if OptionalFeatureVariables.disableNudgeForStandardInstalls && !presentCVEs { @@ -228,7 +234,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { nudgePrimaryState.requiredMinimumOSVersion = osVersion.latest.productVersion nudgePrimaryState.activelyExploitedCVEs = activelyExploitedCVEs releaseDate = selectedOS!.releaseDate ?? Date() - requiredInstallationDate = selectedOS!.releaseDate?.addingTimeInterval(slaExtension) ?? DateManager().getCurrentDate().addingTimeInterval(TimeInterval(OSVersionRequirementVariables.standardInstallationSLA * 86400)) + requiredInstallationDate = selectedOS!.releaseDate?.addingTimeInterval(slaExtension) ?? DateManager().getCurrentDate().addingTimeInterval(TimeInterval(90 * 86400)) LogManager.notice("Extending requiredInstallationDate to \(requiredInstallationDate)", logger: sofaLog) LogManager.notice("SOFA Matched OS Version: \(selectedOS!.productVersion)", logger: sofaLog) diff --git a/Schema/jamf/com.github.macadmins.Nudge.json b/Schema/jamf/com.github.macadmins.Nudge.json index ecb961f0..2639be7e 100644 --- a/Schema/jamf/com.github.macadmins.Nudge.json +++ b/Schema/jamf/com.github.macadmins.Nudge.json @@ -452,8 +452,27 @@ } ] }, - "activelyExploitedCVEsInstallationSLA": { - "description": "When an update is under active exploit, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", + "activelyExploitedCVEsMajorUpgradeSLA": { + "description": "When a major upgrade is under active exploit, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", + "anyOf": [ + { + "title": "Not Configured", + "type": "null" + }, + { + "title": "Configured", + "default": 14, + "type": "integer", + "options": { + "inputAttributes": { + "placeholder": "14" + } + } + } + ] + }, + "activelyExploitedCVEsMinorUpdateSLA": { + "description": "When a minor update is under active exploit, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", "anyOf": [ { "title": "Not Configured", @@ -489,8 +508,27 @@ } ] }, - "nonActivelyExploitedCVEsSLA": { - "description": "When an update is not under active exploit but contains CVEs, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", + "nonActivelyExploitedCVEsMajorUpgradeSLA": { + "description": "When a major upgrade is not under active exploit but contains CVEs, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", + "anyOf": [ + { + "title": "Not Configured", + "type": "null" + }, + { + "title": "Configured", + "default": 21, + "type": "integer", + "options": { + "inputAttributes": { + "placeholder": "21" + } + } + } + ] + }, + "nonActivelyExploitedCVEsMinorUpdateSLA": { + "description": "When a minor update is not under active exploit but contains CVEs, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", "anyOf": [ { "title": "Not Configured", @@ -544,8 +582,27 @@ } ] }, - "standardInstallationSLA": { - "description": "When an update has no known CVEs, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", + "standardMajorUpgradeSLA": { + "description": "When a major upgrade has no known CVEs, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", + "anyOf": [ + { + "title": "Not Configured", + "type": "null" + }, + { + "title": "Configured", + "default": 28, + "type": "integer", + "options": { + "inputAttributes": { + "placeholder": "28" + } + } + } + ] + }, + "standardMinorupdateSLA": { + "description": "When a minor update has no known CVEs, this is the amount of days a user has to install the update. (Note: This key is only used with Nudge v2.0 and higher)", "anyOf": [ { "title": "Not Configured",