Class: SwarmSDK::Permissions::Validator
- Inherits:
-
SimpleDelegator
- Object
- SimpleDelegator
- SwarmSDK::Permissions::Validator
- Defined in:
- lib/swarm_sdk/permissions/validator.rb
Overview
Validator decorates tools to enforce permission checks before execution
Uses the Decorator pattern (via SimpleDelegator) to wrap tool instances and validate file paths and commands before allowing tool execution.
Example:
write_tool = Tools::Write.new
= Config.new(
{
allowed_paths: ["tmp/**/*"],
allowed_commands: ["^git (status|diff)$"]
},
base_directories: ["."]
)
validated_tool = Validator.new(write_tool, )
# This will be denied:
validated_tool.call({"file_path" => "/etc/passwd", "content" => "..."})
Instance Method Summary collapse
-
#call(args) ⇒ String
Intercept RubyLLM's call method to validate permissions.
-
#initialize(tool, permissions_config) ⇒ Validator
constructor
Initialize validator decorator.
Constructor Details
#initialize(tool, permissions_config) ⇒ Validator
Initialize validator decorator
28 29 30 31 32 |
# File 'lib/swarm_sdk/permissions/validator.rb', line 28 def initialize(tool, ) super(tool) @permissions = @tool = tool end |
Instance Method Details
#call(args) ⇒ String
Intercept RubyLLM's call method to validate permissions
RubyLLM calls tool.call(args) where args have string keys. We must override call (not execute) because SimpleDelegator doesn't automatically intercept methods defined in the superclass.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/swarm_sdk/permissions/validator.rb', line 42 def call(args) # Validate Bash commands if this is the Bash tool if bash_tool? command = args["command"] if command && !@permissions.command_allowed?(command) # Find the specific pattern that blocks this command matching_pattern = @permissions.find_blocking_command_pattern(command) return ErrorFormatter.( command: command, allowed_patterns: @permissions.allowed_commands, denied_patterns: @permissions.denied_commands, matching_pattern: matching_pattern, tool_name: @tool.name, ) end end # Extract paths from arguments (handles both string and symbol keys) paths = extract_paths_from_args(args) # Determine if this is a directory search tool (Glob/Grep) directory_search = directory_search_tool? # Validate each path paths.each do |path| next if @permissions.allowed?(path, directory_search: directory_search) # Show absolute path in error message for clarity absolute_path = @permissions.to_absolute(path) # Find the specific pattern that blocks this path matching_pattern = @permissions.find_blocking_pattern(path, directory_search: directory_search) return ErrorFormatter.( path: absolute_path, allowed_patterns: @permissions.allowed_patterns, denied_patterns: @permissions.denied_patterns, matching_pattern: matching_pattern, tool_name: @tool.name, ) end # All permissions validated, call wrapped tool __getobj__.call(args) end |