Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
},
"product/admin/access-requests",
"product/admin/customize-requests",
"product/admin/entitlement-routing-rules",
"product/admin/emergency"
]
},
Expand Down
126 changes: 126 additions & 0 deletions product/admin/entitlement-routing-rules.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
title: Apply request settings automatically with entitlement routing rules
og:title: Apply request settings automatically with entitlement routing rules - C1 docs
og:description: Use entitlement routing rules to resolve the request policy and access request settings for many entitlements at once, based on conditions you define—including conditions that match the role and scope of sparse apps.
description: Use entitlement routing rules to resolve the request policy and access request settings for many entitlements at once, based on conditions you define—including conditions that match the role and scope of sparse apps.
sidebarTitle: Entitlement routing rules
---
{/* Editor Refresh: 2026-06-04 */}

## What are entitlement routing rules?

Entitlement routing rules are app-scoped rules that automatically determine which **request settings**—the [request policy](/product/admin/policies), emergency grant behavior, and maximum grant duration—apply when someone requests an entitlement. Instead of opening each entitlement and configuring its request settings by hand, you write a small, ordered set of rules that match entitlements by their attributes and apply the right settings to every matching entitlement, including entitlements that are created later but fit the same pattern.

Each rule has two parts: a **condition** that decides which entitlements the rule applies to, and the **request settings** the rule provides when its condition matches. Rules are evaluated in priority order, and the **first rule whose condition matches** an entitlement provides that entitlement's effective request settings. Because only the first match wins, order your rules from most specific to most general: put narrow, high-priority rules at the top and broader fallback rules below them. A rule with an **empty condition** acts as a catch-all—it matches every entitlement that no higher-priority rule has already claimed, which is a convenient way to set a default policy for an entire app.

Routing rules work for both **classic** apps (where each entitlement is a single permission, group, or role) and **sparse** apps (where access is modeled as a role granted on a scope). For sparse apps, a rule's condition can match on the granted role and the scope it applies to—see [How the CEL condition works for sparse apps](#how-the-cel-condition-works-for-sparse-apps) below.

<Warning>
A **Super Admin** or an application owner with the **Application Admin** role must configure entitlement routing rules.
</Warning>

## Create an entitlement routing rule

<Steps>
<Step>
Navigate to the **Apps** page and select a managed application.
</Step>
<Step>
Open the application's entitlement configuration and add a new routing rule.
</Step>
<Step>
Define the rule's **condition** using either the Basic or Advanced editor (see [Author a rule condition](#author-a-rule-condition) below). Leave the condition empty to create a catch-all default rule for the app.
</Step>
<Step>
Use the **preview** panel to confirm which of the app's entitlements your draft condition matches. This lets you verify a rule is neither too broad nor too narrow before it affects any live requests.
</Step>
<Step>
Choose the **request settings** the rule should apply when it matches: the request policy, whether emergency grants are allowed, and the maximum grant duration.
</Step>
<Step>
Click **Save**.
</Step>
</Steps>

Rules take effect in priority order. To change which rule wins when more than one could match an entitlement, reorder your rules—lower-priority numbers are evaluated first.

## Author a rule condition

You can author a rule's condition in one of two modes.

### Basic

Build a list of predicate rows, each made up of a **field**, an **operator**, and one or more **values**, combined with a single **AND** or **OR**:

* **Fields:** Entitlement name, Resource type ID, and Risk level ID. For sparse apps, you can also match on Role name and Scope name.
* **Operators:** *equals*, *does not equal*, *starts with*, *ends with*, *contains*, and *is any of*.

The Basic editor covers the most common matching needs without writing any code. C1 compiles your rows into a CEL expression behind the scenes.

### Advanced

Write the condition directly as a [CEL expression](/product/admin/expressions) for full control. When you switch a Basic condition to Advanced, the editor seeds the CEL with the expression compiled from your rows so you can extend it.

<Info>
Switching a condition from Basic to Advanced is one-way for that rule. Once you edit the raw CEL, the structured Basic rows are no longer kept in sync with it.
</Info>

## How the CEL condition works for sparse apps

