Policy Best Practices
Design effective permission policies that balance security with usability. Learn patterns for common scenarios.
Policy Design Principles
1. Start Restrictive, Then Relax
Begin with strict policies and gradually add auto-approvals based on observed patterns and trust levels.
# Default: require approval for everything
- name: "Default require approval"
conditions: {}
action: require_approval
priority: -1000
# Then add specific auto-approvals
- name: "Auto-approve read operations"
conditions:
action:
starts_with: "file.read"
action: auto_approve
priority: 102. Use Explicit Denies for Dangerous Operations
Always explicitly deny operations that should never be allowed:
# Deny dangerous operations regardless of other policies
- name: "Block system commands"
conditions:
action:
in: ["system.exec", "system.shell", "process.spawn"]
action: deny
priority: 1000
- name: "Block credential access"
conditions:
resource:
matches: ".*(password|secret|key|token).*"
action: deny
priority: 10003. Layer Policies by Specificity
Use priority to ensure more specific policies override general ones:
# Most specific: high priority
- name: "Production database"
conditions:
action:
equals: "database.query"
context.environment:
equals: "production"
action: require_approval
priority: 100
# Medium specific
- name: "Any database write"
conditions:
action:
in: ["database.insert", "database.update", "database.delete"]
action: require_approval
priority: 50
# Least specific: low priority
- name: "Database reads"
conditions:
action:
equals: "database.query"
action: auto_approve
priority: 10Common Policy Patterns
Read vs. Write Operations
# Auto-approve reads
- name: "File reads"
conditions:
action:
equals: "file.read"
action: auto_approve
scope_template:
max_size: 10485760 # 10MB
# Require approval for writes
- name: "File writes"
conditions:
action:
equals: "file.write"
action: require_approval
# Deny deletes
- name: "File deletes"
conditions:
action:
equals: "file.delete"
action: denyInternal vs. External Communications
# Auto-approve internal emails
- name: "Internal emails"
conditions:
action:
equals: "email.send"
context.recipient:
matches: ".*@mycompany\.com$"
action: auto_approve
scope_template:
max_emails: 10
# Require approval for external emails
- name: "External emails"
conditions:
action:
equals: "email.send"
action: require_approval
scope_template:
max_emails: 1Time-Based Policies
# Auto-approve during business hours
- name: "Business hours operations"
conditions:
action:
starts_with: "workflow."
context.time_of_day:
in: ["business_hours"]
action: auto_approve
# Require approval outside business hours
- name: "After-hours operations"
conditions:
action:
starts_with: "workflow."
context.time_of_day:
in: ["night", "weekend"]
action: require_approvalAmount-Based Policies
# Auto-approve small transfers
- name: "Small transfers"
conditions:
action:
equals: "payment.transfer"
scope.amount:
less_than: 100
action: auto_approve
# Require approval for medium transfers
- name: "Medium transfers"
conditions:
action:
equals: "payment.transfer"
scope.amount:
less_than: 1000
action: require_approval
# Deny large transfers (require manual process)
- name: "Large transfers"
conditions:
action:
equals: "payment.transfer"
scope.amount:
greater_than: 1000
action: denyAgent-Specific Policies
Create policies for specific agents with different trust levels:
# Trusted agent: more auto-approvals
- name: "Trusted agent operations"
agent_id: "agent_trusted_xxxx"
conditions:
action:
not_in: ["system.exec", "database.drop"]
action: auto_approve
priority: 50
# New agent: require approval for everything
- name: "New agent operations"
agent_id: "agent_new_xxxx"
conditions: {}
action: require_approval
priority: 50
# Restricted agent: deny most operations
- name: "Restricted agent"
agent_id: "agent_restricted_xxxx"
conditions:
action:
not_in: ["file.read", "web.search"]
action: deny
priority: 100Scope Templates
Use scope templates to enforce consistent limits:
- name: "API calls"
conditions:
action:
equals: "api.call"
action: auto_approve
scope_template:
# Rate limits
max_requests_per_minute: 10
max_requests_per_hour: 100
# Size limits
max_request_size: 1048576
max_response_size: 10485760
# Allowed endpoints
allowed_domains:
- "api.example.com"
- "api.another.com"
# Blocked endpoints
blocked_paths:
- "/admin/*"
- "/internal/*"
# Timeout
timeout_seconds: 30Testing Policies
Test your policies before deploying to production:
// Use test API key for policy testing
const testClient = new AgentOTPClient({
apiKey: 'ak_test_xxxx',
});
// Test that read operations are auto-approved
const readPermission = await testClient.requestPermission({
action: 'file.read',
scope: { max_size: 1000 },
});
console.assert(readPermission.status === 'approved');
// Test that writes require approval
const writePermission = await testClient.requestPermission({
action: 'file.write',
scope: { max_size: 1000 },
waitForApproval: false,
});
console.assert(writePermission.status === 'pending');
// Test that deletes are denied
const deletePermission = await testClient.requestPermission({
action: 'file.delete',
scope: {},
});
console.assert(deletePermission.status === 'denied');Policy Versioning
Track policy changes for compliance:
# policies/v2/file-operations.yaml
# Version: 2.0
# Author: security-team
# Date: 2026-01-15
# Changes: Added explicit deny for .env files
- name: "Deny .env access"
conditions:
resource:
matches: ".*\.env.*"
action: deny
priority: 1000
- name: "File reads"
conditions:
action:
equals: "file.read"
action: auto_approveMonitoring & Alerts
Set up alerts for policy violations:
// Monitor denied requests
const deniedRequests = await otp.getAuditLogs({
eventType: 'deny',
startDate: oneDayAgo,
});
if (deniedRequests.length > threshold) {
// Alert security team
sendAlert({
type: 'high_denial_rate',
count: deniedRequests.length,
details: deniedRequests.slice(0, 10),
});
}
// Monitor unusual patterns
const approvalsByAction = groupBy(auditLogs, 'action');
for (const [action, logs] of Object.entries(approvalsByAction)) {
if (logs.length > normalRate[action] * 3) {
sendAlert({
type: 'unusual_activity',
action,
count: logs.length,
});
}
}