45178 cpie reconciler query updates (#46889)

**Related issue:** Resolves #45178

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.


## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually. _Note: Only windows
and Mac OS. Android required by someone with a device._


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved MDM profile applicability on Android, Windows, and Apple to
handle combined include-all, include-any, and exclude-any label rules,
yielding more accurate install/remove decisions.

* **Tests**
* Added cross-platform tests covering combined include/exclude label
scenarios to verify correct profile selection, installation, and removal
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Andrew Mellor
2026-06-05 13:36:52 -04:00
committed by GitHub
co-authored by Copilot Autofix powered by AI
parent 632089ee55
commit 244cdd5558
5 changed files with 642 additions and 49 deletions
+123 -22
View File
@@ -1052,9 +1052,8 @@ const androidApplicableProfilesQuery = `
UNION
-- label-based profiles where the host is a member of all the labels (include-all).
-- by design, "include" labels cannot match if they are broken (the host cannot be
-- a member of a deleted label).
-- include-all only (no exclude labels): host must be a member of every include label.
-- broken include labels disqualify the profile.
SELECT
macp.profile_uuid,
macp.name,
@@ -1077,6 +1076,10 @@ const androidApplicableProfilesQuery = `
ON lm.label_id = mcpl.label_id AND lm.host_id = h.id
WHERE
h.platform = 'android' AND
NOT EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE android_profile_uuid = macp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
macp.profile_uuid, macp.name, h.uuid, h.id
@@ -1085,11 +1088,8 @@ const androidApplicableProfilesQuery = `
UNION
-- label-based entities where the host is NOT a member of any of the labels (exclude-any).
-- explicitly ignore profiles with broken excluded labels so that they are never applied,
-- and ignore profiles that depend on labels created _after_ the label_updated_at timestamp
-- of the host (because we don't have results for that label yet, the host may or may not be
-- a member).
-- exclude-any only (no include labels): host must NOT be a member of any exclude label.
-- broken or not-yet-scanned dynamic exclude labels disqualify the profile.
SELECT
macp.profile_uuid,
macp.name,
@@ -1099,10 +1099,6 @@ const androidApplicableProfilesQuery = `
COUNT(*) as count_profile_labels,
COUNT(mcpl.label_id) as count_non_broken_labels,
COUNT(lm.label_id) as count_host_labels,
-- this helps avoid the case where the host is not a member of a label
-- just because it hasn't reported results for that label yet. But we
-- only need consider this for dynamic labels - manual(type=1) can be
-- considered at any time
SUM(
CASE WHEN lbl.label_membership_type <> 1 AND lbl.created_at IS NOT NULL AND h.label_updated_at >= lbl.created_at THEN 1
WHEN lbl.label_membership_type = 1 AND lbl.created_at IS NOT NULL THEN 1
@@ -1121,20 +1117,21 @@ const androidApplicableProfilesQuery = `
ON lm.label_id = mcpl.label_id AND lm.host_id = h.id
WHERE
h.platform = 'android' AND
NOT EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE android_profile_uuid = macp.profile_uuid AND exclude = 0
) AND
( %s )
GROUP BY
macp.profile_uuid, macp.name, h.uuid, h.id
HAVING
-- considers only the profiles with labels, without any broken label, with results reported after all labels were
-- created and with the host not in any label
count_profile_labels > 0 AND count_profile_labels = count_non_broken_labels AND
count_profile_labels = count_host_updated_after_labels AND count_host_labels = 0
UNION
-- label-based profiles where the host is a member of any of the labels (include-any).
-- by design, "include" labels cannot match if they are broken (the host cannot be
-- a member of a deleted label).
-- include-any only (no exclude labels): host must be a member of at least one include label.
-- broken include labels are skipped (host can't be a member of a deleted label).
SELECT
macp.profile_uuid,
macp.name,
@@ -1157,11 +1154,115 @@ const androidApplicableProfilesQuery = `
ON lm.label_id = mcpl.label_id AND lm.host_id = h.id
WHERE
h.platform = 'android' AND
NOT EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE android_profile_uuid = macp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
macp.profile_uuid, macp.name, h.uuid, h.id
HAVING
count_profile_labels > 0 AND count_host_labels >= 1
UNION
-- include-all + exclude-any: host must be in ALL include labels AND NOT in ANY exclude label.
-- broken include labels or broken/not-yet-scanned dynamic exclude labels disqualify the profile.
SELECT
macp.profile_uuid,
macp.name,
macp.checksum,
h.uuid as host_uuid,
h.id as host_id,
SUM(CASE WHEN mcpl.exclude = 0 THEN 1 ELSE 0 END) as count_profile_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND mcpl.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_non_broken_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND lm_inc.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_host_labels,
SUM(CASE WHEN mcpl.exclude = 1 AND lm_exc.label_id IS NOT NULL THEN 1
WHEN mcpl.exclude = 1 AND (lbl.label_membership_type = 0 AND lbl.created_at IS NOT NULL AND h.label_updated_at < lbl.created_at) THEN 1
WHEN mcpl.exclude = 1 AND mcpl.label_id IS NULL THEN 1
ELSE 0 END) as count_host_updated_after_labels
FROM
mdm_android_configuration_profiles macp
JOIN hosts h
ON h.team_id = macp.team_id OR (h.team_id IS NULL AND macp.team_id = 0)
JOIN android_devices ad
ON ad.host_id = h.id
JOIN mdm_configuration_profile_labels mcpl
ON mcpl.android_profile_uuid = macp.profile_uuid
LEFT OUTER JOIN labels lbl
ON lbl.id = mcpl.label_id
LEFT OUTER JOIN label_membership lm_inc
ON lm_inc.label_id = mcpl.label_id AND lm_inc.host_id = h.id AND mcpl.exclude = 0
LEFT OUTER JOIN label_membership lm_exc
ON lm_exc.label_id = mcpl.label_id AND lm_exc.host_id = h.id AND mcpl.exclude = 1
WHERE
h.platform = 'android' AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE android_profile_uuid = macp.profile_uuid AND exclude = 0 AND require_all = 1
) AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE android_profile_uuid = macp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
macp.profile_uuid, macp.name, h.uuid, h.id
HAVING
-- include gate: host in all include labels (no broken include labels)
count_profile_labels > 0 AND count_non_broken_labels = count_profile_labels AND count_host_labels = count_profile_labels AND
-- exclude gate: host not in any exclude label, no broken/unscanned exclude labels
count_host_updated_after_labels = 0
UNION
-- include-any + exclude-any: host must be in AT LEAST ONE include label AND NOT in ANY exclude label.
-- broken/not-yet-scanned dynamic exclude labels disqualify the profile.
SELECT
macp.profile_uuid,
macp.name,
macp.checksum,
h.uuid as host_uuid,
h.id as host_id,
SUM(CASE WHEN mcpl.exclude = 0 THEN 1 ELSE 0 END) as count_profile_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND mcpl.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_non_broken_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND lm_inc.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_host_labels,
SUM(CASE WHEN mcpl.exclude = 1 AND lm_exc.label_id IS NOT NULL THEN 1
WHEN mcpl.exclude = 1 AND (lbl.label_membership_type = 0 AND lbl.created_at IS NOT NULL AND h.label_updated_at < lbl.created_at) THEN 1
WHEN mcpl.exclude = 1 AND mcpl.label_id IS NULL THEN 1
ELSE 0 END) as count_host_updated_after_labels
FROM
mdm_android_configuration_profiles macp
JOIN hosts h
ON h.team_id = macp.team_id OR (h.team_id IS NULL AND macp.team_id = 0)
JOIN android_devices ad
ON ad.host_id = h.id
JOIN mdm_configuration_profile_labels mcpl
ON mcpl.android_profile_uuid = macp.profile_uuid
LEFT OUTER JOIN labels lbl
ON lbl.id = mcpl.label_id
LEFT OUTER JOIN label_membership lm_inc
ON lm_inc.label_id = mcpl.label_id AND lm_inc.host_id = h.id AND mcpl.exclude = 0
LEFT OUTER JOIN label_membership lm_exc
ON lm_exc.label_id = mcpl.label_id AND lm_exc.host_id = h.id AND mcpl.exclude = 1
WHERE
h.platform = 'android' AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE android_profile_uuid = macp.profile_uuid AND exclude = 0 AND require_all = 0
) AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE android_profile_uuid = macp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
macp.profile_uuid, macp.name, h.uuid, h.id
HAVING
-- include gate: host in at least one include label
count_host_labels >= 1 AND
-- exclude gate: host not in any exclude label, no broken/unscanned exclude labels
count_host_updated_after_labels = 0
`
// ListMDMAndroidProfilesToSend is the android platform equivalent to
@@ -1233,7 +1334,7 @@ func (ds *Datastore) ListMDMAndroidProfilesToSend(ctx context.Context) ([]*fleet
ds.host_uuid IS NULL AND
-- and it is not in pending remove status (in which case it was processed)
( hmap.operation_type != ? OR COALESCE(hmap.status, '') <> ? )
`, fmt.Sprintf(androidApplicableProfilesQuery, "TRUE", "TRUE", "TRUE", "TRUE"))
`, fmt.Sprintf(androidApplicableProfilesQuery, "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE"))
// NOTE: we explicitly don't "ignore" profiles to remove based on broken labels,
// because of how Android profiles are applied vs other platforms (ignoring
@@ -1271,9 +1372,9 @@ func (ds *Datastore) ListMDMAndroidProfilesToSend(ctx context.Context) ([]*fleet
ON hmap.host_uuid = ds.host_uuid AND hmap.profile_uuid = ds.profile_uuid
LEFT OUTER JOIN android_policy_requests apr
ON apr.request_uuid = hmap.policy_request_uuid
`, fmt.Sprintf(androidApplicableProfilesQuery, "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)"))
`, fmt.Sprintf(androidApplicableProfilesQuery, "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)"))
query, args, err := sqlx.In(listToInstallProfilesStmt, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs)
query, args, err := sqlx.In(listToInstallProfilesStmt, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs)
if err != nil {
return ctxerr.Wrap(ctx, err, "building list android host applicable profiles query")
}
@@ -1297,9 +1398,9 @@ func (ds *Datastore) ListMDMAndroidProfilesToSend(ctx context.Context) ([]*fleet
WHERE
hmap.host_uuid IN (?) AND
ds.host_uuid IS NULL
`, fmt.Sprintf(androidApplicableProfilesQuery, "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)"))
`, fmt.Sprintf(androidApplicableProfilesQuery, "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)", "h.uuid IN (?)"))
query, args, err = sqlx.In(listToRemoveProfilesStmt, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs)
query, args, err = sqlx.In(listToRemoveProfilesStmt, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs, hostUUIDs)
if err != nil {
return ctxerr.Wrap(ctx, err, "building list android host to remove profiles query")
}
+86
View File
@@ -38,6 +38,7 @@ func TestAndroid(t *testing.T) {
{"GetMDMAndroidProfilesSummary", testMDMAndroidProfilesSummary},
{"ListMDMAndroidProfilesToSend", testListMDMAndroidProfilesToSend},
{"ListMDMAndroidProfilesToSend_WithExcludeAny", testListMDMAndroidProfilesToSendWithExcludeAny},
{"ListMDMAndroidProfilesToSend_WithCombinedLabels", testListMDMAndroidProfilesToSendWithCombinedLabels},
{"GetMDMAndroidProfilesContents", testGetMDMAndroidProfilesContents},
{"BulkUpsertMDMAndroidHostProfiles", testBulkUpsertMDMAndroidHostProfiles},
{"BulkUpsertMDMAndroidHostProfiles", testBulkUpsertMDMAndroidHostProfiles2},
@@ -1752,6 +1753,91 @@ func testListMDMAndroidProfilesToSendWithExcludeAny(t *testing.T, ds *Datastore)
}, profs)
}
func testListMDMAndroidProfilesToSendWithCombinedLabels(t *testing.T, ds *Datastore) {
test.AddBuiltinLabels(t, ds)
ctx := t.Context()
host := createAndroidHost("enterprise-id-combined")
newHost, err := ds.NewAndroidHost(ctx, host, false)
require.NoError(t, err)
h := newHost.Host
// advance label_updated_at so dynamic labels are immediately evaluated
h.LabelUpdatedAt = time.Now().UTC().Add(time.Second)
h.PolicyUpdatedAt = time.Now().UTC()
err = ds.UpdateHost(ctx, h)
require.NoError(t, err)
inclAllLbl, err := ds.NewLabel(ctx, &fleet.Label{Name: "incl-all-1", LabelMembershipType: fleet.LabelMembershipTypeManual})
require.NoError(t, err)
inclAllLbl2, err := ds.NewLabel(ctx, &fleet.Label{Name: "incl-all-2", LabelMembershipType: fleet.LabelMembershipTypeManual})
require.NoError(t, err)
inclAnyLbl, err := ds.NewLabel(ctx, &fleet.Label{Name: "inclany-any-1", LabelMembershipType: fleet.LabelMembershipTypeManual})
require.NoError(t, err)
exclLbl, err := ds.NewLabel(ctx, &fleet.Label{Name: "exclude-1", LabelMembershipType: fleet.LabelMembershipTypeManual})
require.NoError(t, err)
// include-all + exclude-any profile (requires both incl-all-1 and incl-all-2)
pCombinedAll, err := ds.NewMDMAndroidConfigProfile(ctx, *androidProfileForTest("combined-incl-all", inclAllLbl, inclAllLbl2, exclLbl))
require.NoError(t, err)
// include-any + exclude-any profile
pCombinedAny, err := ds.NewMDMAndroidConfigProfile(ctx, *androidProfileForTest("combined-incl-any", inclAnyLbl, exclLbl))
require.NoError(t, err)
profChecksum := getAndroidProfileChecksum(t, ds, pCombinedAll.ProfileUUID)
// host is not a member of any label → neither profile applies
profs, toRemove, err := ds.ListMDMAndroidProfilesToSend(ctx)
require.NoError(t, err)
require.Empty(t, toRemove)
require.Empty(t, profs)
// host joins include labels but not exclude → both profiles apply
err = ds.AddLabelsToHost(ctx, h.ID, []uint{inclAllLbl.ID, inclAllLbl2.ID, inclAnyLbl.ID})
require.NoError(t, err)
profs, toRemove, err = ds.ListMDMAndroidProfilesToSend(ctx)
require.NoError(t, err)
require.Empty(t, toRemove)
require.Len(t, profs, 2)
require.ElementsMatch(t, []*fleet.MDMAndroidProfilePayload{
{ProfileUUID: pCombinedAll.ProfileUUID, HostUUID: h.UUID, ProfileName: pCombinedAll.Name, Checksum: profChecksum},
{ProfileUUID: pCombinedAny.ProfileUUID, HostUUID: h.UUID, ProfileName: pCombinedAny.Name, Checksum: profChecksum},
}, profs)
// host also joins exclude label → neither profile applies
err = ds.AddLabelsToHost(ctx, h.ID, []uint{exclLbl.ID})
require.NoError(t, err)
profs, toRemove, err = ds.ListMDMAndroidProfilesToSend(ctx)
require.NoError(t, err)
require.Empty(t, toRemove)
require.Empty(t, profs)
// host leaves exclude label → both profiles apply again
err = ds.RemoveLabelsFromHost(ctx, h.ID, []uint{exclLbl.ID})
require.NoError(t, err)
profs, toRemove, err = ds.ListMDMAndroidProfilesToSend(ctx)
require.NoError(t, err)
require.Empty(t, toRemove)
require.Len(t, profs, 2)
require.ElementsMatch(t, []*fleet.MDMAndroidProfilePayload{
{ProfileUUID: pCombinedAll.ProfileUUID, HostUUID: h.UUID, ProfileName: pCombinedAll.Name, Checksum: profChecksum},
{ProfileUUID: pCombinedAny.ProfileUUID, HostUUID: h.UUID, ProfileName: pCombinedAny.Name, Checksum: profChecksum},
}, profs)
// remove host from one include-all label → include-all profile no longer applies, include-any still does
err = ds.RemoveLabelsFromHost(ctx, h.ID, []uint{inclAllLbl2.ID})
require.NoError(t, err)
profs, toRemove, err = ds.ListMDMAndroidProfilesToSend(ctx)
require.NoError(t, err)
require.Empty(t, toRemove)
require.Len(t, profs, 1)
require.Equal(t, pCombinedAny.ProfileUUID, profs[0].ProfileUUID)
}
func testGetMDMAndroidProfilesContents(t *testing.T, ds *Datastore) {
ctx := t.Context()
p1 := androidProfileForTest("p1")
+140 -27
View File
@@ -2464,9 +2464,8 @@ const windowsMDMProfilesDesiredStateQuery = `
UNION
-- label-based profiles where the host is a member of all the labels (include-all).
-- by design, "include" labels cannot match if they are broken (the host cannot be
-- a member of a deleted label).
-- include-all only (no exclude labels): host must be a member of every include label.
-- broken include labels disqualify the profile.
SELECT
mwcp.profile_uuid,
mwcp.name,
@@ -2491,6 +2490,10 @@ const windowsMDMProfilesDesiredStateQuery = `
ON lm.label_id = mcpl.label_id AND lm.host_id = h.id
WHERE
h.platform = 'windows' AND
NOT EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE windows_profile_uuid = mwcp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
mwcp.profile_uuid, mwcp.name, h.uuid
@@ -2499,11 +2502,8 @@ const windowsMDMProfilesDesiredStateQuery = `
UNION
-- label-based entities where the host is NOT a member of any of the labels (exclude-any).
-- explicitly ignore profiles with broken excluded labels so that they are never applied,
-- and ignore profiles that depend on labels created _after_ the label_updated_at timestamp
-- of the host (because we don't have results for that label yet, the host may or may not be
-- a member).
-- exclude-any only (no include labels): host must NOT be a member of any exclude label.
-- broken or not-yet-scanned dynamic exclude labels disqualify the profile.
SELECT
mwcp.profile_uuid,
mwcp.name,
@@ -2513,10 +2513,6 @@ const windowsMDMProfilesDesiredStateQuery = `
COUNT(*) as count_profile_labels,
COUNT(mcpl.label_id) as count_non_broken_labels,
COUNT(lm.label_id) as count_host_labels,
-- this helps avoid the case where the host is not a member of a label
-- just because it hasn't reported results for that label yet. But we
-- only need consider this for dynamic labels - manual(type=1) can be
-- considered at any time
SUM(
CASE WHEN lbl.label_membership_type <> 1 AND lbl.created_at IS NOT NULL AND h.label_updated_at >= lbl.created_at THEN 1
WHEN lbl.label_membership_type = 1 AND lbl.created_at IS NOT NULL THEN 1
@@ -2537,18 +2533,20 @@ const windowsMDMProfilesDesiredStateQuery = `
ON lm.label_id = mcpl.label_id AND lm.host_id = h.id
WHERE
h.platform = 'windows' AND
NOT EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE windows_profile_uuid = mwcp.profile_uuid AND exclude = 0
) AND
( %s )
GROUP BY
mwcp.profile_uuid, mwcp.name, h.uuid
HAVING
-- considers only the profiles with labels, without any broken label, with results reported after all labels were created and with the host not in any label
count_profile_labels > 0 AND count_profile_labels = count_non_broken_labels AND count_profile_labels = count_host_updated_after_labels AND count_host_labels = 0
UNION
-- label-based profiles where the host is a member of any of the labels (include-any).
-- by design, "include" labels cannot match if they are broken (the host cannot be
-- a member of a deleted label).
-- include-any only (no exclude labels): host must be a member of at least one include label.
-- broken include labels are skipped (host can't be a member of a deleted label).
SELECT
mwcp.profile_uuid,
mwcp.name,
@@ -2573,11 +2571,120 @@ const windowsMDMProfilesDesiredStateQuery = `
ON lm.label_id = mcpl.label_id AND lm.host_id = h.id
WHERE
h.platform = 'windows' AND
NOT EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE windows_profile_uuid = mwcp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
mwcp.profile_uuid, mwcp.name, h.uuid
HAVING
count_profile_labels > 0 AND count_host_labels >= 1
UNION
-- include-all + exclude-any: host must be in ALL include labels AND NOT in ANY exclude label.
-- the include and exclude rows are counted separately via conditional aggregation.
-- broken include labels or broken/not-yet-scanned dynamic exclude labels disqualify the profile.
SELECT
mwcp.profile_uuid,
mwcp.name,
mwcp.checksum,
mwcp.secrets_updated_at,
h.uuid as host_uuid,
SUM(CASE WHEN mcpl.exclude = 0 THEN 1 ELSE 0 END) as count_profile_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND mcpl.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_non_broken_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND lm_inc.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_host_labels,
SUM(CASE WHEN mcpl.exclude = 1 AND lm_exc.label_id IS NOT NULL THEN 1
WHEN mcpl.exclude = 1 AND (lbl.label_membership_type = 0 AND lbl.created_at IS NOT NULL AND h.label_updated_at < lbl.created_at) THEN 1
WHEN mcpl.exclude = 1 AND mcpl.label_id IS NULL THEN 1
ELSE 0 END) as count_host_updated_after_labels
FROM
mdm_windows_configuration_profiles mwcp
JOIN hosts h
ON h.team_id = mwcp.team_id OR (h.team_id IS NULL AND mwcp.team_id = 0)
JOIN mdm_windows_enrollments mwe
ON mwe.host_uuid = h.uuid
JOIN host_mdm hmdm
ON hmdm.host_id = h.id AND hmdm.enrolled = 1
JOIN mdm_configuration_profile_labels mcpl
ON mcpl.windows_profile_uuid = mwcp.profile_uuid
LEFT OUTER JOIN labels lbl
ON lbl.id = mcpl.label_id
LEFT OUTER JOIN label_membership lm_inc
ON lm_inc.label_id = mcpl.label_id AND lm_inc.host_id = h.id AND mcpl.exclude = 0
LEFT OUTER JOIN label_membership lm_exc
ON lm_exc.label_id = mcpl.label_id AND lm_exc.host_id = h.id AND mcpl.exclude = 1
WHERE
h.platform = 'windows' AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE windows_profile_uuid = mwcp.profile_uuid AND exclude = 0 AND require_all = 1
) AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE windows_profile_uuid = mwcp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
mwcp.profile_uuid, mwcp.name, h.uuid
HAVING
-- include gate: host in all include labels (no broken include labels)
count_profile_labels > 0 AND count_non_broken_labels = count_profile_labels AND count_host_labels = count_profile_labels AND
-- exclude gate: host not in any exclude label, no broken/unscanned exclude labels (reusing count_host_updated_after_labels)
count_host_updated_after_labels = 0
UNION
-- include-any + exclude-any: host must be in AT LEAST ONE include label AND NOT in ANY exclude label.
-- broken/not-yet-scanned dynamic exclude labels disqualify the profile.
SELECT
mwcp.profile_uuid,
mwcp.name,
mwcp.checksum,
mwcp.secrets_updated_at,
h.uuid as host_uuid,
SUM(CASE WHEN mcpl.exclude = 0 THEN 1 ELSE 0 END) as count_profile_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND mcpl.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_non_broken_labels,
SUM(CASE WHEN mcpl.exclude = 0 AND lm_inc.label_id IS NOT NULL THEN 1 ELSE 0 END) as count_host_labels,
SUM(CASE WHEN mcpl.exclude = 1 AND lm_exc.label_id IS NOT NULL THEN 1
WHEN mcpl.exclude = 1 AND (lbl.label_membership_type = 0 AND lbl.created_at IS NOT NULL AND h.label_updated_at < lbl.created_at) THEN 1
WHEN mcpl.exclude = 1 AND mcpl.label_id IS NULL THEN 1
ELSE 0 END) as count_host_updated_after_labels
FROM
mdm_windows_configuration_profiles mwcp
JOIN hosts h
ON h.team_id = mwcp.team_id OR (h.team_id IS NULL AND mwcp.team_id = 0)
JOIN mdm_windows_enrollments mwe
ON mwe.host_uuid = h.uuid
JOIN host_mdm hmdm
ON hmdm.host_id = h.id AND hmdm.enrolled = 1
JOIN mdm_configuration_profile_labels mcpl
ON mcpl.windows_profile_uuid = mwcp.profile_uuid
LEFT OUTER JOIN labels lbl
ON lbl.id = mcpl.label_id
LEFT OUTER JOIN label_membership lm_inc
ON lm_inc.label_id = mcpl.label_id AND lm_inc.host_id = h.id AND mcpl.exclude = 0
LEFT OUTER JOIN label_membership lm_exc
ON lm_exc.label_id = mcpl.label_id AND lm_exc.host_id = h.id AND mcpl.exclude = 1
WHERE
h.platform = 'windows' AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE windows_profile_uuid = mwcp.profile_uuid AND exclude = 0 AND require_all = 0
) AND
EXISTS (
SELECT 1 FROM mdm_configuration_profile_labels
WHERE windows_profile_uuid = mwcp.profile_uuid AND exclude = 1
) AND
( %s )
GROUP BY
mwcp.profile_uuid, mwcp.name, h.uuid
HAVING
-- include gate: host in at least one include label
count_host_labels >= 1 AND
-- exclude gate: host not in any exclude label, no broken/unscanned exclude labels
count_host_updated_after_labels = 0
`
func (ds *Datastore) ListMDMWindowsProfilesToInstall(ctx context.Context) ([]*fleet.MDMWindowsProfilePayload, error) {
@@ -2640,7 +2747,7 @@ const windowsProfilesToInstallQuery = `
func (ds *Datastore) listAllMDMWindowsProfilesToInstallDB(ctx context.Context, tx sqlx.ExtContext) ([]*fleet.MDMWindowsProfilePayload, error) {
var profiles []*fleet.MDMWindowsProfilePayload
err := sqlx.SelectContext(ctx, tx, &profiles, fmt.Sprintf(windowsProfilesToInstallQuery, "TRUE", "TRUE", "TRUE", "TRUE"), fleet.MDMOperationTypeInstall, fleet.MDMOperationTypeRemove)
err := sqlx.SelectContext(ctx, tx, &profiles, fmt.Sprintf(windowsProfilesToInstallQuery, "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE"), fleet.MDMOperationTypeInstall, fleet.MDMOperationTypeRemove)
if err != nil {
return nil, ctxerr.Wrapf(ctx, err, "selecting windows MDM profiles to install")
}
@@ -2663,7 +2770,7 @@ func (ds *Datastore) listMDMWindowsProfilesToInstallDB(
hostFilter = "mwcp.profile_uuid IN (?) AND h.uuid IN (?)"
}
toInstallQuery := fmt.Sprintf(windowsProfilesToInstallQuery, hostFilter, hostFilter, hostFilter, hostFilter)
toInstallQuery := fmt.Sprintf(windowsProfilesToInstallQuery, hostFilter, hostFilter, hostFilter, hostFilter, hostFilter, hostFilter)
// use a 10k host batch size to match what we do on the macOS side.
selectProfilesBatchSize := 10_000
@@ -2687,10 +2794,12 @@ func (ds *Datastore) listMDMWindowsProfilesToInstallDB(
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
fleet.MDMOperationTypeInstall, fleet.MDMOperationTypeRemove,
)
} else {
stmt, args, err = sqlx.In(toInstallQuery, batchUUIDs, batchUUIDs, batchUUIDs, batchUUIDs, fleet.MDMOperationTypeInstall, fleet.MDMOperationTypeRemove)
stmt, args, err = sqlx.In(toInstallQuery, batchUUIDs, batchUUIDs, batchUUIDs, batchUUIDs, batchUUIDs, batchUUIDs, fleet.MDMOperationTypeInstall, fleet.MDMOperationTypeRemove)
}
if err != nil {
return nil, ctxerr.Wrapf(ctx, err, "building sqlx.In for list MDM windows profiles to install, batch %d of %d", i, selectProfilesTotalBatches)
@@ -2758,8 +2867,8 @@ func (ds *Datastore) ListNextPendingMDMWindowsHostUUIDs(ctx context.Context, aft
// UNION arms so the optimizer filters early. The remove query also
// gets the cursor in its 5th slot (outer WHERE on hmwp.host_uuid)
// for a clean PK range scan on host_mdm_windows_profiles.
toInstall := fmt.Sprintf(windowsProfilesToInstallQuery, "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?")
toRemove := fmt.Sprintf(windowsProfilesToRemoveQuery, "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "hmwp.host_uuid > ?")
toInstall := fmt.Sprintf(windowsProfilesToInstallQuery, "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?")
toRemove := fmt.Sprintf(windowsProfilesToRemoveQuery, "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "h.uuid > ?", "hmwp.host_uuid > ?")
stmt := fmt.Sprintf(`
SELECT host_uuid FROM (
@@ -2772,13 +2881,13 @@ func (ds *Datastore) ListNextPendingMDMWindowsHostUUIDs(ctx context.Context, aft
`, toInstall, toRemove, batchSize)
// Placeholder order in stmt:
// install branches: 4 cursor (h.uuid > ?), 2 op-type (install, remove)
// remove branches: 4 cursor (h.uuid > ?) for desired-state arms, 1 cursor (hmwp.host_uuid > ?) for outer WHERE
// install branches: 6 cursor (h.uuid > ?), 2 op-type (install, remove)
// remove branches: 6 cursor (h.uuid > ?) for desired-state arms, 1 cursor (hmwp.host_uuid > ?) for outer WHERE
var hostUUIDs []string
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &hostUUIDs, stmt,
afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID,
afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID,
fleet.MDMOperationTypeInstall, fleet.MDMOperationTypeRemove,
afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID,
afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID, afterHostUUID,
afterHostUUID,
); err != nil {
return nil, ctxerr.Wrap(ctx, err, "listing next pending MDM windows host UUIDs")
@@ -2863,7 +2972,7 @@ const windowsProfilesToRemoveQuery = `
`
func (ds *Datastore) listAllMDMWindowsProfilesToRemoveDB(ctx context.Context, tx sqlx.ExtContext) (profiles []*fleet.MDMWindowsProfilePayload, err error) {
err = sqlx.SelectContext(ctx, tx, &profiles, fmt.Sprintf(windowsProfilesToRemoveQuery, "TRUE", "TRUE", "TRUE", "TRUE", "TRUE"))
err = sqlx.SelectContext(ctx, tx, &profiles, fmt.Sprintf(windowsProfilesToRemoveQuery, "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE"))
if err != nil {
return nil, ctxerr.Wrapf(ctx, err, "selecting windows MDM profiles to remove")
}
@@ -2889,7 +2998,7 @@ func (ds *Datastore) listMDMWindowsProfilesToRemoveDB(
}
toRemoveQuery := fmt.Sprintf(windowsProfilesToRemoveQuery,
desiredStateFilter, desiredStateFilter, desiredStateFilter, desiredStateFilter,
desiredStateFilter, desiredStateFilter, desiredStateFilter, desiredStateFilter, desiredStateFilter, desiredStateFilter,
outerFilter,
)
@@ -2916,6 +3025,8 @@ func (ds *Datastore) listMDMWindowsProfilesToRemoveDB(
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
onlyProfileUUIDs, batchUUIDs,
)
} else {
stmt, args, err = sqlx.In(toRemoveQuery,
@@ -2924,6 +3035,8 @@ func (ds *Datastore) listMDMWindowsProfilesToRemoveDB(
batchUUIDs,
batchUUIDs,
batchUUIDs,
batchUUIDs,
batchUUIDs,
)
}
if err != nil {
@@ -56,6 +56,7 @@ func TestMDMWindows(t *testing.T) {
{"TestBatchSetMDMWindowsProfiles", testBatchSetMDMWindowsProfiles},
{"TestMDMWindowsProfileLabels", testMDMWindowsProfileLabels},
{"NewMDMWindowsConfigProfileSoftwareUpdateTracking", testNewMDMWindowsConfigProfileSoftwareUpdateTracking},
{"TestMDMWindowsProfileLabelsCombined", testMDMWindowsProfileLabelsCombined},
{"TestMDMWindowsSaveResponse", testSaveResponse},
{"TestSetMDMWindowsProfilesWithVariables", testSetMDMWindowsProfilesWithVariables},
{"TestWindowsMDMManagedSCEPCertificates", testWindowsMDMManagedSCEPCertificates},
@@ -3550,6 +3551,114 @@ func testMDMWindowsProfileLabels(t *testing.T, ds *Datastore) {
}, profilesToInstall)
}
func testMDMWindowsProfileLabelsCombined(t *testing.T, ds *Datastore) {
ctx := context.Background()
// Use a dedicated team to isolate from other tests in the same suite.
tm, err := ds.NewTeam(ctx, &fleet.Team{Name: "combined-label-test-team"})
require.NoError(t, err)
u := uuid.New().String()
host, err := ds.NewHost(ctx, &fleet.Host{
DetailUpdatedAt: time.Now(),
LabelUpdatedAt: time.Now().Add(-5 * time.Second),
PolicyUpdatedAt: time.Now(),
SeenTime: time.Now(),
NodeKey: &u,
UUID: u,
Hostname: u,
Platform: "windows",
TeamID: &tm.ID,
})
require.NoError(t, err)
windowsEnroll(t, ds, host)
incLabel, err := ds.NewLabel(ctx, &fleet.Label{Name: "include-any-combined", Query: "select 1;"})
require.NoError(t, err)
excLabel, err := ds.NewLabel(ctx, &fleet.Label{
Name: "exclude-combined",
LabelMembershipType: fleet.LabelMembershipTypeManual,
})
require.NoError(t, err)
incAllLabel1, err := ds.NewLabel(ctx, &fleet.Label{Name: "include-all-combined-1", Query: "select 1;"})
require.NoError(t, err)
incAllLabel2, err := ds.NewLabel(ctx, &fleet.Label{Name: "include-all-combined-2", Query: "select 1;"})
require.NoError(t, err)
// Profile: include-any + exclude-any (scoped to the test team)
profAnyExcl := windowsConfigProfileForTest(t, "prof-include-any-exclude", "./combined/any", incLabel, excLabel)
profAnyExcl.TeamID = &tm.ID
inclAnyExclProf, err := ds.NewMDMWindowsConfigProfile(ctx, *profAnyExcl, nil)
require.NoError(t, err)
sumAny := md5.Sum(inclAnyExclProf.SyncML) //nolint:gosec
checksumAnyExcl := append([]byte{}, sumAny[:]...)
// Profile: include-all + exclude-any (scoped to the test team)
profAllExcl := windowsConfigProfileForTest(t, "prof-include-all-exclude", "./combined/all", incAllLabel1, incAllLabel2, excLabel)
profAllExcl.TeamID = &tm.ID
inclAllExclProf, err := ds.NewMDMWindowsConfigProfile(ctx, *profAllExcl, nil)
require.NoError(t, err)
sumAll := md5.Sum(inclAllExclProf.SyncML) //nolint:gosec
checksumAllExcl := append([]byte{}, sumAll[:]...)
// Host in include label, not in exclude -> both profiles should apply
err = ds.AsyncBatchInsertLabelMembership(ctx, [][2]uint{
{incLabel.ID, host.ID},
{incAllLabel1.ID, host.ID},
{incAllLabel2.ID, host.ID},
})
require.NoError(t, err)
// Update label_updated_at so dynamic labels are considered
host.LabelUpdatedAt = time.Now().Add(1 * time.Second)
err = ds.UpdateHost(ctx, host)
require.NoError(t, err)
profilesToInstall, err := ds.ListMDMWindowsProfilesToInstall(ctx)
require.NoError(t, err)
require.ElementsMatch(t, []*fleet.MDMWindowsProfilePayload{
{ProfileUUID: inclAnyExclProf.ProfileUUID, ProfileName: inclAnyExclProf.Name, HostUUID: host.UUID, Checksum: checksumAnyExcl},
{ProfileUUID: inclAllExclProf.ProfileUUID, ProfileName: inclAllExclProf.Name, HostUUID: host.UUID, Checksum: checksumAllExcl},
}, profilesToInstall)
// Add host to exclude label -> neither profile should apply
err = ds.AsyncBatchInsertLabelMembership(ctx, [][2]uint{{excLabel.ID, host.ID}})
require.NoError(t, err)
profilesToInstall, err = ds.ListMDMWindowsProfilesToInstall(ctx)
require.NoError(t, err)
require.Empty(t, profilesToInstall)
// Remove host from exclude label -> both profiles should apply again
err = ds.AsyncBatchDeleteLabelMembership(ctx, [][2]uint{{excLabel.ID, host.ID}})
require.NoError(t, err)
profilesToInstall, err = ds.ListMDMWindowsProfilesToInstall(ctx)
require.NoError(t, err)
require.ElementsMatch(t, []*fleet.MDMWindowsProfilePayload{
{ProfileUUID: inclAnyExclProf.ProfileUUID, ProfileName: inclAnyExclProf.Name, HostUUID: host.UUID, Checksum: checksumAnyExcl},
{ProfileUUID: inclAllExclProf.ProfileUUID, ProfileName: inclAllExclProf.Name, HostUUID: host.UUID, Checksum: checksumAllExcl},
}, profilesToInstall)
// Remove host from one include-all label -> include-all profile should no longer apply
err = ds.AsyncBatchDeleteLabelMembership(ctx, [][2]uint{{incAllLabel1.ID, host.ID}})
require.NoError(t, err)
profilesToInstall, err = ds.ListMDMWindowsProfilesToInstall(ctx)
require.NoError(t, err)
require.ElementsMatch(t, []*fleet.MDMWindowsProfilePayload{
{ProfileUUID: inclAnyExclProf.ProfileUUID, ProfileName: inclAnyExclProf.Name, HostUUID: host.UUID, Checksum: checksumAnyExcl},
}, profilesToInstall)
// Remove host from include-any label -> include-any profile should no longer apply either
err = ds.AsyncBatchDeleteLabelMembership(ctx, [][2]uint{{incLabel.ID, host.ID}})
require.NoError(t, err)
profilesToInstall, err = ds.ListMDMWindowsProfilesToInstall(ctx)
require.NoError(t, err)
require.Empty(t, profilesToInstall)
}
func expectWindowsProfiles(
t *testing.T,
ds *Datastore,
+184
View File
@@ -220,6 +220,107 @@ func TestEntityAppliesToHost_DeclarationsShareSameDispatcher(t *testing.T) {
}
}
// TestEntityAppliesToHost_CombinedIncludeExclude covers the combined
// include+exclude targeting cases for both include modes.
func TestEntityAppliesToHost_CombinedIncludeExclude(t *testing.T) {
host := &fleet.AppleHostReconcileInfo{
HostID: 1, UUID: "h1", TeamID: nil, Platform: "darwin",
LabelUpdatedAt: time.Date(2026, 5, 1, 0, 0, 0, 0, time.UTC),
}
excLabel := fleet.AppleProfileLabelRef{
LabelID: new(uint(9)),
CreatedAt: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC),
}
t.Run("include_any + exclude_any", func(t *testing.T) {
p := &fleet.AppleProfileForReconcile{
TeamID: 0,
IncludeMode: fleet.AppleProfileIncludeAny,
IncludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(1))}, {LabelID: new(uint(2))}},
ExcludeLabels: []fleet.AppleProfileLabelRef{excLabel},
}
// in include label, not in exclude -> applies
require.True(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}}))
// in include label, also in exclude -> does not apply
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}, 9: {}}))
// not in any include label -> does not apply
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{9: {}}))
// not in any label -> does not apply
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{}))
})
t.Run("include_all + exclude_any", func(t *testing.T) {
p := &fleet.AppleProfileForReconcile{
TeamID: 0,
IncludeMode: fleet.AppleProfileIncludeAll,
IncludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(1))}, {LabelID: new(uint(2))}},
ExcludeLabels: []fleet.AppleProfileLabelRef{excLabel},
}
// in all include labels, not in exclude -> applies
require.True(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}, 2: {}}))
// in all include labels, also in exclude -> does not apply
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}, 2: {}, 9: {}}))
// missing one include label -> does not apply
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}}))
})
t.Run("no include mode + exclude_any (pure exclude)", func(t *testing.T) {
p := &fleet.AppleProfileForReconcile{
TeamID: 0,
IncludeMode: fleet.AppleProfileIncludeNone,
ExcludeLabels: []fleet.AppleProfileLabelRef{excLabel},
}
// not in exclude label -> applies
require.True(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}}))
// in exclude label -> does not apply
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{9: {}}))
})
t.Run("dynamic exclude label created after host.LabelUpdatedAt disqualifies until host rescans", func(t *testing.T) {
// host.LabelUpdatedAt is 2026-05-01; dynamic exclude label created after that
dynamicExcLabel := fleet.AppleProfileLabelRef{
LabelID: new(uint(99)),
LabelMembershipType: int(fleet.LabelMembershipTypeDynamic),
CreatedAt: time.Date(2026, 5, 2, 0, 0, 0, 0, time.UTC),
}
p := &fleet.AppleProfileForReconcile{
TeamID: 0,
IncludeMode: fleet.AppleProfileIncludeAny,
IncludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(1))}},
ExcludeLabels: []fleet.AppleProfileLabelRef{dynamicExcLabel},
}
// host is in include label and NOT a member of the exclude label, but the
// dynamic exclude label was created after label_updated_at -> disqualified
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}}))
// once host.LabelUpdatedAt advances past the label's CreatedAt, the timing
// gate clears and the profile applies (host is not a member of the exclude label)
advancedHost := &fleet.AppleHostReconcileInfo{
HostID: 1, UUID: "h1", TeamID: nil, Platform: "darwin",
LabelUpdatedAt: time.Date(2026, 5, 3, 0, 0, 0, 0, time.UTC),
}
require.True(t, EntityAppliesToHost(p, advancedHost, map[uint]struct{}{1: {}}))
})
}
// TestEntityAppliesToHost_PureExcludeNoInclude confirms that a profile with
// only exclude labels (no include mode) applies to all hosts that are NOT
// members of any exclude label.
func TestEntityAppliesToHost_PureExcludeNoInclude(t *testing.T) {
host := &fleet.AppleHostReconcileInfo{
HostID: 1, UUID: "h1", TeamID: nil, Platform: "darwin",
LabelUpdatedAt: time.Date(2026, 5, 1, 0, 0, 0, 0, time.UTC),
}
p := &fleet.AppleProfileForReconcile{
TeamID: 0,
IncludeMode: fleet.AppleProfileIncludeNone,
ExcludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(5)), CreatedAt: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)}},
}
require.True(t, EntityAppliesToHost(p, host, map[uint]struct{}{}))
require.True(t, EntityAppliesToHost(p, host, map[uint]struct{}{1: {}}))
require.False(t, EntityAppliesToHost(p, host, map[uint]struct{}{5: {}}))
}
func TestComputeReconcileDeltas(t *testing.T) {
hostA := &fleet.AppleHostReconcileInfo{
HostID: 1, UUID: "uuid-A", TeamID: nil, Platform: "darwin",
@@ -300,6 +401,89 @@ func TestComputeReconcileDeltas(t *testing.T) {
require.Equal(t, "aDeletedProfile", toRemove[0].ProfileUUID)
})
t.Run("combined include_all + exclude_any: host in include but also in exclude -> not desired", func(t *testing.T) {
pCombined := &fleet.AppleProfileForReconcile{
ProfileUUID: "aCombined",
ProfileIdentifier: "com.example.combined",
ProfileName: "Combined",
TeamID: 0,
Checksum: []byte("cccc"),
IncludeMode: fleet.AppleProfileIncludeAll,
IncludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(10))}},
ExcludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(20)), CreatedAt: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)}},
}
profByTeam := map[uint][]*fleet.AppleProfileForReconcile{0: {pGlobal, pCombined}}
// Host in include label but also in exclude label -> combined profile not desired
hostLabels := map[uint]map[uint]struct{}{
hostA.HostID: {10: {}, 20: {}},
}
toInstall, toRemove := ComputeReconcileDeltas(
[]*fleet.AppleHostReconcileInfo{hostA}, hostLabels, nil, profByTeam, profilesWithBrokenLabel,
)
require.Empty(t, toRemove)
require.Len(t, toInstall, 1)
require.Equal(t, "aProfileGlobal", toInstall[0].ProfileUUID)
})
t.Run("combined include_all + exclude_any: host in include not in exclude -> desired", func(t *testing.T) {
pCombined := &fleet.AppleProfileForReconcile{
ProfileUUID: "aCombined",
ProfileIdentifier: "com.example.combined",
ProfileName: "Combined",
TeamID: 0,
Checksum: []byte("cccc"),
IncludeMode: fleet.AppleProfileIncludeAll,
IncludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(10))}},
ExcludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(20)), CreatedAt: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)}},
}
profByTeam := map[uint][]*fleet.AppleProfileForReconcile{0: {pGlobal, pCombined}}
// Host in include label, not in exclude -> both profiles desired
hostLabels := map[uint]map[uint]struct{}{
hostA.HostID: {10: {}},
}
toInstall, toRemove := ComputeReconcileDeltas(
[]*fleet.AppleHostReconcileInfo{hostA}, hostLabels, nil, profByTeam, profilesWithBrokenLabel,
)
require.Empty(t, toRemove)
require.Len(t, toInstall, 2)
})
t.Run("combined include_any + exclude_any: host in include but also in exclude -> not desired, removed if present", func(t *testing.T) {
pCombined := &fleet.AppleProfileForReconcile{
ProfileUUID: "aCombined",
ProfileIdentifier: "com.example.combined",
ProfileName: "Combined",
TeamID: 0,
Checksum: []byte("cccc"),
IncludeMode: fleet.AppleProfileIncludeAny,
IncludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(10))}, {LabelID: new(uint(11))}},
ExcludeLabels: []fleet.AppleProfileLabelRef{{LabelID: new(uint(20)), CreatedAt: time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)}},
}
profByTeam := map[uint][]*fleet.AppleProfileForReconcile{0: {pGlobal, pCombined}}
// Host in one include label AND in exclude label -> combined profile no longer desired, should be removed
hostLabels := map[uint]map[uint]struct{}{
hostA.HostID: {10: {}, 20: {}},
}
current := map[string][]*fleet.MDMAppleProfilePayload{
"uuid-A": {{
ProfileUUID: "aCombined",
HostUUID: "uuid-A",
Checksum: []byte("cccc"),
OperationType: fleet.MDMOperationTypeInstall,
Status: new(fleet.MDMDeliveryVerified),
}},
}
toInstall, toRemove := ComputeReconcileDeltas(
[]*fleet.AppleHostReconcileInfo{hostA}, hostLabels, current, profByTeam, profilesWithBrokenLabel,
)
require.Len(t, toInstall, 1) // pGlobal
require.Len(t, toRemove, 1)
require.Equal(t, "aCombined", toRemove[0].ProfileUUID)
})
t.Run("broken label profile is not removed", func(t *testing.T) {
brokenProf := &fleet.AppleProfileForReconcile{
ProfileUUID: "aBrokenLabel",