diff --git a/ee/server/service/mdm.go b/ee/server/service/mdm.go index 7bfc463cab..9f8193f053 100644 --- a/ee/server/service/mdm.go +++ b/ee/server/service/mdm.go @@ -1056,17 +1056,37 @@ func (svc *Service) GetMDMDiskEncryptionSummary(ctx context.Context, teamID *uin } func (svc *Service) mdmAppleEditedMacOSUpdates(ctx context.Context, teamID *uint, updates fleet.MacOSUpdates) error { - // TODO: must do the equivalent, more or less, of svc.NewMDMAppleDeclaration - // (avoiding the validation that prevents the declaration type, and without - // the activity as we want to leave this Software Updates profile hidden, - // like an internal implementation detail of how Fleet manages those update - // requirements). + // TODO: is there a notion of "DDM enabled" or not, where the DDM profile + // should not be created? if updates.MinimumVersion.Value == "" { // TODO: OS updates disabled, remove the profile return nil } // TODO: OS updates enabled and modified, create or update the profile + + const macOSSoftwareUpdateType = `com.apple.configuration.softwareupdate.enforcement.specific` + ident := uuid.NewString() + // TODO(mna): is that correct payload? Identifier is a uuid? + rawDecl := []byte(fmt.Sprintf(`{ + "Identifier": %q, + "Type": %q, + "Payload": { + "TargetOSVersion": %q, + "TargetLocalDateTime ": "2024-03-01T12:00:00," + } +}`, ident, macOSSoftwareUpdateType, updates.MinimumVersion.Value)) + d := fleet.NewMDMAppleDeclaration(rawDecl, teamID, mdm.FleetMacOSUpdatesProfileName, macOSSoftwareUpdateType, ident) + // TODO(mna): create hidden label targeting macOS >= 14 + //d.Labels = validatedLabels + decl, err := svc.ds.NewMDMAppleDeclaration(ctx, d) + if err != nil { + return err + } + + if err := svc.ds.BulkSetPendingMDMHostProfiles(ctx, nil, nil, []string{decl.DeclarationUUID}, nil); err != nil { + return ctxerr.Wrap(ctx, err, "bulk set pending host declarations") + } return nil } diff --git a/server/datastore/mysql/apple_mdm.go b/server/datastore/mysql/apple_mdm.go index 8c9c3cc153..0dfc1d6a37 100644 --- a/server/datastore/mysql/apple_mdm.go +++ b/server/datastore/mysql/apple_mdm.go @@ -3379,6 +3379,8 @@ WHERE h.uuid = ? } func (ds *Datastore) batchSetMDMAppleDeclarations(ctx context.Context, tx sqlx.ExtContext, tmID *uint, incomingDeclarations []*fleet.MDMAppleDeclaration) ([]*fleet.MDMAppleDeclaration, error) { + // TODO(mna): batch-set should not delete the reserved OS updates DDM. + const insertStmt = ` INSERT INTO mdm_apple_declarations ( declaration_uuid, diff --git a/server/datastore/mysql/mdm.go b/server/datastore/mysql/mdm.go index 0ef788c464..fc915623c3 100644 --- a/server/datastore/mysql/mdm.go +++ b/server/datastore/mysql/mdm.go @@ -168,7 +168,7 @@ FROM ( WHERE team_id = ? AND name NOT IN (?) - + UNION SELECT @@ -185,6 +185,8 @@ FROM ( ) as combined_profiles ` + // TODO(mna): filter-out the reserved OS updates DDM + var globalOrTeamID uint if teamID != nil { globalOrTeamID = *teamID @@ -268,7 +270,7 @@ FROM WHERE mcpl.apple_profile_uuid IN (?) OR mcpl.windows_profile_uuid IN (?) -UNION ALL +UNION ALL SELECT apple_declaration_uuid as profile_uuid, label_name, diff --git a/server/mdm/mdm.go b/server/mdm/mdm.go index e2888fbc50..534c2333c3 100644 --- a/server/mdm/mdm.go +++ b/server/mdm/mdm.go @@ -82,24 +82,31 @@ func GuessProfileExtension(profile []byte) string { } const ( - // FleetdConfigProfileName is the value for the PayloadDisplayName used by // fleetd to read configuration values from the system. FleetdConfigProfileName = "Fleetd configuration" // FleetdFileVaultProfileName is the value for the PayloadDisplayName used // by Fleet to configure FileVault and FileVault Escrow. - FleetFileVaultProfileName = "Disk encryption" + FleetFileVaultProfileName = "Disk encryption" + + // FleetWindowsOSUpdatesProfileName is the name of the profile used by Fleet + // to configure Windows OS updates. FleetWindowsOSUpdatesProfileName = "Windows OS Updates" + + // FleetMacOSUpdatesProfileName is the name of the DDM profile used by Fleet + // to configure macOS OS updates. + FleetMacOSUpdatesProfileName = "Fleet macOS OS Updates" ) -// FleetReservedProfileNames returns a map of PayloadDisplayName strings -// that are reserved by Fleet. +// FleetReservedProfileNames returns a map of PayloadDisplayName or profile +// name strings that are reserved by Fleet. func FleetReservedProfileNames() map[string]struct{} { return map[string]struct{}{ FleetdConfigProfileName: {}, FleetFileVaultProfileName: {}, FleetWindowsOSUpdatesProfileName: {}, + FleetMacOSUpdatesProfileName: {}, } } @@ -108,3 +115,11 @@ func FleetReservedProfileNames() map[string]struct{} { func ListFleetReservedWindowsProfileNames() []string { return []string{FleetWindowsOSUpdatesProfileName} } + +// ListFleetReservedAppleDDMProfileNames returns a list of profile names that +// are reserved by Fleet for Apple DDM declarations. +func ListFleetReservedAppleDDMProfileNames() []string { + return []string{FleetMacOSUpdatesProfileName} + // TODO(mna): use this to filter-out those reserved profiles from status + // summaries/filters. +}