Drift auto-remediation
What it does
When the drift page detects that a customer's CA policy has drifted from the tenant's comparison baseline, Policytab can generate a draft change request that reverts supported drifted fields back to baseline. The change is not auto-applied - it still goes through the normal preview and apply workflow, plus second-admin approval when required. There is no background worker; an operator chooses Revert to baseline from the drift UI.
The feature covers policy state, assignments, conditions, grants, applications, session controls, device filters, authentication contexts, terms of use, and supported risk conditions. Display-name edits and missing or extra policies remain manual.
When to use it
- Customers with high-churn IT teams where direct-portal edits happen often and you want a fast revert path.
- Tenants where the baseline IS the source of truth - any drift is by definition a regression.
- MSPs running many tenants that need a consistent, reviewable revert path.
When not to use it:
- Tenants whose baseline is heavily customized at the tenant layer. The auto-remediator reverts to baseline, not to the customer-specific intent - you'd get noisy change requests for every drift that is actually intentional.
- During heavy migration periods where temporary drift is expected.
How to run it
- Sign in as Admin or Owner.
- Open the tenant Drift page.
- For each supported drift item, choose Revert to baseline (or use bulk actions where offered).
There is no per-tenant toggle - remediation is always operator-initiated.
What drift is detected
Drift is computed by compareTenantSnapshotToBaseline (see lib/baseline/compare-tenant.ts). Each policy in the live snapshot is matched to a baseline policy by code or display name, then field-by-field compared. A drift entry carries:
kind:missing,extra, ormodified(onlymodifiedis auto-remediable today)severity:critical,warning,infochangedFields: the set of normalized-intent fields that differ
The auto-remediator only acts on modified drift. missing would require creating a brand-new policy (the policy.create change kind exists but auto-create is intentionally out of scope - we don't want a runaway loop creating policies if the snapshot has a transient gap). extra is by definition BYO and not in the baseline at all.
How "Revert to baseline" works for non-state drift
The interesting case is non-state drift, where the change-management toolkit doesn't have a "set everything to baseline at once" operation. Auto-remediation handles this by emitting one change request per drifted category, all linked by a shared drift_remediation_group_id recorded in the audit log:
| Category | Emits | Reverts what |
|---|---|---|
state |
policy.state_change |
enabled / disabled / report-only |
assignment |
policy.assignment_change |
exclude-group add/remove deltas only when both sides are concrete Entra GUIDs |
condition |
policy.condition_change |
supported location deltas plus platform and client-app lists |
grant |
policy.grant_change |
set builtInControls list, operator, authentication strength id |
application |
policy.application_change |
include / exclude application id deltas |
session |
policy.session_change |
supported session-control values |
device_filter |
policy.device_filter_change |
device-filter mode and rule |
auth_context |
policy.auth_context_change |
authentication-context references |
terms_of_use |
policy.terms_of_use_change |
terms-of-use agreement references |
risk_condition |
policy.risk_condition_change |
supported user, service-principal, insider, agent, and authentication-flow risk conditions |
A single drifted policy where assignment AND grant both differ produces two change requests, both stamped with the same drift_remediation_group_id. Audit reads can correlate the pair as a single remediation event.
The classifier short-circuits: if a category's changedFields flag is set but the field-level deep-equal says nothing actually differs (e.g. baseline omits the field), no change request is emitted for that category.
Reviewing and applying
For each auto-generated change request:
- Tenant detail → Drift → choose Revert to baseline for a supported policy/category, then open the created draft from Changes.
- Click into the change. The payload is fully populated; the diff is rendered as if you'd typed it.
- Click Run preview. The standard warnings apply (
critical_policy_disable,grant_remove_mfa, etc.). If the auto-revert would itself trip a critical warning, you'll know. - Obtain second-admin approval if required, then choose Apply now. Use Cancel change if the drift is intentional.
If require_approval is on, or the change is critical, the standard four-eyes rule applies (see Approval workflow).
Troubleshooting
- I expected a change request and none appeared. Possible causes, in order:
- The drift category isn't in the supported list, such as a display-name-only change.
- The drift's
kindismissingorextra(auto-remediator only acts onmodified). - The drift was a no-op at field level (the baseline omits a field that the live policy carries set to an empty array - these are equivalent, no change needed).
- Auto-remediation created a change with a critical warning. That's working as intended - the preview is the gate. Resolve or deliberately override the blocker, then obtain any required second-admin approval before apply.
- Multiple linked changes - can I approve them as a group? Not yet. Each change has its own preview and apply step, plus its own approval when required. The shared remediation group is for audit correlation, not bulk approval.
- Auto-remediated change failed to apply. Same path as any apply failure - see Troubleshooting → apply fails. The auto-remediation didn't do anything special on apply; it only built the payload.
Audit log shape
Every auto-generated change emits a drift.auto_remediation.created audit row with:
resource = change_request:<id>payload.drifted_policy_id- the baseline policy codepayload.graph_policy_id- the live Entra object idpayload.category- one of the five categories abovepayload.drift_remediation_group_id- shared across linked changes,nullfor single-category remediations
The subsequent preview, approval when required, and apply events are recorded against the same change resource.