exec_sandbox 0.1.2 → 0.1.3

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.
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source :rubygems
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  # gem 'activesupport', '>= 2.3.5'
5
- gem 'ffi', '>= 1.0.9'
5
+ gem 'ffi', '>= 1.0.11'
6
6
 
7
7
  # Add dependencies to develop your gem here.
8
8
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -2,26 +2,26 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  diff-lcs (1.1.3)
5
- ffi (1.0.9)
5
+ ffi (1.0.11)
6
6
  git (1.2.5)
7
7
  jeweler (1.6.4)
8
8
  bundler (~> 1.0)
9
9
  git (>= 1.2.5)
10
10
  rake
11
- json (1.6.1)
12
- rake (0.9.2)
11
+ json (1.6.3)
12
+ rake (0.9.2.2)
13
13
  rcov (0.9.11)
14
- rdoc (3.10)
14
+ rdoc (3.12)
15
15
  json (~> 1.4)
16
- rspec (2.6.0)
17
- rspec-core (~> 2.6.0)
18
- rspec-expectations (~> 2.6.0)
19
- rspec-mocks (~> 2.6.0)
20
- rspec-core (2.6.4)
21
- rspec-expectations (2.6.0)
16
+ rspec (2.7.0)
17
+ rspec-core (~> 2.7.0)
18
+ rspec-expectations (~> 2.7.0)
19
+ rspec-mocks (~> 2.7.0)
20
+ rspec-core (2.7.1)
21
+ rspec-expectations (2.7.0)
22
22
  diff-lcs (~> 1.1.2)
23
- rspec-mocks (2.6.0)
24
- yard (0.7.2)
23
+ rspec-mocks (2.7.0)
24
+ yard (0.7.4)
25
25
  yard-rspec (0.1)
26
26
  yard
27
27
 
@@ -30,7 +30,7 @@ PLATFORMS
30
30
 
31
31
  DEPENDENCIES
32
32
  bundler (>= 1.0.21)
33
- ffi (>= 1.0.9)
33
+ ffi (>= 1.0.11)
34
34
  jeweler (>= 1.6.4)
35
35
  rcov
36
36
  rdoc (>= 3.10)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
data/exec_sandbox.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "exec_sandbox"
8
- s.version = "0.1.2"
8
+ s.version = "0.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Victor Costan"]
12
- s.date = "2011-10-13"
12
+ s.date = "2011-12-20"
13
13
  s.description = "Temporary users and groups, rlimits"
14
14
  s.email = "costan@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -56,7 +56,7 @@ Gem::Specification.new do |s|
56
56
  s.specification_version = 3
57
57
 
58
58
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
59
- s.add_runtime_dependency(%q<ffi>, [">= 1.0.9"])
59
+ s.add_runtime_dependency(%q<ffi>, [">= 1.0.11"])
60
60
  s.add_development_dependency(%q<rdoc>, [">= 3.10"])
61
61
  s.add_development_dependency(%q<rspec>, [">= 2.6.0"])
62
62
  s.add_development_dependency(%q<yard>, [">= 0.7.2"])
@@ -65,7 +65,7 @@ Gem::Specification.new do |s|
65
65
  s.add_development_dependency(%q<jeweler>, [">= 1.6.4"])
66
66
  s.add_development_dependency(%q<rcov>, [">= 0"])
67
67
  else
68
- s.add_dependency(%q<ffi>, [">= 1.0.9"])
68
+ s.add_dependency(%q<ffi>, [">= 1.0.11"])
69
69
  s.add_dependency(%q<rdoc>, [">= 3.10"])
70
70
  s.add_dependency(%q<rspec>, [">= 2.6.0"])
71
71
  s.add_dependency(%q<yard>, [">= 0.7.2"])
@@ -75,7 +75,7 @@ Gem::Specification.new do |s|
75
75
  s.add_dependency(%q<rcov>, [">= 0"])
76
76
  end
77
77
  else
78
- s.add_dependency(%q<ffi>, [">= 1.0.9"])
78
+ s.add_dependency(%q<ffi>, [">= 1.0.11"])
79
79
  s.add_dependency(%q<rdoc>, [">= 3.10"])
80
80
  s.add_dependency(%q<rspec>, [">= 2.6.0"])
81
81
  s.add_dependency(%q<yard>, [">= 0.7.2"])
@@ -6,6 +6,9 @@ class Sandbox
6
6
  # The path to the sandbox's working directory.
7
7
  attr_reader :path
8
8
 
