Class: Chocomint::Security::PathGuard

Inherits:
Object
  • Object
show all
Defined in:
lib/chocomint/security/path_guard.rb

Overview

許可ディレクトリ配下のみアクセスを許し、パストラバーサルを防ぐ (DESIGN §13)。

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(allowed_dirs, base_dir: Dir.pwd) ⇒ PathGuard

Returns a new instance of PathGuard.



11
12
13
14
15
16
# File 'lib/chocomint/security/path_guard.rb', line 11

def initialize(allowed_dirs, base_dir: Dir.pwd)
  @base_dir = File.expand_path(base_dir)
  @allowed_roots = Array(allowed_dirs).map do |d|
    File.expand_path(d, @base_dir)
  end
end

Instance Attribute Details

#allowed_rootsObject (readonly)

Returns the value of attribute allowed_roots.



9
10
11
# File 'lib/chocomint/security/path_guard.rb', line 9

def allowed_roots
  @allowed_roots
end

#base_dirObject (readonly)

Returns the value of attribute base_dir.



9
10
11
# File 'lib/chocomint/security/path_guard.rb', line 9

def base_dir
  @base_dir
end

Instance Method Details

#allowed?(path) ⇒ Boolean

例外を投げずに許可判定だけ行う。

Returns:

  • (Boolean)


19
20
21
22
23
24
# File 'lib/chocomint/security/path_guard.rb', line 19

def allowed?(path)
  resolve(path)
  true
rescue PathAccessError
  false
end

#resolve(path) ⇒ Object

検証済み絶対パスを返す。許可外なら PathAccessError。

Raises:



27
28
29
30
31
32
33
34
35
36
# File 'lib/chocomint/security/path_guard.rb', line 27

def resolve(path)
  raise PathAccessError, "path is required" if path.nil? || path.to_s.empty?

  abs = File.expand_path(path.to_s, @base_dir)
  unless @allowed_roots.any? { |root| under?(root, abs) }
    raise PathAccessError, "access denied: #{path} is outside allowed directories"
  end

  abs
end

#validate_args!(args) ⇒ Object

run_command / shell の引数トークン列を検査する。ファイル系ツールと違い外部 プロセスは cwd (=base_dir) 配下で好き放題できてしまうため、引数に現れる 「パスらしいトークン」が allowed_roots 内に収まるかだけ事前に確認する。 過剰検知を避けるため、パス判定はスラッシュ/バックスラッシュを含むか ".." を 含むトークンに限る (venv / pandas / init のような非パス引数は素通しする)。 許可外を指すトークンがあれば PathAccessError。



44
45
46
47
48
49
50
51
52
# File 'lib/chocomint/security/path_guard.rb', line 44

def validate_args!(args)
  Array(args).each do |token|
    value = extract_path_value(token.to_s)
    next unless value && path_like?(value)

    resolve(value) # 許可外なら PathAccessError を送出
  end
  true
end