guardrail-removal-upgrades-blocked

A principal who can modify or escape a guardrail (SCP / Org Policy / deny assignment) upgrades the edges that guardrail was suppressing from BLOCKED to their underlying state.

derived any cloud emits ?cap

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanModifyPolicy {'guardrail': None} {'x': None} {'cap': None} {'y': None}

where

node_class(?guardrail) == Policy node_type(?guardrail) in [ServiceControlPolicy, OrganizationPolicy, ConditionalPolicy] # AWS SCP / GCP org policy / Azure deny assignment state_of(match[1]) == BLOCKED blocked_by(match[1]) == ?guardrail # THIS guardrail is what suppresses THIS edge — not merely present in the account

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

{'principal': None} CanModifyConfiguration {'scope_binding': None}

emit

source?x
target?y
conditionsguardrail_removed
state logicUPGRADE (re-emit match[1] in place): the suppressed edge is re-emitted with its UNDERLYING state — the state it would have had absent ?guardrail (ACTIVE, or CONDITIONAL with whatever non-guardrail gate remains). The upgrade is itself CONDITIONAL(guardrail_removed): it is only realizable AFTER the principal actually removes/escapes the guardrail, so keep it CONDITIONAL(guardrail_removed) unless the underlying edge would be BLOCKED for an INDEPENDENT reason (a second guardrail, a hard deny not owned by ?guardrail) — then it stays BLOCKED on that other cause. If ?principal's CanModifyPolicy / move capability is itself CONDITIONAL or BLOCKED, the upgrade inherits that (no upgrade from a BLOCKED modify). Never upgrade an edge that was BLOCKED by something OTHER than this guardrail. Monotonic re-emit updates the existing edge's state in place (RULE-FORMAT: re-derivation updates state).

Narrative

{principal.name} can remove the guardrail {guardrail.name} (by editing it or moving the affected resource out of its scope); doing so lifts the block on "{x.name} {cap} {y.name}", restoring that path to its underlying state.

Raw rule rules/derived/hierarchy-chains.yaml

id: guardrail-removal-upgrades-blocked
emits: ?cap
description: A principal who can modify or escape a guardrail (SCP / Org Policy / deny assignment) upgrades
  the edges that guardrail was suppressing from BLOCKED to their underlying state.
applies_to:
- '*'
match:
- - principal: null
  - CanModifyPolicy
  - guardrail: null
- - x: null
  - cap: null
  - y: null
where:
- node_class(?guardrail) == Policy
- 'node_type(?guardrail) in [ServiceControlPolicy, OrganizationPolicy, ConditionalPolicy]  # AWS SCP /
  GCP org policy / Azure deny assignment'
- state_of(match[1]) == BLOCKED
- "blocked_by(match[1]) == ?guardrail   # THIS guardrail is what suppresses THIS edge \u2014 not merely\
  \ present in the account"
optional:
- - principal: null
  - CanModifyConfiguration
  - scope_binding: null
emit:
  source: ?x
  target: ?y
  permissions: []
  conditions:
  - guardrail_removed
  state_logic: "UPGRADE (re-emit match[1] in place): the suppressed edge is re-emitted with its UNDERLYING\
    \ state \u2014 the state it would have had absent ?guardrail (ACTIVE, or CONDITIONAL with whatever\
    \ non-guardrail gate remains). The upgrade is itself CONDITIONAL(guardrail_removed): it is only realizable\
    \ AFTER the principal actually removes/escapes the guardrail, so keep it CONDITIONAL(guardrail_removed)\
    \ unless the underlying edge would be BLOCKED for an INDEPENDENT reason (a second guardrail, a hard\
    \ deny not owned by ?guardrail) \u2014 then it stays BLOCKED on that other cause. If ?principal's\
    \ CanModifyPolicy / move capability is itself CONDITIONAL or BLOCKED, the upgrade inherits that (no\
    \ upgrade from a BLOCKED modify). Never upgrade an edge that was BLOCKED by something OTHER than this\
    \ guardrail. Monotonic re-emit updates the existing edge's state in place (RULE-FORMAT: re-derivation\
    \ updates state)."
  confidence: min(contributing_confidences)
  derived_from:
  - ?principal CanModifyPolicy ?guardrail (or reparent via CanModifyConfiguration ?scope_binding)
  - ?x ?cap ?y (BLOCKED by ?guardrail)
  - blocked_by == ?guardrail
  false_positive_note: "Fire ONLY when THIS guardrail is the actual cause of the BLOCK \u2014 check blocked_by(edge)==?guardrail,\
    \ not mere co-location in the account/org. Two forms of removal, EITHER suffices: (a) modify the policy\
    \ (AWS organizations:UpdatePolicy/DetachPolicy/DisablePolicyType, GCP orgpolicy.policy.set, Azure\
    \ delete the owning blueprint/managed-app that created the deny assignment); (b) move the resource\
    \ out of scope (AWS MoveAccount/LeaveOrganization, Azure subscription move to another MG, GCP project.move).\
    \ Keep the upgrade CONDITIONAL(guardrail_removed) \u2014 it is a two-step action, not an already-realized\
    \ path \u2014 so path scoring reflects the extra removal step. Do NOT upgrade if a DIFFERENT guardrail\
    \ or an explicit hard deny independently blocks the same edge. AWS SCP nuance: an SCP can only be\
    \ edited from the management account or a delegated administrator \u2014 a member- account principal\
    \ with iam-only permissions CANNOT weaken it; require the organizations:* action at the right scope.\
    \ Azure deny-assignment nuance: most deny assignments are system-managed and not directly writable\
    \ \u2014 prefer the move-out / delete-owning-assignment path and mark CONDITIONAL when only that indirect\
    \ route exists."
  narrative: '{principal.name} can remove the guardrail {guardrail.name} (by editing it or moving the
    affected resource out of its scope); doing so lifts the block on "{x.name} {cap} {y.name}", restoring
    that path to its underlying state.'
move · open · esc close