bwrap 1.0.0.pre.beta1 → 1.1.0.pre.rc1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db6e7253c0a896975954c0d649c68321958ade750f891f353ba30b9ea58880cb
4
- data.tar.gz: 90f384499e8727660b9810711e0237ce604f8ef219ed415c210db16bcd764804
3
+ metadata.gz: a8b6393a69ed3aed4509adc16eb3f1cd6a91e0035d8460ab4a83b89aad6556c6
4
+ data.tar.gz: 4d6b6482993d86b2f481b5bc941ac7ff4186f3393be11f7aa8b28aa7670218f5
5
5
  SHA512:
6
- metadata.gz: 03e6873b068e52bc0c9fbbc072f9fc1a411696ca3c09aabcee05c8e660e5a210030c13fab84348aee720e7bd431600a0b18c3be124dfcb955ac95c250d83aeec
7
- data.tar.gz: 4183575c47d740dd74c88995add7b87366299e75b4a8edaa89c20d422cd73cbd957b411e5bd51b9c9eabcd3881d8af1ba85922ce806b2387d75a0f30d8abd377
6
+ metadata.gz: 04c68f504070bc0f1b5e4b6140430ce568c3c4aef5c3a61a62370c67e71638cd8e1ea5c0b410cc3852056165770af48758402c684b7d8887c127ea8986bfba4a
7
+ data.tar.gz: e0ae2b57a5f7b131754a984351af597c5881bee8cc6464db11eaf58cd6fe057abb82846fa433592ae199790678ff854ebca7de8db667948bac914b41a0ad5bb5
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changes
2
2
 
3
+ ## 1.1.0-rc1 (28.05.2022)
4
+
5
+ * Added info log level
6
+ * Added --quiet cli argument
7
+ * Added more command and output to ExecutionFailed exception
8
+ * Use script’s ruby version to load libraries
9
+
10
+ ## 1.0.0 (16.04.2022)
11
+
12
+ * Handle invalid output to loggers
13
+
14
+ ## 1.0.0-beta2 (02.02.2022)
15
+
16
+ * Added nscd feature
17
+ * Added gem_env_paths to ruby feature
18
+ * If Config#root is set, set working directory to /
19
+ * Execution#execvalue: Allow setting log: true
20
+ * Execution#execvalue: pass all kwargs as kwargs to execute()
21
+ * Output::Log: Don’t die if log file can’t be written to
22
+
3
23
  ## 1.0.0-beta1 (12.12.2021)
4
24
 
5
25
  * optimist gem is now optional dependency
@@ -8,5 +8,40 @@ require "bwrap/version"
8
8
  # In future, there may be some use for classes inside here, but for now they are
9
9
  # only used internally.
10
10
  module Bwrap::Args
11
- # Nya.
11
+ # Used as container for arguments constructed via {Construct}.
12
+ #
13
+ # Where {Hash} defaults to nil as default argument, `Args` defaults to
14
+ # {Array}.
15
+ class Args < Hash
16
+ # Creates new instance of a hash for storing arguments.
17
+ #
18
+ # Where {Hash} defaults to nil as default argument, `Args` defaults to
19
+ # `[]`.
20
+ #
21
+ # @see Hash#initialize
22
+ def initialize(*args)
23
+ if args.empty? and !block_given?
24
+ super(*args) { [] }
25
+ else
26
+ super(*args)
27
+ end
28
+ end
29
+
30
+ # Adds given data to array identified by given type.
31
+ #
32
+ # Following types are meant to be used, though everything is accepted:
33
+ # - :mount
34
+ #
35
+ # @param type [Symbol] Type of the argument
36
+ # @returns self
37
+ def add(type, *data)
38
+ if data.respond_to? :each
39
+ self[type] += data.flatten
40
+ else
41
+ self[type] << data
42
+ end
43
+
44
+ self
45
+ end
46
+ end
12
47
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Ruby feature implementation specific class.
4
+ #
5
+ # @api private
6
+ class Bwrap::Args::Bind::Library::RubyBinds
7
+ # Instance of {Bwrap::Config}.
8
+ attr_writer :config
9
+
10
+ def initialize args
11
+ @args = args
12
+ end
13
+
14
+ def ruby_binds_for_features
15
+ return unless @config and @config.features.ruby.enabled?
16
+
17
+ @mounts = []
18
+
19
+ # Mount some common Ruby executables.
20
+
21
+ # This is most often /usr/bin.
22
+ bindir = Pathname.new @config.features.ruby.ruby_config["bindir"]
23
+
24
+ bind_ruby_executable
25
+ gem_binds bindir
26
+
27
+ @args.add :library_feature_binds, @mounts
28
+ end
29
+
30
+ private def bind_ruby_executable
31
+ path = @config.features.ruby.interpreter
32
+ raise "Ruby interpreter “#{path}” not found." unless File.exist? path
33
+
34
+ @mounts << "--ro-bind" << path.to_s << path.to_s
35
+ end
36
+
37
+ private def gem_binds bindir
38
+ return unless @config.features.ruby.gem_env_paths?
39
+
40
+ path = bindir / "gem"
41
+ return unless File.exist? path
42
+
43
+ @mounts << "--ro-bind" << path.to_s << path.to_s
44
+ end
45
+ end
@@ -8,11 +8,21 @@ require_relative "mime"
8
8
  class Bwrap::Args::Bind
9
9
  # TODO: documentation
10
10
  #
11
+ # TODO: It may be that this should be renamed to “Binary” or ”Executable”, as this
12
+ # handles all binaries, not just libraries.
13
+ #
11
14
  # @api private
12
15
  class Library
16
+ # Requires are here so there is no extra trickiness with namespaces.
17
+ #
18
+ # Feature implementations are not meant to be used outside of this class anyway.
19
+ require_relative "library/ruby_binds"
20
+
13
21
  include Bwrap::Execution::Path
14
22
  include Bwrap::Output
15
23
 
24
+ # The command given to {Bwrap#run}.
25
+ #
16
26
  # @see Bwrap::Args::Construct#command=
17
27
  #
18
28
  # @see (see Bwrap::Args::Construct#command=)
@@ -39,22 +49,22 @@ class Bwrap::Args::Bind
39
49
  @executable_name = resolve_executable_name executable
40
50
  @executable_path = resolve_executable_path @executable_name, not_inside_root: true
41
51
 
42
- @args.append %W{ --ro-bind #{@executable_path} #{@executable_path} }
52
+ @args.add :extra_executable_mounts, %W{ --ro-bind #{@executable_path} #{@executable_path} }
43
53
 
44
54
  resolve_executable_libraries
45
55
  end
46
56
  end
47
57
 
48
- # Convenience method to call {#resolve_executable_libraries}.
58
+ # Checks the command given to {Bwrap#run} and adds the libraries it needs.
49
59
  #
50
- # Used by {#handle_system_mounts}.
51
- def libs_command_requires
60
+ # Convenience method to call {#resolve_executable_libraries}.
61
+ def handle_given_command
52
62
  @executable_name = resolve_executable_name @command
53
63
  @executable_path = resolve_executable_path @executable_name
54
64
 
55
65
  # Actually add the executable to be bound to the sandbox.
56
66
  unless @config&.command_inside_root
57
- @args.append %W{ --ro-bind #{@executable_path} #{@executable_path} }
67
+ @args.add :given_command, %W{ --ro-bind #{@executable_path} #{@executable_path} }
58
68
  end
59
69
 
60
70
  resolve_executable_libraries
@@ -68,7 +78,7 @@ class Bwrap::Args::Bind
68
78
  # @todo Ensure scanelf is available (and throw proper error if it is not, telling to not use
69
79
  # full_system_mounts option.)
70
80
  def resolve_executable_libraries
71
- trace "Resolving executable libraries of #{@executable_path}"
81
+ debug "Resolving executable libraries of #{@executable_path}"
72
82
 
73
83
  # TODO: Put this behind additional flag for extra control/sanity.
74
84
  # Some executables are shell scripts and similar. For them we need to use the interpreter.
@@ -76,6 +86,17 @@ class Bwrap::Args::Bind
76
86
  mime = Mime.new @executable_name, @executable_path
77
87
  return unless mime.resolve_mime_type
78
88
 
89
+ # TODO: Ideally mime stuff should be handled as config,
90
+ # but then shebang parsing logic would be necessary to move to config classes.
91
+ #
92
+ # That may make sense, but for now this is here.
93
+ #
94
+ # This basically allows features to use mime data to get for example path to necessary interpreter.
95
+ #
96
+ # This way there is possibility that wrong mime information would be used,
97
+ # as this thing is more generalized.
98
+ @config.features.mime = mime if @config&.features
99
+
79
100
  # Then find out required libraries
80
101
 
81
102
  library_mounts = []
@@ -89,10 +110,20 @@ class Bwrap::Args::Bind
89
110
  library_mounts << "--ro-bind" << library << library
90
111
  end
91
112
 
92
- @args.append library_mounts
113
+ @args.add :extra_executable_libraries, library_mounts
114
+ end
115
+
116
+ # Some features, like {Bwrap::Config::Features::Nscd}, requires some binds
117
+ # in order to operate properly.
118
+ def binds_for_features
119
+ # NOTE: Still nothing here, as I think this is better for library binds than anything else.
120
+ # The nscd bind is better in another, more generic, place.
121
+ #
122
+ # Keeping this method because I think this really makes sense for structure, in future.
123
+
124
+ ruby_binds_for_features
93
125
  end
94
126
 
95
- # Used by {#libs_command_requires}.
96
127
  private def resolve_executable_name command
97
128
  if command.is_a? String
98
129
  return command
@@ -107,8 +138,6 @@ class Bwrap::Args::Bind
107
138
  end
108
139
 
109
140
  # @warning Requires environment paths to be resolved beforehand.
110
- #
111
- # Used by {#libs_command_requires}.
112
141
  private def resolve_executable_path executable_name, not_inside_root: nil
113
142
  if @config&.command_inside_root.nil? or not_inside_root
114
143
  return which executable_name
@@ -121,5 +150,13 @@ class Bwrap::Args::Bind
121
150
 
122
151
  which executable_name, env_path_var: env_path
123
152
  end
153
+
154
+ private def ruby_binds_for_features
155
+ return unless @config.features.ruby.enabled?
156
+
157
+ binds = RubyBinds.new @args
158
+ binds.config = @config
159
+ binds.ruby_binds_for_features
160
+ end
124
161
  end
125
162
  end
@@ -22,12 +22,13 @@ class Bwrap::Args::Bind
22
22
  @executable_path = executable_path
23
23
  end
24
24
 
25
- # Used by {Bwrap::Args::Bind::Library#libs_command_requires}.
25
+ # Checks if target executable is a script, in which case executable
26
+ # is parsed from a shebang line, if found.
26
27
  #
27
28
  # @return false if caller should also return
28
29
  def resolve_mime_type
29
30
  mime_type = execvalue %W{ file --brief --mime-type #{@executable_path} }
30
- trace "Mime type of #{@executable_path} is #{mime_type}"
31
+ debug "Mime type of #{@executable_path} is #{mime_type}"
31
32
  return true unless mime_type[0..6] == "text/x-"
32
33
 
33
34
  shebang = File.open @executable_path, &:readline
@@ -42,7 +43,11 @@ class Bwrap::Args::Bind
42
43
  true
43
44
  end
44
45
 
46
+ # Parses shebang line to find out path to actual executable
47
+ # used to run the script.
45
48
  private def resolve_real_executable shebang
49
+ #trace "Figuring out correct executable from shebang #{shebang}"
50
+
46
51
  command_line = shebang.delete_prefix("#!").strip
47
52
  real_executable, args = command_line.split " ", 2
48
53
 
@@ -52,6 +57,8 @@ class Bwrap::Args::Bind
52
57
  real_executable = which executable_name
53
58
  end
54
59
 
60
+ debug "Parsed #{real_executable} from the script’s shebang. Using as executable."
61
+
55
62
  @executable_path = real_executable
56
63
  end
57
64
  end
@@ -13,6 +13,8 @@ class Bwrap::Args::Bind
13
13
  # Array of parameters passed to bwrap.
14
14
  attr_writer :args
15
15
 
16
+ # The command given to {Bwrap#run}.
17
+ #
16
18
  # @see Bwrap::Args::Construct#command=
17
19
  #
18
20
  # @see (see Bwrap::Args::Construct#command=)
@@ -26,17 +28,17 @@ class Bwrap::Args::Bind
26
28
 
27
29
  # Arguments to bind /dev/dri from host to sandbox.
28
30
  def bind_dev_dri
29
- @args.append %w{ --dev-bind /dev/dri /dev/dri }
31
+ @args.add :dev_mounts, %w{ --dev-bind /dev/dri /dev/dri }
30
32
  end
31
33
 
32
34
  # Arguments to bind /sys/dev/char from host to sandbox.
33
35
  def bind_sys_dev_char
34
- @args.append %w{ --ro-bind /sys/dev/char /sys/dev/char }
36
+ @args.add :dev_mounts, %w{ --ro-bind /sys/dev/char /sys/dev/char }
35
37
  end
36
38
 
37
39
  # Arguments to bind /sys/devices/pci0000:00 from host to sandbox.
38
40
  def bind_pci_devices
39
- @args.append %w{ --ro-bind /sys/devices/pci0000:00 /sys/devices/pci0000:00 }
41
+ @args.add :dev_mounts, %w{ --ro-bind /sys/devices/pci0000:00 /sys/devices/pci0000:00 }
40
42
  end
41
43
 
42
44
  # Arguments to bind home directory from sandbox directory (`#{@config.sandbox_directory}/home`)
@@ -55,7 +57,23 @@ class Bwrap::Args::Bind
55
57
  @environment["HOME"] = "/home/#{@config.user}"
56
58
 
57
59
  debug "Using #{home_directory} as /home/#{@config.user}"
58
- @args.append %W{ --bind #{home_directory} /home/#{@config.user} }
60
+ @args.add :home_directory, %W{ --bind #{home_directory} /home/#{@config.user} }
61
+ end
62
+
63
+ # Handle command passed to Bwrap#run.
64
+ #
65
+ # Allows subsequent actions to utilize the command.
66
+ def handle_given_command
67
+ construct_library_bind
68
+
69
+ # I’m not completely sure this is a good idea. Maybe only dependent libraries
70
+ # should be skipped and the actual executable should still be checked?
71
+ #
72
+ # Or maybe the data should be calculated and these are excluded in
73
+ # Construct#bwrap_arguments?
74
+ return unless @config.full_system_mounts
75
+
76
+ @library_bind.handle_given_command
59
77
  end
60
78
 
61
79
  # Arguments to read-only bind whole system inside sandbox.
@@ -67,7 +85,7 @@ class Bwrap::Args::Bind
67
85
  end
68
86
  @environment.add_to_path binaries_from
69
87
 
70
- @args.append bindir_mounts
88
+ @args.add :bindir, bindir_mounts
71
89
 
72
90
  if debug?
73
91
  debug "Using following bindir mounts:\n" \
@@ -77,13 +95,9 @@ class Bwrap::Args::Bind
77
95
 
78
96
  libdir_mounts
79
97
 
80
- library_bind = construct_library_bind
81
-
82
- library_bind.extra_executables_mounts
83
-
84
- return unless @config.full_system_mounts
85
-
86
- library_bind.libs_command_requires
98
+ binds_for_features
99
+ @library_bind.binds_for_features
100
+ @library_bind.extra_executables_mounts
87
101
  end
88
102
 
89
103
  # These are something user can specify to do custom --ro-bind binds.
@@ -95,7 +109,7 @@ class Bwrap::Args::Bind
95
109
  binds << "--ro-bind" << source_path.to_s << destination_path.to_s
96
110
  end
97
111
 
98
- @args.append binds
112
+ @args.add :custom_ro_binds, binds unless binds.empty?
99
113
  end
100
114
 
101
115
  # Performs cleanup operations after execution.
@@ -120,7 +134,7 @@ class Bwrap::Args::Bind
120
134
  "(Odd is key, even is value)"
121
135
  end
122
136
 
123
- @args.append libdir_mounts
137
+ @args.add :libdir, libdir_mounts
124
138
  end
125
139
 
126
140
  private def construct_library_bind
@@ -129,6 +143,11 @@ class Bwrap::Args::Bind
129
143
  library_bind.config = @config
130
144
  library_bind.environment = @environment
131
145
 
132
- library_bind
146
+ @library_bind = library_bind
147
+ end
148
+
149
+ # Binds feature specific common directories.
150
+ private def binds_for_features
151
+ # Nya.
133
152
  end
134
153
  end
@@ -3,11 +3,13 @@
3
3
  require "tempfile"
4
4
 
5
5
  require "bwrap/output"
6
+ require_relative "args"
6
7
  require_relative "bind"
7
8
  require_relative "environment"
8
9
  require_relative "features"
9
10
  require_relative "machine_id"
10
11
  require_relative "mount"
12
+ require_relative "network"
11
13
 
12
14
  # Constructs arguments for bwrap execution.
13
15
  class Bwrap::Args::Construct
@@ -25,16 +27,27 @@ class Bwrap::Args::Construct
25
27
  # @param value [Array, String] Command with arguments
26
28
  attr_writer :command
27
29
 
28
- # Constructs arguments for bwrap execution.
29
- def construct_bwrap_args
30
- @args = []
30
+ def initialize
31
+ # If a key is not found, it is initialized with an empty array.
32
+ @args = Bwrap::Args::Args.new
33
+ end
34
+
35
+ # Parses data given with {Config} so it can be outputted in proper
36
+ # order by {#bwrap_arguments}.
37
+ #
38
+ # @note Command given to {Bwrap#run} is set to {Bind#command}.
39
+ def calculate
31
40
  create_objects
32
41
 
42
+ # If necessary, first handle command passed to Bwrap#run so feature binds can utilize
43
+ # the command.
44
+ @bind.handle_given_command
45
+
33
46
  root_mount
34
47
  xauthority_args
35
48
  machine_id = @machine_id.machine_id
36
- @args.append machine_id if machine_id
37
- resolv_conf
49
+ @args.add :machine_id, machine_id if machine_id
50
+ @network.resolv_conf
38
51
  @bind.handle_system_mounts
39
52
  @features.feature_binds
40
53
  @bind.custom_read_only_binds
@@ -47,14 +60,62 @@ class Bwrap::Args::Construct
47
60
  proc_mount
48
61
  tmp_as_tmpfs
49
62
  @bind.bind_home_directory
50
- @args.append "--unshare-all"
51
- share_net
52
- hostname
53
- @args.append @environment.environment_variables
54
- @args.append "--die-with-parent"
55
- @args.append "--new-session"
56
-
57
- @args.compact
63
+ @args.add :unshare_all, "--unshare-all" # Practically means that there would be nothing in the sandbox by default.
64
+ @network.share_net
65
+ @network.hostname
66
+ @args.add :environment, @environment.environment_variables
67
+ @args.add :die_with_parent, "--die-with-parent" # For security, and as intuition says how things should work.
68
+ @args.add :new_session, "--new-session" # Very important for security.
69
+ end
70
+
71
+ # Returns arguments to pass to bwrap.
72
+ #
73
+ # @note Command given to {Bwrap#run} is set to {Bind#command}.
74
+ def bwrap_arguments
75
+ args = []
76
+
77
+ # @args.fetch() could be used here to ensure the key is present, so catching some extra typos,
78
+ # but for now it is not used, for convenience.
79
+
80
+ args += @args[:root_mount]
81
+ args += @args[:xauthority]
82
+ args += @args[:machine_id]
83
+ args += @args[:resolv_conf]
84
+
85
+ # bind.rb
86
+ args += @args[:bindir]
87
+ args += @args[:libdir]
88
+
89
+ # This is what is given to Bwrap#run.
90
+ args += @args[:given_command]
91
+
92
+ args += @args[:extra_executable_libraries]
93
+ args += @args[:library_feature_binds]
94
+ args += @args[:extra_executable_mounts]
95
+
96
+ args += @args[:feature_binds]
97
+
98
+ args += @args[:custom_ro_binds]
99
+ args += @args[:user_dir]
100
+
101
+ args += @args[:audio]
102
+ args += @args[:dev_mounts]
103
+ args += @args[:proc_mount]
104
+ args += @args[:tmp_mount]
105
+
106
+ args += @args[:home_directory]
107
+
108
+ args += @args[:unshare_all]
109
+
110
+ args += @args[:network]
111
+
112
+ args += @args[:hostname]
113
+ args += @args[:environment]
114
+
115
+ args += @args[:die_with_parent]
116
+ args += @args[:new_session]
117
+
118
+ args.compact
58
119
  end
59
120
 
60
121
  # Performs cleanup operations after execution.
@@ -80,6 +141,9 @@ class Bwrap::Args::Construct
80
141
 
81
142
  @machine_id = Bwrap::Args::MachineId.new
82
143
  @machine_id.config = @config
144
+
145
+ @network = Bwrap::Args::Network.new @args
146
+ @network.config = @config
83
147
  end
84
148
 
85
149
  # Arguments for generating .Xauthority file.
@@ -88,23 +152,13 @@ class Bwrap::Args::Construct
88
152
 
89
153
  xauth_args = %W{ --ro-bind #{Dir.home}/.Xauthority #{Dir.home}/.Xauthority }
90
154
  debug "Binding following .Xauthority file: #{Dir.home}/.Xauthority"
91
- @args.append xauth_args
92
- end
93
-
94
- # Arguments to read-only bind /etc/resolv.conf.
95
- private def resolv_conf
96
- # We can’t really bind symlinks, so let’s resolve real path to resolv.conf, in case it is symlinked.
97
- source_resolv_conf = Pathname.new "/etc/resolv.conf"
98
- source_resolv_conf = source_resolv_conf.realpath
99
-
100
- debug "Binding #{source_resolv_conf} as /etc/resolv.conf"
101
- @args.append %W{ --ro-bind #{source_resolv_conf} /etc/resolv.conf }
155
+ @args.add :xauthority, xauth_args
102
156
  end
103
157
 
104
158
  # Arguments to create `/run/user/#{uid}`.
105
159
  private def create_user_dir
106
160
  trace "Creating directory /run/user/#{uid}"
107
- @args.append %W{ --dir /run/user/#{uid} }
161
+ @args.add :user_dir, %W{ --dir /run/user/#{uid} }
108
162
  end
109
163
 
110
164
  # Arguments to bind necessary pulseaudio data for audio support.
@@ -112,23 +166,7 @@ class Bwrap::Args::Construct
112
166
  return unless @config.audio.include? :pulseaudio
113
167
 
114
168
  debug "Binding pulseaudio"
115
- @args.append %W{ --ro-bind /run/user/#{uid}/pulse /run/user/#{uid}/pulse }
116
- end
117
-
118
- # Arguments to allow network connection inside sandbox.
119
- private def share_net
120
- return unless @config.share_net
121
-
122
- verb "Sharing network"
123
- @args.append %w{ --share-net }
124
- end
125
-
126
- # Arguments to set hostname to whatever is configured.
127
- private def hostname
128
- return unless @config.hostname
129
-
130
- debug "Setting hostname to #{@config.hostname}"
131
- @args.append %W{ --hostname #{@config.hostname} }
169
+ @args.add :audio, %W{ --ro-bind /run/user/#{uid}/pulse /run/user/#{uid}/pulse }
132
170
  end
133
171
 
134
172
  # Returns current user id.
@@ -1,15 +1,23 @@
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
 
15
+ def initialize
16
+ super
17
+
18
+ self["PATH"] ||= []
19
+ end
20
+
13
21
  # Returns used environment variables wrapped as bwrap arguments.
14
22
  def environment_variables
15
23
  if debug?
@@ -31,11 +39,11 @@ class Bwrap::Args::Environment < Hash
31
39
  # @return [Array] All environment paths added via {Config#add_env_path} and other parsing logic
32
40
  def env_paths
33
41
  if @config.env_paths.respond_to? :each
34
- self["PATH"] ||= []
35
-
36
42
  self["PATH"] |= @config.env_paths
37
43
  end
38
44
 
45
+ features_env_paths
46
+
39
47
  self["PATH"]
40
48
  end
41
49
 
@@ -43,8 +51,6 @@ class Bwrap::Args::Environment < Hash
43
51
  #
44
52
  # @param elements [String, Array] Path(s) to be added added to PATH environment variable
45
53
  def add_to_path elements
46
- self["PATH"] ||= []
47
-
48
54
  if elements.respond_to? :each
49
55
  self["PATH"] += elements
50
56
  else
@@ -52,4 +58,25 @@ class Bwrap::Args::Environment < Hash
52
58
  self["PATH"] << elements
53
59
  end
54
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
55
82
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @abstract
4
+ #
5
+ # Base class for binds.
6
+ #
7
+ # @api private
8
+ class Bwrap::Args::Features::BindsBase
9
+ # @param config [Config] Instance of Config.
10
+ def initialize config
11
+ @config = config
12
+ end
13
+ end