Author policies

Visual builder

A graph-based editor for Cedar policies. Round-tripped to ensure visual + actual Cedar never drift.

The visual builder is a graph view of your Cedar policy. Drag actions, scope by resource, gate by condition — the editor emits Cedar in real time. Every save round-trips through the parser: visual → IR → Cedar → parsed IR. If the round-trip doesn't match, the save fails. You cannot ship a policy where the visual and the actual Cedar disagree.

Open the builder

On any policy detail page → Visual tab.

Visual policy builder canvas with permit + forbid nodes connected to action + resource scopes
Each permit / forbid is a node. Wires connect them to action sets and resource conditions.

The five primitives

  1. 1
    Permit / Forbid blocks

    Start with + Permit. Cedar's default is deny; permits are what allow. Forbid blocks override permits.

  2. 2
    Action sets

    Drag actions into the permit's action input. Auto-grouped by provider. Pick individual actions or whole groups (e.g. all GitHub read actions).

  3. 3
    Resource conditions

    resource.owner == "acme" — type in the visual builder's condition input. The builder hints valid keys from the YAML adapter (owner, repo, channel, account_id…).

  4. 4
    Context conditions

    context.cosigner == true — the gate for step-up. Or context.now.hour >= 9 for business hours. Context keys come from the PDP — see Dynamic intent.

  5. 5
    Principal scoping

    Rarely needed — most policies apply to "this App" by default. If you're writing a cross-app policy, scope to specific principals here.

A worked example

Goal: allow read on every GitHub action, allow PR create only on acme/app, forbid deletes unless cosigner is true.

  1. + Permit → drag GitHub read actions → no conditions → save.
  2. + Permit → action /github/pr/create → resource owner == "acme" && repo == "app".
  3. + Forbid → actions matching */delete* → condition !context.cosigner.

The emitted Cedar (right pane):

cedar
permit ( principal, action in [Action::"/github/issue/list", Action::"/github/issue/get",
                                /* … */], resource );
permit ( principal, action == Action::"/github/pr/create", resource )
  when { resource.owner == "acme" && resource.repo == "app" };
forbid ( principal, action like "/github/*/delete", resource )
  when { !context.cosigner };

What the round-trip guarantees

Visual = Cedar.

When you click save, the builder serializes the canvas to IR, emits Cedar, parses it back, and compares. Mismatch = block save with a diff message. You cannot ship a policy whose visual and Cedar disagree.

This matters because:

  • A buggy visual editor could otherwise show "deny on delete" while emitting Cedar that allows delete. That class of bug becomes unshippable.
  • New visual features (e.g. a new condition operator) ship only when the round-trip succeeds for every existing policy.

When to drop to Cedar

  • Multi-clause unless conditions.
  • Custom UCAN attribute lookups (principal.delegationDepth < 3).
  • Cross-resource invariants.

Switch tabs to Source. Edit Cedar directly. The visual tab re-parses on the next load.