diff --git a/ee/server/service/teams.go b/ee/server/service/teams.go index 56ff97fe09..861a6997d5 100644 --- a/ee/server/service/teams.go +++ b/ee/server/service/teams.go @@ -213,17 +213,23 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T } } - // Always check whether specified versions are supported by Apple (even if they weren't updated) + // Only check whether specified versions are supported by Apple if they were updated in this request. // 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. - if errs := apple_mdm.ValidateMDMSettingsAppleSupportedOSVersion(team.Config.MDM, false); len(errs) > 0 { - invalid := &fleet.InvalidArgumentError{} - for k, v := range errs { - invalid.Append(k, v.Error()) - } - return nil, invalid + m, err := apple_mdm.ValidateMDMSettingsAppleSupportedOSVersion(team.Config.MDM, false) + if err != nil { + return nil, fleet.NewInvalidArgumentError("mdm", err.Error()) + } + if v, ok := m["macos"]; ok && macOSMinVersionUpdated { + return nil, fleet.NewInvalidArgumentError("macos_updates.minimum_version", v) + } + if v, ok := m["ios"]; ok && iOSMinVersionUpdated { + return nil, fleet.NewInvalidArgumentError("ios_updates.minimum_version", v) + } + if v, ok := m["ipados"]; ok && iPadOSMinVersionUpdated { + return nil, fleet.NewInvalidArgumentError("ipados_updates.minimum_version", v) } if payload.MDM.WindowsUpdates != nil { diff --git a/server/mdm/apple/apple_mdm.go b/server/mdm/apple/apple_mdm.go index dc2704df20..091074c216 100644 --- a/server/mdm/apple/apple_mdm.go +++ b/server/mdm/apple/apple_mdm.go @@ -1609,7 +1609,7 @@ 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 { +func ValidateMDMSettingsAppleSupportedOSVersion[T fleet.MDM | fleet.TeamMDM](settings T, excludeNonPublicAssetSets bool) (map[string]string, error) { var macOSUpdates, iOSUpdates, iPadOSUpdates fleet.AppleOSUpdateSettings if m, ok := any(settings).(fleet.MDM); ok { macOSUpdates = m.MacOSUpdates @@ -1620,25 +1620,25 @@ func ValidateMDMSettingsAppleSupportedOSVersion[T fleet.MDM | fleet.TeamMDM](set iOSUpdates = t.IOSUpdates iPadOSUpdates = t.IPadOSUpdates } else { - return nil + return nil, errors.New("invalid settings type") } if macOSUpdates.MinimumVersion.Value == "" && iOSUpdates.MinimumVersion.Value == "" && iPadOSUpdates.MinimumVersion.Value == "" { - return nil + return nil, nil } am, err := gdmf.GetAssetMetadata() if err != nil { - return map[string]error{"mdm": fmt.Errorf("fetching Apple asset metadata: %w", err)} + return nil, 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")} + return nil, errors.New("Apple asset metadata is not available") } - errs := make(map[string]error, 3) + invalid := make(map[string]string, 3) if macOSUpdates.MinimumVersion.Value != "" { if ok := am.IsSupportedMacOSVersion(macOSUpdates.MinimumVersion.Value, excludeNonPublicAssetSets); !ok { - errs["mdm.macos_updates.minimum_version"] = errors.New(fleet.AppleOSVersionUnsupportedMessage) + invalid["macos"] = fleet.AppleOSVersionUnsupportedMessage } } if iOSUpdates.MinimumVersion.Value != "" { @@ -1646,16 +1646,16 @@ func ValidateMDMSettingsAppleSupportedOSVersion[T fleet.MDM | fleet.TeamMDM](set // 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) + invalid["ios"] = 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) + invalid["ipados"] = fleet.AppleOSVersionUnsupportedMessage } } - return errs + return invalid, nil } // RecoveryLockCommander defines the interface for sending recovery lock commands. diff --git a/server/mdm/apple/apple_mdm_test.go b/server/mdm/apple/apple_mdm_test.go index f4545c1f04..e6e3356388 100644 --- a/server/mdm/apple/apple_mdm_test.go +++ b/server/mdm/apple/apple_mdm_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "io" "log/slog" "net/http" @@ -323,14 +322,13 @@ func TestValidateMDMSettingsAppleSupportedOSVersion(t *testing.T) { } // 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) + checkErr := func(platform string, wantErr string, gotErrs map[string]string, msg string) { 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]) + assert.Contains(t, gotErrs, platform, msg+": expected error for platform %s but key not found in error map: %v", platform, gotErrs) + assert.Contains(t, gotErrs[platform], wantErr, msg+": expected error for platform %s but got: %v", platform, gotErrs[platform]) } } @@ -339,35 +337,59 @@ func TestValidateMDMSettingsAppleSupportedOSVersion(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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("macos", "", got, "expect public macOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("macos", "", got, "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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("macos", "", got, "expect non-public macOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported macOS version to return error when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("macos", "", got, "expect public macOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("macos", "", got, "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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("macos", "", got, "expect non-public macOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported macOS version to return error when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("macos", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported macOS version to return error when excluding non-public asset sets") }) }) @@ -375,31 +397,55 @@ func TestValidateMDMSettingsAppleSupportedOSVersion(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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("ios", "", got, "expect public iOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("ios", "", got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("ios", "", got, "expect non-public iOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported iOS version to return error when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("ios", "", got, "expect public iOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("ios", "", got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("ios", "", got, "expect non-public iOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported iOS version to return error when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("ios", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported iOS version to return error when excluding non-public asset sets") }) }) @@ -407,33 +453,80 @@ func TestValidateMDMSettingsAppleSupportedOSVersion(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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("ipados", "", got, "expect public iPadOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("ipados", "", got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("ipados", "", got, "expect non-public iPadOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.NoError(t, err) + checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported iPadOS version to return error when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(ac, true) + require.NoError(t, err) + checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err := ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("ipados", "", got, "expect public iPadOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("ipados", "", got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("ipados", "", got, "expect non-public iPadOS version to be supported when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, got, "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") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.NoError(t, err) + checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported iPadOS version to return error when including non-public asset sets") + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, true) + require.NoError(t, err) + checkErr("ipados", fleet.AppleOSVersionUnsupportedMessage, got, "expect unsupported iPadOS version to return error when excluding non-public asset sets") }) }) + + // These subtests are placed last so that the dev_mode override cleanup for the error server + // doesn't interfere with the earlier subtests that rely on the valid mock server. + t.Run("GetAssetMetadata error", func(t *testing.T) { + // Use a server that returns invalid JSON so GetAssetMetadata returns an error. + errSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte("not valid json")) + require.NoError(t, err) + })) + t.Cleanup(errSrv.Close) + dev_mode.SetOverride("FLEET_DEV_GDMF_URL", errSrv.URL, t) + + ac := mockAppConfigMDM() + got, err := ValidateMDMSettingsAppleSupportedOSVersion(ac, false) + require.Error(t, err) + assert.Nil(t, got) + + tm := mockTeamMDM() + got, err = ValidateMDMSettingsAppleSupportedOSVersion(tm, false) + require.Error(t, err) + assert.Nil(t, got) + }) } type notFoundError struct{} diff --git a/server/service/appconfig.go b/server/service/appconfig.go index 0efe19de8c..08e9638c29 100644 --- a/server/service/appconfig.go +++ b/server/service/appconfig.go @@ -1487,13 +1487,24 @@ 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) + // Only check whether specified versions are supported by Apple if they were updated in this request. // 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()) + m, err := apple_mdm.ValidateMDMSettingsAppleSupportedOSVersion(*mdm, false) + if err != nil { + invalid.Append("mdm", fmt.Sprintf("validating Apple OS versions: %v", err)) + return nil + } + if v, ok := m["macos"]; ok && updatingMacOSVersion { + invalid.Append("macos_updates.minimum_version", v) + } + if v, ok := m["ios"]; ok && updatingIOSVersion { + invalid.Append("ios_updates.minimum_version", v) + } + if v, ok := m["ipados"]; ok && updatingIPadOSVersion { + invalid.Append("ipados_updates.minimum_version", v) } if err := mdm.MacOSSetup.Validate(); err != nil {