Skip to content

Fix: Fix tenant group resolution for scripted alerts - #475

Open
kris6673 wants to merge 3 commits into
CyberDrain:devfrom
kris6673:fix/scripted-alert-tenant-group-runtime
Open

Fix: Fix tenant group resolution for scripted alerts#475
kris6673 wants to merge 3 commits into
CyberDrain:devfrom
kris6673:fix/scripted-alert-tenant-group-runtime

Conversation

@kris6673

@kris6673 kris6673 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

issue

a scripted alert scoped to 2+ tenant groups stops firing for a tenant that joins one of those groups after the alert was saved. audit log alerts on the same groups deliver normally.

Invoke-AddScriptedAlert expanded the groups at save time, rewrote the alert to Tenant = 'AllTenants', and froze the complement of the selection into excludedTenants. nothing recomputes it. audit alerts store the selection verbatim and re-expand on every match, which is why only the scripted side breaks. it fails open too: a tenant onboarded after the save is in neither group, isn't in the frozen list, and gets the alert.
So in human language: if you have a scripted alert that is scoped to 2 tenant groups, in the backend its now a "AllTenants" alert with an exclusion list of all tenants that were not in the 2 tenant groups at the time the alert was saved. this exclusion list is then never updated again.
so adding tenants to the groups causes the alerts to never run for the added tenants

fix

Start-UserTasksOrchestrator now resolves scope on every run from Tenants — the verbatim selection already stored on every existing row — falling back to TenantGroup, then the bare tenant. Tenant stays the 'AllTenants' literal the execution gates rely on, so the execution path is unchanged. Invoke-AddScriptedAlert drops the complement and the selection rides in the single Add-CIPPScheduledTask write.

backwards compatible, no migration: new rows carry TenantSelectionVersion = 2; rows without it have their snapshot exclusions ignored and logged, so existing alerts heal on deploy. excludedTenantGroups was never part of the snapshot and always applies.

also stops Invoke-ListAlertsQueue wiping operator exclusions on every save, and closes out a run whose groups resolve to zero tenants instead of leaving the row Pending. no frontend changes.

test plan

  • 28 new tests across 4 files; Start-UserTasksOrchestrator had no coverage before
  • pwsh backend/Tests/Invoke-CippTests.ps1 -Path backend/Tests/Scheduler backend/Tests/Alerts → 82/82
  • confirmed the regression tests fail against the pre-fix code with the reported symptom

Multi-group scripted alerts expanded groups at save time and froze the
complement into excludedTenants, so a tenant joining a targeted group afterwards
never received the alert. Scope is now resolved on every run from the verbatim
selection in Tenants, as audit log alerts already do. Rows without the new
TenantSelectionVersion marker have their snapshot exclusions ignored, so
existing alerts heal without a re-save.
…tion

Failed is terminal, so a transient failure resolving a task's tenants parked a
recurring task there permanently; recurring tasks now go to Failed - Planned
with an advanced schedule. The stored Tenants selection is only honoured on a
row Push-ExecScheduledCommand also reads as multi-tenant, so the fan-out and
the execution gates cannot disagree about the task's shape. Stale snapshot
exclusions are logged only when they would actually have dropped a tenant that
is in scope, instead of once per legacy row on every run.
Signed-off-by: Kristian Kjærgård <31723128+kris6673@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant