Class: OllamaAgent::Tools::RunShell
- Defined in:
- lib/ollama_agent/tools/shell_tools.rb
Overview
Safe shell command execution tool.
Safety controls:
- allowlist: commands must match at least one allowlist pattern
- denylist: commands are rejected if they match any denylist pattern
- dry_run: if true, returns the command without executing
- timeout: kills the process after N seconds
- redaction: scrubs secret-like values from output
- sandbox: restricts working directory to project root
rubocop:disable Metrics/ClassLength – single tool: policy tables + process I/O loop
Constant Summary collapse
- DEFAULT_TIMEOUT =
30- MAX_OUTPUT_BYTES =
64 KB
65_536- DEFAULT_ALLOWLIST =
Default allowlist: common development workflows
[ /\Agit\s/, /\Abundle\s/, /\Arspec\b/, /\Arubocop\b/, /\Aruby\s/, /\Aecho\s/, /\Aprintf\s/, /\Acat\s/, /\Als\b/, /\Apwd\b/, /\Amkdir\s/, /\Acp\s/, /\Amv\s/, /\Awk\s/, /\Ased\s/, /\Agrep\s/, /\Afind\s/, /\Ayarn\s/, /\Anpm\s/, /\Amake\s/ ].freeze
- DEFAULT_DENYLIST =
Default denylist: dangerous patterns regardless of allowlist
[ /rm\s+(-[a-z]*r[a-z]*f|-[a-z]*f[a-z]*r|--recursive.*--force|--force.*--recursive)/i, /sudo\s/, /chmod\s+777/, /:\(\)\s*\{.*\}/, # fork bomb /curl[^|]*\|[^|]*sh/i, # curl | bash /wget[^|]*\|[^|]*sh/i, # wget | bash %r{>\s*/etc/}, # write to /etc %r{>\s*/usr/}, # write to /usr %r{dd\s+.*of=/dev/}i, # write to devices /mkfs\b/, # format filesystem /passwd\b/, # change passwords /visudo\b/, # edit sudoers /crontab\s+-[re]/i # modify crontabs ].freeze
- SECRET_PATTERNS =
Patterns that look like secrets — redacted from output
[ /(?:password|passwd|secret|api.?key|token|bearer)\s*[=:]\s*\S+/i, /AKIA[0-9A-Z]{16}/, # AWS access key /sk-[A-Za-z0-9]{32,}/, # OpenAI key pattern %r{eyJ[A-Za-z0-9+/=]{40,}} # JWT-ish ].freeze
Constants inherited from Base
Instance Attribute Summary
Attributes inherited from Base
#description, #input_schema, #name, #output_schema, #requires_approval, #risk_level
Instance Method Summary collapse
-
#call(args, context: {}) ⇒ Object
rubocop:enable Metrics/ParameterLists.
-
#initialize(allowlist: nil, denylist: nil, timeout: DEFAULT_TIMEOUT, dry_run: false, redact_secrets: true, **_opts) ⇒ RunShell
constructor
rubocop:disable Metrics/ParameterLists – explicit knobs for CLI/embedders.
Methods inherited from Base
#to_anthropic_schema, #to_ollama_schema, #to_s, tool_description, tool_name, tool_output_schema, tool_requires_approval, tool_risk, tool_schema
Constructor Details
#initialize(allowlist: nil, denylist: nil, timeout: DEFAULT_TIMEOUT, dry_run: false, redact_secrets: true, **_opts) ⇒ RunShell
rubocop:disable Metrics/ParameterLists – explicit knobs for CLI/embedders
98 99 100 101 102 103 104 105 106 |
# File 'lib/ollama_agent/tools/shell_tools.rb', line 98 def initialize(allowlist: nil, denylist: nil, timeout: DEFAULT_TIMEOUT, dry_run: false, redact_secrets: true, **_opts) super() @allowlist = allowlist || DEFAULT_ALLOWLIST @denylist = denylist || DEFAULT_DENYLIST @timeout = timeout @dry_run = dry_run @redact_secrets = redact_secrets end |
Instance Method Details
#call(args, context: {}) ⇒ Object
rubocop:enable Metrics/ParameterLists
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/ollama_agent/tools/shell_tools.rb', line 109 def call(args, context: {}) cmd = args["command"].to_s.strip return "Error: empty command" if cmd.empty? cwd = resolve_cwd(args["working_dir"], context[:root]) timeout = [args["timeout_seconds"]&.to_i || @timeout, 120].min check_allowlist!(cmd) check_denylist!(cmd) return { dry_run: true, command: cmd, cwd: cwd } if @dry_run || context[:read_only] run_command(cmd, cwd: cwd, timeout: timeout) end |