Update macOS settings status filter and aggregate host counts to incorporate disk encryption key status (#11182)

This commit is contained in:
gillespi314
2023-04-19 10:03:44 -05:00
committed by GitHub
parent c43d8bdfea
commit be76e209d9
4 changed files with 421 additions and 128 deletions
@@ -0,0 +1,2 @@
* Updated macOS settings status filters and aggregate counts to more accurately reflect the status of
FileVault settings.
+114 -45
View File
@@ -1424,61 +1424,130 @@ func (ds *Datastore) UpdateOrDeleteHostMDMAppleProfile(ctx context.Context, prof
return err
}
func subqueryHostsMacOSSettingsStatusFailing() (string, []interface{}) {
sql := `
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND hmap.status = ?`
args := []interface{}{fleet.MDMAppleDeliveryFailed}
return sql, args
}
func subqueryHostsMacOSSettingsStatusPending() (string, []interface{}) {
sql := `
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND (hmap.status IS NULL
OR hmap.status = ?
OR(hmap.profile_identifier = ?
AND hmap.status = ?
AND hmap.operation_type = ?
AND NOT EXISTS (
SELECT
1 FROM host_disk_encryption_keys hdek
WHERE
h.id = hdek.host_id
AND hdek.decryptable = 1)))
AND NOT EXISTS (
SELECT
1 FROM host_mdm_apple_profiles hmap2
WHERE
h.uuid = hmap2.host_uuid
AND hmap2.status = ?)`
args := []interface{}{
fleet.MDMAppleDeliveryPending,
mobileconfig.FleetFileVaultPayloadIdentifier,
fleet.MDMAppleDeliveryApplied,
fleet.MDMAppleOperationTypeInstall,
fleet.MDMAppleDeliveryFailed,
}
return sql, args
}
func subqueryHostsMacOSSetttingsStatusLatest() (string, []interface{}) {
sql := `
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND hmap.status = ?
AND(hmap.profile_identifier != ?
OR EXISTS (
SELECT
1 FROM host_disk_encryption_keys hdek
WHERE
h.id = hdek.host_id
AND hdek.decryptable = 1))
AND NOT EXISTS (
SELECT
1 FROM host_mdm_apple_profiles hmap2
WHERE
h.uuid = hmap2.host_uuid
AND (hmap2.status IS NULL
OR hmap2.status != ?
OR(hmap2.profile_identifier = ?
AND hmap2.status = ?
AND hmap2.operation_type = ?
AND NOT EXISTS (
SELECT
1 FROM host_disk_encryption_keys hdek
WHERE
h.id = hdek.host_id
AND hdek.decryptable = 1))))`
args := []interface{}{
fleet.MDMAppleDeliveryApplied,
mobileconfig.FleetFileVaultPayloadIdentifier,
fleet.MDMAppleDeliveryApplied,
mobileconfig.FleetFileVaultPayloadIdentifier,
fleet.MDMAppleDeliveryApplied,
fleet.MDMAppleOperationTypeInstall,
}
return sql, args
}
func (ds *Datastore) GetMDMAppleHostsProfilesSummary(ctx context.Context, teamID *uint) (*fleet.MDMAppleHostsProfilesSummary, error) {
// TODO(sarah): add cases to handle Fleet-managed profiles (e.g., disk encryption)
var args []interface{}
subqueryFailed, subqueryFailedArgs := subqueryHostsMacOSSettingsStatusFailing()
args = append(args, subqueryFailedArgs...)
subqueryPending, subqueryPendingArgs := subqueryHostsMacOSSettingsStatusPending()
args = append(args, subqueryPendingArgs...)
subqueryLatest, subqueryLatestArgs := subqueryHostsMacOSSetttingsStatusLatest()
args = append(args, subqueryLatestArgs...)
sqlFmt := `
SELECT
count(
CASE WHEN EXISTS (
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND hmap.status = 'failed') THEN
1
END) AS failed,
count(
CASE WHEN EXISTS (
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND (hmap.status = 'pending' OR hmap.status IS NULL))
AND NOT EXISTS (
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND hmap.status = 'failed') THEN
1
END) AS pending,
count(
CASE WHEN EXISTS (
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND hmap.status = 'applied')
AND NOT EXISTS (
SELECT
1 FROM host_mdm_apple_profiles hmap
WHERE
h.uuid = hmap.host_uuid
AND (hmap.status IS NULL OR hmap.status != 'applied')) THEN
1
END) AS applied
COUNT(
CASE WHEN EXISTS (%s)
THEN 1
END) AS failed,
COUNT(
CASE WHEN EXISTS (%s)
THEN 1
END) AS pending,
COUNT(
CASE WHEN EXISTS (%s)
THEN 1
END) AS applied
FROM
hosts h
hosts h
WHERE
%s`
%s`
teamFilter := "h.team_id IS NULL"
if teamID != nil && *teamID > 0 {
teamFilter = fmt.Sprintf("h.team_id = %d", *teamID)
teamFilter = "h.team_id = ?"
args = append(args, *teamID)
}
stmt := fmt.Sprintf(sqlFmt, subqueryFailed, subqueryPending, subqueryLatest, teamFilter)
var res fleet.MDMAppleHostsProfilesSummary
err := sqlx.GetContext(ctx, ds.reader, &res, fmt.Sprintf(sqlFmt, teamFilter))
err := sqlx.GetContext(ctx, ds.reader, &res, stmt, args...)
if err != nil {
return nil, err
}
@@ -1540,7 +1609,7 @@ const SQLDiskEncryptionRemovingEnforcement = `h.uuid = hmap.host_uuid
func (ds *Datastore) GetMDMAppleFileVaultSummary(ctx context.Context, teamID *uint) (*fleet.MDMAppleFileVaultSummary, error) {
sqlFmt := `
SELECT
SELECT
COUNT(
CASE WHEN EXISTS (
SELECT
+296 -63
View File
@@ -43,6 +43,7 @@ func TestMDMAppleConfigProfile(t *testing.T) {
{"TestBatchSetMDMAppleProfiles", testBatchSetMDMAppleProfiles},
{"TestMDMAppleProfileManagement", testMDMAppleProfileManagement},
{"TestGetMDMAppleProfilesContents", testGetMDMAppleProfilesContents},
{"TestAggregateMacOSSettingsStatusWithFileVault", testAggregateMacOSSettingsStatusWithFileVault},
{"TestMDMAppleHostsProfilesStatus", testMDMAppleHostsProfilesStatus},
{"TestMDMAppleInsertIdPAccount", testMDMAppleInsertIdPAccount},
{"TestIgnoreMDMClientError", testIgnoreMDMClientError},
@@ -1383,6 +1384,177 @@ func upsertHostCPs(
require.NoError(t, err)
}
func testAggregateMacOSSettingsStatusWithFileVault(t *testing.T, ds *Datastore) {
ctx := context.Background()
checkListHosts := func(status fleet.MacOSSettingsStatus, teamID *uint, expected []*fleet.Host) bool {
expectedIDs := []uint{}
for _, h := range expected {
expectedIDs = append(expectedIDs, h.ID)
}
gotHosts, err := ds.ListHosts(ctx, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String("admin")}}, fleet.HostListOptions{MacOSSettingsFilter: status, TeamFilter: teamID})
gotIDs := []uint{}
for _, h := range gotHosts {
gotIDs = append(gotIDs, h.ID)
}
return assert.NoError(t, err) && assert.Len(t, gotHosts, len(expected)) && assert.ElementsMatch(t, expectedIDs, gotIDs)
}
var hosts []*fleet.Host
for i := 0; i < 10; i++ {
h := test.NewHost(t, ds, fmt.Sprintf("foo.local.%d", i), "1.1.1.1",
fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), time.Now())
hosts = append(hosts, h)
}
// create somes config profiles for no team
var noTeamCPs []*fleet.MDMAppleConfigProfile
for i := 0; i < 10; i++ {
cp, err := ds.NewMDMAppleConfigProfile(ctx, *generateCP(fmt.Sprintf("name%d", i), fmt.Sprintf("identifier%d", i), 0))
require.NoError(t, err)
noTeamCPs = append(noTeamCPs, cp)
}
// add filevault profile for no team
fvNoTeam, err := ds.NewMDMAppleConfigProfile(ctx, *generateCP("filevault", "com.fleetdm.fleet.mdm.filevault", 0))
require.NoError(t, err)
upsertHostCPs(hosts, append(noTeamCPs, fvNoTeam), fleet.MDMAppleOperationTypeInstall, nil, ctx, ds, t)
res, err := ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)), res.Pending)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.Latest)
upsertHostCPs(hosts, noTeamCPs, fleet.MDMAppleOperationTypeInstall, &fleet.MDMAppleDeliveryApplied, ctx, ds, t)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)), res.Pending) // still pending because filevault not installed
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.Latest)
upsertHostCPs(hosts, []*fleet.MDMAppleConfigProfile{fvNoTeam}, fleet.MDMAppleOperationTypeInstall, &fleet.MDMAppleDeliveryPending, ctx, ds, t)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)), res.Pending) // still pending because filevault pending
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.Latest)
upsertHostCPs(hosts, []*fleet.MDMAppleConfigProfile{fvNoTeam}, fleet.MDMAppleOperationTypeInstall, &fleet.MDMAppleDeliveryApplied, ctx, ds, t)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)), res.Pending) // still pending because no disk encryption key
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.Latest)
err = ds.SetOrUpdateHostDiskEncryptionKey(ctx, hosts[0].ID, "foo")
require.NoError(t, err)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)), res.Pending) // still pending because disk encryption key decryptable is not set
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.Latest)
err = ds.SetHostsDiskEncryptionKeyStatus(ctx, []uint{hosts[0].ID}, false, time.Now().Add(1*time.Hour))
require.NoError(t, err)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)), res.Pending) // still pending because disk encryption key decryptable is false
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.Latest)
err = ds.SetHostsDiskEncryptionKeyStatus(ctx, []uint{hosts[0].ID}, true, time.Now().Add(1*time.Hour))
require.NoError(t, err)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)-1), res.Pending)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(1), res.Latest) // hosts[0] now has filevault fully enforced
err = ds.SetOrUpdateHostDiskEncryptionKey(ctx, hosts[1].ID, "bar")
require.NoError(t, err)
err = ds.SetHostsDiskEncryptionKeyStatus(ctx, []uint{hosts[1].ID}, false, time.Now().Add(1*time.Hour))
require.NoError(t, err)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)-1), res.Pending) // hosts[1] still pending because disk encryption key decryptable is false
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(1), res.Latest)
err = ds.SetHostsDiskEncryptionKeyStatus(ctx, []uint{hosts[1].ID}, true, time.Now().Add(1*time.Hour))
require.NoError(t, err)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(len(hosts)-2), res.Pending)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(2), res.Latest) // hosts[0] and hosts[1] now have filevault fully enforced
// check that list hosts by status matches summary
require.True(t, checkListHosts(fleet.MacOSSettingsStatusPending, nil, hosts[2:]))
require.True(t, checkListHosts(fleet.MacOSSettingsStatusLatest, nil, hosts[:2]))
// create a team
team, err := ds.NewTeam(ctx, &fleet.Team{Name: "test"})
require.NoError(t, err)
// add hosts[9] to team
err = ds.AddHostsToTeam(ctx, &team.ID, []uint{hosts[9].ID})
require.NoError(t, err)
// remove profiles from hosts[9]
upsertHostCPs(hosts[9:10], append(noTeamCPs, fvNoTeam), fleet.MDMAppleOperationTypeRemove, &fleet.MDMAppleDeliveryApplied, ctx, ds, t)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, &team.ID)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(0), res.Pending)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(1), res.Latest)
// create somes config profiles for team
var teamCPs []*fleet.MDMAppleConfigProfile
for i := 0; i < 2; i++ {
cp, err := ds.NewMDMAppleConfigProfile(ctx, *generateCP(fmt.Sprintf("name%d", i), fmt.Sprintf("identifier%d", i), team.ID))
require.NoError(t, err)
teamCPs = append(teamCPs, cp)
}
// add filevault profile for team
fvTeam, err := ds.NewMDMAppleConfigProfile(ctx, *generateCP("filevault", mobileconfig.FleetFileVaultPayloadIdentifier, team.ID))
require.NoError(t, err)
upsertHostCPs(hosts[9:10], append(teamCPs, fvTeam), fleet.MDMAppleOperationTypeInstall, &fleet.MDMAppleDeliveryApplied, ctx, ds, t)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, &team.ID)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Pending) // hosts[9] is pending because it has no disk encryption key
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.Latest)
err = ds.SetOrUpdateHostDiskEncryptionKey(ctx, hosts[9].ID, "baz")
require.NoError(t, err)
err = ds.SetHostsDiskEncryptionKeyStatus(ctx, []uint{hosts[9].ID}, true, time.Now().Add(1*time.Hour))
require.NoError(t, err)
res, err = ds.GetMDMAppleHostsProfilesSummary(ctx, &team.ID)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(0), res.Pending)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(1), res.Latest) // hosts[9] now has filevault fully enforced
// check that list hosts by status matches summary
require.True(t, checkListHosts(fleet.MacOSSettingsStatusPending, &team.ID, []*fleet.Host{}))
require.True(t, checkListHosts(fleet.MacOSSettingsStatusLatest, &team.ID, hosts[9:10]))
}
func testMDMAppleHostsProfilesStatus(t *testing.T, ds *Datastore) {
ctx := context.Background()
@@ -1801,14 +1973,21 @@ func TestMDMAppleFileVaultSummary(t *testing.T) {
oneMinuteAfterThreshold := time.Now().Add(+1 * time.Minute)
createDiskEncryptionRecord(ctx, ds, t, appliedHost.ID, "key-1", true, oneMinuteAfterThreshold)
res, err := ds.GetMDMAppleFileVaultSummary(ctx, nil)
fvProfileSummary, err := ds.GetMDMAppleFileVaultSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(0), res.ActionRequired)
require.Equal(t, uint(0), res.Enforcing)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(0), fvProfileSummary.ActionRequired)
require.Equal(t, uint(0), fvProfileSummary.Enforcing)
require.Equal(t, uint(0), fvProfileSummary.Failed)
require.Equal(t, uint(0), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err := ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(0), allProfilesSummary.Pending)
require.Equal(t, uint(0), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
// action required status
requiredActionHost := hosts[1]
@@ -1821,14 +2000,21 @@ func TestMDMAppleFileVaultSummary(t *testing.T) {
err = ds.SetHostsDiskEncryptionKeyStatus(ctx, []uint{requiredActionHost.ID}, false, oneMinuteAfterThreshold)
require.NoError(t, err)
res, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
fvProfileSummary, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(1), res.ActionRequired)
require.Equal(t, uint(0), res.Enforcing)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(1), fvProfileSummary.ActionRequired)
require.Equal(t, uint(0), fvProfileSummary.Enforcing)
require.Equal(t, uint(0), fvProfileSummary.Failed)
require.Equal(t, uint(0), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), allProfilesSummary.Pending)
require.Equal(t, uint(0), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
// enforcing status
enforcingHost := hosts[2]
@@ -1841,14 +2027,21 @@ func TestMDMAppleFileVaultSummary(t *testing.T) {
&fleet.MDMAppleDeliveryPending, ctx, ds, t,
)
res, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
fvProfileSummary, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(1), res.ActionRequired)
require.Equal(t, uint(1), res.Enforcing)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(1), fvProfileSummary.ActionRequired)
require.Equal(t, uint(1), fvProfileSummary.Enforcing)
require.Equal(t, uint(0), fvProfileSummary.Failed)
require.Equal(t, uint(0), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(2), allProfilesSummary.Pending)
require.Equal(t, uint(0), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
// host profile status does not exist
upsertHostCPs(
@@ -1858,14 +2051,21 @@ func TestMDMAppleFileVaultSummary(t *testing.T) {
nil, ctx, ds, t,
)
res, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
fvProfileSummary, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(1), res.ActionRequired)
require.Equal(t, uint(1), res.Enforcing)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(1), fvProfileSummary.ActionRequired)
require.Equal(t, uint(1), fvProfileSummary.Enforcing)
require.Equal(t, uint(0), fvProfileSummary.Failed)
require.Equal(t, uint(0), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(2), allProfilesSummary.Pending)
require.Equal(t, uint(0), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
// host profile status is applied but decryptable key field does not exist
upsertHostCPs(
@@ -1877,41 +2077,61 @@ func TestMDMAppleFileVaultSummary(t *testing.T) {
err = ds.SetHostsDiskEncryptionKeyStatus(ctx, []uint{enforcingHost.ID}, false, oneMinuteAfterThreshold)
require.NoError(t, err)
res, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
fvProfileSummary, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(1), res.ActionRequired)
require.Equal(t, uint(1), res.Enforcing)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(1), fvProfileSummary.ActionRequired)
require.Equal(t, uint(1), fvProfileSummary.Enforcing)
require.Equal(t, uint(0), fvProfileSummary.Failed)
require.Equal(t, uint(0), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(2), allProfilesSummary.Pending)
require.Equal(t, uint(0), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
// failed status
failedHost := hosts[3]
upsertHostCPs([]*fleet.Host{failedHost}, []*fleet.MDMAppleConfigProfile{noTeamFVProfile}, fleet.MDMAppleOperationTypeInstall, &fleet.MDMAppleDeliveryFailed, ctx, ds, t)
res, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
fvProfileSummary, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(1), res.ActionRequired)
require.Equal(t, uint(1), res.Enforcing)
require.Equal(t, uint(1), res.Failed)
require.Equal(t, uint(0), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(1), fvProfileSummary.ActionRequired)
require.Equal(t, uint(1), fvProfileSummary.Enforcing)
require.Equal(t, uint(1), fvProfileSummary.Failed)
require.Equal(t, uint(0), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(2), allProfilesSummary.Pending)
require.Equal(t, uint(1), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
// removing enforcement status
removingEnforcementHost := hosts[4]
upsertHostCPs([]*fleet.Host{removingEnforcementHost}, []*fleet.MDMAppleConfigProfile{noTeamFVProfile}, fleet.MDMAppleOperationTypeRemove, &fleet.MDMAppleDeliveryPending, ctx, ds, t)
res, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
fvProfileSummary, err = ds.GetMDMAppleFileVaultSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(1), res.ActionRequired)
require.Equal(t, uint(1), res.Enforcing)
require.Equal(t, uint(1), res.Failed)
require.Equal(t, uint(1), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(1), fvProfileSummary.ActionRequired)
require.Equal(t, uint(1), fvProfileSummary.Enforcing)
require.Equal(t, uint(1), fvProfileSummary.Failed)
require.Equal(t, uint(1), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err = ds.GetMDMAppleHostsProfilesSummary(ctx, nil)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(3), allProfilesSummary.Pending)
require.Equal(t, uint(1), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
// teams filter tests =====
appliedTeam1Host := hosts[6]
@@ -1924,15 +2144,22 @@ func TestMDMAppleFileVaultSummary(t *testing.T) {
upsertHostCPs([]*fleet.Host{appliedTeam1Host}, []*fleet.MDMAppleConfigProfile{team1FVProfile}, fleet.MDMAppleOperationTypeInstall, &fleet.MDMAppleDeliveryApplied, ctx, ds, t)
createDiskEncryptionRecord(ctx, ds, t, appliedTeam1Host.ID, "key-2", true, oneMinuteAfterThreshold)
res, err = ds.GetMDMAppleFileVaultSummary(ctx, &tm.ID)
fvProfileSummary, err = ds.GetMDMAppleFileVaultSummary(ctx, &tm.ID)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, uint(1), res.Applied)
require.Equal(t, uint(0), res.ActionRequired)
require.Equal(t, uint(0), res.Enforcing)
require.Equal(t, uint(0), res.Failed)
require.Equal(t, uint(0), res.RemovingEnforcement)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(1), fvProfileSummary.Applied)
require.Equal(t, uint(0), fvProfileSummary.ActionRequired)
require.Equal(t, uint(0), fvProfileSummary.Enforcing)
require.Equal(t, uint(0), fvProfileSummary.Failed)
require.Equal(t, uint(0), fvProfileSummary.RemovingEnforcement)
allProfilesSummary, err = ds.GetMDMAppleHostsProfilesSummary(ctx, &tm.ID)
require.NoError(t, err)
require.NotNil(t, fvProfileSummary)
require.Equal(t, uint(0), allProfilesSummary.Pending)
require.Equal(t, uint(0), allProfilesSummary.Failed)
require.Equal(t, uint(1), allProfilesSummary.Latest)
}
func testBulkSetPendingMDMAppleHostProfiles(t *testing.T, ds *Datastore) {
@@ -2205,12 +2432,18 @@ func testBulkSetPendingMDMAppleHostProfiles(t *testing.T, ds *Datastore) {
// (meant to be called from the MDMDirector in response from MDM commands), it would delete/update
// all rows in this test since we don't have command uuids.
err = ds.BulkUpsertMDMAppleHostProfiles(ctx, []*fleet.MDMAppleBulkUpsertHostProfilePayload{
{HostUUID: enrolledHosts[0].UUID, ProfileID: globalProfiles[0].ProfileID,
Status: &fleet.MDMAppleDeliveryApplied, OperationType: fleet.MDMAppleOperationTypeRemove, Checksum: []byte("csum")},
{HostUUID: enrolledHosts[0].UUID, ProfileID: globalProfiles[1].ProfileID,
Status: &fleet.MDMAppleDeliveryApplied, OperationType: fleet.MDMAppleOperationTypeRemove, Checksum: []byte("csum")},
{HostUUID: enrolledHosts[0].UUID, ProfileID: globalProfiles[2].ProfileID,
Status: &fleet.MDMAppleDeliveryFailed, OperationType: fleet.MDMAppleOperationTypeRemove, Checksum: []byte("csum")},
{
HostUUID: enrolledHosts[0].UUID, ProfileID: globalProfiles[0].ProfileID,
Status: &fleet.MDMAppleDeliveryApplied, OperationType: fleet.MDMAppleOperationTypeRemove, Checksum: []byte("csum"),
},
{
HostUUID: enrolledHosts[0].UUID, ProfileID: globalProfiles[1].ProfileID,
Status: &fleet.MDMAppleDeliveryApplied, OperationType: fleet.MDMAppleOperationTypeRemove, Checksum: []byte("csum"),
},
{
HostUUID: enrolledHosts[0].UUID, ProfileID: globalProfiles[2].ProfileID,
Status: &fleet.MDMAppleDeliveryFailed, OperationType: fleet.MDMAppleOperationTypeRemove, Checksum: []byte("csum"),
},
})
require.NoError(t, err)
+9 -20
View File
@@ -877,38 +877,27 @@ func filterHostsByMacOSSettingsStatus(sql string, opt fleet.HostListOptions, par
}
newSQL := ""
newParams := []interface{}{}
if opt.TeamFilter == nil {
// macOS settings filter is not compatible with the "all teams" option so append the "no
// team" filter here (note that filterHostsByTeam applies the "no team" filter if TeamFilter == 0)
newSQL += ` AND h.team_id IS NULL`
}
newSQL += ` AND EXISTS (
SELECT 1
FROM host_mdm_apple_profiles hmap
WHERE hmap.host_uuid = h.uuid
AND `
var subquery string
var subqueryParams []interface{}
switch opt.MacOSSettingsFilter {
case fleet.MacOSSettingsStatusFailing:
newSQL += `hmap.status = ?)`
newParams = append(newParams, fleet.MDMAppleDeliveryFailed)
subquery, subqueryParams = subqueryHostsMacOSSettingsStatusFailing()
case fleet.MacOSSettingsStatusPending:
newSQL += `(hmap.status = ? OR hmap.status IS NULL) AND NOT EXISTS
(SELECT 1 FROM host_mdm_apple_profiles hmap2 WHERE h.uuid = hmap2.host_uuid AND hmap2.status = ?))`
newParams = append(newParams, fleet.MDMAppleDeliveryPending, fleet.MDMAppleDeliveryFailed)
subquery, subqueryParams = subqueryHostsMacOSSettingsStatusPending()
case fleet.MacOSSettingsStatusLatest:
newSQL += `hmap.status = ? AND NOT EXISTS (
SELECT 1 FROM host_mdm_apple_profiles hmap2
WHERE h.uuid = hmap2.host_uuid AND (hmap2.status IS NULL OR hmap2.status != ?) ))`
newParams = append(newParams, fleet.MDMAppleDeliveryApplied, fleet.MDMAppleDeliveryApplied)
subquery, subqueryParams = subqueryHostsMacOSSetttingsStatusLatest()
}
if subquery != "" {
newSQL += fmt.Sprintf(` AND EXISTS (%s)`, subquery)
}
return sql + newSQL, append(params, newParams...)
return sql + newSQL, append(params, subqueryParams...)
}
func filterHostsByMacOSDiskEncryptionStatus(sql string, opt fleet.HostListOptions, params []interface{}) (string, []interface{}) {