Class: RuboCop::Cop::RosettAi::ShellInterpolation

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/rosett_ai/shell_interpolation.rb

Overview

Flags system, exec, and spawn calls where the first argument is an interpolated string, and backtick commands with interpolation. Both patterns risk shell injection.

Use array-form instead: system('cmd', arg1, arg2) or IO.popen([cmd, arg], &:read).

Examples:

# bad
system("rm #{filename}")
exec("echo #{user_input}")
spawn("process #{data}")
`#{cmd} --flag`

# good
system('rm', filename)
system(ENV.fetch('EDITOR', 'vim'), file)
IO.popen([cmd, '--flag'], &:read)
`ls -la`

Constant Summary collapse

MSG =
'Use array-form `system(cmd, arg, ...)` instead of interpolated string to avoid shell injection.'
BACKTICK_MSG =
'Use `IO.popen([cmd, arg], &:read)` instead of backtick interpolation to avoid shell injection.'
SHELL_METHODS =
[:system, :exec, :spawn].freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



40
41
42
43
44
# File 'lib/rubocop/cop/rosett_ai/shell_interpolation.rb', line 40

def on_send(node)
  return unless shell_with_interpolation?(node)

  add_offense(node)
end

#on_xstr(node) ⇒ Object



46
47
48
49
50
# File 'lib/rubocop/cop/rosett_ai/shell_interpolation.rb', line 46

def on_xstr(node)
  return unless node.children.any?(&:begin_type?)

  add_offense(node, message: BACKTICK_MSG)
end

#shell_with_interpolation?(node) ⇒ Object

system/exec/spawn with a dstr (interpolated string) as first argument



36
37
38
# File 'lib/rubocop/cop/rosett_ai/shell_interpolation.rb', line 36

def_node_matcher :shell_with_interpolation?, <<~PATTERN
  (send nil? {#{SHELL_METHODS.map { |method| ":#{method}" }.join(' ')}} dstr ...)
PATTERN