diff --git a/ee/server/service/mdm.go b/ee/server/service/mdm.go index 641b5de6e5..95de007b5f 100644 --- a/ee/server/service/mdm.go +++ b/ee/server/service/mdm.go @@ -1082,7 +1082,7 @@ func (svc *Service) mdmAppleEditedMacOSUpdates(ctx context.Context, teamID *uint "Type": %q, "Payload": { "TargetOSVersion": %q, - "TargetLocalDateTime ": "%sT12:00:00" + "TargetLocalDateTime": "%sT12:00:00" } }`, macOSSoftwareUpdateIdent, macOSSoftwareUpdateType, updates.MinimumVersion.Value, updates.Deadline.Value)) d := fleet.NewMDMAppleDeclaration(rawDecl, teamID, mdm.FleetMacOSUpdatesProfileName, macOSSoftwareUpdateType, macOSSoftwareUpdateIdent) diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index 70891e6a23..f7d9889557 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -2162,6 +2162,34 @@ func (s *integrationEnterpriseTestSuite) TestWindowsUpdatesTeamConfig() { }, http.StatusUnprocessableEntity, &tmResp) } +func (s *integrationEnterpriseTestSuite) assertMacOSUpdatesDeclaration(teamID *uint, expected *fleet.MacOSUpdates) { + t := s.T() + if teamID == nil { + teamID = ptr.Uint(0) + } + + var declUUID string + mysql.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error { + err := sqlx.GetContext(context.Background(), q, &declUUID, + `SELECT declaration_uuid FROM mdm_apple_declarations WHERE team_id = ? AND name = ?`, teamID, mdm.FleetMacOSUpdatesProfileName) + if expected == nil { + require.Error(t, err) + return nil + } + return err + }) + + if expected == nil { + // we already validated that the declaration did not exist + return + } + decl, err := s.ds.GetMDMAppleDeclaration(context.Background(), declUUID) + require.NoError(t, err) + + require.Contains(t, string(decl.RawJSON), fmt.Sprintf(`"TargetOSVersion": "%s"`, expected.MinimumVersion.Value)) + require.Contains(t, string(decl.RawJSON), fmt.Sprintf(`"TargetLocalDateTime": "%sT12:00:00"`, expected.Deadline.Value)) +} + func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesTeamConfig() { t := s.T() @@ -2176,32 +2204,41 @@ func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesTeamConfig() { require.Equal(t, team.Name, tmResp.Team.Name) team.ID = tmResp.Team.ID + // no OS updates settings at the moment + s.assertMacOSUpdatesDeclaration(&team.ID, nil) + // modify the team's config + updates := &fleet.MacOSUpdates{ + MinimumVersion: optjson.SetString("10.15.0"), + Deadline: optjson.SetString("2021-01-01"), + } s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{ "mdm": map[string]any{ - "macos_updates": &fleet.MacOSUpdates{ - MinimumVersion: optjson.SetString("10.15.0"), - Deadline: optjson.SetString("2021-01-01"), - }, + "macos_updates": updates, }, }, http.StatusOK, &tmResp) require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value) require.Equal(t, "2021-01-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value) s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "minimum_version": "10.15.0", "deadline": "2021-01-01"}`, team.ID, team.Name), 0) + s.assertMacOSUpdatesDeclaration(&team.ID, updates) + // only update the deadline + updates = &fleet.MacOSUpdates{ + MinimumVersion: optjson.SetString("10.15.0"), + Deadline: optjson.SetString("2025-10-01"), + } s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{ "mdm": map[string]any{ - "macos_updates": &fleet.MacOSUpdates{ - MinimumVersion: optjson.SetString("10.15.0"), - Deadline: optjson.SetString("2025-10-01"), - }, + "macos_updates": updates, }, }, http.StatusOK, &tmResp) require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion.Value) require.Equal(t, "2025-10-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value) lastActivity := s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "minimum_version": "10.15.0", "deadline": "2025-10-01"}`, team.ID, team.Name), 0) + s.assertMacOSUpdatesDeclaration(&team.ID, updates) + // setting the windows updates doesn't alter the macos updates tmResp = teamResponse{} s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{ @@ -2220,6 +2257,8 @@ func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesTeamConfig() { s.lastActivityOfTypeMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), "", lastActivity) lastActivity = s.lastActivityMatches(fleet.ActivityTypeEditedWindowsUpdates{}.ActivityName(), ``, 0) + s.assertMacOSUpdatesDeclaration(&team.ID, updates) + // sending a nil MDM or MacOSUpdate config doesn't modify anything s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{ "mdm": nil, @@ -2234,6 +2273,8 @@ func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesTeamConfig() { // no new activity is created s.lastActivityMatches("", "", lastActivity) + s.assertMacOSUpdatesDeclaration(&team.ID, updates) + // sending macos settings but no macos_updates does not change the macos updates s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{ "mdm": map[string]any{ @@ -2247,6 +2288,8 @@ func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesTeamConfig() { // no new activity is created s.lastActivityMatches("", "", lastActivity) + s.assertMacOSUpdatesDeclaration(&team.ID, updates) + // sending empty MacOSUpdate fields empties both fields s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), map[string]any{ "mdm": map[string]any{ @@ -2260,6 +2303,8 @@ func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesTeamConfig() { require.Empty(t, tmResp.Team.Config.MDM.MacOSUpdates.Deadline.Value) s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "minimum_version": "", "deadline": ""}`, team.ID, team.Name), 0) + s.assertMacOSUpdatesDeclaration(&team.ID, nil) + // error checks: // try to set an invalid deadline @@ -2768,6 +2813,8 @@ func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() { // edited macos min version activity got created s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2022-01-01", "minimum_version":"12.3.1", "team_id": null, "team_name": null}`, 0) + s.assertMacOSUpdatesDeclaration(nil, &fleet.MacOSUpdates{ + MinimumVersion: optjson.SetString("12.3.1"), Deadline: optjson.SetString("2022-01-01")}) // get the appconfig acResp = appConfigResponse{} @@ -2790,6 +2837,8 @@ func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() { // another edited macos min version activity got created lastActivity = s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2024-01-01", "minimum_version":"12.3.1", "team_id": null, "team_name": null}`, 0) + s.assertMacOSUpdatesDeclaration(nil, &fleet.MacOSUpdates{ + MinimumVersion: optjson.SetString("12.3.1"), Deadline: optjson.SetString("2024-01-01")}) // update something unrelated - the transparency url acResp = appConfigResponse{} @@ -2799,6 +2848,8 @@ func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() { // no activity got created s.lastActivityMatches("", ``, lastActivity) + s.assertMacOSUpdatesDeclaration(nil, &fleet.MacOSUpdates{ + MinimumVersion: optjson.SetString("12.3.1"), Deadline: optjson.SetString("2024-01-01")}) // clear the macos requirement acResp = appConfigResponse{} @@ -2815,6 +2866,7 @@ func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() { // edited macos min version activity got created with empty requirement lastActivity = s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"", "minimum_version":"", "team_id": null, "team_name": null}`, 0) + s.assertMacOSUpdatesDeclaration(nil, nil) // update again with empty macos requirement acResp = appConfigResponse{} @@ -2831,6 +2883,7 @@ func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() { // no activity got created s.lastActivityMatches("", ``, lastActivity) + s.assertMacOSUpdatesDeclaration(nil, nil) } func (s *integrationEnterpriseTestSuite) TestSSOJITProvisioning() {