9
+ # The un-privileged user that execs sandboxed binaries.
10
+ attr_reader :user_name
11
+
9
12
  # Empty sandbox.
10
13
  #
11
14
  # @param [String] admin the name of a user who will be able to peek into the
@@ -142,6 +145,17 @@ class Sandbox
142
145
  def finalize
143
146
  close
144
147
  end
148
+
149
+ # Removes temporary users created by old sandboxes.
150
+ #
151
+ # Sandboxes usually clean up after themselves. For the rare circumstances
152
+ # where that doesn't happen (VM crash, Ctrl+C, SIGKILL), this method finds and
153
+ # cleans up the temporary users created for sandboxing.
154
+ #
155
+ # @return [Array<String>] the names of the deleted users
156
+ def self.cleanup
157
+ Users.destroy_temps
158
+ end
145
159
  end # module ExecSandbox::Sandbox
146
160
 
147
161
  # Creates a sandbox, yields it, and destroys it.
@@ -8,6 +8,8 @@ module ExecSandbox
8
8
  module Users
9
9
  # Creates an unprivileged user.
10
10
  #
11
+ # @param [String] prefix used at the beginning of temporary user names to
12
+ # help identify the application that created the users
11
13
  # @return [String] the user's name
12
14
  def self.temp(prefix = 'xsbx.rb')
13
15
  loop do
@@ -81,10 +83,12 @@ module Users
81
83
 
82
84
  else # Linux
83
85
  if group_id
84
- command = ['useradd', '--gid', group_id.to_s,
85
- '--no-create-home', '--no-user-group', user_name]
86
+ command = ['useradd', '--gid', group_id.to_s, '--no-user-group',
87
+ '--no-create-home', '--system',
88
+ '--comment', 'exec_sandbox.rb temporary user', user_name]
86
89
  else
87
- command = ['useradd', '--no-create-home', user_name]
90
+ command = ['useradd', '--user-group', '--no-create-home', '--system',
91
+ '--comment', 'exec_sandbox.rb temporary user', user_name]
88
92
  end
89
93
  unless Kernel.system(*command)
90
94
  raise RuntimeError, "User creation failed at #{command.inspect}!"
@@ -151,6 +155,29 @@ module Users
151
155
  end
152
156
  end # RUBY_PLATFORM
153
157
  end
158
+
159
+ # Finds users whose names match a String or Regexp pattern.
160
+ #
161
+ # @param [String] pattern matched against user names using ===
162
+ # @return [Array<String>] names of users
163
+ def self.named(pattern)
164
+ users = []
165
+ Etc.passwd do |user|
166
+ users << user.name if pattern === user.name
167
+ end
168
+ users
169
+ end
170
+
171
+ # Destroys users created by temp.
172
+ #
173
+ # @param [String] prefix match the prefix given to temp
174
+ # @return [Array<String>] names of users that were deleted
175
+ def self.destroy_temps(prefix = 'xsbx.rb')
176
+ # Matches the names created by temp.
177
+ pattern = /^#{prefix}\-[0-9a-f]+\.[0-9a-f]+\.[0-9a-f]+$/
178
+ # Each returns the collection that it iterates over.
179
+ self.named(pattern).each { |name| destroy name }
180
+ end
154
181
  end # module ExecSandbox::Users
155
182
 
156
183
  end # namespace ExecSandbox
@@ -154,4 +154,24 @@ describe ExecSandbox::Sandbox do
154
154
  end
155
155
  end
156
156
  end
157
+
158
+ describe '#cleanup' do
159
+ describe 'in a system with an open sandbox' do
160
+ before do
161
+ @all_users = ExecSandbox::Users.named(/.*/).sort
162
+
163
+ @sandbox = ExecSandbox.open
164
+ @removed = ExecSandbox::Sandbox.cleanup
165
+ end
166
+
167
+ it 'should not remove the sandbox user' do
168
+ ExecSandbox::Users.named(/.*/).sort.should == @all_users
169
+ end
170
+
171
+ it 'should return an array with the sandbox user' do
172
+ @removed.should == [@sandbox.user_name]
173
+ end
174
+ end
175
+
176
+ end
157
177
  end
@@ -3,6 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
3
  describe ExecSandbox::Users do
4
4
  let(:test_user) { 'exec_sandbox_rspec' }
5
5
  let(:test_group) { Etc.getgrgid(Etc.getpwnam(Etc.getlogin).gid).name }
6
+ let(:current_user) { Etc.getlogin }
6
7
 
7
8
  describe '#temp' do
8
9
  before { @user_name = ExecSandbox::Users.temp 'exsbx.rspec' }
