Update macOS settings status filter and aggregate host counts to incorporate disk encryption key status (#11182)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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{}) {
|
||||
|
||||
Reference in New Issue
Block a user