Class: Ask::Sandbox::Local

Inherits:
Base
  • Object
show all
Defined in:
lib/ask/sandbox/local.rb

Overview

Executes commands in a local subprocess with resource limits. Available on all platforms (macOS, Linux). Uses stdlib only.

Constant Summary collapse

MAX_OUTPUT_SIZE =
102_400
STRIP_ENV_PREFIXES =
%w[BUNDLE_ GEM_].freeze
STRIP_ENV_VARS =
%w[RUBYOPT RUBYLIB BASH_ENV GEM_PATH GEM_HOME
BUNDLE_GEMFILE BUNDLE_PATH BUNDLE_BIN_PATH
BUNDLE_SETUP BUNDLE_WITHOUT BUNDLE_FROZEN].freeze
RLIMITS =
{
  rlimit_cpu: [10, 30],
  rlimit_nproc: [50, 50],
  rlimit_fsize: [10_485_760, 10_485_760],
  rlimit_nofile: [200, 200],
  rlimit_as: [2_147_483_648, 2_147_483_648]
}.freeze
POLL_INTERVAL =
0.05

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(timeout: 30, max_output: MAX_OUTPUT_SIZE) ⇒ Local

Returns a new instance of Local.



28
29
30
31
# File 'lib/ask/sandbox/local.rb', line 28

def initialize(timeout: 30, max_output: MAX_OUTPUT_SIZE)
  @default_timeout = timeout
  @max_output = max_output
end

Class Method Details

.supported_rlimitsObject



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/ask/sandbox/local.rb', line 70

def self.supported_rlimits
  @supported_rlimits ||= {}.tap do |opts|
    RLIMITS.each do |option, (soft, hard)|
      begin
        pid = Process.spawn({}, "true", {option => [soft, hard]})
        Process.waitpid(pid)
        opts[option] = [soft, hard]
      rescue ArgumentError, Errno::EINVAL, NotImplementedError
      end
    end
  end
end

Instance Method Details

#call(command, timeout: @default_timeout, workdir: nil, env: {}, stdin: nil) ⇒ Object

Raises:

  • (ArgumentError)


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ask/sandbox/local.rb', line 33

def call(command, timeout: @default_timeout, workdir: nil, env: {}, stdin: nil)
  raise ArgumentError, "command must not be nil" if command.nil?
  raise ArgumentError, "command must not be empty" if command.respond_to?(:empty?) && command.empty?

  argv = build_argv(command)
  child_env = build_environment(env)

  if workdir
    execute_in_dir(argv, child_env, workdir, timeout, stdin)
  else
    Dir.mktmpdir("ask_sandbox") do |dir|
      execute_in_dir(argv, child_env, dir, timeout, stdin)
    end
  end
end