@@ -122,4 +123,76 @@ describe ExecSandbox::Users do
122
123
  end
123
124
  end
124
125
  end
126
+
127
+ describe '#named' do
128
+ describe 'with non-matching RegExp' do
129
+ it 'should not return any user' do
130
+ ExecSandbox::Users.named(/exec_sandbox_rspec/).should be_empty
131
+ end
132
+ end
133
+
134
+ describe 'with non-matching String' do
135
+ it 'should not return any user' do
136
+ ExecSandbox::Users.named(/exec_sandbox_rspec/).should be_empty
137
+ end
138
+ end
139
+
140
+ describe 'with the name of the current user' do
141
+ it 'should return the current user' do
142
+ ExecSandbox::Users.named(current_user).should == [current_user]
143
+ end
144
+ end
145
+
146
+ describe 'with RegExp matching one user' do
147
+ before do
148
+ ExecSandbox::Users.create test_user, test_group
149
+ end
150
+ after do
151
+ ExecSandbox::Users.destroy test_user
152
+ end
153
+ it 'should return that one user' do
154
+ ExecSandbox::Users.named(/exec.sandbox.rspe/).should ==
155
+ ['exec_sandbox_rspec']
156
+ end
157
+ end
158
+ end
159
+
160
+ describe '#destroy_temps' do
161
+ let(:temp_prefix) { 'exsbx.rspec' }
162
+
163
+ before do
164
+ @all_users = ExecSandbox::Users.named(/.*/).sort
165
+ end
166
+
167
+ describe 'in a system with no temps' do
168
+ before do
169
+ @removed = ExecSandbox::Users.destroy_temps temp_prefix
170
+ end
171
+
172
+ it 'should not remove any users' do
173
+ ExecSandbox::Users.named(/.*/).sort.should == @all_users
174
+ end
175
+
176
+ it 'should return an empty array' do
177
+ @removed.should be_empty
178
+ end
179
+ end
180
+
181
+ describe 'in a system with two temps' do
182
+ before do
183
+ @temp1 = ExecSandbox::Users.temp temp_prefix
184
+ @temp2 = ExecSandbox::Users.temp temp_prefix
185
+
186
+ @removed = ExecSandbox::Users.destroy_temps temp_prefix
187
+ end
188
+
189
+ it 'should only remove the two temps' do
190
+ ExecSandbox::Users.named(/.*/).sort.should == @all_users
191
+ end
192
+
193
+ it 'should return the two temps' do
194
+ @removed.sort.should == [@temp1, @temp2].sort
195
+ end
196
+ end
197
+ end
125
198
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exec_sandbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-13 00:00:00.000000000Z
12
+ date: 2011-12-20 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi
16
- requirement: &24549880 !ruby/object:Gem::Requirement
16
+ requirement: &15824600 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.0.9
21
+ version: 1.0.11
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *24549880
24
+ version_requirements: *15824600
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rdoc
27
- requirement: &24549360 !ruby/object:Gem::Requirement
27
+ requirement: &15824120 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '3.10'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *24549360
35
+ version_requirements: *15824120
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &24548820 !ruby/object:Gem::Requirement
38
+ requirement: &15823640 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.6.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *24548820
46
+ version_requirements: *15823640
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: yard
49
- requirement: &24548320 !ruby/object:Gem::Requirement
49
+ requirement: &15823160 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.7.2
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *24548320
57
+ version_requirements: *15823160
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: yard-rspec
60
- requirement: &24547800 !ruby/object:Gem::Requirement
60
+ requirement: &15822680 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0.1'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *24547800
68
+ version_requirements: *15822680
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
- requirement: &24547220 !ruby/object:Gem::Requirement
71
+ requirement: &15822200 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 1.0.21
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *24547220
79
+ version_requirements: *15822200
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: jeweler
82
- requirement: &24546700 !ruby/object:Gem::Requirement
82
+ requirement: &15821720 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 1.6.4
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *24546700
90
+ version_requirements: *15821720
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rcov
93
- requirement: &24546160 !ruby/object:Gem::Requirement
93
+ requirement: &15821240 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *24546160
101
+ version_requirements: *15821240
102
102
  description: Temporary users and groups, rlimits
103
103
  email: costan@gmail.com
104
104
  executables: []
@@ -150,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
150
150
  version: '0'
151
151
  segments:
152
152
  - 0
153
- hash: -4313873554503945480
153
+ hash: -3240483873242314683
154
154
  required_rubygems_version: !ruby/object:Gem::Requirement
155
155
  none: false
156
156
  requirements: