Add the PIM-only management security check on top of the shared
_get_pim_alerts implementation already introduced for the PIM stale
sign-in alert check (#10798). Avoid duplicating the service-layer fetch
that the original branch carried with its own beta endpoint + httpx
client; instead, consume the v1.0 unified roleManagement alerts feed via
the dict already populated on entra_client.
Detection logic: look up an active PIM alert whose definition id contains
'RolesAssignedOutsidePim'. FAIL when the alert is active with affected
items, PASS when it exists with no items (or is inactive), and MANUAL
when the alert is unavailable (no Microsoft Entra ID P2, alert disabled,
or insufficient permissions).
Compliance: extend CIS 4.0/6.0 control 5.3.1 and ISO 27001:2022 A.5.16 /
A.5.18 mappings to include this check alongside the stale sign-in alert
counterpart.
Apply poetry's black to entra_service.py so the file matches the
configuration CI's sdk-code-quality job uses. Also remove the redundant
tests/__init__.py for this check; pytest discovers tests by path and the
project convention is to keep test directories package-free.
The PIM stale sign-in alert check entry was placed under the already
released 5.24.1 section. Move it to a new [5.27.0] (UNRELEASED) block at
the top of the changelog so the entry lands in the actual shipping
release notes.
The DirectoryRoleStaleSignInAlertIncident schema does not expose 'subject',
'createdDateTime', or any field whose 'id' represents the affected user, so
the previous fallbacks silently substituted the wrong values and made
status_extended messages refer to the incident GUID instead of the actual
user when the API response omitted assigneeId/assigneeDisplayName.
Read each field directly from the documented incident properties so an
empty value stays empty rather than being papered over with unrelated
data.
The PIM alert object exposes an is_active flag that goes False once the
alert condition stops firing, even though the previous number_of_affected_items
count can stick around in the API response. The check was ignoring that
flag, so a tenant whose alert was already resolved or dismissed could
still receive a FAIL based on stale counters.
Gate the FAIL branch on alert.is_active so only currently-firing alerts
produce findings; everything else (resolved alert, inactive with leftover
counts) is reported as PASS. A regression test covers the inactive-with-
counts case to lock the behavior in.
The previous behavior fanned out a FAIL finding for every Organization the
tenant returned whenever the stale sign-in alert was missing from the API
response. That conflates three distinct conditions — no Microsoft Entra ID
P2 license, alert disabled, or insufficient permission — into the same
verdict, penalizes tenants without PIM, and emits N near-duplicate findings
for what is logically a single tenant-level state.
Emit a single MANUAL finding pinned to the first organization instead, with
a status_extended that lists the actionable causes so the operator can
choose what to remediate. MANUAL is the right verdict because the cause may
be legitimate (no P2) rather than misconfiguration.