Class: Chocomint::Tools::RunCommand

Inherits:
Base
  • Object
show all
Defined in:
lib/chocomint/tools/run_command.rb

Overview

whitelist に登録されたコマンドのみを実行する (DESIGN §13)。 shell を介さず引数配列で spawn するため、shell 展開・インジェクションは起きない。

Instance Method Summary collapse

Methods inherited from Base

#to_tool_definition

Constructor Details

#initialize(allowed_commands:, timeout_sec:, max_output_bytes:, cwd: Dir.pwd, path_guard: nil, allow_all: false) ⇒ RunCommand

Returns a new instance of RunCommand.



12
13
14
15
16
17
18
19
20
# File 'lib/chocomint/tools/run_command.rb', line 12

def initialize(allowed_commands:, timeout_sec:, max_output_bytes:, cwd: Dir.pwd,
               path_guard: nil, allow_all: false)
  @allowed_commands = Array(allowed_commands)
  @timeout_sec = timeout_sec
  @max_output_bytes = max_output_bytes
  @cwd = cwd
  @path_guard = path_guard
  @allow_all = allow_all
end

Instance Method Details

#call(args) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/chocomint/tools/run_command.rb', line 49

def call(args)
  measure do
    command = args["command"].to_s
    cmd_args = Array(args["args"]).map(&:to_s)

    unless @allow_all || @allowed_commands.include?(command)
      next fail(stderr: "command not allowed: #{command}")
    end

    # 外部プロセスは cwd 配下で自由に書き込めるため、引数に現れるパスが
    # 許可ディレクトリ内に収まるか事前に検証する (allowed_dirs の隔離を守る)。
    if @path_guard
      begin
        @path_guard.validate_args!(cmd_args)
      rescue PathAccessError => e
        next fail(stderr: e.message)
      end
    end

    run(command, cmd_args)
  end
end

#descriptionObject



24
25
26
27
28
29
30
31
32
# File 'lib/chocomint/tools/run_command.rb', line 24

def description
  if @allow_all
    "任意のコマンドを引数付きで実行する (whitelist 無効化 - allow_all_commands: true)。" \
      "shell 展開は行われない (args は個別のトークンとして渡す)。"
  else
    "許可されたコマンドを引数付きで実行する。許可コマンド: #{@allowed_commands.join(', ')}" \
      "shell 展開は行われない (args は個別のトークンとして渡す)。"
  end
end

#nameObject



22
# File 'lib/chocomint/tools/run_command.rb', line 22

def name = "run_command"

#schemaObject



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/chocomint/tools/run_command.rb', line 34

def schema
  {
    "type" => "object",
    "properties" => {
      "command" => { "type" => "string" },
      "args" => {
        "type" => "array",
        "items" => { "type" => "string" }
      }
    },
    "required" => %w[command],
    "additionalProperties" => false
  }
end