bwrap 1.0.0.pre.alpha3 → 1.0.0.pre.beta2
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +39 -0
- data/README.md +2 -0
- data/lib/bwrap/args/args.rb +5 -1
- data/lib/bwrap/args/bind/library.rb +188 -0
- data/lib/bwrap/args/bind/mime.rb +58 -0
- data/lib/bwrap/args/bind.rb +90 -27
- data/lib/bwrap/args/construct.rb +69 -35
- data/lib/bwrap/args/environment.rb +59 -1
- data/lib/bwrap/args/features.rb +128 -0
- data/lib/bwrap/args/library.rb +137 -0
- data/lib/bwrap/args/machine_id.rb +6 -3
- data/lib/bwrap/args/mount.rb +12 -3
- data/lib/bwrap/bwrap.rb +151 -0
- data/lib/bwrap/bwrap_module.rb +26 -0
- data/lib/bwrap/config/features.rb +116 -0
- data/lib/bwrap/config.rb +130 -17
- data/lib/bwrap/execution/exceptions.rb +24 -0
- data/lib/bwrap/execution/execute.rb +5 -2
- data/lib/bwrap/execution/execution.rb +147 -3
- data/lib/bwrap/execution/labels.rb +8 -1
- data/lib/bwrap/execution/path.rb +84 -0
- data/lib/bwrap/execution.rb +6 -172
- data/lib/bwrap/output/colors.rb +0 -2
- data/lib/bwrap/output/log.rb +11 -5
- data/lib/bwrap/output/output_impl.rb +182 -0
- data/lib/bwrap/output.rb +8 -148
- data/lib/bwrap/version.rb +1 -2
- data/lib/bwrap.rb +1 -72
- data.tar.gz.sig +0 -0
- metadata +18 -21
- metadata.gz.sig +0 -0
- data/lib/bwrap/output/output.rb +0 -8
@@ -1,24 +1,82 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bwrap/execution"
|
3
4
|
require "bwrap/output"
|
4
5
|
require_relative "args"
|
5
6
|
|
6
7
|
# Environment variable calculation for bwrap.
|
7
8
|
class Bwrap::Args::Environment < Hash
|
9
|
+
include Bwrap::Execution
|
8
10
|
include Bwrap::Output
|
9
11
|
|
10
12
|
# Instance of {Config}.
|
11
13
|
attr_writer :config
|
12
14
|
|
13
|
-
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
|
18
|
+
self["PATH"] ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns used environment variables wrapped as bwrap arguments.
|
14
22
|
def environment_variables
|
15
23
|
if debug?
|
16
24
|
debug "Passing following environment variables to bwrap:\n" \
|
17
25
|
"#{self}"
|
18
26
|
end
|
19
27
|
|
28
|
+
env_paths
|
29
|
+
|
20
30
|
map do |key, value|
|
31
|
+
if key == "PATH" and value.respond_to? :join
|
32
|
+
value = value.join ":"
|
33
|
+
end
|
34
|
+
|
21
35
|
[ "--setenv", key, value ]
|
22
36
|
end
|
23
37
|
end
|
38
|
+
|
39
|
+
# @return [Array] All environment paths added via {Config#add_env_path} and other parsing logic
|
40
|
+
def env_paths
|
41
|
+
if @config.env_paths.respond_to? :each
|
42
|
+
self["PATH"] |= @config.env_paths
|
43
|
+
end
|
44
|
+
|
45
|
+
features_env_paths
|
46
|
+
|
47
|
+
self["PATH"]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Adds given paths to PATH environment variable defined in the sandbox.
|
51
|
+
#
|
52
|
+
# @param elements [String, Array] Path(s) to be added added to PATH environment variable
|
53
|
+
def add_to_path elements
|
54
|
+
if elements.respond_to? :each
|
55
|
+
self["PATH"] += elements
|
56
|
+
else
|
57
|
+
# Expecting elements to be single path element as a string.
|
58
|
+
self["PATH"] << elements
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Feature specific environment path handling.
|
63
|
+
private def features_env_paths
|
64
|
+
ruby_env_paths
|
65
|
+
end
|
66
|
+
|
67
|
+
# Ruby feature specific environment path handling.
|
68
|
+
private def ruby_env_paths
|
69
|
+
return unless @config.features.ruby.enabled?
|
70
|
+
return unless @config.features.ruby.gem_env_paths?
|
71
|
+
|
72
|
+
unless command_available? "gem"
|
73
|
+
warn "gem is not installed in the system, so can’t add its bindirs to PATH."
|
74
|
+
return
|
75
|
+
end
|
76
|
+
|
77
|
+
gempath = execvalue %w{ gem environment gempath }
|
78
|
+
gempath.split(":").each do |path|
|
79
|
+
self["PATH"] << "#{path}/bin"
|
80
|
+
end
|
81
|
+
end
|
24
82
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/output"
|
4
|
+
require_relative "args"
|
5
|
+
require_relative "library"
|
6
|
+
|
7
|
+
# Feature parameter construction.
|
8
|
+
#
|
9
|
+
# @see Config::Features
|
10
|
+
class Bwrap::Args::Features < Hash
|
11
|
+
include Bwrap::Output
|
12
|
+
|
13
|
+
# Implementation for Bash feature set.
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
class BashBinds
|
17
|
+
# Mounts stuff like /bin/bash.
|
18
|
+
def bash_mounts
|
19
|
+
mounts = []
|
20
|
+
|
21
|
+
if File.file? "/bin/bash"
|
22
|
+
mounts << "--ro-bind" << "/bin/bash" << "/bin/bash"
|
23
|
+
end
|
24
|
+
if File.file? "/usr/bin/bash"
|
25
|
+
mounts << "--ro-bind" << "/usr/bin/bash" << "/usr/bin/bash"
|
26
|
+
end
|
27
|
+
|
28
|
+
mounts
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Implementation for nscd feature set.
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
class NscdBinds
|
36
|
+
# Custom binds needed by the feature.
|
37
|
+
def custom_binds
|
38
|
+
mounts = []
|
39
|
+
|
40
|
+
# TODO: Probably some path checking is needed here. Or somewhere.
|
41
|
+
# TODO: Since on many systems /var/run is symlinked to /run, that probably should be handled.
|
42
|
+
mounts << "--ro-bind" << "/var/run/nscd" << "/var/run/nscd"
|
43
|
+
|
44
|
+
mounts
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Implementation for Ruby feature set.
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
class RubyBinds
|
52
|
+
# Returns mounts needed by Ruby feature set.
|
53
|
+
attr_reader :mounts
|
54
|
+
|
55
|
+
# Bind system paths so scripts works inside sandbox.
|
56
|
+
def sitedir_mounts
|
57
|
+
mounts = []
|
58
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["sitedir"] << RbConfig::CONFIG["sitedir"]
|
59
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["rubyhdrdir"] << RbConfig::CONFIG["rubyhdrdir"]
|
60
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["rubylibdir"] << RbConfig::CONFIG["rubylibdir"]
|
61
|
+
mounts << "--ro-bind" << RbConfig::CONFIG["vendordir"] << RbConfig::CONFIG["vendordir"]
|
62
|
+
|
63
|
+
mounts
|
64
|
+
end
|
65
|
+
|
66
|
+
# Create binds for required system libraries.
|
67
|
+
#
|
68
|
+
# These are in path like /usr/lib64/ruby/2.5.0/x86_64-linux-gnu/,
|
69
|
+
# and as they are mostly shared libraries, they may have some extra
|
70
|
+
# dependencies that also need to be bound inside the sandbox.
|
71
|
+
def stdlib_mounts stdlib
|
72
|
+
library_mounts = []
|
73
|
+
library = Bwrap::Args::Library.new
|
74
|
+
stdlib.each do |lib|
|
75
|
+
path = "#{RbConfig::CONFIG["rubyarchdir"]}/#{lib}.so"
|
76
|
+
|
77
|
+
library.needed_libraries(path).each do |requisite_library|
|
78
|
+
library_mounts << "--ro-bind" << requisite_library << requisite_library
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
library_mounts
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# `Array` of parameters passed to bwrap.
|
87
|
+
attr_writer :args
|
88
|
+
|
89
|
+
# Instance of {Config}.
|
90
|
+
attr_writer :config
|
91
|
+
|
92
|
+
# Resolves binds required by different features.
|
93
|
+
#
|
94
|
+
# Currently implemented feature sets:
|
95
|
+
# - ruby
|
96
|
+
def feature_binds
|
97
|
+
bash_binds
|
98
|
+
nscd_binds
|
99
|
+
ruby_binds
|
100
|
+
end
|
101
|
+
|
102
|
+
private def bash_binds
|
103
|
+
return unless @config.features.bash.enabled?
|
104
|
+
|
105
|
+
binds = BashBinds.new
|
106
|
+
|
107
|
+
@args.append binds.bash_mounts
|
108
|
+
end
|
109
|
+
|
110
|
+
private def nscd_binds
|
111
|
+
return unless @config.features.nscd.enabled?
|
112
|
+
|
113
|
+
binds = NscdBinds.new
|
114
|
+
|
115
|
+
@args.append binds.custom_binds
|
116
|
+
end
|
117
|
+
|
118
|
+
# @note This does not allow development headers needed for compilation for now.
|
119
|
+
# I’ll look at it after I have an use for it.
|
120
|
+
private def ruby_binds
|
121
|
+
return unless @config.features.ruby.enabled?
|
122
|
+
|
123
|
+
binds = RubyBinds.new
|
124
|
+
|
125
|
+
@args.append binds.sitedir_mounts
|
126
|
+
@args.append binds.stdlib_mounts(@config.features.ruby.stdlib)
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bwrap/execution"
|
4
|
+
require "bwrap/output"
|
5
|
+
require_relative "args"
|
6
|
+
|
7
|
+
# Class to clean up namespace for implementation specific reasons.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class Bwrap::Args::Library
|
11
|
+
include Bwrap::Execution
|
12
|
+
include Bwrap::Output
|
13
|
+
|
14
|
+
# NOTE: This caching can be made more efficient, but need to look at it later, what to do about it.
|
15
|
+
@@needed_libraries_cache ||= []
|
16
|
+
|
17
|
+
# Empties {@@needed_libraries_cache}.
|
18
|
+
def self.clear_needed_libraries_cache
|
19
|
+
@@needed_libraries_cache.clear
|
20
|
+
end
|
21
|
+
|
22
|
+
# Otherwise similar to {#needed_libraries}, but checks used libc to handle musl executables.
|
23
|
+
#
|
24
|
+
# @param executable [String] Path to the executable to find dependencies for
|
25
|
+
def libraries_needed_by executable
|
26
|
+
# %i == interpreter, the library used to load the executable by kernel.
|
27
|
+
# %F == Path to given file.
|
28
|
+
output_format = "%i::SEPARATOR::%F"
|
29
|
+
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} }
|
30
|
+
scanelf_command << executable
|
31
|
+
|
32
|
+
data = execvalue scanelf_command
|
33
|
+
data = data.strip
|
34
|
+
interpreter, _executable_path = data.split "::SEPARATOR::"
|
35
|
+
interpreter = Pathname.new interpreter
|
36
|
+
|
37
|
+
if interpreter.basename.to_s[0..6] == "ld-musl"
|
38
|
+
musl_needed_libraries executable
|
39
|
+
else
|
40
|
+
# For glibc, scanelf can return full paths for us most of time.
|
41
|
+
needed_libraries executable
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
46
|
+
#
|
47
|
+
# @todo Maybe caching should be done here too?
|
48
|
+
def musl_needed_libraries binary_paths
|
49
|
+
trace "Finding musl libraries #{binary_paths} requires"
|
50
|
+
@needed_libraries = []
|
51
|
+
|
52
|
+
if binary_paths.is_a? String
|
53
|
+
binary_paths = [ binary_paths ]
|
54
|
+
end
|
55
|
+
|
56
|
+
binary_paths.each do |binary_path|
|
57
|
+
output = execvalue %W{ ldd #{binary_path} }
|
58
|
+
lines = output.split "\n"
|
59
|
+
_interpreter_line = lines.shift
|
60
|
+
|
61
|
+
lines.each do |line|
|
62
|
+
parse_ldd_line line
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
@needed_libraries
|
67
|
+
end
|
68
|
+
|
69
|
+
# Used by {Bwrap::Args::Bind#libs_command_requires}.
|
70
|
+
#
|
71
|
+
# @param binary_paths [String, Array] one or more paths to be resolved
|
72
|
+
def needed_libraries binary_paths
|
73
|
+
trace "Finding libraries #{binary_paths} requires"
|
74
|
+
@needed_libraries = []
|
75
|
+
|
76
|
+
# %i == interpreter, the library used to load the executable by kernel.
|
77
|
+
output_format = "%F::SEPARATOR::%n"
|
78
|
+
scanelf_command = %W{ scanelf --nobanner --quiet --format #{output_format} --ldcache --needed }
|
79
|
+
|
80
|
+
if binary_paths.is_a? String
|
81
|
+
binary_paths = [ binary_paths ]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Check if the exe is already resolved.
|
85
|
+
binary_paths.delete_if do |binary_path|
|
86
|
+
@@needed_libraries_cache.include? binary_path
|
87
|
+
end
|
88
|
+
|
89
|
+
return [] if binary_paths.empty?
|
90
|
+
|
91
|
+
data = execvalue(scanelf_command + binary_paths)
|
92
|
+
trace "scanelf found following libraries: #{data}"
|
93
|
+
|
94
|
+
lines = data.split "\n"
|
95
|
+
lines.each do |line|
|
96
|
+
parse_scanelf_line line
|
97
|
+
end
|
98
|
+
|
99
|
+
@needed_libraries
|
100
|
+
end
|
101
|
+
|
102
|
+
# Used by {#needed_libraries}.
|
103
|
+
private def parse_scanelf_line line
|
104
|
+
binary_path, libraries_line = line.split "::SEPARATOR::"
|
105
|
+
libraries = libraries_line.split ","
|
106
|
+
|
107
|
+
(@needed_libraries & libraries).each do |library|
|
108
|
+
verb "Binding #{library} as dependency of #{binary_path}"
|
109
|
+
end
|
110
|
+
|
111
|
+
@needed_libraries |= libraries
|
112
|
+
|
113
|
+
# Also check if requisite libraries needs some libraries.
|
114
|
+
inner = Bwrap::Args::Library.new
|
115
|
+
@needed_libraries |= inner.needed_libraries libraries
|
116
|
+
|
117
|
+
@@needed_libraries_cache |= libraries
|
118
|
+
end
|
119
|
+
|
120
|
+
# Used by {#musl_needed_libraries}.
|
121
|
+
private def parse_ldd_line line
|
122
|
+
line = line.strip
|
123
|
+
_library_name, library_data = line.split " => "
|
124
|
+
|
125
|
+
matches = library_data.match(/(.*) \(0x[0-9a-f]+\)/)
|
126
|
+
library_path = matches[1]
|
127
|
+
|
128
|
+
unless @needed_libraries.include? library_path
|
129
|
+
@needed_libraries << library_path
|
130
|
+
end
|
131
|
+
|
132
|
+
# Also check if requisite libraries needs some libraries.
|
133
|
+
inner = Bwrap::Args::Library.new
|
134
|
+
@needed_libraries |= inner.musl_needed_libraries library_path
|
135
|
+
end
|
136
|
+
end
|
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
|
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.
|
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
|
|
data/lib/bwrap/args/mount.rb
CHANGED
@@ -4,21 +4,30 @@ require_relative "args"
|
|
4
4
|
|
5
5
|
# Bind arguments for bwrap.
|
6
6
|
module Bwrap::Args::Mount
|
7
|
+
# Arguments for readwrite-binding {Config#root} as /.
|
8
|
+
private def root_mount
|
9
|
+
return unless @config.root
|
10
|
+
|
11
|
+
debug "Binding #{@config.root} as /"
|
12
|
+
@args.append %W{ --bind #{@config.root} / }
|
13
|
+
@args.append %w{ --chdir / }
|
14
|
+
end
|
15
|
+
|
7
16
|
# Arguments for mounting devtmpfs to /dev.
|
8
17
|
private def dev_mount
|
9
18
|
debug "Mounting new devtmpfs to /dev"
|
10
|
-
%w{ --dev /dev }
|
19
|
+
@args.append %w{ --dev /dev }
|
11
20
|
end
|
12
21
|
|
13
22
|
# Arguments for mounting procfs to /proc.
|
14
23
|
private def proc_mount
|
15
24
|
debug "Mounting new procfs to /proc"
|
16
|
-
%w{ --proc /proc }
|
25
|
+
@args.append %w{ --proc /proc }
|
17
26
|
end
|
18
27
|
|
19
28
|
# Arguments for mounting tmpfs to /tmp.
|
20
29
|
private def tmp_as_tmpfs
|
21
30
|
debug "Mounting tmpfs to /tmp"
|
22
|
-
%w{ --tmpfs /tmp }
|
31
|
+
@args.append %w{ --tmpfs /tmp }
|
23
32
|
end
|
24
33
|
end
|
data/lib/bwrap/bwrap.rb
ADDED
@@ -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
|