Skip to content

Policy shadows

A shadow is two policies covering the same (SCIM group, segment) pair with the same action. Redundant. Probably safe.

A conflict is the same overlap with different actions. One says ALLOW, the other says BLOCK_ACCESS. Whichever has the lower RuleOrder wins, but the existence of both is a smell - the losing rule is either dead or hiding intent that nobody documented.

Endpoint

GET /api/v1/analytics/policy-shadows

Returns

type PolicyShadowReport struct {
PolicyA PolicySummary
PolicyB PolicySummary // higher RuleOrder, the shadowed one
SharedScimGroups []NamedRef
SharedSegments []NamedRef
Verdict string // "shadow" or "conflict"
}
type PolicySummary struct {
ID string
Name string
Action string // ALLOW | BLOCK_ACCESS
RuleOrder int
}

PolicyA.RuleOrder < PolicyB.RuleOrder. PolicyA is the one that actually fires; PolicyB is the one that gets reached only when PolicyA’s conditions do not match.

Verdict semantics

PolicyA.ActionPolicyB.ActionVerdict
ALLOWALLOWshadow
BLOCK_ACCESSBLOCK_ACCESSshadow
ALLOWBLOCK_ACCESSconflict
BLOCK_ACCESSALLOWconflict

How

For each policy, build the set of (scimGroupID, segmentID) pairs it covers. Walk every pair of policies; if their pair-sets intersect, produce a report. Quadratic in policy count - on a tenant with 500 policies that is 125k comparisons, fast enough to do live.

Use it for

  • Cleanup. Shadows are pure redundancy. Pick one, delete the other.
  • Audit. Conflicts mean somebody added a BLOCK_ACCESS later without removing the original ALLOW (or vice versa). Find the author, ask why.
  • Refactor planning. Heavy overlap across many policies usually means the SCIM group or segment group hierarchy needs rethinking.