combining algorithms
deny-overrides, allow-overrides, first-match, and highest-priority — pick the right strategy for each policy.
Pick an algorithm
| Algorithm | Default? | Use case |
|---|---|---|
deny-overrides | yes | Restriction policies |
allow-overrides | no | RBAC, permissive grants |
first-match | no | Firewall-style ordered lists |
highest-priority | no | Emergency overrides, tiered rules |
deny-overrides
The default and most conservative algorithm. Any deny beats any allow.
const p = policy('strict')
.algorithm('deny-overrides')
.rule('allow-read', (r) => r.allow().on('read').of('post'))
.rule('deny-drafts', (r) =>
r
.deny()
.on('read')
.of('post')
.when((w) => w.resourceAttr('status', 'eq', 'draft')),
)
.build()const p = policy('strict')
.algorithm('deny-overrides')
.rule('allow-read', (r) => r.allow().on('read').of('post'))
.rule('deny-drafts', (r) =>
r
.deny()
.on('read')
.of('post')
.when((w) => w.resourceAttr('status', 'eq', 'draft')),
)
.build()Evaluation logic:
- Find all matching rules
- If any has
effect: 'deny', the policy result is deny - Else if any has
effect: 'allow', the policy result is allow - Else fall back to
defaultEffect
Use this for restriction policies — a single deny blocks access regardless of how many allow rules match.
allow-overrides
The inverse: any allow beats any deny. Used by the auto-generated RBAC policy.
const p = policy('permissive')
.algorithm('allow-overrides')
.rule('deny-default', (r) => r.deny().on('*').of('*'))
.rule('vip-access', (r) =>
r
.allow()
.on('*')
.of('premium-content')
.when((w) => w.attr('tier', 'in', ['pro', 'enterprise'])),
)
.build()const p = policy('permissive')
.algorithm('allow-overrides')
.rule('deny-default', (r) => r.deny().on('*').of('*'))
.rule('vip-access', (r) =>
r
.allow()
.on('*')
.of('premium-content')
.when((w) => w.attr('tier', 'in', ['pro', 'enterprise'])),
)
.build()Evaluation logic:
- Find all matching rules
- If any has
effect: 'allow', the policy result is allow - Else if any has
effect: 'deny', the policy result is deny - Else fall back to
defaultEffect
Use this for deny-by-default policies where specific allow rules grant access.
first-match
The first matching rule wins. Order matters.
const p = policy('firewall')
.algorithm('first-match')
.rule('block-bad-ip', (r) =>
r
.deny()
.on('*')
.of('*')
.when((w) => w.env('ip', 'in', ['10.0.0.99', '10.0.0.100'])),
)
.rule('allow-internal', (r) =>
r
.allow()
.on('*')
.of('*')
.when((w) => w.env('ip', 'starts_with', '10.')),
)
.rule('deny-external', (r) => r.deny().on('*').of('*'))
.build()const p = policy('firewall')
.algorithm('first-match')
.rule('block-bad-ip', (r) =>
r
.deny()
.on('*')
.of('*')
.when((w) => w.env('ip', 'in', ['10.0.0.99', '10.0.0.100'])),
)
.rule('allow-internal', (r) =>
r
.allow()
.on('*')
.of('*')
.when((w) => w.env('ip', 'starts_with', '10.')),
)
.rule('deny-external', (r) => r.deny().on('*').of('*'))
.build()Evaluation logic:
- Walk rules in order
- Collect all matching rules
- The first matching rule's effect is the policy result
- If none match, fall back to
defaultEffect
Use this for firewall-style ordered rule lists.
highest-priority
The matching rule with the highest priority wins.
const p = policy('priority')
.algorithm('highest-priority')
.rule('normal-allow', (r) => r.allow().on('read').of('post').priority(10))
.rule('elevated-deny', (r) =>
r
.deny()
.on('read')
.of('post')
.when((w) => w.resourceAttr('classification', 'eq', 'top-secret'))
.priority(50),
)
.rule('emergency-override', (r) =>
r
.allow()
.on('*')
.of('*')
.when((w) => w.role('super-admin'))
.priority(100),
)
.build()const p = policy('priority')
.algorithm('highest-priority')
.rule('normal-allow', (r) => r.allow().on('read').of('post').priority(10))
.rule('elevated-deny', (r) =>
r
.deny()
.on('read')
.of('post')
.when((w) => w.resourceAttr('classification', 'eq', 'top-secret'))
.priority(50),
)
.rule('emergency-override', (r) =>
r
.allow()
.on('*')
.of('*')
.when((w) => w.role('super-admin'))
.priority(100),
)
.build()Evaluation logic:
- Find all matching rules
- Sort by
prioritydescending - The highest-priority rule's effect is the policy result
- If tied, the first encountered among tied rules wins
- If none match, fall back to
defaultEffect
Use this when rules have clear priority tiers and definition order shouldn't matter.
Cross-policy AND
Across policies, the engine AND-combines results. A deny from any policy is final regardless of what each policy's combining algorithm chose.
Policy A (allow-overrides) → ALLOW
Policy B (deny-overrides) → DENY
Policy C (first-match) → ALLOW
Final result: DENY (Policy B's deny is final)
This is fixed engine-level behavior — you can't change it with a per-policy algorithm. To make a policy purely advisory, scope it tightly with targets.