RBAC Simulator Guide
The RBAC Simulator lets you test how your policies behave under different user roles and permissions. Define roles like Admin, User, and Guest, run policy evaluations with each role’s context injected, and compare results side-by-side to verify your access control logic works as expected.
The simulator runs entirely in the browser using your workspace’s role definitions stored in Supabase.
Overview
The RBAC Simulator is available inside any policy view in your workspace. It has three tabs:
| Tab | Purpose |
|---|
| Roles | Create, edit, and manage role definitions |
| Simulate | Run a policy evaluation with a selected role |
| Compare | View simulation results across multiple roles side-by-side |
Open the simulator from the policy editor — it appears below the code editor when you select a policy.
1. Defining Roles
A role represents a user type in your system. Each role has a name, a set of permissions, custom attributes, and metadata.
Role Structure
interface RoleDefinition {
id: string; // Unique identifier (e.g., "admin")
name: string; // Display name (e.g., "Administrator")
permissions: string[]; // Permission strings (e.g., ["read", "write", "delete"])
attributes: Record<string, any>; // Custom attributes injected into policy context
metadata: {
description: string;
groups: string[];
level: number;
customFields: Record<string, any>;
};
}
Creating a Role
- Open the RBAC Simulator and go to the Roles tab
- Click ”+ New Role”
- Fill in the role definition form
- Click Save
Built-in Example Roles
| Role | Permissions | Level | Key Attributes |
|---|
| Administrator | read, write, delete, approve, manage_users | 10 | clearanceLevel: high, canAccessPII: true |
| Standard User | read, write | 5 | clearanceLevel: medium, canAccessPII: false |
| Guest | read | 1 | clearanceLevel: low, canAccessPII: false |
2. Running Simulations
Simulations execute your policy code with a specific role’s context injected, so you can see exactly what decision the policy makes for each user type.
How It Works
- Go to the Simulate tab
- Select one or more roles from the role list
- Configure an evaluation scenario (prompt, provider, model, parameters)
- Click Run Simulation
The simulator calls simulateWithRole() for each selected role. Your policy’s evaluate() function receives a context object containing the role:
{
role: {
id: "admin",
name: "Administrator",
permissions: ["read", "write", "delete", "approve", "manage_users"],
attributes: { department: "IT", clearanceLevel: "high", canAccessPII: true },
metadata: { ... }
},
user: {
id: "sim-user-admin",
attributes: { department: "IT", clearanceLevel: "high", canAccessPII: true }
},
environment: {
timestamp: "2026-03-15T10:30:00Z",
simulation: true
}
}
3. Comparing Role Results
The Compare tab shows simulation results side-by-side and highlights where roles produce different outcomes.
| Dimension | Flagged When |
|---|
| Decision | One role gets ALLOW, another gets DENY |
| Reason | The policy returns different reason strings |
| Execution Time | Difference exceeds 100ms between roles |
4. Importing and Exporting Roles
Role definitions can be shared across workspaces or teams using JSON import/export.
Exporting Roles
Click the Export button in the simulator header. All roles are exported as a JSON file.
Importing Roles
Click the Import button, select a JSON file, and the simulator validates each role’s structure before adding them.
5. Examples
Example 1: PII Access Control Policy
function evaluate(context, scenario) {
const containsPII = scenario.parameters.containsPII || false;
if (containsPII && !context.role.attributes.canAccessPII) {
return {
allowed: false,
reason: `Role "${context.role.name}" does not have PII access`,
metadata: { blockedField: 'canAccessPII' }
};
}
return { allowed: true, reason: 'Access granted', metadata: {} };
}
| Role | Decision | Reason |
|---|
| Administrator | ALLOW | Access granted |
| Standard User | DENY | Role “Standard User” does not have PII access |
| Guest | DENY | Role “Guest” does not have PII access |
Example 2: Permission-Based Write Guard
function evaluate(context, scenario) {
if (!context.role.permissions.includes('write')) {
return {
allowed: false,
reason: `Role "${context.role.name}" lacks write permission`,
metadata: { requiredPermission: 'write' }
};
}
return { allowed: true, reason: 'Write access confirmed', metadata: {} };
}
Example 3: Clearance-Level Gating
function evaluate(context, scenario) {
const sensitiveModels = ['gpt-4', 'claude-3-opus'];
const requiredLevel = 5;
if (sensitiveModels.includes(scenario.model) && context.role.metadata.level < requiredLevel) {
return {
allowed: false,
reason: `Level ${context.role.metadata.level} insufficient for ${scenario.model} (requires ${requiredLevel})`,
metadata: { requiredLevel, actualLevel: context.role.metadata.level }
};
}
return { allowed: true, reason: 'Model access granted', metadata: {} };
}
6. Tips and Best Practices
- Start with the built-in roles. Admin, User, and Guest cover the most common access patterns.
- Use attributes for business logic. Permissions control actions; attributes let policies make context-aware decisions.
- Test edge cases. Create a role with zero permissions to verify graceful handling.
- Export roles to version control. Keep role definitions alongside policies for CI/CD testing.
- Check the
simulation: true flag. Use it to skip side effects during test runs.
- Compare after every policy change. Run a quick simulation across all roles to catch unintended access changes.