Update DEP enrollment flow to apply minimum macOS version check when specified (#40720)
This commit is contained in:
+1
-1
@@ -371,7 +371,7 @@ func (m AppleOSUpdateSettings) Validate() error {
|
||||
}
|
||||
|
||||
if _, err := time.Parse("2006-01-02", m.Deadline.Value); err != nil {
|
||||
return errors.New(`deadline accepts YYYY-MM-DD format only (E.g., "2023-06-01.")`)
|
||||
return errors.New(AppleOSVersionDeadlineInvalidMessage)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -25,6 +25,8 @@ var (
|
||||
AndroidMDMNotConfiguredMessage = "Android MDM isn't turned on. For more information about setting up MDM, please visit https://fleetdm.com/learn-more-about/how-to-connect-android-enterprise"
|
||||
AppleMDMNotConfiguredMessage = "macOS MDM isn't turned on. Visit https://fleetdm.com/docs/using-fleet to learn how to turn on MDM."
|
||||
AppleABMDefaultTeamDeprecatedMessage = "mdm.apple_bm_default_team has been deprecated. Please use the new mdm.apple_business_manager key documented here: https://fleetdm.com/learn-more-about/apple-business-manager-gitops"
|
||||
AppleOSVersionUnsupportedMessage = "The minimum version isn't supported by Apple."
|
||||
AppleOSVersionDeadlineInvalidMessage = "The deadline isn't a valid date."
|
||||
CantTurnOffMDMForWindowsHostsMessage = "Can't turn off MDM for Windows hosts."
|
||||
CantTurnOffMDMForPersonalHostsMessage = "Couldn't turn off MDM. This command isn't available for personal hosts."
|
||||
CantWipePersonalHostsMessage = "Couldn't wipe. This command isn't available for personal hosts."
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/apple/gdmf"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/internal/commonmdm"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/nanodep/godep"
|
||||
@@ -1397,7 +1398,8 @@ func (pb *ProfileBimap) add(wantedProfile, currentProfile *fleet.MDMAppleProfile
|
||||
type NewActivityFunc = fleet.NewActivityFunc
|
||||
|
||||
func IOSiPadOSRefetch(ctx context.Context, ds fleet.Datastore, commander *MDMAppleCommander, logger *slog.Logger,
|
||||
newActivityFn NewActivityFunc) error {
|
||||
newActivityFn NewActivityFunc,
|
||||
) error {
|
||||
appCfg, err := ds.AppConfig(ctx)
|
||||
if err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "fetching app config")
|
||||
@@ -1511,7 +1513,8 @@ func IOSiPadOSRefetch(ctx context.Context, ds fleet.Datastore, commander *MDMApp
|
||||
// turnOffMDMIfAPNSFailed checks if the error is an APNSDeliveryError and turns off MDM for the failed devices.
|
||||
// Returns a boolean value to indicate whether or not MDM was turned off.
|
||||
func turnOffMDMIfAPNSFailed(ctx context.Context, ds fleet.Datastore, err error, logger *slog.Logger, newActivityFn NewActivityFunc) (bool,
|
||||
error) {
|
||||
error,
|
||||
) {
|
||||
var e *APNSDeliveryError
|
||||
if !errors.As(err, &e) {
|
||||
return false, nil
|
||||
@@ -1606,6 +1609,55 @@ func IOSiPadOSRevive(ctx context.Context, ds fleet.Datastore, commander *MDMAppl
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateMDMSettingsAppleSupportedOSVersion[T fleet.MDM | fleet.TeamMDM](settings T, excludeNonPublicAssetSets bool) map[string]error {
|
||||
var macOSUpdates, iOSUpdates, iPadOSUpdates fleet.AppleOSUpdateSettings
|
||||
if m, ok := any(settings).(fleet.MDM); ok {
|
||||
macOSUpdates = m.MacOSUpdates
|
||||
iOSUpdates = m.IOSUpdates
|
||||
iPadOSUpdates = m.IPadOSUpdates
|
||||
} else if t, ok := any(settings).(fleet.TeamMDM); ok {
|
||||
macOSUpdates = t.MacOSUpdates
|
||||
iOSUpdates = t.IOSUpdates
|
||||
iPadOSUpdates = t.IPadOSUpdates
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if macOSUpdates.MinimumVersion.Value == "" && iOSUpdates.MinimumVersion.Value == "" && iPadOSUpdates.MinimumVersion.Value == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
am, err := gdmf.GetAssetMetadata()
|
||||
if err != nil {
|
||||
return map[string]error{"mdm": fmt.Errorf("fetching Apple asset metadata: %w", err)}
|
||||
} else if am == nil {
|
||||
// this should never happen, but just in case, return an error indicating that the metadata is not available instead of panicking with a nil pointer dereference
|
||||
return map[string]error{"mdm": errors.New("Apple asset metadata is not available")}
|
||||
}
|
||||
|
||||
errs := make(map[string]error, 3)
|
||||
if macOSUpdates.MinimumVersion.Value != "" {
|
||||
if ok := am.IsSupportedMacOSVersion(macOSUpdates.MinimumVersion.Value, excludeNonPublicAssetSets); !ok {
|
||||
errs["mdm.macos_updates.minimum_version"] = errors.New(fleet.AppleOSVersionUnsupportedMessage)
|
||||
}
|
||||
}
|
||||
if iOSUpdates.MinimumVersion.Value != "" {
|
||||
// NOTE: iPod generally falls in the category of iOS in Fleet, but we're only validating against iPhone here
|
||||
// because we assume Apple will eventually remove iPod versions from the Apple Software Lookup Service
|
||||
// and we want to avoid breaking workflows for users in that event
|
||||
if ok := am.IsSupportedIOSVersion(iOSUpdates.MinimumVersion.Value, "iphone", excludeNonPublicAssetSets); !ok {
|
||||
errs["mdm.ios_updates.minimum_version"] = errors.New(fleet.AppleOSVersionUnsupportedMessage)
|
||||
}
|
||||
}
|
||||
if iPadOSUpdates.MinimumVersion.Value != "" {
|
||||
if ok := am.IsSupportedIOSVersion(iPadOSUpdates.MinimumVersion.Value, "ipad", excludeNonPublicAssetSets); !ok {
|
||||
errs["mdm.ipados_updates.minimum_version"] = errors.New(fleet.AppleOSVersionUnsupportedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// RecoveryLockCommander defines the interface for sending recovery lock commands.
|
||||
// This interface is implemented by MDMAppleCommander and allows for testing.
|
||||
type RecoveryLockCommander interface {
|
||||
|
||||
@@ -4,14 +4,18 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/pkg/optjson"
|
||||
"github.com/fleetdm/fleet/v4/server/dev_mode"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/apple/mobileconfig"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm/nanodep/client"
|
||||
@@ -270,6 +274,168 @@ func TestGenerateEnrollmentProfileMobileconfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateMDMSettingsAppleSupportedOSVersion(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// load the test data from the file
|
||||
b, err := os.ReadFile("./gdmf/testdata/gdmf.json")
|
||||
require.NoError(t, err)
|
||||
_, err = w.Write(b)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
dev_mode.SetOverride("FLEET_DEV_GDMF_URL", srv.URL, t)
|
||||
|
||||
// selected versions of from testdata/gdmf.json that we'll use in out tests
|
||||
expectSupportedMacOSPublic := []string{"14.6.1", "13.6.9", "12.7.6", "11.7.10"}
|
||||
expectSupportedMacOSNonPublic := []string{"14.5", "14.6", "13.6.8", "13.6.7", "12.7.5"}
|
||||
expectSupportedIOSPublic := "17.6.1"
|
||||
expectSupportedIOSNonPublic := "17.5.1"
|
||||
// lastIPodSupportedVersion : = "15.8.3"
|
||||
|
||||
// helper function to initialize app config MDM settings with known good versions (tests will modify as needed)
|
||||
mockAppConfigMDM := func() fleet.MDM {
|
||||
return fleet.MDM{
|
||||
MacOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(expectSupportedMacOSPublic[0]),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(expectSupportedIOSPublic),
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(expectSupportedIOSPublic),
|
||||
},
|
||||
}
|
||||
}
|
||||
// helper function to initialize team MDM settings with known good versions (tests will modify as needed)
|
||||
mockTeamMDM := func() fleet.TeamMDM {
|
||||
return fleet.TeamMDM{
|
||||
MacOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(expectSupportedMacOSPublic[0]),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(expectSupportedIOSPublic),
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(expectSupportedIOSPublic),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to check if the error matches expectations for a given platform and log appropriately
|
||||
checkErr := func(platform string, wantErr string, gotErrs map[string]error, msg string) {
|
||||
key := fmt.Sprintf("mdm.%s_updates.minimum_version", platform)
|
||||
if wantErr == "" {
|
||||
assert.Empty(t, gotErrs, msg+": expected no error for platform %s but got: %v", platform, gotErrs)
|
||||
} else {
|
||||
assert.Len(t, gotErrs, 1, msg+": expected error for platform %s but got no errors", platform)
|
||||
assert.Contains(t, gotErrs, key, msg+": expected error for platform %s but got no error", platform)
|
||||
assert.ErrorContains(t, gotErrs[key], wantErr, msg+": expected error for platform %s but got: %v", platform, gotErrs[key])
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("macos", func(t *testing.T) {
|
||||
t.Run("app config mdm settings", func(t *testing.T) {
|
||||
ac := mockAppConfigMDM()
|
||||
for _, v := range expectSupportedMacOSPublic {
|
||||
ac.MacOSUpdates.MinimumVersion = optjson.SetString(v)
|
||||
checkErr("macos", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect public macOS version to be supported when including non-public asset sets")
|
||||
checkErr("macos", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect public macOS version to be supported when excluding non-public asset sets")
|
||||
}
|
||||
for _, v := range expectSupportedMacOSNonPublic {
|
||||
ac.MacOSUpdates.MinimumVersion = optjson.SetString(v)
|
||||
checkErr("macos", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect non-public macOS version to be supported when including non-public asset sets")
|
||||
checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect non-public macOS version to return error when excluding non-public asset sets")
|
||||
}
|
||||
|
||||
ac.MacOSUpdates.MinimumVersion = optjson.SetString("11.7.9") // not supported in either asset set, so we expect an error in both cases
|
||||
checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect unsupported macOS version to return error when including non-public asset sets")
|
||||
checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect unsupported macOS version to return error when excluding non-public asset sets")
|
||||
})
|
||||
t.Run("team mdm settings", func(t *testing.T) {
|
||||
tm := mockTeamMDM()
|
||||
for _, v := range expectSupportedMacOSPublic {
|
||||
tm.MacOSUpdates.MinimumVersion = optjson.SetString(v)
|
||||
checkErr("macos", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect public macOS version to be supported when including non-public asset sets")
|
||||
checkErr("macos", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect public macOS version to be supported when excluding non-public asset sets")
|
||||
}
|
||||
for _, v := range expectSupportedMacOSNonPublic {
|
||||
tm.MacOSUpdates.MinimumVersion = optjson.SetString(v)
|
||||
checkErr("macos", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect non-public macOS version to be supported when including non-public asset sets")
|
||||
checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect non-public macOS version to return error when excluding non-public asset sets")
|
||||
}
|
||||
|
||||
tm.MacOSUpdates.MinimumVersion = optjson.SetString("11.7.9") // not supported in either asset set, so we expect an error in both cases
|
||||
checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect unsupported macOS version to return error when including non-public asset sets")
|
||||
checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect unsupported macOS version to return error when excluding non-public asset sets")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("ios", func(t *testing.T) {
|
||||
t.Run("app config mdm settings", func(t *testing.T) {
|
||||
ac := mockAppConfigMDM()
|
||||
ac.IOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSPublic)
|
||||
checkErr("ios", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect public iOS version to be supported when including non-public asset sets")
|
||||
checkErr("ios", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect public iOS version to be supported when excluding non-public asset sets")
|
||||
|
||||
ac.IOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSNonPublic)
|
||||
checkErr("ios", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect non-public iOS version to be supported when including non-public asset sets")
|
||||
checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect non-public iOS version to return error when excluding non-public asset sets")
|
||||
|
||||
ac.IOSUpdates.MinimumVersion = optjson.SetString("5.3.9") // only supported for Apple Watch, so we expect an error
|
||||
checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect unsupported iOS version to return error when including non-public asset sets")
|
||||
checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect unsupported iOS version to return error when excluding non-public asset sets")
|
||||
})
|
||||
|
||||
t.Run("team mdm settings", func(t *testing.T) {
|
||||
tm := mockTeamMDM()
|
||||
tm.IOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSPublic)
|
||||
checkErr("ios", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect public iOS version to be supported when including non-public asset sets")
|
||||
checkErr("ios", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect public iOS version to be supported when excluding non-public asset sets")
|
||||
|
||||
tm.IOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSNonPublic)
|
||||
checkErr("ios", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect non-public iOS version to be supported when including non-public asset sets")
|
||||
checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect non-public iOS version to return error when excluding non-public asset sets")
|
||||
|
||||
tm.IOSUpdates.MinimumVersion = optjson.SetString("5.3.9") // only supported for Apple Watch, so we expect an error
|
||||
checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect unsupported iOS version to return error when including non-public asset sets")
|
||||
checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect unsupported iOS version to return error when excluding non-public asset sets")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("ipados", func(t *testing.T) {
|
||||
t.Run("app config mdm settings", func(t *testing.T) {
|
||||
ac := mockAppConfigMDM()
|
||||
ac.IPadOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSPublic)
|
||||
checkErr("ipados", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect public iPadOS version to be supported when including non-public asset sets")
|
||||
checkErr("ipados", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect public iPadOS version to be supported when excluding non-public asset sets")
|
||||
|
||||
ac.IPadOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSNonPublic)
|
||||
checkErr("ipados", "", ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect non-public iPadOS version to be supported when including non-public asset sets")
|
||||
checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect non-public iPadOS version to return error when excluding non-public asset sets")
|
||||
|
||||
ac.IPadOSUpdates.MinimumVersion = optjson.SetString("5.3.9") // only supported for Apple Watch, so we expect an error
|
||||
checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, false), "expect unsupported iPadOS version to return error when including non-public asset sets")
|
||||
checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(ac, true), "expect unsupported iPadOS version to return error when excluding non-public asset sets")
|
||||
})
|
||||
|
||||
t.Run("team mdm settings", func(t *testing.T) {
|
||||
tm := mockTeamMDM()
|
||||
tm.IPadOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSPublic)
|
||||
checkErr("ipados", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect public iPadOS version to be supported when including non-public asset sets")
|
||||
checkErr("ipados", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect public iPadOS version to be supported when excluding non-public asset sets")
|
||||
|
||||
tm.IPadOSUpdates.MinimumVersion = optjson.SetString(expectSupportedIOSNonPublic)
|
||||
checkErr("ipados", "", ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect non-public iPadOS version to be supported when including non-public asset sets")
|
||||
checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect non-public iPadOS version to return error when excluding non-public asset sets")
|
||||
|
||||
tm.IPadOSUpdates.MinimumVersion = optjson.SetString("5.3.9") // only supported for Apple Watch, so we expect an error
|
||||
checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, false), "expect unsupported iPadOS version to return error when including non-public asset sets")
|
||||
checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, ValidateMDMSettingsAppleSupportedOSVersion(tm, true), "expect unsupported iPadOS version to return error when excluding non-public asset sets")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type notFoundError struct{}
|
||||
|
||||
func (e notFoundError) IsNotFound() bool { return true }
|
||||
|
||||
@@ -58,34 +58,79 @@ type AssetSets struct {
|
||||
// XROS []Asset `json:"xrOS"` // Fleet doesn't support xrOS yet
|
||||
}
|
||||
|
||||
// APIResponse represents the response from the Apple Software Lookup Service[1][2].
|
||||
// AssetMetadata represents the response from the Apple Software Lookup Service[1][2].
|
||||
// [1]: http://gdmf.apple.com/v2/pmv
|
||||
// [2]: https://support.apple.com/guide/deployment/use-mdm-to-deploy-software-updates-depafd2fad80/web
|
||||
type APIResponse struct {
|
||||
type AssetMetadata struct {
|
||||
PublicAssetSets AssetSets `json:"PublicAssetSets"`
|
||||
AssetSets AssetSets `json:"AssetSets"`
|
||||
// PublicRapidSecurityResponses interface{} `json:"PublicRapidSecurityResponses"` // Fleet doesn't support PublicRapidSecurityResponses yet
|
||||
}
|
||||
|
||||
// IsSupportedMacOSVersion checks if the given macOS version is supported by Apple. The
|
||||
// excludeNonPublicAssetSets parameter controls whether to check against the full asset set or just
|
||||
// the public asset set, which is relevant for DEP enrollment where only public versions are valid.
|
||||
func (a AssetMetadata) IsSupportedMacOSVersion(version string, excludeNonPublicAssetSets bool) bool {
|
||||
as := a.AssetSets.MacOS
|
||||
if excludeNonPublicAssetSets {
|
||||
as = a.PublicAssetSets.MacOS
|
||||
}
|
||||
|
||||
for _, s := range as {
|
||||
if s.ProductVersion == version {
|
||||
return true // version is supported
|
||||
}
|
||||
}
|
||||
|
||||
return false // version is not supported
|
||||
}
|
||||
|
||||
// IsSupportedIOSVersion checks if the given iOS version is supported by Apple for the given device
|
||||
// prefix (e.g. "iPhone", "iPad"). If devicePrefix is empty, it checks if the version is supported
|
||||
// for any iOS device (which includes things like iPod, Apple Watch, and Apple TV). The
|
||||
// excludeNonPublicAssetSets parameter controls whether to check against the full asset set or just
|
||||
// the public asset set, which is relevant for DEP enrollment where only public versions are valid.
|
||||
func (a AssetMetadata) IsSupportedIOSVersion(version string, devicePrefix string, excludeNonPublicAssetSets bool) bool {
|
||||
as := a.AssetSets.IOS
|
||||
if excludeNonPublicAssetSets {
|
||||
as = a.PublicAssetSets.IOS
|
||||
}
|
||||
|
||||
for _, s := range as {
|
||||
if s.ProductVersion == version {
|
||||
if devicePrefix == "" {
|
||||
return true // version is supported for iOS with any device prefix
|
||||
}
|
||||
for _, d := range s.SupportedDevices {
|
||||
if strings.HasPrefix(strings.ToLower(d), strings.ToLower(devicePrefix)) {
|
||||
return true // version is supported for device with the given prefix
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false // version is not supported
|
||||
}
|
||||
|
||||
// GetLatestOSVersion returns the latest OS version for the given device. The device is matched
|
||||
// against the Apple Software Update Lookup Service[1][2] to find the latest version. If no matching
|
||||
// asset is found, an error is returned.
|
||||
// against the Apple Software Update Lookup Service[1][2] to find the latest version in the
|
||||
// PublicAssetSets. If no matching asset is found, an error is returned.
|
||||
// [1]: http://gdmf.apple.com/v2/pmv
|
||||
// [2]: https://support.apple.com/guide/deployment/use-mdm-to-deploy-software-updates-depafd2fad80/web
|
||||
func GetLatestOSVersion(device fleet.MDMAppleMachineInfo) (*Asset, error) {
|
||||
r, err := GetAssetMetadata()
|
||||
am, err := GetAssetMetadata()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("retrieving asset metadata: %w", err)
|
||||
}
|
||||
|
||||
assetSet := r.PublicAssetSets.MacOS // default to public asset set; note that if the device is not macOS, iPhone, iPad, or iPod we'll fail to match the supported device and return an error below
|
||||
assetSet := am.PublicAssetSets.MacOS // default to public asset set; note that if the device is not macOS, iPhone, iPad, or iPod we'll fail to match the supported device and return an error below
|
||||
if strings.HasPrefix(device.Product, "iPhone") ||
|
||||
strings.HasPrefix(device.Product, "iPod") ||
|
||||
strings.HasPrefix(device.Product, "iPad") ||
|
||||
strings.HasPrefix(device.SoftwareUpdateDeviceID, "iPhone") ||
|
||||
strings.HasPrefix(device.SoftwareUpdateDeviceID, "iPod") ||
|
||||
strings.HasPrefix(device.SoftwareUpdateDeviceID, "iPad") {
|
||||
assetSet = r.PublicAssetSets.IOS
|
||||
assetSet = am.PublicAssetSets.IOS
|
||||
}
|
||||
latestIdx := -1
|
||||
for i, s := range assetSet {
|
||||
@@ -129,7 +174,7 @@ func createClient() *http.Client {
|
||||
// GetAssetMetadata retrieves the asset metadata from the Apple Software Lookup Service[1][2].
|
||||
// [1]: http://gdmf.apple.com/v2/pmv
|
||||
// [2]: https://support.apple.com/guide/deployment/use-mdm-to-deploy-software-updates-depafd2fad80/web
|
||||
func GetAssetMetadata() (*APIResponse, error) {
|
||||
func GetAssetMetadata() (*AssetMetadata, error) {
|
||||
baseURL := getBaseURL()
|
||||
reqURL, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
@@ -151,7 +196,7 @@ func GetAssetMetadata() (*APIResponse, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading response body from Apple endpoint: %w", err)
|
||||
}
|
||||
var dest APIResponse
|
||||
var dest AssetMetadata
|
||||
if err := json.Unmarshal(body, &dest); err != nil {
|
||||
return nil, fmt.Errorf("decoding response data from Apple endpoint: %w", err)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestGetLatest(t *testing.T) {
|
||||
_, err = w.Write(b)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer srv.Close()
|
||||
t.Cleanup(srv.Close)
|
||||
dev_mode.SetOverride("FLEET_DEV_GDMF_URL", srv.URL, t)
|
||||
|
||||
// test the function
|
||||
@@ -225,11 +225,8 @@ func TestRetries(t *testing.T) {
|
||||
_, err := w.Write([]byte(`{"error": "bad request"}`))
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
dev_mode.SetOverride("FLEET_DEV_GDMF_URL", srv.URL)
|
||||
t.Cleanup(func() {
|
||||
srv.Close()
|
||||
dev_mode.ClearOverride("FLEET_DEV_GDMF_URL")
|
||||
})
|
||||
t.Cleanup(srv.Close)
|
||||
dev_mode.SetOverride("FLEET_DEV_GDMF_URL", srv.URL, t)
|
||||
|
||||
latest, err := GetLatestOSVersion(fleet.MDMAppleMachineInfo{
|
||||
OSVersion: "14.4.1",
|
||||
|
||||
@@ -5,7 +5,16 @@ import (
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/dev_mode"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func NewTestMDMAppleCertTemplate() *x509.Certificate {
|
||||
@@ -27,3 +36,23 @@ func NewTestMDMAppleCertTemplate() *x509.Certificate {
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
}
|
||||
|
||||
// StartNewAppleGDMFTestServer creates a new test server that serves the GDMF data from the testdata
|
||||
// file. It also sets the necessary dev mode overrides to point to the test server and disable
|
||||
// caching. It closes the server and clears the underlying overrides when the test finishes.
|
||||
func StartNewAppleGDMFTestServer(t *testing.T) {
|
||||
_, thisFile, _, _ := runtime.Caller(0)
|
||||
gdmfTestDataPath := filepath.Join(filepath.Dir(thisFile), "../apple/gdmf/testdata/gdmf.json")
|
||||
|
||||
appleGDMFSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// load the test data from the file
|
||||
b, err := os.ReadFile(gdmfTestDataPath)
|
||||
require.NoError(t, err)
|
||||
_, err = w.Write(b)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
t.Cleanup(appleGDMFSrv.Close)
|
||||
|
||||
dev_mode.SetOverride("FLEET_DEV_GDMF_URL", appleGDMFSrv.URL, t)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/license"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/endpointer"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/version"
|
||||
@@ -1486,6 +1487,15 @@ func (svc *Service) validateMDM(
|
||||
invalid.Append("ipados_updates", err.Error())
|
||||
}
|
||||
|
||||
// Always check whether specified versions are supported by Apple (even if they weren't updated)
|
||||
// Note that we're validating against the full, non-public asset set of OS versions here because
|
||||
// in our DEP flow the minimum version just acts as the threshold for whether or not to update
|
||||
// the host to the latest, public version. We don't need to install the specified version on the
|
||||
// host during DEP so it doesn't need to be in the public asset set.
|
||||
for k, v := range apple_mdm.ValidateMDMSettingsAppleSupportedOSVersion(*mdm, false) {
|
||||
invalid.Append(k, v.Error())
|
||||
}
|
||||
|
||||
if err := mdm.MacOSSetup.Validate(); err != nil {
|
||||
var invalidArgErr *fleet.InvalidArgumentError
|
||||
if errors.As(err, &invalidArgErr) {
|
||||
|
||||
+34
-28
@@ -2081,16 +2081,17 @@ func (svc *Service) CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx context.Cont
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
needsUpdate, err := svc.needsOSUpdateForDEPEnrollment(ctx, *m)
|
||||
// shouldUpdate depends on the app_config settings for minimum_version and update_new_hosts
|
||||
shouldUpdate, err := svc.shouldOSUpdateForDEPEnrollment(ctx, *m)
|
||||
if err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "checking os updates settings", "serial", m.Serial)
|
||||
}
|
||||
|
||||
if !needsUpdate {
|
||||
} else if !shouldUpdate {
|
||||
svc.logger.DebugContext(ctx, "device is above minimum or update new host not checked, skipping os version check", "serial", m.Serial)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if the device should update based on appconfig settings, we also need to check what versions
|
||||
// are actually available for the device from Apple
|
||||
sur, err := svc.getAppleSoftwareUpdateRequiredForDEPEnrollment(*m)
|
||||
if err != nil {
|
||||
// log for debugging but allow enrollment to proceed
|
||||
@@ -2101,7 +2102,7 @@ func (svc *Service) CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx context.Cont
|
||||
return sur, nil
|
||||
}
|
||||
|
||||
func (svc *Service) needsOSUpdateForDEPEnrollment(ctx context.Context, m fleet.MDMAppleMachineInfo) (bool, error) {
|
||||
func (svc *Service) shouldOSUpdateForDEPEnrollment(ctx context.Context, m fleet.MDMAppleMachineInfo) (bool, error) {
|
||||
// NOTE: Under the hood, the datastore is joining host_dep_assignments to the hosts table to
|
||||
// look up DEP hosts by serial number. It grabs the team id and platform from the
|
||||
// hosts table. Then it uses the team id to get either the global config or team config.
|
||||
@@ -2124,35 +2125,40 @@ func (svc *Service) needsOSUpdateForDEPEnrollment(ctx context.Context, m fleet.M
|
||||
}
|
||||
|
||||
minVersion := settings.MinimumVersion.Value
|
||||
hasMinVersion := settings.MinimumVersion.Set && settings.MinimumVersion.Valid && minVersion != ""
|
||||
|
||||
// For macOS hosts, whether to update new hosts during DEP enrollment is determined solely by UpdateNewHosts
|
||||
if platform == "darwin" {
|
||||
updateNewHosts := settings.UpdateNewHosts.Set && settings.UpdateNewHosts.Valid && settings.UpdateNewHosts.Value
|
||||
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings for macos, update will be forced if UpdateNewHosts is set",
|
||||
"update_new_hosts", updateNewHosts,
|
||||
"serial", m.Serial,
|
||||
)
|
||||
return updateNewHosts, nil
|
||||
isSetMinVersion := settings.MinimumVersion.Set && settings.MinimumVersion.Valid && minVersion != ""
|
||||
logs := []any{
|
||||
"platform", platform,
|
||||
"minimum_version", minVersion,
|
||||
"current_version", m.OSVersion,
|
||||
"serial", m.Serial,
|
||||
}
|
||||
|
||||
// TODO: confirm what this check should do
|
||||
if !hasMinVersion {
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings, minimum version not set",
|
||||
"serial", m.Serial,
|
||||
"current_version", m.OSVersion,
|
||||
"minimum_version", minVersion,
|
||||
)
|
||||
if platform != "darwin" && !isSetMinVersion {
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings for non-macos platform, minimum version not set, skipping version check", logs...)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if platform == "darwin" {
|
||||
updateNewHosts := settings.UpdateNewHosts.Set && settings.UpdateNewHosts.Valid && settings.UpdateNewHosts.Value
|
||||
logs = append(logs, "update_new_hosts", updateNewHosts)
|
||||
switch {
|
||||
case !updateNewHosts:
|
||||
// never update macos if updateNewHosts is false
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings for macos, new hosts should not update", logs...)
|
||||
return false, nil
|
||||
case !isSetMinVersion:
|
||||
// always update macos if updateNewHosts is true and minimum version is not set
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings for macos, new hosts should always update to latest", logs...)
|
||||
return true, nil
|
||||
default:
|
||||
// default to normal version check (require update if less than minimum version)
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings for macos, new hosts should update to latest if below minimum version", logs...)
|
||||
}
|
||||
}
|
||||
|
||||
needsUpdate, err := apple_mdm.IsLessThanVersion(m.OSVersion, minVersion)
|
||||
if err != nil {
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings, cannot compare versions",
|
||||
"serial", m.Serial,
|
||||
"current_version", m.OSVersion,
|
||||
"minimum_version", minVersion,
|
||||
)
|
||||
svc.logger.InfoContext(ctx, "checking os updates settings, cannot compare versions", logs...)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5287,7 +5287,7 @@ func TestUnmarshalAppList(t *testing.T) {
|
||||
assert.ElementsMatch(t, expectedSoftware, software)
|
||||
}
|
||||
|
||||
func TestNeedsOSUpdateForDEPEnrollment(t *testing.T) {
|
||||
func TestShouldOSUpdateForDEPEnrollment(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
platform string
|
||||
@@ -5321,7 +5321,7 @@ func TestNeedsOSUpdateForDEPEnrollment(t *testing.T) {
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
name: "if platform is macOS and update_new_hosts is set",
|
||||
name: "if platform is macOS and both update_new_hosts and minimum_version are set and host is below the minimum version",
|
||||
platform: string(fleet.MacOSPlatform),
|
||||
appleMachineInfo: fleet.MDMAppleMachineInfo{
|
||||
OSVersion: "16.0.1",
|
||||
@@ -5332,6 +5332,29 @@ func TestNeedsOSUpdateForDEPEnrollment(t *testing.T) {
|
||||
},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "if platform is macOS and both update_new_hosts and minimum_version are set and host is at the minimum version",
|
||||
platform: string(fleet.MacOSPlatform),
|
||||
appleMachineInfo: fleet.MDMAppleMachineInfo{
|
||||
OSVersion: "16.0.2",
|
||||
},
|
||||
appleOSUpdateSettings: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("16.0.2"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
name: "if platform is macOS and update_new_hosts is set but minimum_version is not set",
|
||||
platform: string(fleet.MacOSPlatform),
|
||||
appleMachineInfo: fleet.MDMAppleMachineInfo{
|
||||
OSVersion: "16.0.1",
|
||||
},
|
||||
appleOSUpdateSettings: fleet.AppleOSUpdateSettings{
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "if platform is not macOS and min_version is not set",
|
||||
platform: string(fleet.IPadOSPlatform),
|
||||
@@ -5376,7 +5399,7 @@ func TestNeedsOSUpdateForDEPEnrollment(t *testing.T) {
|
||||
svc := &Service{ds: ds, logger: slog.New(slog.DiscardHandler)}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := svc.needsOSUpdateForDEPEnrollment(ctx, tt.appleMachineInfo)
|
||||
result, err := svc.shouldOSUpdateForDEPEnrollment(ctx, tt.appleMachineInfo)
|
||||
require.Equal(t, tt.expectedResult, result)
|
||||
require.Equal(t, tt.expectedErr, err)
|
||||
})
|
||||
@@ -5400,6 +5423,9 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
latestMacOSVersion := "14.6.1"
|
||||
latestMacOSBuild := "23G93"
|
||||
|
||||
latestIOSVersion := "17.6.1"
|
||||
latestIOSBuild := "21G93"
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
machineInfo *fleet.MDMAppleMachineInfo
|
||||
@@ -5485,17 +5511,62 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
// FIXME: When we have more time, this whole test is overdue for a refactor because a bunch of jank
|
||||
// came with the update new hosts settings for macOS that made the test cases more dependent on
|
||||
// subtle differences in the machine info for macOS vs non-macOS platforms and made the setup
|
||||
// more complex and harder to reason about. For now, we can get away with some nested subtests
|
||||
// to reuse the test cases for both macOS and non-macOS platforms, but ideally we would refactor
|
||||
// the function under test to separate out the platform-specific logic so that we can have
|
||||
// clearer and more focused tests for each platform without needing to have a bunch of
|
||||
// conditional logic in the test itself.
|
||||
for _, tt := range testCases {
|
||||
// Non-macOS platforms
|
||||
for _, platform := range []string{"ios", "ipados"} {
|
||||
|
||||
if tt.name == "no match for software update device ID" {
|
||||
// skip this test case for non-macOS platforms since SUDeviceID is really only relevant for macOS updates
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("%s: %s", platform, tt.name), func(t *testing.T) {
|
||||
// switch up the machine info to match the platform because test cases were
|
||||
// originally written with macOS in mind
|
||||
var product, osVersion, suDeviceID string
|
||||
var mi *fleet.MDMAppleMachineInfo
|
||||
if tt.machineInfo != nil {
|
||||
osVersion = strings.Replace(tt.machineInfo.OSVersion, "14", "17", 1)
|
||||
if platform == "ios" {
|
||||
product = "iPhone16,2"
|
||||
suDeviceID = strings.Replace(tt.machineInfo.SoftwareUpdateDeviceID, "J516sAP", "iPhone", 1)
|
||||
} else {
|
||||
product = "iPad14,11"
|
||||
suDeviceID = strings.Replace(tt.machineInfo.SoftwareUpdateDeviceID, "J516sAP", "iPad", 1)
|
||||
}
|
||||
|
||||
mi = &fleet.MDMAppleMachineInfo{
|
||||
MDMCanRequestSoftwareUpdate: tt.machineInfo.MDMCanRequestSoftwareUpdate,
|
||||
Product: product,
|
||||
OSVersion: osVersion,
|
||||
SupplementalBuildVersion: tt.machineInfo.SupplementalBuildVersion,
|
||||
SoftwareUpdateDeviceID: suDeviceID,
|
||||
}
|
||||
}
|
||||
// same for update required details
|
||||
var details *fleet.MDMAppleSoftwareUpdateRequiredDetails
|
||||
if tt.updateRequired != nil {
|
||||
details = &fleet.MDMAppleSoftwareUpdateRequiredDetails{
|
||||
OSVersion: latestIOSVersion,
|
||||
BuildVersion: latestIOSBuild,
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("settings minimum equal to latest", func(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(latestMacOSVersion),
|
||||
return platform, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(latestIOSVersion),
|
||||
}, nil
|
||||
}
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, mi)
|
||||
if tt.err != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tt.err)
|
||||
@@ -5505,7 +5576,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
if tt.updateRequired != nil {
|
||||
require.Equal(t, &fleet.MDMAppleSoftwareUpdateRequired{
|
||||
Code: fleet.MDMAppleSoftwareUpdateRequiredCode,
|
||||
Details: *tt.updateRequired,
|
||||
Details: *details,
|
||||
}, sur)
|
||||
} else {
|
||||
require.Nil(t, sur)
|
||||
@@ -5514,11 +5585,11 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
|
||||
t.Run("settings minimum below latest", func(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("14.5"),
|
||||
return platform, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.5"),
|
||||
}, nil
|
||||
}
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, mi)
|
||||
if tt.err != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tt.err)
|
||||
@@ -5528,7 +5599,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
if tt.updateRequired != nil {
|
||||
require.Equal(t, &fleet.MDMAppleSoftwareUpdateRequired{
|
||||
Code: fleet.MDMAppleSoftwareUpdateRequiredCode,
|
||||
Details: *tt.updateRequired,
|
||||
Details: *details,
|
||||
}, sur)
|
||||
} else {
|
||||
require.Nil(t, sur)
|
||||
@@ -5538,11 +5609,11 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
t.Run("settings minimum above latest", func(t *testing.T) {
|
||||
// edge case, but in practice it would get treated as if minimum was equal to latest
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("14.7"),
|
||||
return platform, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.7"),
|
||||
}, nil
|
||||
}
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, mi)
|
||||
if tt.err != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tt.err)
|
||||
@@ -5552,7 +5623,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
if tt.updateRequired != nil {
|
||||
require.Equal(t, &fleet.MDMAppleSoftwareUpdateRequired{
|
||||
Code: fleet.MDMAppleSoftwareUpdateRequiredCode,
|
||||
Details: *tt.updateRequired,
|
||||
Details: *details,
|
||||
}, sur)
|
||||
} else {
|
||||
require.Nil(t, sur)
|
||||
@@ -5561,11 +5632,11 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
|
||||
t.Run("device above settings minimum", func(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("14.1"),
|
||||
return platform, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.1"),
|
||||
}, nil
|
||||
}
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, mi)
|
||||
if tt.err != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tt.err)
|
||||
@@ -5578,27 +5649,27 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
|
||||
t.Run("minimum not set", func(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", &fleet.AppleOSUpdateSettings{}, nil
|
||||
return platform, &fleet.AppleOSUpdateSettings{}, nil
|
||||
}
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, mi)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, sur)
|
||||
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", &fleet.AppleOSUpdateSettings{
|
||||
return platform, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString(""),
|
||||
}, nil
|
||||
}
|
||||
sur, err = svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
sur, err = svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, mi)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, sur)
|
||||
})
|
||||
|
||||
t.Run("minimum not found", func(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", nil, ¬FoundError{}
|
||||
return platform, nil, ¬FoundError{}
|
||||
}
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, mi)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, sur)
|
||||
})
|
||||
@@ -5621,6 +5692,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("when UpdateNewHosts is set and minimum is not set", func(t *testing.T) {
|
||||
// test with min version not present
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "darwin", &fleet.AppleOSUpdateSettings{
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
@@ -5640,6 +5712,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
require.Nil(t, sur)
|
||||
}
|
||||
|
||||
// test again with min version explicitly set to empty string
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "darwin", &fleet.AppleOSUpdateSettings{
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
@@ -5664,6 +5737,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "darwin", nil, ¬FoundError{}
|
||||
}
|
||||
// never block enrollment when settings are not found
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, sur)
|
||||
@@ -5692,6 +5766,30 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
require.Nil(t, sur)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("when UpdateNewHosts is set and required minimum is less than latest", func(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "darwin", &fleet.AppleOSUpdateSettings{
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
MinimumVersion: optjson.SetString("14.5"),
|
||||
}, nil
|
||||
}
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
if tt.err != "" {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tt.err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
if tt.updateRequired != nil {
|
||||
require.Equal(t, &fleet.MDMAppleSoftwareUpdateRequired{
|
||||
Code: fleet.MDMAppleSoftwareUpdateRequiredCode,
|
||||
Details: *tt.updateRequired,
|
||||
}, sur)
|
||||
} else {
|
||||
require.Nil(t, sur)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5701,7 +5799,7 @@ func TestCheckMDMAppleEnrollmentWithMinimumOSVersion(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ds.GetMDMAppleOSUpdatesSettingsByHostSerialFunc = func(ctx context.Context, serial string) (string, *fleet.AppleOSUpdateSettings, error) {
|
||||
return "ios", &fleet.AppleOSUpdateSettings{MinimumVersion: optjson.SetString(latestMacOSVersion)}, nil
|
||||
return "macos", &fleet.AppleOSUpdateSettings{MinimumVersion: optjson.SetString(latestMacOSVersion), UpdateNewHosts: optjson.SetBool(true)}, nil
|
||||
}
|
||||
|
||||
sur, err := svc.CheckMDMAppleEnrollmentWithMinimumOSVersion(ctx, tt.machineInfo)
|
||||
|
||||
@@ -51,6 +51,7 @@ import (
|
||||
"github.com/fleetdm/fleet/v4/server/live_query/live_query_mock"
|
||||
"github.com/fleetdm/fleet/v4/server/mdm"
|
||||
maintained_apps "github.com/fleetdm/fleet/v4/server/mdm/maintainedapps"
|
||||
mdmtest "github.com/fleetdm/fleet/v4/server/mdm/testing_utils"
|
||||
"github.com/fleetdm/fleet/v4/server/policies"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/fleetdm/fleet/v4/server/pubsub"
|
||||
@@ -180,6 +181,9 @@ func (s *integrationEnterpriseTestSuite) clearOktaConditionalAccess() {
|
||||
func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
||||
t := s.T()
|
||||
|
||||
// Mock Apple GDMF API (required for validating OS update minimum version settings)
|
||||
mdmtest.StartNewAppleGDMFTestServer(t)
|
||||
|
||||
// create a team through the service so it initializes the agent ops
|
||||
teamName := t.Name() + "team1"
|
||||
teamNameDecomposed := teamName + "ᄀ" + "ᅡ" // Add a decomposed Unicode character
|
||||
@@ -228,16 +232,16 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
||||
"features": &features,
|
||||
"mdm": map[string]any{
|
||||
"macos_updates": map[string]any{
|
||||
"minimum_version": "10.15.0",
|
||||
"minimum_version": "14.6.1",
|
||||
"deadline": "2021-01-01",
|
||||
"update_new_hosts": true,
|
||||
},
|
||||
"ios_updates": map[string]any{
|
||||
"minimum_version": "17.5.1",
|
||||
"minimum_version": "17.6.1",
|
||||
"deadline": "2024-07-23",
|
||||
},
|
||||
"ipados_updates": map[string]any{
|
||||
"minimum_version": "18.0",
|
||||
"minimum_version": "17.6.1",
|
||||
"deadline": "2024-08-24",
|
||||
},
|
||||
},
|
||||
@@ -260,17 +264,17 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
||||
}, team.Config.Features)
|
||||
require.Equal(t, fleet.TeamMDM{
|
||||
MacOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2021-01-01"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.5.1"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-07-23"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("18.0"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-08-24"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
@@ -393,17 +397,17 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
||||
require.Equal(t, applyResp.TeamIDsByName[teamName], team.ID)
|
||||
require.Equal(t, fleet.TeamMDM{
|
||||
MacOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2021-01-01"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.5.1"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-07-23"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("18.0"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-08-24"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
@@ -434,17 +438,17 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
||||
s.DoJSON("GET", "/api/latest/fleet/teams/"+fmt.Sprint(team.ID), nil, http.StatusOK, &getTmResp)
|
||||
require.Equal(t, fleet.TeamMDM{
|
||||
MacOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2021-01-01"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.5.1"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-07-23"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("18.0"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-08-24"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
@@ -477,17 +481,17 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
||||
require.Equal(t, team.ID, listTmResp.Teams[0].ID)
|
||||
require.Equal(t, fleet.TeamMDM{
|
||||
MacOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2021-01-01"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.5.1"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-07-23"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("18.0"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-08-24"),
|
||||
UpdateNewHosts: optjson.Bool{Set: true},
|
||||
},
|
||||
@@ -2979,6 +2983,9 @@ func (s *integrationEnterpriseTestSuite) TestNoTeamFailingPolicyWebhookTrigger()
|
||||
func (s *integrationEnterpriseTestSuite) TestWindowsUpdatesTeamConfig() {
|
||||
t := s.T()
|
||||
|
||||
// Mock Apple GDMF API (required for validating OS update minimum version settings)
|
||||
mdmtest.StartNewAppleGDMFTestServer(t)
|
||||
|
||||
// Create a team
|
||||
team := &fleet.Team{
|
||||
Name: t.Name(),
|
||||
@@ -3075,12 +3082,12 @@ func (s *integrationEnterpriseTestSuite) TestWindowsUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"macos_updates": &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2021-01-01"),
|
||||
},
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2021-01-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, 6, tmResp.Team.Config.MDM.WindowsUpdates.DeadlineDays.Value)
|
||||
require.Equal(t, 2, tmResp.Team.Config.MDM.WindowsUpdates.GracePeriodDays.Value)
|
||||
@@ -3102,7 +3109,7 @@ func (s *integrationEnterpriseTestSuite) TestWindowsUpdatesTeamConfig() {
|
||||
"windows_updates": nil,
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2021-01-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, 6, tmResp.Team.Config.MDM.WindowsUpdates.DeadlineDays.Value)
|
||||
require.Equal(t, 2, tmResp.Team.Config.MDM.WindowsUpdates.GracePeriodDays.Value)
|
||||
@@ -3246,6 +3253,9 @@ func (s *integrationEnterpriseTestSuite) assertAppleOSUpdatesDeclaration(teamID
|
||||
func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
t := s.T()
|
||||
|
||||
// Mock Apple GDMF API (required for validating OS update minimum version settings)
|
||||
mdmtest.StartNewAppleGDMFTestServer(t)
|
||||
|
||||
team := &fleet.Team{
|
||||
Name: t.Name(),
|
||||
Description: "Team description",
|
||||
@@ -3263,7 +3273,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
|
||||
// modify the team's config (macOS first)
|
||||
macOSUpdates := &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2021-01-01"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
}
|
||||
@@ -3272,13 +3282,13 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
"macos_updates": macOSUpdates,
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2021-01-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, true, tmResp.Team.Config.MDM.MacOSUpdates.UpdateNewHosts.Value)
|
||||
|
||||
s.lastActivityOfTypeMatches(
|
||||
fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(),
|
||||
fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "10.15.0", "deadline": "2021-01-01"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "14.6.1", "deadline": "2021-01-01"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
|
||||
s.lastActivityOfTypeMatches(
|
||||
fleet.ActivityTypeEnabledMacosUpdateNewHosts{}.ActivityName(),
|
||||
@@ -3295,12 +3305,12 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
|
||||
// modify the team's config (now iOS and iPadOS)
|
||||
iOSUpdates := &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("11.11.11"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2022-02-02"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
}
|
||||
iPadOSUpdates := &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("12.12.12"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2023-03-03"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
}
|
||||
@@ -3311,23 +3321,23 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
"ipados_updates": iPadOSUpdates,
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2021-01-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.SetBool(true), tmResp.Team.Config.MDM.MacOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "11.11.11", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2022-02-02", tmResp.Team.Config.MDM.IOSUpdates.Deadline.Value)
|
||||
// UpdateNewHosts values are ignored for iOS
|
||||
require.Equal(t, optjson.Bool{Set: true}, tmResp.Team.Config.MDM.IOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "12.12.12", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2023-03-03", tmResp.Team.Config.MDM.IPadOSUpdates.Deadline.Value)
|
||||
// UpdateNewHosts values are ignored for iPadOS
|
||||
require.Equal(t, optjson.Bool{Set: true}, tmResp.Team.Config.MDM.IPadOSUpdates.UpdateNewHosts)
|
||||
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "10.15.0", "deadline": "2021-01-01"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "11.11.11", "deadline": "2022-02-02"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "12.12.12", "deadline": "2023-03-03"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "14.6.1", "deadline": "2021-01-01"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "17.6.1", "deadline": "2022-02-02"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "17.6.1", "deadline": "2023-03-03"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
|
||||
s.assertAppleOSUpdatesDeclaration(&team.ID, mdm.FleetMacOSUpdatesProfileName, macOSUpdates)
|
||||
s.assertAppleOSUpdatesDeclaration(&team.ID, mdm.FleetIOSUpdatesProfileName, iOSUpdates)
|
||||
@@ -3335,16 +3345,16 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
|
||||
// only update the deadlines
|
||||
macOSUpdates = &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2025-10-01"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
}
|
||||
iOSUpdates = &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("11.11.11"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-02-02"),
|
||||
}
|
||||
iPadOSUpdates = &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("12.12.12"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-03-03"),
|
||||
}
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
@@ -3354,21 +3364,21 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
"ipados_updates": iPadOSUpdates,
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2025-10-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.SetBool(true), tmResp.Team.Config.MDM.MacOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "11.11.11", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-02-02", tmResp.Team.Config.MDM.IOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, tmResp.Team.Config.MDM.IOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "12.12.12", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-03-03", tmResp.Team.Config.MDM.IPadOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, tmResp.Team.Config.MDM.IPadOSUpdates.UpdateNewHosts)
|
||||
|
||||
macOSLastActivity := s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "10.15.0", "deadline": "2025-10-01"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
iOSLastActivity := s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "11.11.11", "deadline": "2024-02-02"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
iPadOSLastActivity := s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "12.12.12", "deadline": "2024-03-03"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
macOSLastActivity := s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "14.6.1", "deadline": "2025-10-01"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
iOSLastActivity := s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "17.6.1", "deadline": "2024-02-02"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
iPadOSLastActivity := s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "fleet_id": %d, "fleet_name": %q, "minimum_version": "17.6.1", "deadline": "2024-03-03"}`, team.ID, team.Name, team.ID, team.Name), 0)
|
||||
|
||||
s.assertAppleOSUpdatesDeclaration(&team.ID, mdm.FleetMacOSUpdatesProfileName, macOSUpdates)
|
||||
s.assertAppleOSUpdatesDeclaration(&team.ID, mdm.FleetIOSUpdatesProfileName, iOSUpdates)
|
||||
@@ -3376,16 +3386,16 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
|
||||
// Unchecking the UpdateNewHosts flag should register as an activity
|
||||
macOSUpdates = &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("10.15.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2025-10-01"),
|
||||
UpdateNewHosts: optjson.SetBool(false),
|
||||
}
|
||||
iOSUpdates = &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("11.11.11"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-02-02"),
|
||||
}
|
||||
iPadOSUpdates = &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("12.12.12"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-03-03"),
|
||||
}
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
@@ -3415,11 +3425,11 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
},
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2025-10-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, "11.11.11", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-02-02", tmResp.Team.Config.MDM.IOSUpdates.Deadline.Value)
|
||||
require.Equal(t, "12.12.12", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-03-03", tmResp.Team.Config.MDM.IPadOSUpdates.Deadline.Value)
|
||||
require.Equal(t, 10, tmResp.Team.Config.MDM.WindowsUpdates.DeadlineDays.Value)
|
||||
require.Equal(t, 2, tmResp.Team.Config.MDM.WindowsUpdates.GracePeriodDays.Value)
|
||||
@@ -3442,11 +3452,11 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
"macos_updates": nil,
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2025-10-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, "11.11.11", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-02-02", tmResp.Team.Config.MDM.IOSUpdates.Deadline.Value)
|
||||
require.Equal(t, "12.12.12", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6.1", tmResp.Team.Config.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-03-03", tmResp.Team.Config.MDM.IPadOSUpdates.Deadline.Value)
|
||||
// no new activity is created
|
||||
s.lastActivityMatches("", "", lastActivity)
|
||||
@@ -3463,7 +3473,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
},
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2025-10-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
// no new activity is created
|
||||
s.lastActivityMatches("", "", lastActivity)
|
||||
@@ -3509,7 +3519,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"macos_updates": map[string]any{
|
||||
"minimum_version": "10.15.0",
|
||||
"minimum_version": "14.6.1",
|
||||
"deadline": "2021-01-01T00:00:00Z",
|
||||
},
|
||||
},
|
||||
@@ -3517,7 +3527,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"ios_updates": map[string]any{
|
||||
"minimum_version": "10.15.0",
|
||||
"minimum_version": "14.6.1",
|
||||
"deadline": "2021-01-01T00:00:00Z",
|
||||
},
|
||||
},
|
||||
@@ -3525,7 +3535,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"ipados_updates": map[string]any{
|
||||
"minimum_version": "10.15.0",
|
||||
"minimum_version": "14.6.1",
|
||||
"deadline": "2021-01-01T00:00:00Z",
|
||||
},
|
||||
},
|
||||
@@ -3535,7 +3545,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"macos_updates": map[string]any{
|
||||
"minimum_version": "10.15.0 (19A583)",
|
||||
"minimum_version": "14.6.1 (19A583)",
|
||||
"deadline": "2021-01-01T00:00:00Z",
|
||||
},
|
||||
},
|
||||
@@ -3543,7 +3553,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"ios_updates": map[string]any{
|
||||
"minimum_version": "10.15.0 (19A583)",
|
||||
"minimum_version": "14.6.1 (19A583)",
|
||||
"deadline": "2021-01-01T00:00:00Z",
|
||||
},
|
||||
},
|
||||
@@ -3551,7 +3561,7 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"ipados_updates": map[string]any{
|
||||
"minimum_version": "10.15.0 (19A583)",
|
||||
"minimum_version": "14.6.1 (19A583)",
|
||||
"deadline": "2021-01-01T00:00:00Z",
|
||||
},
|
||||
},
|
||||
@@ -3607,21 +3617,21 @@ func (s *integrationEnterpriseTestSuite) TestAppleOSUpdatesTeamConfig() {
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"macos_updates": map[string]any{
|
||||
"minimum_version": "10.15.0 (19A583)",
|
||||
"minimum_version": "14.6.1 (19A583)",
|
||||
},
|
||||
},
|
||||
}, http.StatusUnprocessableEntity, &tmResp)
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"ios_updates": map[string]any{
|
||||
"minimum_version": "10.15.0 (19A583)",
|
||||
"minimum_version": "14.6.1 (19A583)",
|
||||
},
|
||||
},
|
||||
}, http.StatusUnprocessableEntity, &tmResp)
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{
|
||||
"mdm": map[string]any{
|
||||
"ipados_updates": map[string]any{
|
||||
"minimum_version": "10.15.0 (19A583)",
|
||||
"minimum_version": "14.6.1 (19A583)",
|
||||
},
|
||||
},
|
||||
}, http.StatusUnprocessableEntity, &tmResp)
|
||||
@@ -4363,6 +4373,9 @@ func (s *integrationEnterpriseTestSuite) TestMDMWindowsUpdates() {
|
||||
func (s *integrationEnterpriseTestSuite) TestMDMAppleOSUpdates() {
|
||||
t := s.T()
|
||||
|
||||
// Mock Apple GDMF API (required for validating OS update minimum version settings)
|
||||
mdmtest.StartNewAppleGDMFTestServer(t)
|
||||
|
||||
// keep the last activity, to detect newly created ones
|
||||
var activitiesResp listActivitiesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/activities", nil, http.StatusOK, &activitiesResp, "order_key", "a.id", "order_direction", "desc")
|
||||
@@ -4489,64 +4502,64 @@ func (s *integrationEnterpriseTestSuite) TestMDMAppleOSUpdates() {
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{
|
||||
"mdm": {
|
||||
"macos_updates": {
|
||||
"minimum_version": "12.3.1",
|
||||
"minimum_version": "13.6.9",
|
||||
"deadline": "2022-01-01",
|
||||
"update_new_hosts": true
|
||||
},
|
||||
"ios_updates": {
|
||||
"minimum_version": "13.13.13",
|
||||
"minimum_version": "17.6",
|
||||
"deadline": "2023-03-03",
|
||||
"update_new_hosts": true
|
||||
},
|
||||
"ipados_updates": {
|
||||
"minimum_version": "14.14.14",
|
||||
"minimum_version": "17.6",
|
||||
"deadline": "2024-04-04",
|
||||
"update_new_hosts": true
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK, &acResp)
|
||||
require.Equal(t, "12.3.1", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "13.6.9", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2022-01-01", acResp.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.SetBool(true), acResp.MDM.MacOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "13.13.13", acResp.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6", acResp.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2023-03-03", acResp.MDM.IOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, acResp.MDM.IOSUpdates.UpdateNewHosts) // posted value is ignored for iOS
|
||||
|
||||
require.Equal(t, "14.14.14", acResp.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6", acResp.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-04-04", acResp.MDM.IPadOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, acResp.MDM.IPadOSUpdates.UpdateNewHosts) // posted value is ignored for iOS
|
||||
|
||||
// edited macos min version activity got created
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2022-01-01", "minimum_version":"12.3.1", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), `{"deadline":"2023-03-03", "minimum_version":"13.13.13", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), `{"deadline":"2024-04-04", "minimum_version":"14.14.14", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2022-01-01", "minimum_version":"13.6.9", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), `{"deadline":"2023-03-03", "minimum_version":"17.6", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), `{"deadline":"2024-04-04", "minimum_version":"17.6", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
|
||||
// Activity for 'Update New Hosts checked' got created
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEnabledMacosUpdateNewHosts{}.ActivityName(), "", 0)
|
||||
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetMacOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("12.3.1"), Deadline: optjson.SetString("2022-01-01"),
|
||||
MinimumVersion: optjson.SetString("13.6.9"), Deadline: optjson.SetString("2022-01-01"),
|
||||
})
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetIOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("13.13.13"), Deadline: optjson.SetString("2023-03-03"),
|
||||
MinimumVersion: optjson.SetString("17.6"), Deadline: optjson.SetString("2023-03-03"),
|
||||
})
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetIPadOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("14.14.14"), Deadline: optjson.SetString("2024-04-04"),
|
||||
MinimumVersion: optjson.SetString("17.6"), Deadline: optjson.SetString("2024-04-04"),
|
||||
})
|
||||
|
||||
// get the appconfig
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/config", nil, http.StatusOK, &acResp)
|
||||
require.Equal(t, "12.3.1", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "13.6.9", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2022-01-01", acResp.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.SetBool(true), acResp.MDM.MacOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "13.13.13", acResp.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6", acResp.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2023-03-03", acResp.MDM.IOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, acResp.MDM.IOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "14.14.14", acResp.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6", acResp.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-04-04", acResp.MDM.IPadOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, acResp.MDM.IOSUpdates.UpdateNewHosts)
|
||||
|
||||
@@ -4555,63 +4568,63 @@ func (s *integrationEnterpriseTestSuite) TestMDMAppleOSUpdates() {
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{
|
||||
"mdm": {
|
||||
"macos_updates": {
|
||||
"minimum_version": "12.3.1",
|
||||
"minimum_version": "13.6.9",
|
||||
"deadline": "2024-01-01",
|
||||
"update_new_hosts": false
|
||||
},
|
||||
"ios_updates": {
|
||||
"minimum_version": "13.13.13",
|
||||
"minimum_version": "17.6",
|
||||
"deadline": "2025-05-05"
|
||||
},
|
||||
"ipados_updates": {
|
||||
"minimum_version": "14.14.14",
|
||||
"minimum_version": "17.6",
|
||||
"deadline": "2026-06-06"
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK, &acResp)
|
||||
require.Equal(t, "12.3.1", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "13.6.9", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-01-01", acResp.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.SetBool(false), acResp.MDM.MacOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "13.13.13", acResp.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6", acResp.MDM.IOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2025-05-05", acResp.MDM.IOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, acResp.MDM.IOSUpdates.UpdateNewHosts)
|
||||
|
||||
require.Equal(t, "14.14.14", acResp.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "17.6", acResp.MDM.IPadOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2026-06-06", acResp.MDM.IPadOSUpdates.Deadline.Value)
|
||||
require.Equal(t, optjson.Bool{Set: true}, acResp.MDM.IPadOSUpdates.UpdateNewHosts)
|
||||
|
||||
// another edited macos min version activity got created
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeDisabledMacosUpdateNewHosts{}.ActivityName(), "", 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2024-01-01", "minimum_version":"12.3.1", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), `{"deadline":"2025-05-05", "minimum_version":"13.13.13", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
lastActivity = s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), `{"deadline":"2026-06-06", "minimum_version":"14.14.14", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2024-01-01", "minimum_version":"13.6.9", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIOSMinVersion{}.ActivityName(), `{"deadline":"2025-05-05", "minimum_version":"17.6", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
lastActivity = s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedIPadOSMinVersion{}.ActivityName(), `{"deadline":"2026-06-06", "minimum_version":"17.6", "team_id": null, "team_name": null, "fleet_id": null, "fleet_name": null}`, 0)
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetMacOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("12.3.1"), Deadline: optjson.SetString("2024-01-01"),
|
||||
MinimumVersion: optjson.SetString("13.6.9"), Deadline: optjson.SetString("2024-01-01"),
|
||||
})
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetIOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("13.13.13"), Deadline: optjson.SetString("2025-05-05"),
|
||||
MinimumVersion: optjson.SetString("17.6"), Deadline: optjson.SetString("2025-05-05"),
|
||||
})
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetIPadOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("14.14.14"), Deadline: optjson.SetString("2026-06-06"),
|
||||
MinimumVersion: optjson.SetString("17.6"), Deadline: optjson.SetString("2026-06-06"),
|
||||
})
|
||||
|
||||
// update something unrelated - the transparency url
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{"fleet_desktop":{"transparency_url": "customURL"}}`), http.StatusOK, &acResp)
|
||||
require.Equal(t, "12.3.1", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "13.6.9", acResp.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "2024-01-01", acResp.MDM.MacOSUpdates.Deadline.Value)
|
||||
|
||||
// no activity got created
|
||||
s.lastActivityMatches("", ``, lastActivity)
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetMacOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("12.3.1"), Deadline: optjson.SetString("2024-01-01"),
|
||||
MinimumVersion: optjson.SetString("13.6.9"), Deadline: optjson.SetString("2024-01-01"),
|
||||
})
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetIOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("13.13.13"), Deadline: optjson.SetString("2025-05-05"),
|
||||
MinimumVersion: optjson.SetString("17.6"), Deadline: optjson.SetString("2025-05-05"),
|
||||
})
|
||||
s.assertAppleOSUpdatesDeclaration(nil, mdm.FleetIPadOSUpdatesProfileName, &fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("14.14.14"), Deadline: optjson.SetString("2026-06-06"),
|
||||
MinimumVersion: optjson.SetString("17.6"), Deadline: optjson.SetString("2026-06-06"),
|
||||
})
|
||||
|
||||
// clear the apple OS requirements
|
||||
|
||||
@@ -579,7 +579,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
"mdm": {
|
||||
"macos_updates": {
|
||||
"deadline": "2023-12-31",
|
||||
"minimum_version": "13.3.7"
|
||||
"minimum_version": "14.6.1"
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK)
|
||||
@@ -587,7 +587,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
MDM: &fleet.TeamPayloadMDM{
|
||||
MacOSUpdates: &fleet.AppleOSUpdateSettings{
|
||||
Deadline: optjson.SetString("1992-01-01"),
|
||||
MinimumVersion: optjson.SetString("13.1.1"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
},
|
||||
},
|
||||
}, http.StatusOK)
|
||||
@@ -5275,7 +5275,7 @@ func (s *integrationMDMTestSuite) TestMDMBatchSetProfilesKeepsReservedNames() {
|
||||
},
|
||||
"macos_updates": {
|
||||
"deadline": "2023-12-31",
|
||||
"minimum_version": "13.3.7"
|
||||
"minimum_version": "14.6.1"
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK, &acResp)
|
||||
@@ -5328,7 +5328,7 @@ func (s *integrationMDMTestSuite) TestMDMBatchSetProfilesKeepsReservedNames() {
|
||||
},
|
||||
MacOSUpdates: &fleet.AppleOSUpdateSettings{
|
||||
Deadline: optjson.SetString("2023-12-31"),
|
||||
MinimumVersion: optjson.SetString("13.3.8"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
UpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
},
|
||||
@@ -5340,7 +5340,7 @@ func (s *integrationMDMTestSuite) TestMDMBatchSetProfilesKeepsReservedNames() {
|
||||
require.Equal(t, 4, tmResp.Team.Config.MDM.WindowsUpdates.DeadlineDays.Value)
|
||||
require.Equal(t, 1, tmResp.Team.Config.MDM.WindowsUpdates.GracePeriodDays.Value)
|
||||
require.Equal(t, "2023-12-31", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value)
|
||||
require.Equal(t, "13.3.8", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, "14.6.1", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value)
|
||||
require.Equal(t, true, tmResp.Team.Config.MDM.MacOSUpdates.UpdateNewHosts.Value)
|
||||
|
||||
require.NoError(t, ReconcileAppleProfiles(ctx, s.ds, s.mdmCommander, s.logger))
|
||||
@@ -8814,15 +8814,15 @@ func (s *integrationMDMTestSuite) TestSpecTeamsOSUpdatesDeployToHosts() {
|
||||
Name: teamName,
|
||||
MDM: fleet.TeamSpecMDM{
|
||||
MacOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("14.1.0"),
|
||||
MinimumVersion: optjson.SetString("14.6.1"),
|
||||
Deadline: optjson.SetString("2024-03-01"),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.1.0"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-03-01"),
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.1.0"),
|
||||
MinimumVersion: optjson.SetString("17.6.1"),
|
||||
Deadline: optjson.SetString("2024-03-01"),
|
||||
},
|
||||
WindowsUpdates: fleet.WindowsUpdates{
|
||||
@@ -8878,11 +8878,11 @@ func (s *integrationMDMTestSuite) TestSpecTeamsOSUpdatesDeployToHosts() {
|
||||
Deadline: optjson.SetString("2025-06-01"),
|
||||
},
|
||||
IOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.3.0"),
|
||||
MinimumVersion: optjson.SetString("16.7.2"),
|
||||
Deadline: optjson.SetString("2025-06-01"),
|
||||
},
|
||||
IPadOSUpdates: fleet.AppleOSUpdateSettings{
|
||||
MinimumVersion: optjson.SetString("17.3.0"),
|
||||
MinimumVersion: optjson.SetString("16.7.2"),
|
||||
Deadline: optjson.SetString("2025-06-01"),
|
||||
},
|
||||
WindowsUpdates: fleet.WindowsUpdates{
|
||||
|
||||
@@ -709,8 +709,8 @@ func (s *integrationMDMTestSuite) SetupSuite() {
|
||||
_, err = w.Write(b)
|
||||
require.NoError(s.T(), err)
|
||||
}))
|
||||
dev_mode.SetOverride("FLEET_DEV_GDMF_URL", s.appleGDMFSrv.URL, s.T())
|
||||
|
||||
s.T().Setenv("FLEET_DEV_GDMF_URL", s.appleGDMFSrv.URL)
|
||||
s.T().Setenv("TEST_FLEETDM_API_URL", fleetdmSrv.URL)
|
||||
s.T().Setenv("FLEET_DEV_STOKEN_AUTHENTICATED_APPS_URL", s.appleVPPProxySrv.URL)
|
||||
|
||||
@@ -7950,7 +7950,7 @@ func (s *integrationMDMTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
mdm:
|
||||
macos_updates:
|
||||
deadline: 2022-01-04
|
||||
minimum_version: 12.1.3
|
||||
minimum_version: 14.6.1
|
||||
`))
|
||||
|
||||
// still empty if MDM is turned off for the host
|
||||
@@ -7971,7 +7971,7 @@ func (s *integrationMDMTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
|
||||
resp = orbitGetConfigResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
|
||||
wantCfg, err := fleet.NewNudgeConfig(fleet.AppleOSUpdateSettings{Deadline: optjson.SetString("2022-01-04"), MinimumVersion: optjson.SetString("12.1.3")})
|
||||
wantCfg, err := fleet.NewNudgeConfig(fleet.AppleOSUpdateSettings{Deadline: optjson.SetString("2022-01-04"), MinimumVersion: optjson.SetString("14.6.1")})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantCfg, resp.NudgeConfig)
|
||||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 20:00:00 +0000 UTC")
|
||||
@@ -8001,7 +8001,7 @@ func (s *integrationMDMTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
MDM: &fleet.TeamPayloadMDM{
|
||||
MacOSUpdates: &fleet.AppleOSUpdateSettings{
|
||||
Deadline: optjson.SetString("1992-01-01"),
|
||||
MinimumVersion: optjson.SetString("13.1.1"),
|
||||
MinimumVersion: optjson.SetString("13.6.9"),
|
||||
},
|
||||
},
|
||||
}, http.StatusOK, &tmResp)
|
||||
@@ -8009,7 +8009,7 @@ func (s *integrationMDMTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
|
||||
resp = orbitGetConfigResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
|
||||
wantCfg, err = fleet.NewNudgeConfig(fleet.AppleOSUpdateSettings{Deadline: optjson.SetString("1992-01-01"), MinimumVersion: optjson.SetString("13.1.1")})
|
||||
wantCfg, err = fleet.NewNudgeConfig(fleet.AppleOSUpdateSettings{Deadline: optjson.SetString("1992-01-01"), MinimumVersion: optjson.SetString("13.6.9")})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantCfg, resp.NudgeConfig)
|
||||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "1992-01-01 20:00:00 +0000 UTC")
|
||||
@@ -8031,7 +8031,7 @@ func (s *integrationMDMTestSuite) TestOrbitConfigNudgeSettings() {
|
||||
|
||||
resp = orbitGetConfigResponse{}
|
||||
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h2.OrbitNodeKey)), http.StatusOK, &resp)
|
||||
wantCfg, err = fleet.NewNudgeConfig(fleet.AppleOSUpdateSettings{Deadline: optjson.SetString("2022-01-04"), MinimumVersion: optjson.SetString("12.1.3")})
|
||||
wantCfg, err = fleet.NewNudgeConfig(fleet.AppleOSUpdateSettings{Deadline: optjson.SetString("2022-01-04"), MinimumVersion: optjson.SetString("14.6.1")})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wantCfg, resp.NudgeConfig)
|
||||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 20:00:00 +0000 UTC")
|
||||
|
||||
Reference in New Issue
Block a user