safe_ruby 1.0.2 → 1.0.5
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 +5 -5
- data/.gitignore +2 -1
- data/.gitlab-ci.yml +42 -0
- data/Gemfile +28 -1
- data/Gemfile.lock +76 -29
- data/README.md +2 -2
- data/Rakefile +15 -6
- data/config/rspec +4 -0
- data/config/rubocop.yml +76 -0
- data/lib/constant_allowlist.rb +124 -0
- data/lib/make_safe_code.rb +48 -43
- data/lib/method_allowlist.rb +272 -0
- data/lib/safe_ruby/runner.rb +45 -26
- data/lib/safe_ruby/version.rb +10 -1
- data/lib/safe_ruby.rb +3 -6
- data/safe_ruby.gemspec +18 -16
- data/spec/safe_ruby_spec.rb +52 -44
- data/spec/spec_helper.rb +5 -2
- data/tasks/console.rake +8 -0
- data/tasks/package.rake +4 -0
- data/tasks/smelling_code.rake +23 -0
- data/tasks/test.rake +19 -0
- metadata +27 -63
- data/lib/constant_whitelist.rb +0 -13
- data/lib/method_whitelist.rb +0 -271
@@ -0,0 +1,272 @@
|
|
1
|
+
# Copyright (c) 2018 Uku Taht
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
IO_S_METHODS = %w[
|
5
|
+
new
|
6
|
+
foreach
|
7
|
+
open
|
8
|
+
].freeze
|
9
|
+
|
10
|
+
KERNEL_S_METHODS = %w[
|
11
|
+
Array
|
12
|
+
binding
|
13
|
+
block_given?
|
14
|
+
catch
|
15
|
+
chomp
|
16
|
+
chomp!
|
17
|
+
chop
|
18
|
+
chop!
|
19
|
+
eval
|
20
|
+
fail
|
21
|
+
Float
|
22
|
+
format
|
23
|
+
global_variables
|
24
|
+
gsub
|
25
|
+
gsub!
|
26
|
+
Integer
|
27
|
+
iterator?
|
28
|
+
lambda
|
29
|
+
local_variables
|
30
|
+
loop
|
31
|
+
method_missing
|
32
|
+
proc
|
33
|
+
raise
|
34
|
+
scan
|
35
|
+
split
|
36
|
+
sprintf
|
37
|
+
String
|
38
|
+
sub
|
39
|
+
sub!
|
40
|
+
throw
|
41
|
+
].freeze
|
42
|
+
|
43
|
+
SYMBOL_S_METHODS = %w[
|
44
|
+
all_symbols
|
45
|
+
].freeze
|
46
|
+
|
47
|
+
STRING_S_METHODS = [].freeze
|
48
|
+
|
49
|
+
KERNEL_METHODS = %w[
|
50
|
+
==
|
51
|
+
|
52
|
+
ray
|
53
|
+
nding
|
54
|
+
ock_given?
|
55
|
+
tch
|
56
|
+
omp
|
57
|
+
omp!
|
58
|
+
op
|
59
|
+
op!
|
60
|
+
ass
|
61
|
+
clone
|
62
|
+
dup
|
63
|
+
eql?
|
64
|
+
equal?
|
65
|
+
eval
|
66
|
+
fail
|
67
|
+
Float
|
68
|
+
format
|
69
|
+
freeze
|
70
|
+
frozen?
|
71
|
+
global_variables
|
72
|
+
gsub
|
73
|
+
gsub!
|
74
|
+
hash
|
75
|
+
id
|
76
|
+
initialize_copy
|
77
|
+
inspect
|
78
|
+
instance_eval
|
79
|
+
instance_of?
|
80
|
+
instance_variables
|
81
|
+
instance_variable_get
|
82
|
+
instance_variable_set
|
83
|
+
instance_variable_defined?
|
84
|
+
Integer
|
85
|
+
is_a?
|
86
|
+
iterator?
|
87
|
+
kind_of?
|
88
|
+
lambda
|
89
|
+
local_variables
|
90
|
+
loop
|
91
|
+
methods
|
92
|
+
method_missing
|
93
|
+
nil?
|
94
|
+
private_methods
|
95
|
+
print
|
96
|
+
proc
|
97
|
+
protected_methods
|
98
|
+
public_methods
|
99
|
+
raise
|
100
|
+
remove_instance_variable
|
101
|
+
respond_to?
|
102
|
+
respond_to_missing?
|
103
|
+
scan
|
104
|
+
send
|
105
|
+
singleton_methods
|
106
|
+
singleton_method_added
|
107
|
+
singleton_method_removed
|
108
|
+
singleton_method_undefined
|
109
|
+
split
|
110
|
+
sprintf
|
111
|
+
String
|
112
|
+
sub
|
113
|
+
sub!
|
114
|
+
taint
|
115
|
+
tainted?
|
116
|
+
throw
|
117
|
+
to_a
|
118
|
+
to_s
|
119
|
+
type
|
120
|
+
untaint
|
121
|
+
__send__
|
122
|
+
].freeze
|
123
|
+
|
124
|
+
NILCLASS_METHODS = %w[
|
125
|
+
&
|
126
|
+
inspect
|
127
|
+
nil?
|
128
|
+
to_a
|
129
|
+
to_f
|
130
|
+
to_i
|
131
|
+
to_s
|
132
|
+
^
|
133
|
+
|
|
134
|
+
].freeze
|
135
|
+
|
136
|
+
SYMBOL_METHODS = %w[
|
137
|
+
===
|
138
|
+
id2name
|
139
|
+
inspect
|
140
|
+
to_i
|
141
|
+
to_int
|
142
|
+
to_s
|
143
|
+
to_sym
|
144
|
+
].freeze
|
145
|
+
|
146
|
+
TRUECLASS_METHODS = %w[
|
147
|
+
&
|
148
|
+
to_s
|
149
|
+
^
|
150
|
+
|
|
151
|
+
].freeze
|
152
|
+
|
153
|
+
FALSECLASS_METHODS = %w[
|
154
|
+
&
|
155
|
+
to_s
|
156
|
+
^
|
157
|
+
|
|
158
|
+
].freeze
|
159
|
+
|
160
|
+
ENUMERABLE_METHODS = %w[
|
161
|
+
all?
|
162
|
+
any?
|
163
|
+
collect
|
164
|
+
detect
|
165
|
+
each_with_index
|
166
|
+
entries
|
167
|
+
find
|
168
|
+
find_all
|
169
|
+
grep
|
170
|
+
include?
|
171
|
+
inject
|
172
|
+
map
|
173
|
+
max
|
174
|
+
member?
|
175
|
+
min
|
176
|
+
partition
|
177
|
+
reject
|
178
|
+
select
|
179
|
+
sort
|
180
|
+
sort_by
|
181
|
+
to_a
|
182
|
+
zip
|
183
|
+
].freeze
|
184
|
+
|
185
|
+
STRING_METHODS = %w[
|
186
|
+
%
|
187
|
+
*
|
188
|
+
+
|
189
|
+
<<
|
190
|
+
<=>
|
191
|
+
==
|
192
|
+
=~
|
193
|
+
capitalize
|
194
|
+
capitalize!
|
195
|
+
casecmp
|
196
|
+
center
|
197
|
+
chomp
|
198
|
+
chomp!
|
199
|
+
chop
|
200
|
+
chop!
|
201
|
+
concat
|
202
|
+
count
|
203
|
+
crypt
|
204
|
+
delete
|
205
|
+
delete!
|
206
|
+
downcase
|
207
|
+
downcase!
|
208
|
+
dump
|
209
|
+
each
|
210
|
+
each_byte
|
211
|
+
each_line
|
212
|
+
empty?
|
213
|
+
eql?
|
214
|
+
gsub
|
215
|
+
gsub!
|
216
|
+
hash
|
217
|
+
hex
|
218
|
+
include?
|
219
|
+
index
|
220
|
+
initialize
|
221
|
+
initialize_copy
|
222
|
+
insert
|
223
|
+
inspect
|
224
|
+
intern
|
225
|
+
length
|
226
|
+
ljust
|
227
|
+
lines
|
228
|
+
lstrip
|
229
|
+
lstrip!
|
230
|
+
match
|
231
|
+
next
|
232
|
+
next!
|
233
|
+
oct
|
234
|
+
replace
|
235
|
+
reverse
|
236
|
+
reverse!
|
237
|
+
rindex
|
238
|
+
rjust
|
239
|
+
rstrip
|
240
|
+
rstrip!
|
241
|
+
scan
|
242
|
+
size
|
243
|
+
slice
|
244
|
+
slice!
|
245
|
+
split
|
246
|
+
squeeze
|
247
|
+
squeeze!
|
248
|
+
strip
|
249
|
+
strip!
|
250
|
+
start_with?
|
251
|
+
sub
|
252
|
+
sub!
|
253
|
+
succ
|
254
|
+
succ!
|
255
|
+
sum
|
256
|
+
swapcase
|
257
|
+
swapcase!
|
258
|
+
to_f
|
259
|
+
to_i
|
260
|
+
to_s
|
261
|
+
to_str
|
262
|
+
to_sym
|
263
|
+
tr
|
264
|
+
tr!
|
265
|
+
tr_s
|
266
|
+
tr_s!
|
267
|
+
upcase
|
268
|
+
upcase!
|
269
|
+
upto
|
270
|
+
[]
|
271
|
+
[]=
|
272
|
+
].freeze
|
data/lib/safe_ruby/runner.rb
CHANGED
@@ -1,36 +1,56 @@
|
|
1
|
-
|
1
|
+
# Copyright (c) 2018 Uku Taht
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require('childprocess')
|
5
|
+
require('tempfile')
|
2
6
|
|
3
7
|
class EvalError < StandardError
|
4
|
-
def initialize(msg); super; end
|
5
8
|
end
|
6
9
|
|
10
|
+
# main class
|
7
11
|
class SafeRuby
|
8
|
-
DEFAULTS = {
|
9
|
-
|
12
|
+
DEFAULTS = {
|
13
|
+
timeout: 5,
|
14
|
+
raise_errors: true
|
15
|
+
}.freeze
|
16
|
+
private_constant :DEFAULTS
|
10
17
|
|
11
|
-
|
18
|
+
# rubocop:disable Style/OptionHash
|
19
|
+
def self.eval(code, options = {})
|
20
|
+
new(code, options).eval
|
21
|
+
end
|
22
|
+
# rubocop:enable Style/OptionHash
|
23
|
+
|
24
|
+
def self.check(code, expected)
|
25
|
+
# rubocop:disable Security/Eval
|
26
|
+
eval(code) == eval(expected)
|
27
|
+
# rubocop:enable Security/Eval
|
28
|
+
end
|
29
|
+
|
30
|
+
# rubocop:disable Style/OptionHash
|
31
|
+
def initialize(code, options = {})
|
12
32
|
options = DEFAULTS.merge(options)
|
13
33
|
|
14
34
|
@code = code
|
15
35
|
@raise_errors = options[:raise_errors]
|
16
36
|
@timeout = options[:timeout]
|
17
37
|
end
|
38
|
+
# rubocop:enable Style/OptionHash
|
18
39
|
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
40
|
+
# rubocop:disable Metrics/AbcSize
|
41
|
+
# rubocop:disable Metrics/MethodLength
|
23
42
|
def eval
|
24
43
|
temp = build_tempfile
|
25
44
|
read, write = IO.pipe
|
26
|
-
ChildProcess.build(
|
45
|
+
ChildProcess.build('ruby', temp.path).tap do |process|
|
27
46
|
process.io.stdout = write
|
28
47
|
process.io.stderr = write
|
29
48
|
process.start
|
30
49
|
begin
|
31
50
|
process.poll_for_exit(@timeout)
|
32
51
|
rescue ChildProcess::TimeoutError => e
|
33
|
-
|
52
|
+
# tries increasingly harsher methods to kill the process.
|
53
|
+
process.stop
|
34
54
|
return e.message
|
35
55
|
end
|
36
56
|
write.close
|
@@ -39,30 +59,29 @@ class SafeRuby
|
|
39
59
|
|
40
60
|
data = read.read
|
41
61
|
begin
|
62
|
+
# rubocop:disable Security/MarshalLoad
|
42
63
|
Marshal.load(data)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
else
|
47
|
-
return data
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
64
|
+
# rubocop:enable Security/MarshalLoad
|
65
|
+
rescue StandardError
|
66
|
+
raise(data) if @raise_errors
|
51
67
|
|
52
|
-
|
53
|
-
|
68
|
+
data
|
69
|
+
end
|
54
70
|
end
|
55
|
-
|
71
|
+
# rubocop:enable Metrics/AbcSize
|
72
|
+
# rubocop:enable Metrics/MethodLength
|
56
73
|
|
57
74
|
private
|
58
75
|
|
59
76
|
def build_tempfile
|
60
77
|
file = Tempfile.new('saferuby')
|
61
78
|
file.write(MAKE_SAFE_CODE)
|
62
|
-
file.write
|
63
|
-
|
64
|
-
|
65
|
-
|
79
|
+
file.write(
|
80
|
+
<<~STRING
|
81
|
+
result = eval(%q(#{@code}))
|
82
|
+
print Marshal.dump(result)
|
83
|
+
STRING
|
84
|
+
)
|
66
85
|
file.rewind
|
67
86
|
file
|
68
87
|
end
|
data/lib/safe_ruby/version.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
|
+
# Copyright (c) 2018 Uku Taht
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# main class
|
1
5
|
class SafeRuby
|
2
6
|
MAJOR_VERSION = 1
|
3
7
|
MINOR_VERSION = 0
|
4
|
-
RELEASE_VERSION =
|
8
|
+
RELEASE_VERSION = 5
|
9
|
+
|
10
|
+
private_constant :MAJOR_VERSION
|
11
|
+
private_constant :MINOR_VERSION
|
12
|
+
private_constant :RELEASE_VERSION
|
5
13
|
|
6
14
|
VERSION = [MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION].join('.')
|
15
|
+
public_constant :VERSION
|
7
16
|
end
|
data/lib/safe_ruby.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# Copyright (c) 2018 Uku Taht
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
4
|
require_relative 'make_safe_code'
|
5
5
|
require_relative 'safe_ruby/runner'
|
6
6
|
require_relative 'safe_ruby/version'
|
7
|
-
|
8
|
-
class SafeRuby
|
9
|
-
end
|
data/safe_ruby.gemspec
CHANGED
@@ -1,28 +1,30 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# Copyright (c) 2018 Uku Taht
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
require 'safe_ruby/version'
|
5
7
|
|
6
8
|
Gem::Specification.new do |s|
|
9
|
+
s.required_ruby_version = '>= 2.7'
|
7
10
|
s.name = 'safe_ruby'
|
8
11
|
s.version = SafeRuby::VERSION
|
9
|
-
s.
|
10
|
-
s.
|
11
|
-
s.email = 'uku.taht@gmail.com'
|
12
|
+
s.authors = ['Jérôme Arbez-Gindre', 'Uku Taht']
|
13
|
+
s.email = 'jeromearbezgindre@gmail.com'
|
12
14
|
|
13
|
-
s.summary =
|
14
|
-
s.description =
|
15
|
-
|
15
|
+
s.summary = 'Run untrusted ruby code in a safe environment'
|
16
|
+
s.description = 'Evaluates ruby code by writing it to a tempfile and spawning a child ' \
|
17
|
+
'process. Uses a allowlist of methods and constants to keep, for example ' \
|
18
|
+
'one cannot run system commands in the environment created by this gem. ' \
|
19
|
+
'The environment created by the untrusted code does not leak out into ' \
|
20
|
+
'the parent process.'
|
21
|
+
s.homepage = 'https://gitlab.com/defmastership/safe_ruby/'
|
16
22
|
s.license = 'MIT'
|
17
23
|
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
19
25
|
s.files = `git ls-files`.split("\n")
|
20
|
-
s.
|
21
|
-
s.require_paths = ["lib"]
|
22
|
-
|
23
|
-
s.add_runtime_dependency 'childprocess', '>= 0.3.9'
|
26
|
+
s.require_paths = ['lib']
|
24
27
|
|
25
|
-
s.
|
26
|
-
s.
|
27
|
-
s.add_development_dependency 'rspec'
|
28
|
+
s.add_dependency('childprocess', '~> 5')
|
29
|
+
s.metadata['rubygems_mfa_required'] = 'true'
|
28
30
|
end
|
data/spec/safe_ruby_spec.rb
CHANGED
@@ -1,73 +1,81 @@
|
|
1
|
+
# Copyright (c) 2018 Uku Taht
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
1
4
|
require 'spec_helper'
|
2
5
|
|
6
|
+
MALICIOUS_OPERATIONS = [
|
7
|
+
"system('rm *')",
|
8
|
+
'`rm *`',
|
9
|
+
'Kernel.abort',
|
10
|
+
'cat spec/spec_helper.rb',
|
11
|
+
'File.class_eval { `echo Hello` }',
|
12
|
+
'FileUtils.class_eval { `echo Hello` }',
|
13
|
+
'Dir.class_eval { `echo Hello` }',
|
14
|
+
'FileTest.class_eval { `echo Hello` }',
|
15
|
+
'File.eval "`echo Hello`"',
|
16
|
+
'FileUtils.eval "`echo Hello`"',
|
17
|
+
'Dir.eval "`echo Hello`"',
|
18
|
+
'FileTest.eval "`echo Hello`"',
|
19
|
+
'File.instance_eval { `echo Hello` }',
|
20
|
+
'FileUtils.instance_eval { `echo Hello` }',
|
21
|
+
'Dir.instance_eval { `echo Hello` }',
|
22
|
+
'FileTest.instance_eval { `echo Hello` }',
|
23
|
+
"f=IO.popen('uname'); f.readlines; f.close",
|
24
|
+
"IO.binread('/etc/passwd')",
|
25
|
+
"IO.read('/etc/passwd')"
|
26
|
+
].freeze
|
27
|
+
|
3
28
|
describe SafeRuby do
|
4
29
|
describe '#eval' do
|
5
30
|
it 'allows basic operations' do
|
6
|
-
expect(
|
7
|
-
expect(SafeRuby.eval('[4, 5].map{|n| n+1}')).to eq [5 ,6]
|
31
|
+
expect(described_class.eval('4 + 5')).to(eq(9))
|
8
32
|
end
|
9
33
|
|
10
|
-
it '
|
11
|
-
expect(
|
34
|
+
it 'allows basic operations with map' do
|
35
|
+
expect(described_class.eval('[4, 5].map{|n| n+1}')).to(eq([5, 6]))
|
12
36
|
end
|
13
37
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
"Kernel.abort",
|
18
|
-
"cat spec/spec_helper.rb",
|
19
|
-
"File.class_eval { `echo Hello` }",
|
20
|
-
"FileUtils.class_eval { `echo Hello` }",
|
21
|
-
"Dir.class_eval { `echo Hello` }",
|
22
|
-
"FileTest.class_eval { `echo Hello` }",
|
23
|
-
"File.eval \"`echo Hello`\"",
|
24
|
-
"FileUtils.eval \"`echo Hello`\"",
|
25
|
-
"Dir.eval \"`echo Hello`\"",
|
26
|
-
"FileTest.eval \"`echo Hello`\"",
|
27
|
-
"File.instance_eval { `echo Hello` }",
|
28
|
-
"FileUtils.instance_eval { `echo Hello` }",
|
29
|
-
"Dir.instance_eval { `echo Hello` }",
|
30
|
-
"FileTest.instance_eval { `echo Hello` }",
|
31
|
-
"f=IO.popen('uname'); f.readlines; f.close",
|
32
|
-
"IO.binread('/etc/passwd')",
|
33
|
-
"IO.read('/etc/passwd')",
|
34
|
-
]
|
38
|
+
it 'returns correct object' do
|
39
|
+
expect(described_class.eval('[1,2,3]')).to(eq([1, 2, 3]))
|
40
|
+
end
|
35
41
|
|
36
42
|
MALICIOUS_OPERATIONS.each do |op|
|
37
43
|
it "protects from malicious operations like (#{op})" do
|
38
|
-
expect{
|
39
|
-
|
40
|
-
}.to raise_error RuntimeError
|
44
|
+
expect { described_class.eval(op) }
|
45
|
+
.to(raise_error(RuntimeError))
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
44
|
-
describe
|
45
|
-
describe
|
49
|
+
describe 'options' do
|
50
|
+
describe 'timeout' do
|
46
51
|
it 'defaults to a 5 second timeout' do
|
47
|
-
time =
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
time =
|
53
|
+
Benchmark.realtime do
|
54
|
+
described_class.eval('(1..100000).map {|n| n**100}')
|
55
|
+
end
|
56
|
+
expect(time).to(be_within(0.5).of(5))
|
51
57
|
end
|
52
58
|
|
53
59
|
it 'allows custom timeout' do
|
54
|
-
time =
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
time =
|
61
|
+
Benchmark.realtime do
|
62
|
+
described_class.eval('(1..100000).map {|n| n**100}', timeout: 1)
|
63
|
+
end
|
64
|
+
expect(time).to(be_within(0.5).of(1))
|
58
65
|
end
|
59
66
|
end
|
60
67
|
|
61
|
-
describe
|
62
|
-
it
|
63
|
-
expect{
|
68
|
+
describe 'raising errors' do
|
69
|
+
it 'defaults to raising errors' do
|
70
|
+
expect { described_class.eval('asdasdasd') }
|
71
|
+
.to(raise_error(RuntimeError))
|
64
72
|
end
|
65
73
|
|
66
|
-
it
|
67
|
-
expect {
|
74
|
+
it 'allows not raising errors' do
|
75
|
+
expect { described_class.eval('asdasd', raise_errors: false) }
|
76
|
+
.not_to(raise_error)
|
68
77
|
end
|
69
78
|
end
|
70
79
|
end
|
71
|
-
|
72
80
|
end
|
73
81
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
|
1
|
+
# Copyright (c) 2018 Uku Taht
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'benchmark'
|
5
|
+
require 'safe_ruby'
|
3
6
|
|
4
7
|
RSpec.configure do |config|
|
5
8
|
config.run_all_when_everything_filtered = true
|
6
|
-
config.filter_run
|
9
|
+
config.filter_run(:focus)
|
7
10
|
|
8
11
|
config.order = 'random'
|
9
12
|
end
|
data/tasks/console.rake
ADDED
data/tasks/package.rake
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Copyright (c) 2023 Jerome Arbez-Gindre
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
namespace 'quality' do
|
5
|
+
begin
|
6
|
+
require('rubocop/rake_task')
|
7
|
+
|
8
|
+
RuboCop::RakeTask.new do |task|
|
9
|
+
task.options << '--display-cop-names'
|
10
|
+
task.options << '--config=config/rubocop.yml'
|
11
|
+
end
|
12
|
+
rescue LoadError
|
13
|
+
task(:rubocop) do
|
14
|
+
puts('Install rubocop to run its rake tasks')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Runs all quality code check'
|
19
|
+
task(all: ['quality:rubocop'])
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Synonym for quality:rubocop'
|
23
|
+
task(rubocop: 'quality:rubocop')
|
data/tasks/test.rake
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Copyright (c) 2023 Jerome Arbez-Gindre
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require('rspec/core/rake_task')
|
5
|
+
|
6
|
+
namespace 'test' do
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
8
|
+
t.rspec_opts = ['--options config/rspec']
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Runs all unit tests and acceptance tests'
|
12
|
+
task(all: ['test:spec'])
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Synonym for test:spec'
|
16
|
+
task(spec: 'test:spec')
|
17
|
+
|
18
|
+
desc 'Synonym for test:all'
|
19
|
+
task(test: 'test:all')
|