Class: Kreator::ToolContext

Inherits:
Object
  • Object
show all
Defined in:
lib/kreator/tool_context.rb

Constant Summary collapse

DEFAULT_BASH_TIMEOUT =
30
APPROVAL_POLICIES =
%w[auto prompt deny].freeze
INITIALIZE_OPTIONS =
%i[
  cwd
  bash_timeout
  path_allowlist
  bash_deny_patterns
  bash_env
  approval_policy
  approval_callback
  plugin_approval_policy
  plugin_approval_callback
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**options) ⇒ ToolContext

Returns a new instance of ToolContext.

Raises:

  • (ArgumentError)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/kreator/tool_context.rb', line 22

def initialize(**options)
  validate_initialize_options!(options)
  cwd = options.fetch(:cwd, Dir.pwd)
  @cwd = File.expand_path(cwd)
  bash_timeout = options.fetch(:bash_timeout, DEFAULT_BASH_TIMEOUT)
  @bash_timeout = Integer(bash_timeout)
  path_allowlist = options.fetch(:path_allowlist, nil)
  @path_allowlist = Array(path_allowlist || [@cwd]).map { |path| File.expand_path(path, @cwd) }
  bash_deny_patterns = options.fetch(:bash_deny_patterns, [])
  @bash_deny_patterns = Array(bash_deny_patterns).map { |pattern| Regexp.new(pattern.to_s) }
  bash_env = options.fetch(:bash_env, {})
  @bash_env = bash_env || {}
  approval_policy = options.fetch(:approval_policy, "auto")
  @approval_policy = approval_policy.to_s
  @approval_callback = options.fetch(:approval_callback, nil)
  plugin_approval_policy = options.fetch(:plugin_approval_policy, "prompt")
  @plugin_approval_policy = plugin_approval_policy.to_s
  @plugin_approval_callback = options.fetch(:plugin_approval_callback, nil)
  raise ArgumentError, "unknown approval policy: #{@approval_policy}" unless APPROVAL_POLICIES.include?(@approval_policy)
  return if APPROVAL_POLICIES.include?(@plugin_approval_policy)

  raise ArgumentError, "unknown plugin approval policy: #{@plugin_approval_policy}"
end

Instance Attribute Details

#approval_policyObject (readonly)

Returns the value of attribute approval_policy.



19
20
21
# File 'lib/kreator/tool_context.rb', line 19

def approval_policy
  @approval_policy
end

#bash_deny_patternsObject (readonly)

Returns the value of attribute bash_deny_patterns.



19
20
21
# File 'lib/kreator/tool_context.rb', line 19

def bash_deny_patterns
  @bash_deny_patterns
end

#bash_envObject (readonly)

Returns the value of attribute bash_env.



19
20
21
# File 'lib/kreator/tool_context.rb', line 19

def bash_env
  @bash_env
end

#bash_timeoutObject (readonly)

Returns the value of attribute bash_timeout.



19
20
21
# File 'lib/kreator/tool_context.rb', line 19

def bash_timeout
  @bash_timeout
end

#cwdObject (readonly)

Returns the value of attribute cwd.



19
20
21
# File 'lib/kreator/tool_context.rb', line 19

def cwd
  @cwd
end

#path_allowlistObject (readonly)

Returns the value of attribute path_allowlist.



19
20
21
# File 'lib/kreator/tool_context.rb', line 19

def path_allowlist
  @path_allowlist
end

#plugin_approval_policyObject (readonly)

Returns the value of attribute plugin_approval_policy.



19
20
21
# File 'lib/kreator/tool_context.rb', line 19

def plugin_approval_policy
  @plugin_approval_policy
end

Instance Method Details

#approve!(action:, target:, details: {}) ⇒ Object



73
74
75
# File 'lib/kreator/tool_context.rb', line 73

def approve!(action:, target:, details: {})
  approve_with_policy!(approval_policy, @approval_callback, action: action, target: target, details: details)
end

#approve_plugin_tool!(plugin:, tool:, description:, args:) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/kreator/tool_context.rb', line 77

def approve_plugin_tool!(plugin:, tool:, description:, args:)
  approve_with_policy!(
    plugin_approval_policy,
    @plugin_approval_callback,
    action: :plugin_tool,
    target: tool,
    details: {
      "plugin" => plugin,
      "tool" => tool,
      "description" => description,
      "args" => args
    }
  )
end

#ensure_bash_allowed!(command) ⇒ Object



63
64
65
66
67
68
69
70
71
# File 'lib/kreator/tool_context.rb', line 63

def ensure_bash_allowed!(command)
  pattern = bash_deny_patterns.find { |candidate| command.match?(candidate) }
  return unless pattern

  raise ToolPermissionError.new(
    "bash command denied by policy: #{pattern.source}",
    details: { "command" => command, "pattern" => pattern.source }
  )
end

#ensure_not_cancelled!(signal) ⇒ Object



92
93
94
95
96
# File 'lib/kreator/tool_context.rb', line 92

def ensure_not_cancelled!(signal)
  return unless signal.respond_to?(:aborted?) && signal.aborted?

  raise ToolCancellationError
end

#ensure_path_allowed!(path, action:) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/kreator/tool_context.rb', line 50

def ensure_path_allowed!(path, action:)
  expanded = File.expand_path(path)
  allowed = path_allowlist.any? do |allowed_path|
    expanded == allowed_path || expanded.start_with?("#{allowed_path}#{File::SEPARATOR}")
  end
  return expanded if allowed

  raise ToolPermissionError.new(
    "#{action} denied outside allowed paths: #{expanded}",
    details: { "path" => expanded, "allowed_paths" => path_allowlist, "action" => action.to_s }
  )
end

#resolve_path(path) ⇒ Object



46
47
48
# File 'lib/kreator/tool_context.rb', line 46

def resolve_path(path)
  File.expand_path(path, cwd)
end