Scopes
Understanding permission scopes in AgentSudo.
Scopes define what actions an agent can perform. They follow a simple, hierarchical format.
Scope Format
Scopes use a colon-separated format:
action:resource:qualifier
Examples:
read:orders- Read orderswrite:refunds- Create refundsadmin:users:delete- Delete users (admin)
Hierarchical Scopes
Scopes can be hierarchical, allowing fine-grained control:
# Specific scope
"write:refunds:small" # Only small refunds
"write:refunds:large" # Only large refunds
# Parent scope (includes children)
"write:refunds" # All refunds
# Top-level scope
"write" # All write operations
Wildcard Scopes
Use * for wildcard matching:
# Match all read operations
"read:*"
# Match all operations on orders
"*:orders"
# Full access (superuser)
"*"
⚠️
Use wildcard scopes sparingly. Prefer specific scopes for better security.
Using the @sudo Decorator
Protect functions with the @sudo decorator:
from agentsudo import sudo
@sudo(scope="read:orders")
def get_order(order_id: str):
return {"id": order_id}
@sudo(scope="write:orders")
def update_order(order_id: str, data: dict):
pass
@sudo(scope="delete:orders")
def delete_order(order_id: str):
pass
Multiple Scopes
Require multiple scopes with scopes:
@sudo(scopes=["read:orders", "read:customers"])
def get_order_with_customer(order_id: str):
# Requires BOTH scopes
pass
Any Scope
Require any one of multiple scopes:
@sudo(scopes=["admin:orders", "write:orders"], require_all=False)
def modify_order(order_id: str):
# Requires at least ONE scope
pass
Common Scope Patterns
CRUD Operations
# Create
@sudo(scope="create:products")
def create_product(data): pass
# Read
@sudo(scope="read:products")
def get_product(id): pass
# Update
@sudo(scope="update:products")
def update_product(id, data): pass
# Delete
@sudo(scope="delete:products")
def delete_product(id): pass
Role-Based Access
# Support tier
support_scopes = [
"read:orders",
"read:customers",
"write:tickets",
"write:refunds:small"
]
# Manager tier
manager_scopes = [
*support_scopes,
"write:refunds:large",
"read:analytics"
]
# Admin tier
admin_scopes = ["*"]
Resource-Specific Access
# Access to specific resources
"read:orders:own" # Only own orders
"read:orders:team" # Team's orders
"read:orders:all" # All orders
# Implementation
@sudo(scope="read:orders:own")
def get_my_orders(user_id: str):
pass
Scope Matching Rules
- Exact match:
read:ordersmatchesread:orders - Wildcard match:
read:*matchesread:orders,read:customers - Hierarchical match:
write:refundsmatcheswrite:refunds:small - Superuser:
*matches everything
Examples
| Agent Scope | Required Scope | Result |
|---|---|---|
read:orders | read:orders | ✅ Allowed |
read:* | read:orders | ✅ Allowed |
write:refunds | write:refunds:small | ✅ Allowed |
* | admin:delete | ✅ Allowed |
read:orders | write:orders | ❌ Denied |
write:refunds:small | write:refunds:large | ❌ Denied |
Best Practices
1. Be Specific
# ✅ Good
scopes = ["read:orders", "write:tickets"]
# ❌ Bad
scopes = ["*"]
2. Use Consistent Naming
# ✅ Good - consistent pattern
"read:orders"
"write:orders"
"delete:orders"
# ❌ Bad - inconsistent
"get_orders"
"orders:write"
"remove-orders"
3. Document Your Scopes
# Define scopes in a central location
class Scopes:
"""Application permission scopes."""
# Order scopes
READ_ORDERS = "read:orders"
WRITE_ORDERS = "write:orders"
DELETE_ORDERS = "delete:orders"
# Refund scopes
REFUND_SMALL = "write:refunds:small" # Up to $50
REFUND_MEDIUM = "write:refunds:medium" # Up to $500
REFUND_LARGE = "write:refunds:large" # Unlimited
4. Group Related Scopes
# Define scope groups for common roles
SUPPORT_SCOPES = [
Scopes.READ_ORDERS,
Scopes.REFUND_SMALL,
]
MANAGER_SCOPES = [
*SUPPORT_SCOPES,
Scopes.REFUND_MEDIUM,
Scopes.REFUND_LARGE,
]