Resource Limits and Rate Limiting
Overview
Implement resource consumption limits to prevent abuse and ensure fair resource allocation across users.
Problem Statement
Current limitations:
- Only timeout limit exists (60 seconds for commands)
- No output size limits
- No rate limiting per user
- No concurrent operation limits
- Memory and CPU are unrestricted
Abuse Scenarios:
- Infinite loop commands consuming CPU
- Commands generating massive output
- Rapid-fire requests overwhelming system
- Memory exhaustion via large file operations
- Fork bombs via spawn tool
Proposed Solution
Resource Limiter
// core/src/sandbox/resource.rs
pub struct ResourceLimiter {
limits: ResourceLimits,
usage: ResourceUsageTracker,
}
pub struct ResourceLimits {
// Time limits
pub command_timeout_seconds: u64,
pub file_operation_timeout_seconds: u64,
pub web_request_timeout_seconds: u64,
// Size limits
pub max_command_output_bytes: usize,
pub max_file_read_bytes: usize,
pub max_web_response_bytes: usize,
// Rate limits
pub max_commands_per_minute: u32,
pub max_file_ops_per_minute: u32,
pub max_web_requests_per_minute: u32,
// Concurrency limits
pub max_concurrent_commands: u32,
pub max_concurrent_subagents: u32,
}
pub struct ResourceUsageTracker {
// Per-user tracking
user_usage: HashMap<UserId, UserUsage>,
// Global tracking
global_usage: GlobalUsage,
}
pub struct UserUsage {
commands_this_minute: u32,
file_ops_this_minute: u32,
web_requests_this_minute: u32,
active_commands: u32,
active_subagents: u32,
last_reset: Instant,
}
Rate Limiting Implementation
impl ResourceLimiter {
pub fn check_rate_limit(&self, user: &UserId, operation: Operation) -> Result<(), RateLimitError> {
let usage = self.usage.get_or_create_user(user);
usage.reset_if_minute_elapsed();
match operation {
Operation::Command => {
if usage.commands_this_minute >= self.limits.max_commands_per_minute {
return Err(RateLimitError::CommandLimitExceeded {
limit: self.limits.max_commands_per_minute,
reset_in: usage.seconds_until_reset(),
});
}
}
Operation::FileOp => {
if usage.file_ops_this_minute >= self.limits.max_file_ops_per_minute {
return Err(RateLimitError::FileOpLimitExceeded);
}
}
// ... other operations
}
Ok(())
}
pub fn increment_usage(&self, user: &UserId, operation: Operation) {
let usage = self.usage.get_or_create_user(user);
match operation {
Operation::Command => usage.commands_this_minute += 1,
Operation::FileOp => usage.file_ops_this_minute += 1,
// ... other operations
}
}
}
Output Truncation
impl ResourceLimiter {
pub fn truncate_output(&self, output: &[u8], operation: Operation) -> Cow<[u8]> {
let max_size = match operation {
Operation::Command => self.limits.max_command_output_bytes,
Operation::FileRead => self.limits.max_file_read_bytes,
Operation::WebRequest => self.limits.max_web_response_bytes,
};
if output.len() <= max_size {
Cow::Borrowed(output)
} else {
let truncated = &output[..max_size];
let message = format!("\n\n[TRUNCATED: Output exceeded {} bytes]", max_size);
Cow::Owned([truncated, message.as_bytes()].concat())
}
}
}
Concurrency Control
impl ResourceLimiter {
pub async fn acquire_slot(&self, user: &UserId, operation: Operation) -> Result<ResourceSlot, ResourceError> {
let usage = self.usage.get_or_create_user(user);
match operation {
Operation::Command => {
if usage.active_commands >= self.limits.max_concurrent_commands {
return Err(ResourceError::ConcurrencyLimitExceeded);
}
usage.active_commands += 1;
}
Operation::SpawnSubagent => {
if usage.active_subagents >= self.limits.max_concurrent_subagents {
return Err(ResourceError::SubagentLimitExceeded);
}
usage.active_subagents += 1;
}
}
Ok(ResourceSlot { user: user.clone(), operation })
}
}
impl Drop for ResourceSlot {
fn drop(&mut self) {
// Automatically release slot when dropped
}
}
Default Limits
{
"resource_limits": {
"timeouts": {
"command_seconds": 60,
"file_operation_seconds": 30,
"web_request_seconds": 30
},
"sizes": {
"max_command_output_mb": 1,
"max_file_read_mb": 10,
"max_web_response_mb": 1
},
"rates": {
"commands_per_minute": 30,
"file_ops_per_minute": 60,
"web_requests_per_minute": 30
},
"concurrency": {
"max_concurrent_commands": 3,
"max_concurrent_subagents": 5
}
}
}
Per-Role Limits
{
"role_limits": {
"guest": {
"commands_per_minute": 10,
"max_concurrent_commands": 1
},
"member": {
"commands_per_minute": 30,
"max_concurrent_commands": 3
},
"admin": {
"commands_per_minute": 100,
"max_concurrent_commands": 10
}
}
}
Implementation Tasks
Acceptance Criteria
Related
Resource Limits and Rate Limiting
Overview
Implement resource consumption limits to prevent abuse and ensure fair resource allocation across users.
Problem Statement
Current limitations:
Abuse Scenarios:
Proposed Solution
Resource Limiter
Rate Limiting Implementation
Output Truncation
Concurrency Control
Default Limits
{ "resource_limits": { "timeouts": { "command_seconds": 60, "file_operation_seconds": 30, "web_request_seconds": 30 }, "sizes": { "max_command_output_mb": 1, "max_file_read_mb": 10, "max_web_response_mb": 1 }, "rates": { "commands_per_minute": 30, "file_ops_per_minute": 60, "web_requests_per_minute": 30 }, "concurrency": { "max_concurrent_commands": 3, "max_concurrent_subagents": 5 } } }Per-Role Limits
{ "role_limits": { "guest": { "commands_per_minute": 10, "max_concurrent_commands": 1 }, "member": { "commands_per_minute": 30, "max_concurrent_commands": 3 }, "admin": { "commands_per_minute": 100, "max_concurrent_commands": 10 } } }Implementation Tasks
ResourceLimiterstructAcceptance Criteria
Related