A routing rule condition is a CEL expression evaluated against a single variable, **`entitlement`**, that describes the entitlement being routed. The expression returns `true` (the rule matches) or `false` (it doesn't). For example:

```cel
entitlement.display_name == "Admin"
entitlement.app_resource_type_id == "group"
entitlement.display_name.startsWith("prod-")
```

For **sparse apps**—apps that model access as a role granted on a scope (a scope-role binding) rather than as a single flat entitlement—the entitlement also carries the granted **role** and the **scope** it applies to. These are exposed as nested objects, `entitlement.role` and `entitlement.scope`, so you can match on them directly:

```cel
// Any sparse entitlement that grants an Admin role
entitlement.role.display_name.contains("Admin")

// A specific scope resource type
entitlement.scope.app_resource_type_id == "production_database"

// An Admin role granted on a production-prefixed scope
entitlement.role.display_name.contains("Admin")
&& entitlement.scope.display_name.startsWith("prod-")

// Pin by stable IDs so the rule survives an upstream rename
entitlement.role.id == "ROLE_RESOURCE_ID" && entitlement.scope.id == "SCOPE_RESOURCE_ID"
```

The key detail is how `role` and `scope` behave across app types:

* For a **sparse** (role-scope) entitlement, `entitlement.role.*` and `entitlement.scope.*` are populated from the binding.
* For a **classic** entitlement, those nested objects are empty—every string field is `""`.

A rule therefore implicitly fences itself to one shape or the other by which fields it references. A condition like `entitlement.role.display_name.contains("Admin")` can only match sparse entitlements, because the role display name is always empty on a classic entitlement. To make a rule explicitly sparse-only, use the canonical guard:

```cel
// True only for sparse targets; false for classic ones
entitlement.scope.id != ""
```

### Available fields

The most commonly used accessors are listed below. String comparisons support the standard CEL string methods—`==`, `!=`, `.startsWith(...)`, `.endsWith(...)`, and `.contains(...)`—and you can match against a set with the `in` operator (for example, `entitlement.app_resource_type_id in ["group", "role"]`). Combine multiple checks with `&&` and `||`.

Check warning on line 109 in product/admin/entitlement-routing-rules.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/entitlement-routing-rules.mdx#L109

Did you really mean 'accessors'?

| Field | Description |
|-------|-------------|
| `entitlement.display_name` | Display name. For sparse targets, mirrors the role's display name. |
| `entitlement.app_resource_type_id` | Resource type the entitlement is on. For sparse targets, the role's resource type. |
| `entitlement.app_resource_id` | Resource the entitlement is on. For sparse targets, the role's resource. |
| `entitlement.risk_level_value_id` | Risk level value ID, if one is set. |
| `entitlement.role.display_name` | Display name of the granted role *(sparse only)*. |
| `entitlement.role.id` | Stable ID of the granted role *(sparse only)*. |
| `entitlement.role.app_resource_type_id` | Resource type of the role *(sparse only)*. |
| `entitlement.scope.display_name` | Display name of the scope the role applies to *(sparse only)*. |
| `entitlement.scope.id` | Stable ID of the scope *(sparse only)*. |
| `entitlement.scope.app_resource_type_id` | Resource type of the scope *(sparse only)*. |

<Info>
Routing rule conditions see only the entitlement and its role/scope context. They do not have access to the requestor, the request, or the app itself, since rules are already scoped to a single app. When you're unsure whether a condition matches what you intend, use the preview panel to check it against the app's real entitlements before saving.

Check warning on line 125 in product/admin/entitlement-routing-rules.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/entitlement-routing-rules.mdx#L125

Did you really mean 'requestor'?
</Info>
2 changes: 1 addition & 1 deletion product/admin/expressions-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

### Enum types

Enums are predefined constants. Always use the full enum name (e.g., `UserStatus.ENABLED`, not just `ENABLED`).

Check warning on line 60 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L60

Did you really mean 'Enums'?

#### UserStatus

Expand All @@ -83,7 +83,7 @@
| `TaskOrigin.WEBAPP` | Created in C1 web interface |
| `TaskOrigin.SLACK` | Created via Slack integration |
| `TaskOrigin.API` | Created via API |
| `TaskOrigin.JIRA` | Created via Jira integration |

Check warning on line 86 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L86

Did you really mean 'Jira'?
| `TaskOrigin.COPILOT` | Created via Copilot |
| `TaskOrigin.PROFILE_MEMBERSHIP_AUTOMATION` | Created by automation |
| `TaskOrigin.TIME_REVOKE` | Created by time-based revocation |
Expand Down Expand Up @@ -120,7 +120,7 @@
These are complex types returned by functions or available as variables.

<Info>
**User vs AppUser:** These are different types. A `User` is a person in the C1 directory (your identity provider sync). An `AppUser` is that person's account within a specific application (their GitHub account, Okta account, etc.). One User can have many AppUsers across different apps.

Check warning on line 123 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L123

Did you really mean 'Okta'?
</Info>

#### User
Expand Down Expand Up @@ -201,7 +201,7 @@

The entitlement (permission/role) being requested. See [Entitlement object](#entitlement-object) for all fields.

**Available as:** `entitlement` (in policy expressions)
**Available as:** `entitlement` (in policy expressions and [entitlement routing rules](/product/admin/entitlement-routing-rules); in routing rules for sparse apps, `entitlement.role` and `entitlement.scope` are also populated)

#### IP

Expand All @@ -227,13 +227,13 @@

| Variable | Type | Available in | Description |
|:---------|:-----|:-------------|:------------|
| `subject` | User | Policies, Groups, Automations, Campaigns, Account provisioning | The current user being evaluated |

Check warning on line 230 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L230

Did you really mean 'Automations'?
| `account` | AppUser | Policies only | The application user (account) associated with the access request |
| `task` | Task | Policies only | The current access request |
| `entitlement` | Entitlement | Policies only | The entitlement being requested |
| `appOwners` | list&lt;User&gt; | Policy step approvers only | Owners of the application |

Check warning on line 234 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L234

Did you really mean 'approvers'?
| `ctx` | Context | Automations only | Workflow context and trigger data |

Check warning on line 235 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L235

Did you really mean 'Automations'?
| `ip` | IP | Policies, Automations | Requestor's IP address (when available) |

Check warning on line 236 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L236

Did you really mean 'Automations'?

Check warning on line 236 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L236

Did you really mean 'Requestor's'?

---

Expand All @@ -245,11 +245,11 @@

| Function | Accepts | Returns | Availability |
|:----------|:---------|:---------|:--------------|
| `c1.user.v1.HasApp` | user, app ID | Boolean | Policies, Groups, Automations, Account provisioning |

Check warning on line 248 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L248

Did you really mean 'Automations'?
| `c1.user.v1.HasEntitlement` | user, app ID, entitlement ID | Boolean | Policies, Groups, Automations, Account provisioning |

Check warning on line 249 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L249

Did you really mean 'Automations'?
| `c1.user.v1.GrantedFromEnrollment` | user, app ID, entitlement ID | Boolean | Policy conditions only |
| `c1.user.v1.AutomaticallyGrantedFromEnrollment` | user, app ID, entitlement ID | Boolean | Policy conditions only |
| `c1.user.v1.ListAppUsersForUser` | user, app ID | List of AppUser | Automations, Account provisioning |

Check warning on line 252 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L252

Did you really mean 'Automations'?

**What can go wrong:**
- Invalid app ID or entitlement ID returns `false` for boolean functions (no error thrown)
Expand All @@ -259,13 +259,13 @@

| Function | Accepts | Returns | Availability |
|:----------|:---------|:---------|:--------------|
| `c1.directory.users.v1.FindByEmail` | email | user | Policies, Groups, Automations, Account provisioning |

Check warning on line 262 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L262

Did you really mean 'Automations'?
| `c1.directory.users.v1.FindByName` | display name | user | Policies, Groups, Automations, Account provisioning |

Check warning on line 263 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L263

Did you really mean 'Automations'?
| `c1.directory.users.v1.GetByID` | user ID | user | Policies, Groups, Automations, Account provisioning |

Check warning on line 264 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L264

Did you really mean 'Automations'?
| `c1.directory.users.v1.GetManagers` | user | list of users | Policies, Groups, Automations, Account provisioning |

Check warning on line 265 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L265

Did you really mean 'Automations'?
| `c1.directory.users.v1.DirectReports` | user or list of users | list of users | Policies, Groups, Automations, Account provisioning |

Check warning on line 266 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L266

Did you really mean 'Automations'?
| `c1.directory.groups.v1.FindByName` | group name | group | Policies, Groups, Automations, Account provisioning |

Check warning on line 267 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L267

Did you really mean 'Automations'?
| `c1.directory.apps.v1.GetEntitlementMembers` | app ID, entitlement ID | list of users | Policies, Groups, Automations, Account provisioning |

Check warning on line 268 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L268

Did you really mean 'Automations'?
| `c1.directory.apps.v1.GetEntitlementOwners` | app ID + entitlement ID, or entitlement | list of users | Policies |

**What can go wrong:**
Expand All @@ -291,19 +291,19 @@
```
</Warning>

<Tip>

Check warning on line 294 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L294

Did you really mean 'ip'?
Go to an application or entitlement's details page to look up its ID, or use [Cone](/product/cli/install/).
</Tip>

<Info>
**Function availability varies by context.**

Note that automation triggers do NOT have access to directory or user library functions - they can only access the `ctx.trigger` object and basic enums.

Check warning on line 301 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L301

Did you really mean 'enums'?
</Info>

### Time functions

C1 provides comprehensive time functions for working with dates and times in CEL expressions. These functions are available in **all CEL contexts** (Policies, Groups, Automations, Account provisioning).

Check warning on line 306 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L306

Did you really mean 'Automations'?

#### Core time functions

Expand Down Expand Up @@ -397,7 +397,7 @@

#### Issue insights

Issue insights are discrete security findings (for example, critical CVEs or misconfigurations) synced from Wiz Insights.

Check warning on line 400 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L400

Did you really mean 'CVEs'?

Check warning on line 400 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L400

Did you really mean 'misconfigurations'?

| Function | Accepts | Returns | Availability |
|:----------|:---------|:---------|:--------------|
Expand Down Expand Up @@ -448,7 +448,7 @@
| `subject.manager_id` | string | User's manager ID | `subject.manager_id != ""` | Check if user has manager |

<Info>
Both `subject.manager` (email) and `subject.manager_id` (ID) are available. Use `manager` for email-based comparisons and `manager_id` to check existence or for ID-based lookups with `GetByID`.

Check warning on line 451 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L451

Did you really mean 'lookups'?
</Info>

#### Organizational fields
Expand Down Expand Up @@ -539,11 +539,11 @@
| `ip.is4` | Boolean | Whether IP is IPv4 | `ip.is4` | IPv4-specific logic |
| `ip.is6` | Boolean | Whether IP is IPv6 | `ip.is6` | IPv6-specific logic |
| `ip.isPrivate` | Boolean | Whether IP is private | `ip.isPrivate` | Internal network access |
| `ip.isLoopback` | Boolean | Whether IP is loopback | `ip.isLoopback` | Localhost detection |

Check warning on line 542 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L542

Did you really mean 'loopback'?
| `ip.isGlobalUnicast` | Boolean | Whether IP is global unicast | `ip.isGlobalUnicast` | Public IP detection |

Check warning on line 543 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L543

Did you really mean 'unicast'?
| `ip.isMulticast` | Boolean | Whether IP is multicast | `ip.isMulticast` | Multicast traffic detection |

Check warning on line 544 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L544

Did you really mean 'multicast'?

Check warning on line 544 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L544

Did you really mean 'Multicast'?
| `ip.isInterfaceLocalMulticast` | Boolean | Whether IP is interface local multicast | `ip.isInterfaceLocalMulticast` | Local multicast detection |

Check warning on line 545 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L545

Did you really mean 'multicast'?

Check warning on line 545 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L545

Did you really mean 'multicast'?
| `ip.isLinkLocalMulticast` | Boolean | Whether IP is link local multicast | `ip.isLinkLocalMulticast` | Link local multicast detection |

Check warning on line 546 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L546

Did you really mean 'multicast'?

Check warning on line 546 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L546

Did you really mean 'multicast'?
| `ip.isUnspecified` | Boolean | Whether IP is unspecified | `ip.isUnspecified` | Invalid IP detection |

### IP CIDR object
Expand All @@ -562,7 +562,7 @@

### Quick object reference table

| Object | Policies | Groups | Automations | Campaigns | Account provisioning |

Check warning on line 565 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L565

Did you really mean 'Automations'?
| :--- | :--- | :--- | :--- | :--- | :--- |
| subject | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="square-check" iconType="solid" color="#c937ae"/>* | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="square-check" iconType="solid" color="#c937ae"/> |
| user | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="square-check" iconType="solid" color="#c937ae"/>* | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="circle-minus" iconType="solid" color="red"/>️ |
Expand All @@ -571,9 +571,9 @@
| entitlement | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="circle-minus" iconType="solid" color="red"/>️ |
| ctx | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="circle-minus" iconType="solid" color="red"/>️ |
| ip | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="circle-minus" iconType="solid" color="red"/>️ |
| ip CIDR | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="square-check" iconType="solid" color="#c937ae"/> | <Icon icon="circle-minus" iconType="solid" color="red"/>️ | <Icon icon="circle-minus" iconType="solid" color="red"/>️ |

Check warning on line 574 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L574

Did you really mean 'ip'?

\* In Automations, user data is accessed through the `ctx` object (e.g., `ctx.trigger.newUser`, `ctx.trigger.oldUser`)

Check warning on line 576 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L576

Did you really mean 'Automations'?

### Subject object
**Available in:** <Icon icon="square-check" iconType="solid" color="#c937ae"/> Policies <Icon icon="square-check" iconType="solid" color="#c937ae"/> Groups <Icon icon="square-check" iconType="solid" color="#c937ae"/> Automations <Icon icon="square-check" iconType="solid" color="#c937ae"/> Campaigns <Icon icon="square-check" iconType="solid" color="#c937ae"/> Account provisioning
Expand All @@ -597,7 +597,7 @@
subject.department == "Engineering" && subject.status == UserStatus.ENABLED
```

*In Automations:*

Check warning on line 600 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L600

Did you really mean 'Automations'?
```go
// Automation trigger - when user status changes
subject.status == UserStatus.DISABLED
Expand Down Expand Up @@ -634,7 +634,7 @@
user.department == "Engineering"
```

*In Automations:*

Check warning on line 637 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L637

Did you really mean 'Automations'?
```go
// Automation step - modify specific user
user.status == UserStatus.DISABLED
Expand Down Expand Up @@ -717,7 +717,7 @@
### IP address object
**Available in:** <Icon icon="square-check" iconType="solid" color="#c937ae"/> Policies <Icon icon="circle-minus" iconType="solid" color="red"/>️ Groups <Icon icon="square-check" iconType="solid" color="#c937ae"/> Automations <Icon icon="circle-minus" iconType="solid" color="red"/>️ Campaigns <Icon icon="circle-minus" iconType="solid" color="red"/>️ Account provisioning
**Description:** Used for network-based access control and filtering
**Usage:** Available in policies and automations for network-based logic

Check warning on line 720 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L720

Did you really mean 'automations'?

**Context-specific examples:**

Expand All @@ -730,7 +730,7 @@
ip.is4
```

*In Automations:*

Check warning on line 733 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L733

Did you really mean 'Automations'?
```go
// Automation trigger - when IP is from private network
ip.isPrivate
Expand All @@ -739,7 +739,7 @@
### IP CIDR object
**Available in:** <Icon icon="square-check" iconType="solid" color="#c937ae"/> Policies <Icon icon="circle-minus" iconType="solid" color="red"/>️ Groups <Icon icon="square-check" iconType="solid" color="#c937ae"/> Automations <Icon icon="circle-minus" iconType="solid" color="red"/>️ Campaigns <Icon icon="circle-minus" iconType="solid" color="red"/>️ Account provisioning
**Description:** Used for network range-based access control and filtering
**Usage:** Available in policies and automations for network range checking

Check warning on line 742 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L742

Did you really mean 'automations'?

**Context-specific examples:**

Expand All @@ -749,7 +749,7 @@
cidr('10.1.2.0/24').contains(ip('10.1.2.5'))
```

*In Automations:*

Check warning on line 752 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L752

Did you really mean 'Automations'?
```go
// Automation trigger - when IP is in specific range
ip('10.1.2.5').within(cidr('10.1.2.0/24'))
Expand All @@ -758,7 +758,7 @@
### Context object (ctx)
**Available in:** <Icon icon="circle-minus" iconType="solid" color="red"/>️ Policies <Icon icon="circle-minus" iconType="solid" color="red"/>️ Groups <Icon icon="square-check" iconType="solid" color="#c937ae"/> Automation Triggers <Icon icon="square-check" iconType="solid" color="#c937ae"/> Workflow Steps <Icon icon="circle-minus" iconType="solid" color="red"/>️ Campaigns <Icon icon="circle-minus" iconType="solid" color="red"/>️ Account provisioning
**Description:** Provides access to workflow execution context and trigger data
**Usage:** Used in automations to access trigger data and previous step outputs

Check warning on line 761 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L761

Did you really mean 'automations'?

**Available fields:**

Expand Down Expand Up @@ -798,13 +798,13 @@
<Warning>
**Important:**

Automation triggers have limited function access. They do NOT have access to directory functions (`c1.directory.*`) or user entitlement checking functions (`c1.user.v1.HasApp`, etc.). Only basic user/account field access and status enums are available.

Check warning on line 801 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L801

Did you really mean 'enums'?
</Warning>

## Important notes

### Use camelCase

Check warning on line 806 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L806

Did you really mean 'camelCase'?
CEL expressions should be written in camelCase. C1 is moving away from snake_case for consistency and readability. Existing expressions in snake_case will still work, but new ones should follow the camelCase convention.

Check warning on line 807 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L807

Did you really mean 'camelCase'?

Check warning on line 807 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L807

Did you really mean 'snake_case'?

Check warning on line 807 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L807

Did you really mean 'snake_case'?

Check warning on line 807 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L807

Did you really mean 'camelCase'?

### Null safety with has()
Use the `has()` macro to check for existence of optional fields, especially in profile maps:
Expand All @@ -822,8 +822,8 @@
c1.directory.users.v1.FindByEmail(subject.email) && subject.department == "Engineering"
```

### Function memoization

Check warning on line 825 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L825

Did you really mean 'memoization'?
Directory function calls are automatically memoized within a single expression evaluation, so calling the same function multiple times is safe and efficient.

Check warning on line 826 in product/admin/expressions-reference.mdx

View check run for this annotation

Mintlify / Mintlify Validation (conductorone) - vale-spellcheck

product/admin/expressions-reference.mdx#L826

Did you really mean 'memoized'?

### Template syntax
Only Workflow Steps support `{{ expression }}` template syntax for embedding CEL expressions in strings.
Expand Down
1 change: 1 addition & 0 deletions product/admin/expressions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ C1 uses CEL expressions in many contexts. Each context provides different variab
| **Push config filters** | true/false | Target users for push rule provisioning |
| **Account provisioning** | text | Compute dynamic account attributes during grants |
| **User attribute mapping** | text or list of text | Derive user attributes from existing data |
| **Entitlement routing rules** | true/false | Match entitlements (including a sparse app's role and scope) to resolve request policies and access request settings—see [entitlement routing rules](/product/admin/entitlement-routing-rules) |

<Info>
Each context provides different variables. For example, `subject` is available in most contexts, but `ctx.trigger` is only available in automations. See the [expressions reference](/product/admin/expressions-reference) for details.
Expand Down
99 changes: 99 additions & 0 deletions rap/cel-expressions/env-app-entitlement-routing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Entitlement Routing Rule Expressions

Entitlement routing rules are app-scoped rules that resolve the **request settings** (request policy, emergency grant behavior, maximum grant duration) for an entitlement. Each rule's condition evaluates to `bool`. Rules are evaluated by priority (then id), and the first rule whose condition returns `true` provides the effective settings. An empty condition is a catch-all that matches every entitlement no higher-priority rule has claimed.

The condition can be authored in **Basic** mode (field/operator/value rows joined by a single AND/OR, compiled to CEL) or **Advanced** mode (raw CEL).

## Available Variables

Every evaluation receives a single top-level variable: **`entitlement`**.

| Variable | Type | Description |
|----------|------|-------------|
| `entitlement` | `AppEntitlement` | The entitlement being routed. For sparse (role-scope) targets, `entitlement.role` and `entitlement.scope` are populated. |

There is **no** `subject`, `task`, `user`, or `app` variable here—routing rules see only the entitlement and its binding context, and are already scoped per-app.

### `entitlement` fields

| Field | Type | Description |
|-------|------|-------------|
| `entitlement.id` | string | Entitlement identifier. Empty for sparse targets unless persisted. |
| `entitlement.app_id` | string | App that owns the entitlement. |
| `entitlement.app_resource_type_id` | string | Resource type the entitlement is on (for sparse: the role's resource type). |
| `entitlement.app_resource_id` | string | Resource the entitlement is on (for sparse: the role's resource). |
| `entitlement.display_name` | string | Display name. For sparse targets, mirrors the role's display name. |
| `entitlement.description` | string | Description. For sparse targets, mirrors the role's description. |
| `entitlement.risk_level_value_id` | string | Risk-level value id, if set. |

camelCase aliases also work (`appId`, `appResourceTypeId`, `appResourceId`, `displayName`).

### `entitlement.role` and `entitlement.scope` (sparse targets only)

For **classic** targets these nested resources are empty—every string field is `""`. For **sparse** (role-scope binding) targets they are filled from the binding.

| Field | Type | Description |
|-------|------|-------------|
| `entitlement.role.id` | string | Role resource identifier. |
| `entitlement.role.app_resource_type_id` | string | Resource type of the role. |
| `entitlement.role.display_name` | string | Role display name. |
| `entitlement.scope.id` | string | Scope resource identifier. |
| `entitlement.scope.app_resource_type_id` | string | Resource type of the scope. |
| `entitlement.scope.display_name` | string | Scope display name. |

## Common Patterns

### Classic targets

```cel
// Match every entitlement on a specific resource type
entitlement.app_resource_type_id == "group"

// Match by display-name pattern
entitlement.display_name.startsWith("prod-")

// Match a specific entitlement
entitlement.display_name == "Admin"
```

### Sparse (role-scope binding) targets

These rules only fire for sparse targets—the empty-string sentinel on classic targets makes the comparison fail.

```cel
// Any sparse target that grants an admin role
entitlement.role.display_name.contains("Admin")

// Sparse target on a specific scope resource type
entitlement.scope.app_resource_type_id == "production_database"

// Admin-role grant on a production-prefixed scope
entitlement.role.display_name.contains("Admin")
&& entitlement.scope.display_name.startsWith("prod-")

// Pin by stable IDs (survives an upstream rename)
entitlement.role.id == "ROLE_ID" && entitlement.scope.id == "SCOPE_ID"
```

### Sparse-only / classic-only gating

```cel
// Sparse-only: scope.id is "" for classic targets
entitlement.scope.id != ""

// Classic-only: role.id is "" for classic targets
entitlement.role.id == ""
```

## What Can Go Wrong

| Scenario | What Happens | How to Handle |
|----------|--------------|---------------|
| `entitlement.role.*` referenced on a classic app | Comparison returns `false` (fields are `""`) | Expected—this is what fences a rule to sparse targets |
| Two rules can match the same entitlement | First by (priority, id) wins | Order specific rules above general ones |
| No rule matches | Entitlement falls through to the app default | Add a catch-all rule with an empty condition |
| Typo in a field name | Compile-time error | Expression won't save |

## Best Practice

Keep each condition simple and use ordering rather than complex boolean logic. Use the rule editor's preview panel to confirm which entitlements a draft condition matches before saving.
1 change: 1 addition & 0 deletions rap/cel-expressions/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ These files document where CEL expressions are used and what variables/functions
| `env-workflow.md` | Workflow templates, step data flow, ctx object, interpolation |
| `env-account-provisioning.md` | Account attribute mapping, provisioning expressions |
| `env-user-attribute.md` | Derived user attributes, computed attribute values |
| `env-app-entitlement-routing.md` | Entitlement routing rules, applying request policies/settings by condition, matching a sparse app's role and scope |

### Functions

Expand Down