bwrap 1.0.0.pre.alpha5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ require_relative "args"
6
6
 
7
7
  # Class to clean up namespace for implementation specific reasons.
8
8
  #
9
- # @api internal
9
+ # @api private
10
10
  class Bwrap::Args::Library
11
11
  include Bwrap::Execution
12
12
  include Bwrap::Output
@@ -14,6 +14,11 @@ class Bwrap::Args::Library
14
14
  # NOTE: This caching can be made more efficient, but need to look at it later, what to do about it.
15
15
  @@needed_libraries_cache ||= []
16
16
 
17
+ # Empties {@@needed_libraries_cache}.
18
+ def self.clear_needed_libraries_cache
19
+ @@needed_libraries_cache.clear
20
+ end
21
+
17
22
  # Otherwise similar to {#needed_libraries}, but checks used libc to handle musl executables.
18
23
  #
19
24
  # @param executable [String] Path to the executable to find dependencies for
@@ -99,17 +104,17 @@ class Bwrap::Args::Library
99
104
  binary_path, libraries_line = line.split "::SEPARATOR::"
100
105
  libraries = libraries_line.split ","
101
106
 
102
- @needed_libraries += libraries
107
+ (@needed_libraries & libraries).each do |library|
108
+ verb "Binding #{library} as dependency of #{binary_path}"
109
+ end
110
+
111
+ @needed_libraries |= libraries
103
112
 
104
113
  # Also check if requisite libraries needs some libraries.
105
114
  inner = Bwrap::Args::Library.new
106
- @needed_libraries += inner.needed_libraries libraries
115
+ @needed_libraries |= inner.needed_libraries libraries
107
116
 
108
- # Mark library cached only after its dependencies have been also handled.
109
- libraries.each do |library|
110
- verb "Binding #{library} as dependency of #{binary_path}"
111
- @@needed_libraries_cache << library
112
- end
117
+ @@needed_libraries_cache |= libraries
113
118
  end
114
119
 
115
120
  # Used by {#musl_needed_libraries}.
@@ -120,11 +125,13 @@ class Bwrap::Args::Library
120
125
  matches = library_data.match(/(.*) \(0x[0-9a-f]+\)/)
121
126
  library_path = matches[1]
122
127
 
123
- @needed_libraries << library_path
128
+ unless @needed_libraries.include? library_path
129
+ @needed_libraries << library_path
130
+ end
124
131
 
125
132
  # Also check if requisite libraries needs some libraries.
126
133
  inner = Bwrap::Args::Library.new
127
- @needed_libraries += inner.musl_needed_libraries library_path
134
+ @needed_libraries |= inner.musl_needed_libraries library_path
128
135
  end
129
136
  end
130
137
  # class Library ended
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "securerandom"
4
+ require "tempfile"
4
5
 
5
6
  require "bwrap/output"
6
7
  require_relative "args"
@@ -24,7 +25,7 @@ class Bwrap::Args::MachineId
24
25
  # Returning [] means that execute() will ignore this fully.
25
26
  # Nil would be converted to empty string, causing spawn() to pass it as argument, causing
26
27
  # bwrap to misbehave.
27
- return unless @config.machine_id
28
+ return unless @config&.machine_id
28
29
 
29
30
  machine_id = @config.machine_id
30
31
 
@@ -51,10 +52,10 @@ class Bwrap::Args::MachineId
51
52
  debug "Using random machine id as /etc/machine-id"
52
53
 
53
54
  @machine_id_file = Tempfile.new "bwrap-random_machine_id-", @config.tmpdir
54
- @machine_id_file.write SecureRandom.uuid.gsub("-", "")
55
+ @machine_id_file.write SecureRandom.uuid.tr("-", "")
55
56
  @machine_id_file.flush
56
57
 
