# Coming from Cedar **In short:** Cedar gives you three fixed decision rules (deny by default, a forbid always wins, any satisfied permit allows) and returns the deciding policies with the answer. In Arxo none of these is built in: each is written as a rule or a priority, with a name and a stated reason. The result is the same decision on ordinary requests, but "no permit applied" and "a forbid applied" stay two different supports for the refusal, instead of one Deny. This page follows the authorization example of the [Cedar comparison](/comparisons/cedar/): groups with inheritance, permits that check clearance and team, an explicit forbid, an optional attribute behind a `has` guard, and template-linked policies. The Arxo package quoted here passes `law engine check`; its scenarios and the Cedar side of the experiment have not been run yet, so the page shows how the policies are written, not measured outcomes. ## Concept map | Cedar | Arxo | What changes for you | |---|---|---| | `permit` policy | Strict rules that establish a basis (`permitted_by`, then `access_basis` with the attribute checks) and one defeasible rule, `AccessAllowed`, that concludes `access_allowed` from the basis | The permit is split into "which group grants this" and "do the attributes match", each a named rule | | `forbid` policy | A defeasible rule with head `not access_allowed(...)` and a `priority` over the allowing rule with `reason explicit_exception` | "A forbid always wins" is a declaration you can read, not an engine rule | | Deny by default (no satisfied permit) | A presumption: a defeasible rule that refuses every request, beaten by `AccessAllowed` through a `priority` with `reason lex_specialis` | A refusal by default and a refusal by forbid are supported by different rules and stay distinguishable | | `principal in Group::"g"` through the entity hierarchy | Two strict rules, direct membership and inheritance, with the recursive step marked `monotone(...)` | The hierarchy is ordinary rules over facts about groups | | `has` guard on an optional attribute | No `has` introspection: the adapter supplies a presence fact, and a `closure` over the subject register turns its absence into an explicit "not present" | Absence of an attribute is a statement about a complete register, not a property of the entity record | | Template-linked policy | A fact recording the link between template, principal and resource, supplied with the case | Template editing that applies instantly is outside the example | | Deciding policies in the answer | The proof of the answer names the rules that support it | The witness lists rules and facts, including the presumption when nothing else applied | | Error in a policy: skipped, reported in diagnostics | A missing attribute is a missing fact: the rule that needs it does not fire. Malformed policy text has no skip-on-error counterpart | Errors are a different stage on each side, not a different verdict | | Allow and Deny as the decision | In addition, deontic positions: a liberty for an allowed access and a prohibition for a forbidden one | The answer can be read as "may" and "must not", with the same precedence | | JSON form of policies, `unspecified` placeholders | No counterpart: a policy is `.law` text and every request is typed | Nothing to port | ## Group hierarchy In Cedar, `principal in Group::"g"` follows the entity hierarchy for you. In Arxo the hierarchy is two rules over the membership and inheritance facts of the case. (The `label` lines of the rules on this page carry Russian descriptions and are omitted from the excerpts.) ```law rule HoldsDirect strict { for p: Principal; for g: Group; when member(p, g); then holds(p, g); } rule HoldsInherited strict { for p: Principal; for child: Group; for parent: Group; when monotone(holds(p, child)) and inherits(child, parent); then holds(p, parent); } ``` The recursive step is wrapped in `monotone(...)`: a bare atom inside the cycle would be rejected by the compiler. ## Permit, forbid and the default A Cedar permit combines a scope (principal, action, resource) with conditions. The Arxo package splits it: first, which group of the subject grants or forbids the action; then, whether the attributes match. ```law rule PermittedBy strict { for p: Principal; for g: Group; for a: CedarAction; for res: Resource; when access_requested(p, a, res) and holds(p, g) and permits(g, a, res); then permitted_by(p, a, res); } rule DeniedBy strict { for p: Principal; for g: Group; for a: CedarAction; for res: Resource; when access_requested(p, a, res) and holds(p, g) and forbids(g, a, res); then denied_by(p, a, res); } rule AttrBasis strict { for p: Principal; for a: CedarAction; for res: Resource; for t: Team; for c: Integer; for k: Integer; when permitted_by(p, a, res) and clearance(p, c) and security_level(res, k) and (c >= k) and team_of_principal(p, t) and team_of_resource(res, t); then access_basis(p, a, res); } ``` The decision itself comes from three defeasible rules, all about `access_allowed(p, a, res)`: `AccessAllowed` concludes it from a request with a basis; `ExplicitDeny` concludes its negation from a request the subject's group forbids; `DefaultDeny` concludes its negation from the request alone. Cedar's two fixed combining rules become two priorities: ```law priority BasisRebutsDefaultDeny { prefer AccessAllowed over DefaultDeny; reason lex_specialis; } priority DenyOverAllow { prefer ExplicitDeny over AccessAllowed; reason explicit_exception; } ``` For a request with a basis and no forbid, the basis beats the presumption. For a request with both, the forbid beats the basis. For a request with neither, the presumption stands. Each refusal is supported by a different rule, so "not permitted" and "prohibited" stay apart in the answer. If the forbid priority is removed, the package no longer says which side wins and the conflict is kept as `BOTH`; Cedar, by design, still answers Deny. The experiment includes that mutant to show the difference, not to rank it. ## Optional attributes and `has` Cedar guards an optional attribute with `has` so that a missing value does not become an evaluation error. Arxo has no introspection on an entity record. The adapter supplies a fact saying the attribute is present, and a closure over the register of subjects says that a subject on file without that fact does not have the attribute: ```law closure TitlePresence { predicate title_present; domain principal_on_file; snapshot "urn:snapshot:exp-cedar-authz:subjects:2026-09-30"; complete_as_of @2026-09-30T00:00:00Z; derive_explicit_negative true; } rule GuardedBasis strict { for p: Principal; for a: CedarAction; for res: Resource; when permitted_by(p, a, res) and title_present(p) and title(p, "VP"); then access_basis(p, a, res); } ``` Outside the domain of the closure, silence stays silence: the premise is not established, and the rule does not fire. ## Allow and Deny as positions Cedar's decision is Allow or Deny. The Arxo package also states what the decision means for the subject: an allowed access is a liberty, a forbidden one is a prohibition, and the prohibition wins for the same reason the forbid does. ```law rule AllowedIsLiberty strict { for p: Principal; for a: CedarAction; for res: Resource; when access_allowed(p, a, res); then liberty MayAccess { holder p; action access_requested(p, a, res); window [@2000-01-01, infinity); }; } rule DeniedIsProhibition strict { for p: Principal; for a: CedarAction; for res: Resource; when access_requested(p, a, res) and denied_by(p, a, res); then prohibition MustNotAccess { bearer p; action access_requested(p, a, res); window [@2000-01-01, infinity); }; } priority DenyOverridesAllow { prefer DeniedIsProhibition over AllowedIsLiberty; reason explicit_exception; } ``` ## What you gain, what you give up - **Gain: refusals that keep their reason.** "No permit applied" and "a forbid applied" are different supports, so a downstream reader can tell them apart without inspecting the deciding-policy set. - **Gain: precedence and conflicts you can read.** The combining rules are declarations with named reasons; removing one leaves a visible conflict instead of a silent change of verdict. - **Give up: set-level analysis.** Cedar's policy-set analysis (never-errors, always-allows, subsumption, equivalence, with counterexamples) and its formalized authorizer and validator have no counterpart here. Arxo's evidence is per answer: a derivation that costs more to produce and proves less about the whole policy set. - **Different scope.** Time and editions of the policy text are outside Cedar's purpose and outside this comparison. ## Next steps - [Cedar](/comparisons/cedar/): the full comparison, the studied versions and what is still open. - [Priority](/constructs/priority/), [Presumptions and fictions](/constructs/presumption-fiction/), [Negation and truth statuses](/constructs/negation-and-status/): the forms behind default deny and forbid-overrides. - [Prohibitions](/constructs/prohibition/) and [Liberties and immunities](/constructs/liberty-immunity/): positions in more detail. - [Guide](/guide/): getting started with Arxo.