57
- %W{ --ro-bind-data #{machine_id_file.fileno} /etc/machine-id }
58
+ %W{ --ro-bind-data #{@machine_id_file.fileno} /etc/machine-id }
58
59
  end
59
60
 
60
61
  # Uses `10000000000000000000000000000000` as machine id.
@@ -79,6 +80,8 @@ class Bwrap::Args::MachineId
79
80
  end
80
81
 
81
82
  # Uses file inside sandbox directory as machine id.
83
+ #
84
+ # TODO: I kind of want to deprecate this one. It may make sense, but eh... Let’s see.
82
85
  private def machine_id_inside_sandbox_dir sandbox_directory
83
86
  machine_id_file = "#{sandbox_directory}/machine-id"
84
87
 
@@ -10,6 +10,7 @@ module Bwrap::Args::Mount
10
10
 
11
11
  debug "Binding #{@config.root} as /"
12
12
  @args.append %W{ --bind #{@config.root} / }
13
+ @args.append %w{ --chdir / }
13
14
  end
14
15
 
15
16
  # Arguments for mounting devtmpfs to /dev.
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ #require "deep-cover" if ENV["DEEP_COVER"]
4
+
5
+ require_relative "bwrap_module"
6
+ require "bwrap/version"
7
+ require "bwrap/args/construct"
8
+ require "bwrap/config"
9
+ require "bwrap/execution"
10
+
11
+ # Executes given command under {https://github.com/containers/bubblewrap bwrap}
12
+ # using given configuration.
13
+ #
14
+ # @see ::Bwrap Bwrap module for usage example
15
+ class Bwrap::Bwrap
16
+ include Bwrap::Execution
17
+
18
+ # @param config [Bwrap::Config] Configuration used to tailor bwrap
19
+ def initialize config
20
+ # TODO: Ensure that costruct.rb and utilities it uses does not enforce Config to be valid object.
21
+ # Create a test for that also. Well, as long as that makes sense. If it doesn’t work, validate
22
+ # Config object to be valid here.
23
+ @config = config
24
+ end
25
+
26
+ # Parses command line arguments given to caller script.
27
+ #
28
+ # @note This method automatically sets output levels according parsed
29
+ # options. It is also possible to set the levels manually using
30
+ # {Bwrap::Output.handle_output_options}, for example with flags
31
+ # parsed with optparse’s `OptionParser`, found in Ruby’s standard
32
+ # library.
33
+ #
34
+ # @warning Requires optimist gem to be installed, which is not a dependency of this gem.
35
+ def parse_command_line_arguments
36
+ options = parse_options
37
+
38
+ Bwrap::Output.handle_output_options options
39
+ end
40
+
41
+ # Binds and executes given command available on running system inside bwrap.
42
+ #
43
+ # If {Config#root} has been set, given executable is scanned for necessary
44
+ # libraries and they are bound inside sandbox. This often reduces amount of
45
+ # global binds, but some miscellaneous things may need custom handling.
46
+ #
47
+ # @see Config#features about binding bigger feature sets to sandbox.
48
+ #
49
+ # Executed command is constructed using configuration passed to constructor.
50
+ # After execution has completed, bwrap will also shut down.
51
+ #
52
+ # @param command [String, Array] Command to be executed inside bwrap along with necessary arguments
53
+ # @see #run_inside_root to execute a command that already is inside sandbox.
54
+ def run command
55
+ construct = Bwrap::Args::Construct.new
56
+ construct.command = command
57
+ construct.config = @config
58
+ bwrap_args = construct.construct_bwrap_args
59
+
60
+ exec_command = [ "bwrap" ]
61
+ exec_command += bwrap_args
62
+ exec_command.append command
63
+ exec_command += @cli_args if @cli_args
64
+
65
+ execute exec_command
66
+
67
+ construct.cleanup
68
+ end
69
+
70
+ # Convenience method to executes a command that is inside bwrap.
71
+ #
72
+ # Given command is expected to already be inside {Config#root}.
73
+ #
74
+ # Calling this method is equivalent to setting {Config#command_inside_root} to `true`.
75
+ #
76
+ # @note This may have a bit unintuitive usage, as most things are checked anyway, so this is not
77
+ # akin to running something inside a chroot, but rather for convenience.
78
+ #
79
+ # @param command [String, Array] Command to be executed inside bwrap along with necessary arguments
80
+ # @see #run to execute a command that needs to be bound to the sandbox.
81
+ def run_inside_root command
82
+ if @config
83
+ config = @config.dup
84
+ config.command_inside_root = true
85
+ else
86
+ config = nil
87
+ end
88
+
89
+ construct = Bwrap::Args::Construct.new
90
+ construct.command = command
91
+ construct.config = config
92
+ bwrap_args = construct.construct_bwrap_args
93
+
94
+ exec_command = [ "bwrap" ]
95
+ exec_command += bwrap_args
96
+ exec_command.append command
97
+ exec_command += @cli_args if @cli_args
98
+
99
+ execute exec_command
100
+
101
+ construct.cleanup
102
+ end
103
+
104
+ # Parses global bwrap flags using Optimist.
105
+ #
106
+ # Sets instance variable `@cli_args`.
107
+ #
108
+ # @warning Requires optimist gem to be installed, which is not a dependency of this gem.
109
+ #
110
+ # @api private
111
+ # @return [Hash] options parsed by `Optimist.options`
112
+ private def parse_options
113
+ begin
114
+ require "optimist"
115
+ rescue LoadError => e
116
+ puts "Failed to load optimist gem. In order to use Bwrap::Bwrap#parse_command_line_arguments, " \
117
+ "ensure optimist gem is present for example in your Gemfile."
118
+ puts
119
+ raise e
120
+ end
121
+
122
+ options = Optimist.options do
123
+ version ::Bwrap::VERSION
124
+
125
+ banner "Usage:"
126
+ banner " #{$PROGRAM_NAME} [global options]\n \n"
127
+ banner "Global options:"
128
+ opt :verbose,
129
+ "Show verbose output",
130
+ short: "v"
131
+ opt :debug,
132
+ "Show debug output (useful when debugging a problem)",
133
+ short: "d"
134
+ opt :trace,
135
+ "Show trace output (noisiest, probably not useful for most of time)",
136
+ short: :none
137
+ opt :version,
138
+ "Print version and exit",
139
+ short: "V"
140
+ opt :help,
141
+ "Show help message",
142
+ short: "h"
143
+
144
+ educate_on_error
145
+ end
146
+
147
+ @cli_args = ARGV.dup
148
+
149
+ options
150
+ end
151
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ruby-bwrap provides easy-to-use interface to run complex programs in sandboxes created with
4
+ # {https://github.com/containers/bubblewrap bubblewrap}.
5
+ #
6
+ # To run a program inside bubblewrap, a wrapper executable can be created. For example:
7
+ #
8
+ # require "bwrap"
9
+ #
10
+ # config = Bwrap::Config.new
11
+ # config.user = "dummy_user"
12
+ # config.full_system_mounts = true
13
+ # config.binaries_from = %w{
14
+ # /bin
15
+ # /usr/bin
16
+ # }
17
+ #
18
+ # bwrap = Bwrap::Bwrap.new config
19
+ # bwrap.parse_command_line_arguments
20
+ # bwrap.run "/bin/true"
21
+ #
22
+ # There also are few generic utilities, {Bwrap::Output} for handling output of scripts and
23
+ # {Bwrap::Execution} to run executables.
24
+ module Bwrap
25
+ # Empty module.
26
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bwrap::Config
4
+ # Methods to enable or disable feature sets to control various aspects of sandboxing.
5
+ class Features
6
+ # @abstract
7
+ #
8
+ # Base of all features.
9
+ class Base
10
+ # @param features [Bwrap::Config::Features] Instance of features object in {Config}
11
+ def initialize features
12
+ @features = features
13
+ end
14
+
15
+ # Checks if the feature has been enabled.
16
+ #
17
+ # @return [Boolean] whether feature is enabled
18
+ def enabled?
19
+ @enabled
20
+ end
21
+
22
+ # Enable the feature.
23
+ def enable
24
+ @enabled = true
25
+ end
26
+
27
+ # Disable the feature.
28
+ def disable
29
+ @enabled = false
30
+ end
31
+ end
32
+
33
+ # Defines Bash feature set.
34
+ class Bash < Base
35
+ # Nya.
36
+ end
37
+
38
+ # Defines Nscd feature set.
39
+ #
40
+ # nscd is short of name service cache daemon. It may make sense to
41
+ # have this class under another name, but I don’t know how nscd specific
42
+ # this feature can be, so this name it is for now.
43
+ class Nscd < Base
44
+ # Nya.
45
+ end
46
+
47
+ # Defines Ruby feature set.
48
+ #
49
+ # Implies {Nscd} feature.
50
+ class Ruby < Base
51
+ # Extra libraries to be loaded from `RbConfig::CONFIG["rubyarchdir"]`.
52
+ #
53
+ # @note This is only required to be called if extra dependencies are necessary.
54
+ # For example, psych.so requires libyaml.so.
55
+ #
56
+ # @return [Array] list of needed libraries.
57
+ #
58
+ # @overload stdlib
59
+ # @overload stdlib=(libs)
60
+ attr_reader :stdlib
61
+
62
+ def initialize features
63
+ super features
64
+
65
+ @gem_env_paths = true
66
+ @stdlib = []
67
+ end
68
+
69
+ # @return true if bindirs from “gem environment” should be added to sandbox.
70
+ def gem_env_paths?
71
+ @gem_env_paths
72
+ end
73
+
74
+ # Enable Ruby feature set.
75
+ #
76
+ # Among others, binds `RbConfig::CONFIG["sitedir"]` so scripts works.
77
+ #
78
+ # @note This does not allow development headers needed for compilation for now.
79
+ # I’ll look at it after I have an use for it.
80
+ #
81
+ # @note Also enables {Nscd} feature.
82
+ def enable
83
+ super
84
+
85
+ @features.nscd.enable
86
+ end
87
+
88
+ # @see #stdlib
89
+ def stdlib= libs
90
+ # Just a little check to have error earlier.
91
+ libs.each do |lib|
92
+ unless File.exist? "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
93
+ raise "Library “#{lib}” passed to Bwrap::Config::Ruby.stdlib= does not exist."
94
+ end
95
+ end
96
+
97
+ @stdlib = libs
98
+ end
99
+ end
100
+
101
+ # @return [Bash] Instance of feature class for Bash
102
+ def bash
103
+ @bash ||= Bash.new self
104
+ end
105
+
106
+ # @return [Nscd] Instance of feature class for nscd
107
+ def nscd
108
+ @nscd ||= Nscd.new self
109
+ end
110
+
111
+ # @return [Ruby] Instance of feature class for Ruby
112
+ def ruby
113
+ @ruby ||= Ruby.new self
114
+ end
115
+ end
116
+ end
data/lib/bwrap/config.rb CHANGED
@@ -3,13 +3,60 @@
3
3
  require "bwrap/output"
4
4
  require "bwrap/version"
5
5
 
6
- # Represents configuration set by user for bwrap execution.
6
+ # Features classes, used through {Config#features}.
7
+ require_relative "config/features"
8
+
9
+ # Represents configuration used to tailor bwrap execution.
10
+ #
11
+ # @developer_note
12
+ # Logger methods (debug, warn and so on) can’t be used here as logger
13
+ # isn’t initialized before this class.
14
+ #
15
+ # For same reason, it’s not advised to execute anything here.
7
16
  #
8
- # Implementation NOTE: logger methods (debug, warn and so on) can’t be used here as logger
9
- # isn’t initialized before this class.
17
+ # Note that all attributes also have writers, even though they are not documented.
18
+ #
19
+ # @todo Add some documentation about syntax where necessary, like for #binaries_from.
10
20
  class Bwrap::Config
21
+ # Array of audio schemes usable inside chroot.
22
+ #
23
+ # Currently supports:
24
+ # - :pulseaudio
25
+ #
26
+ attr_accessor :audio
27
+
28
+ # Set to `true` if command given to {Bwrap::Bwrap#run} is expected to
29
+ # be inside sandbox, and not bound from host.
30
+ #
31
+ # @return [Boolean] `true` if executed command is inside sandbox
32
+ attr_accessor :command_inside_root
33
+
34
+ attr_accessor :extra_executables
35
+
36
+ # TODO: IIRC this doesn’t match the reality any more. So write correct documentation.
37
+ #
38
+ # Causes libraries required by the executable given to {Bwrap#run} to be
39
+ # mounted inside sandbox.
40
+ #
41
+ # Often it is enough to use this flag instead of binding all system libraries
42
+ # using {#libdir_mounts=}
43
+ #
44
+ # @return [Boolean] true if Linux library loaders are mounted inside chroot
45
+ attr_accessor :full_system_mounts
46
+
11
47
  attr_accessor :hostname
12
48
 
49
+ # Set to true if basic system directories, like /usr/lib and /usr/lib64,
50
+ # should be bound inside chroot.
51
+ #
52
+ # /usr/bin can be mounted using {Config#binaries_from=}.
53
+ #
54
+ # Often it is enough to use {#full_system_mounts=} instead of binding all
55
+ # system libraries using this flag.
56
+ #
57
+ # @return [Boolean] true if libdirs are mounted to the chroot
58
+ attr_accessor :libdir_mounts
59
+
13
60
  # What should be used as /etc/machine_id file.
14
61
  #
15
62
  # If not specified, no /etc/machine_id handling is done.
@@ -24,6 +71,9 @@ class Bwrap::Config
24
71
  # Given file as bound as /etc/machine_id.
25
72
  attr_accessor :machine_id
26
73
 
74
+ # @return [Boolean] true if network should be shared from host.
75
+ attr_accessor :share_net
76
+
27
77
  # Name of the user inside chroot.
28
78
  #
29
79
  # This is optional and defaults to no user.
@@ -35,34 +85,23 @@ class Bwrap::Config
35
85
  # @return [Boolean] Whether Xorg specific binds are used.
36
86
  attr_accessor :xorg_application
37
87
 
38
- # Array of audio schemes usable inside chroot.
88
+ # Array of directories to be bind mounted in sandbox.
39
89
  #
40
- # Currently supports:
41
- # - :pulseaudio
90
+ # Given paths are also added to PATH environment variable inside sandbox.
42
91
  #
43
- attr_accessor :audio
44
-
45
- # @return [Boolean] true if network should be shared from host.
46
- attr_accessor :share_net
47
-
48
- # TODO: This should cause Bind#full_system_mounts to mount /lib64/ld-linux-x86-64.so.2 and so on,
49
- # probably according executable type of specified command. But that needs some magic.
92
+ # @hint At least on SUSE, many executables are symlinks to /etc/alternatives/*,
93
+ # which in turn symlinks to versioned executable under the same bindir.
94
+ # To use these executables, /etc/alternatives should also be bound:
50
95
  #
51
- # For now this just mounts all relevant files it can find.
96
+ # config.ro_binds["/etc/alternatives"] = "/etc/alternatives"
52
97
  #
53
- # @return [Boolean] true if Linux library loaders are mounted inside chroot
54
- attr_accessor :full_system_mounts
98
+ # @return [Array] Paths to directories where binaries are looked from.
99
+ attr_reader :binaries_from
55
100
 
56
- # Set to true if basic system directories, like /usr/lib and /usr/lib64,
57
- # should be bound inside chroot.
101
+ # Paths to be added to sandbox instance’s PATH environment variable.
58
102
  #
59
- # /usr/bin can be mounted using {Config#binaries_from=}.
60
- #
61
- # @return [Boolean] true if libdirs are mounted to the chroot
62
- attr_accessor :libdir_mounts
63
-
64
- # Array of directories to be bind mounted and used to construct PATH environment variable.
65
- attr_reader :binaries_from
103
+ # @see #add_env_path
104
+ attr_reader :env_paths
66
105
 
67
106
  # TODO: Document this.
68
107
  # TODO: I wonder if this should just be removed. I don’t know, this is a bit ...
@@ -72,71 +111,34 @@ class Bwrap::Config
72
111
  # Use given directory as root. End result is similar to classic chroot.
73
112
  attr_reader :root
74
113
 
75
- # `Hash`[`Pathname`] => `Pathname` containing custom read-only binds.
114
+ # @overload ro_binds
115
+ # `Hash`[`Pathname`] => `Pathname` containing custom read-only binds.
116
+ # @overload ro_binds=
117
+ # Set given hash of paths to be bound with --ro-bind.
118
+ #
119
+ # Key is source path, value is destination path.
120
+ #
121
+ # Given source paths must exist.
76
122
  attr_reader :ro_binds
77
123
 
78
- # Path to temporary directory.
124
+ # @overload tmpdir
125
+ # Path to temporary directory.
79
126
  #
80
- # Defaults to Dir.tmpdir.
127
+ # Defaults to Dir.tmpdir.
128
+ # @overload tmpdir=(dir)
129
+ # Sets given directory as temporary directory for certain operations.
130
+ #
131
+ # @note Requires `dir` to be path to existing directory.
132
+ # @raise [RuntimeError] If given directory does not exist
133
+ # @param dir Path to temporary directory
81
134
  attr_reader :tmpdir
82
135
 
83
- # Methods to enable or disable feature sets to control various aspects of sandboxing.
84
- class Features
85
- # Defines Ruby feature set.
86
- class Ruby
87
- # @return [Array] list of needed libraries.
88
- attr_reader :stdlib
89
-
90
- def initialize
91
- @stdlib = []
92
- end
93
-
94
- # @see enabled=
95
- def enabled?
96
- @enabled
97
- end
98
-
99
- # Enable Ruby feature set.
100
- #
101
- # Among others, binds RbConfig::CONFIG["sitedir"] so scripts works.
102
- #
103
- # @note This does not allow development headers needed for compilation for now.
104
- # I’ll look at it after I have an use for it.
105
- def enable
106
- @enabled = true
107
- end
108
-
109
- # Disable Ruby feature set.
110
- def disable
111
- @enabled = false
112
- end
113
-
114
- # Extra libraries to be loaded from `RbConfig::CONFIG["rubyarchdir"]`.
115
- #
116
- # @note This is only required to be called if extra dependencies are necessary.
117
- # For example, psych.so requires libyaml.so.
118
- def stdlib= libs
119
- # Just a little check to have error earlier.
120
- libs.each do |lib|
121
- unless File.exist? "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
122
- raise "Library “#{lib}” passed to Bwrap::Config::Ruby.stdlib= does not exist."
123
- end
124
- end
125
-
126
- @stdlib = libs
127
- end
128
- end
129
-
130
- # @return [Ruby] Instance of feature class for Ruby
131
- def ruby
132
- @ruby ||= Ruby.new
133
- end
134
- end
135
-
136
136
  def initialize
137
+ @audio = []
137
138
  @binaries_from = []
139
+ @env_paths = []
140
+ @ro_binds = {}
138
141
  @tmpdir = Dir.tmpdir
139
- @audio = []
140
142
  end
141
143
 
142
144
  def binaries_from= array
@@ -178,14 +180,13 @@ class Bwrap::Config
178
180
  @root = directory
179
181
  end
180
182
 
181
- # Set given hash of paths to be bound with --ro-bind.
182
- #
183
- # Key is source path, value is destination path.
184
- #
185
- # Given source paths must exist.
186
183
  def ro_binds= binds
187
184
  @ro_binds = {}
188
185
  binds.each do |source_path, destination_path|
186
+ if destination_path.nil?
187
+ raise "binds should be key-value storage of Strings, for example a Hash."
188
+ end
189
+
189
190
  source_path = Pathname.new source_path
190
191
  unless source_path.exist?
191
192
  raise "Given read only bind does not exist. Please check path “#{source_path}” is correct."
@@ -197,14 +198,17 @@ class Bwrap::Config
197
198
  end
198
199
  end
199
200
 
200
- # Sets given directory as temporary directory for certain operations.
201
- #
202
- # @note Requires `dir` to be path to existing directory.
203
- # @raise [RuntimeError] If given directory does not exist
204
- # @param dir Path to temporary directory
201
+ # See attr_accessor :tmpdir for documentation.
205
202
  def tmpdir= dir
206
203
  raise "Directory to be set as a temporary directory, “#{dir}”, does not exist." unless Dir.exist? dir
207
204
 
208
205
  @tmpdir = dir
209
206
  end
207
+
208
+ # Add a path to sandbox instance’s PATH environment variable.
209
+ #
210
+ # @param path [String] Path to be added added to PATH environment variable
211
+ def add_env_path path
212
+ @env_paths << path
213
+ end
210
214
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bwrap::Execution
4
+ # Unspecified execution related error.
5
+ class CommandError < StandardError
6
+ end
7
+
8
+ # Signifies that command execution has failed.
9
+ class ExecutionFailed < CommandError
10
+ end
11
+
12
+ # Thrown if given command was not found.
13
+ class CommandNotFound < CommandError
14
+ # Command that was looked at.
15
+ attr_reader :command
16
+
17
+ def initialize command:
18
+ @command = command
19
+ msg = "Failed to find #{command} from PATH."
20
+
21
+ super msg
22
+ end
23
+ end
24
+ end
@@ -3,11 +3,14 @@
3
3
  # force_encoding modifies string, so can’t freeze strings.
4
4
 
5
5
  require "bwrap/output"
6
+ require_relative "exceptions"
6
7
  require_relative "execution"
7
8
 
8
9
  # Methods that performs actual execution logic.
9
10
  #
10
- # @api internal
11
+ # @note This is kind of pseudo-internal API. Hopefully there won’t be breaking changes.
12
+ # But please use {Bwrap::Execution} instead of relying functionality of this class,
13
+ # outside of {.prepend_rootcmd}.
11
14
  class Bwrap::Execution::Execute
12
15
  include Bwrap::Output
13
16