rufus-treechecker 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.txt ADDED
@@ -0,0 +1,29 @@
1
+
2
+ = rufus-treechecker CHANGELOG.txt
3
+
4
+
5
+ == rufus-treechecker - 1.0.4 released 2010/12/22
6
+
7
+ - require rufus/tree_checker and rufus-tree_checker
8
+ - Rufus::Treechecker.parse(code) => tree
9
+
10
+
11
+ == rufus-treechecker - 1.0.3 released 2008/10/29
12
+
13
+ - todo #22570 : moved to ruby_parser 2.0
14
+
15
+
16
+ == rufus-treechecker - 1.0.2 released 2008/09/02
17
+
18
+ - complete refactoring, huge perf gain
19
+
20
+
21
+ == rufus-treechecker - 1.0.1 released 2008/09/01
22
+
23
+ - more rules, slightly less code
24
+
25
+
26
+ == rufus-treechecker - 1.0 released 2008/09/01
27
+
28
+ - initial release
29
+
data/CREDITS.txt ADDED
@@ -0,0 +1,6 @@
1
+
2
+ = CREDITS.txt
3
+
4
+ Leverages ruby_parser and parsetree by Ryan Davis
5
+ (http://rubyforge.org/projects/parsetree/)
6
+
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+
2
+ Copyright (c) 2008-2011, John Mettraux, jmettraux@gmail.com
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
data/README.txt CHANGED
@@ -8,7 +8,7 @@ Initialize a Rufus::TreeChecker and pass some ruby code to make sure it's safe b
8
8
 
9
9
  == getting it
10
10
 
11
- sudo gem install -y rufus-treechecker
11
+ gem install -y rufus-treechecker
12
12
 
13
13
  or download[http://rubyforge.org/frs/?group_id=4812] it from RubyForge.
14
14
 
@@ -16,40 +16,40 @@ or download[http://rubyforge.org/frs/?group_id=4812] it from RubyForge.
16
16
  == usage
17
17
 
18
18
  The treechecker uses ruby_parser (http://rubyforge.org/projects/parsetree)
19
- to turn Ruby code into s-expressions, the treechecker then
20
- checks this sexp tree and raises a Rufus::SecurityError if an excluded pattern
19
+ to turn Ruby code into s-expressions, the treechecker then
20
+ checks this sexp tree and raises a Rufus::SecurityError if an excluded pattern
21
21
  is spotted.
22
22
 
23
23
  The excluded patterns are defined at the initialization of the TreeChecker
24
24
  instance by listing rules.
25
25
 
26
- require 'rubygems'
27
- require 'rufus-treechecker'
26
+ require 'rubygems'
27
+ require 'rufus-treechecker'
28
28
 
29
- tc = Rufus::TreeChecker.new do
30
- exclude_fvcall :abort
31
- exclude_fvcall :exit, :exit!
32
- end
33
-
34
- tc.check("1 + 1; abort") # will raise a SecurityError
35
- tc.check("puts (1..10).to_a.inspect") # OK
29
+ tc = Rufus::TreeChecker.new do
30
+ exclude_fvcall :abort
31
+ exclude_fvcall :exit, :exit!
32
+ end
33
+
34
+ tc.check("1 + 1; abort") # will raise a SecurityError
35
+ tc.check("puts (1..10).to_a.inspect") # OK
36
36
 
37
37
 
38
38
  Nice, but how do I know what to exclude ?
39
39
 
40
- require 'rubygems'
41
- require 'rufus-treechecker'
40
+ require 'rubygems'
41
+ require 'rufus-treechecker'
42
42
 
43
- Rufus::TreeChecker.new.ptree('a = 5 + 6; puts a')
43
+ Rufus::TreeChecker.new.ptree('a = 5 + 6; puts a')
44
44
 
45
45
  will yield
46
46
 
47
- "a = 5 + 6; puts a"
48
- =>
49
- [:block,
50
- [:lasgn, :a, [:call, [:lit, 5], :+, [:array, [:lit, 6]]]],
51
- [:fcall, :puts, [:array, [:lvar, :a]]]
52
- ]
47
+ "a = 5 + 6; puts a"
48
+ =>
49
+ [:block,
50
+ [:lasgn, :a, [:call, [:lit, 5], :+, [:array, [:lit, 6]]]],
51
+ [:fcall, :puts, [:array, [:lvar, :a]]]
52
+ ]
53
53
 
54
54
 
55
55
  For more documentation, see http://github.com/jmettraux/rufus-treechecker/tree/master/lib/rufus/treechecker.rb
@@ -57,26 +57,26 @@ For more documentation, see http://github.com/jmettraux/rufus-treechecker/tree/m
57
57
 
58
58
  == dependencies
59
59
 
60
- the 'rogue-parser' gem
60
+ the 'ruby_parser' gem by Ryan Davis.
61
61
 
62
62
 
63
63
  == mailing list
64
64
 
65
65
  On the Rufus-Ruby list[http://groups.google.com/group/rufus-ruby] :
66
66
 
67
- http://groups.google.com/group/rufus-ruby
67
+ http://groups.google.com/group/rufus-ruby
68
68
 
69
69
 
70
70
  == issue tracker
71
71
 
72
- http://rubyforge.org/tracker/?atid=18584&group_id=4812&func=browse
72
+ http://rubyforge.org/tracker/?atid=18584&group_id=4812&func=browse
73
73
 
74
74
 
75
75
  == source
76
76
 
77
77
  http://github.com/jmettraux/rufus-treechecker
78
78
 
79
- git clone git://github.com/jmettraux/rufus-treechecker.git
79
+ git clone git://github.com/jmettraux/rufus-treechecker.git
80
80
 
81
81
 
82
82
  == author
data/Rakefile ADDED
@@ -0,0 +1,83 @@
1
+
2
+ $:.unshift('.') # 1.9.2
3
+
4
+ require 'rubygems'
5
+
6
+ require 'rake'
7
+ require 'rake/clean'
8
+ require 'rake/rdoctask'
9
+
10
+
11
+ #
12
+ # clean
13
+
14
+ CLEAN.include('pkg', 'rdoc')
15
+
16
+
17
+ #
18
+ # test / spec
19
+
20
+ task :spec do
21
+ sh 'rspec spec/'
22
+ end
23
+ task :test => :spec
24
+ task :default => :spec
25
+
26
+
27
+ #
28
+ # gem
29
+
30
+ GEMSPEC_FILE = Dir['*.gemspec'].first
31
+ GEMSPEC = eval(File.read(GEMSPEC_FILE))
32
+ GEMSPEC.validate
33
+
34
+
35
+ desc %{
36
+ builds the gem and places it in pkg/
37
+ }
38
+ task :build do
39
+
40
+ sh "gem build #{GEMSPEC_FILE}"
41
+ sh "mkdir pkg" rescue nil
42
+ sh "mv #{GEMSPEC.name}-#{GEMSPEC.version}.gem pkg/"
43
+ end
44
+
45
+ desc %{
46
+ builds the gem and pushes it to rubygems.org
47
+ }
48
+ task :push => :build do
49
+
50
+ sh "gem push pkg/#{GEMSPEC.name}-#{GEMSPEC.version}.gem"
51
+ end
52
+
53
+
54
+ #
55
+ # rdoc
56
+ #
57
+ # make sure to have rdoc 2.5.x to run that
58
+
59
+ Rake::RDocTask.new do |rd|
60
+
61
+ rd.main = 'README.txt'
62
+ rd.rdoc_dir = "rdoc/#{GEMSPEC.name}"
63
+
64
+ rd.rdoc_files.include('README.txt', 'CHANGELOG.txt', 'CREDITS.txt', 'lib/**/*.rb')
65
+
66
+ rd.title = "#{GEMSPEC.name} #{GEMSPEC.version}"
67
+ end
68
+
69
+
70
+ #
71
+ # upload_rdoc
72
+
73
+ desc %{
74
+ upload the rdoc to rubyforge
75
+ }
76
+ task :upload_rdoc => [ :clean, :rdoc ] do
77
+
78
+ account = 'jmettraux@rubyforge.org'
79
+ webdir = "/var/www/gforge-projects/rufus"
80
+
81
+ sh "rsync -azv -e ssh rdoc/#{GEMSPEC.name} #{account}:#{webdir}/"
82
+ end
83
+
@@ -0,0 +1,3 @@
1
+
2
+ require 'rufus/treechecker'
3
+
@@ -1,6 +1,5 @@
1
- #
2
1
  #--
3
- # Copyright (c) 2008, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2008-2011, John Mettraux, jmettraux@gmail.com
4
3
  #
5
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -19,14 +18,12 @@
19
18
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
19
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
20
  # THE SOFTWARE.
22
- #++
23
- #
24
-
25
21
  #
26
22
  # "made in Japan" (as opposed to "swiss made")
27
- #
23
+ #++
28
24
 
29
- require 'ruby_parser' # gem 'rogue_parser'
25
+
26
+ require 'ruby_parser'
30
27
 
31
28
 
32
29
  module Rufus
@@ -125,27 +122,24 @@ module Rufus
125
122
  #
126
123
  class TreeChecker
127
124
 
128
- VERSION = '1.0.3'
125
+ VERSION = '1.0.4'
129
126
 
130
- #
131
127
  # pretty-prints the sexp tree of the given rubycode
132
128
  #
133
- def ptree (rubycode)
129
+ def ptree(rubycode)
134
130
  puts stree(rubycode)
135
131
  end
136
132
 
137
- #
138
133
  # returns the pretty-printed string of the given rubycode
139
134
  # (thanks ruby_parser).
140
135
  #
141
- def stree (rubycode)
136
+ def stree(rubycode)
142
137
  "#{rubycode.inspect}\n =>\n#{parse(rubycode).inspect}"
143
138
  end
144
139
 
145
- #
146
140
  # initializes the TreeChecker, expects a block
147
141
  #
148
- def initialize (&block)
142
+ def initialize(&block)
149
143
 
150
144
  @root_set = RuleSet.new
151
145
  @set = RuleSet.new
@@ -162,12 +156,11 @@ module Rufus
162
156
  s << @set.to_s
163
157
  end
164
158
 
165
- #
166
159
  # Performs the check on the given String of ruby code. Will raise a
167
160
  # Rufus::SecurityError if there is something excluded by the rules
168
161
  # specified at the initialization of the TreeChecker instance.
169
162
  #
170
- def check (rubycode)
163
+ def check(rubycode)
171
164
 
172
165
  sexp = parse(rubycode)
173
166
 
@@ -179,8 +172,7 @@ module Rufus
179
172
  do_check(sexp)
180
173
  end
181
174
 
182
- #
183
- # return a copy of this TreeChecker instance
175
+ # Return a copy of this TreeChecker instance
184
176
  #
185
177
  def clone
186
178
 
@@ -190,18 +182,16 @@ module Rufus
190
182
  tc
191
183
  end
192
184
 
185
+ # Adds a set of checks (rules) to this treechecker. Returns self.
193
186
  #
194
- # adds a set of checks (rules) to this treechecker. Returns self.
195
- #
196
- def add_rules (&block)
187
+ def add_rules(&block)
197
188
 
198
189
  instance_eval(&block) if block
199
190
 
200
191
  self
201
192
  end
202
193
 
203
- #
204
- # freezes the treechecker instance "in depth"
194
+ # Freezes the treechecker instance "in depth"
205
195
  #
206
196
  def freeze
207
197
  super
@@ -228,23 +218,23 @@ module Rufus
228
218
  rs
229
219
  end
230
220
 
231
- def exclude_symbol (s, message)
221
+ def exclude_symbol(s, message)
232
222
 
233
223
  @excluded_symbols[s] = (message || ":#{s} is excluded")
234
224
  end
235
225
 
236
- def accept_pattern (pat)
226
+ def accept_pattern(pat)
237
227
 
238
228
  (@accepted_patterns[pat.first] ||= []) << pat
239
229
  end
240
230
 
241
- def exclude_pattern (pat, message)
231
+ def exclude_pattern(pat, message)
242
232
 
243
233
  (@excluded_patterns[pat.first] ||= []) << [
244
234
  pat, message || "#{pat.inspect} is excluded" ]
245
235
  end
246
236
 
247
- def check (sexp)
237
+ def check(sexp)
248
238
 
249
239
  if sexp.is_a?(Symbol)
250
240
 
@@ -304,7 +294,7 @@ module Rufus
304
294
 
305
295
  protected
306
296
 
307
- def check_pattern (sexp, pat)
297
+ def check_pattern(sexp, pat)
308
298
 
309
299
  return false if sexp.length < pat.length
310
300
 
@@ -320,18 +310,17 @@ module Rufus
320
310
  # the methods used to define the checks
321
311
  #++
322
312
 
323
- #
324
- # within the 'at_root' block, rules are added to the @root_checks, ie
313
+ # Within the 'at_root' block, rules are added to the @root_checks, ie
325
314
  # they are evaluated only for the toplevel (root) sexp.
326
315
  #
327
- def at_root (&block)
316
+ def at_root(&block)
328
317
 
329
318
  @current_set = @root_set
330
319
  add_rules(&block)
331
320
  @current_set = @set
332
321
  end
333
322
 
334
- def extract_message (args)
323
+ def extract_message(args)
335
324
 
336
325
  message = nil
337
326
  args = args.dup
@@ -339,7 +328,7 @@ module Rufus
339
328
  [ args, message ]
340
329
  end
341
330
 
342
- def expand_class (arg)
331
+ def expand_class(arg)
343
332
 
344
333
  if arg.is_a?(Class) or arg.is_a?(Module)
345
334
  [ parse(arg.to_s), parse("::#{arg.to_s}") ]
@@ -348,8 +337,7 @@ module Rufus
348
337
  end
349
338
  end
350
339
 
351
- #
352
- # adds a rule that will forbid sexps that begin with the given head
340
+ # Adds a rule that will forbid sexps that begin with the given head
353
341
  #
354
342
  # tc = TreeChecker.new do
355
343
  # exclude_head [ :block ]
@@ -358,44 +346,43 @@ module Rufus
358
346
  # tc.check('a = 2') # ok
359
347
  # tc.check('a = 2; b = 5') # will raise an error as it's a block
360
348
  #
361
- def exclude_head (head, message=nil)
349
+ def exclude_head(head, message=nil)
362
350
 
363
351
  @current_set.exclude_pattern(head, message)
364
352
  end
365
353
 
366
- def exclude_symbol (*args)
354
+ def exclude_symbol(*args)
367
355
  args, message = extract_message(args)
368
356
  args.each { |a| @current_set.exclude_symbol(a, message) }
369
357
  end
370
358
 
371
- def exclude_fcall (*args)
359
+ def exclude_fcall(*args)
372
360
  do_exclude_pair(:fcall, args)
373
361
  end
374
362
 
375
- def exclude_vcall (*args)
363
+ def exclude_vcall(*args)
376
364
  do_exclude_pair(:vcall, args)
377
365
  end
378
366
 
379
- def exclude_fvcall (*args)
367
+ def exclude_fvcall(*args)
380
368
  do_exclude_pair(:fcall, args)
381
369
  do_exclude_pair(:vcall, args)
382
370
  end
383
371
 
384
- def exclude_call_on (*args)
372
+ def exclude_call_on(*args)
385
373
  do_exclude_pair(:call, args)
386
374
  end
387
375
 
388
- def exclude_call_to (*args)
376
+ def exclude_call_to(*args)
389
377
  args, message = extract_message(args)
390
378
  args.each { |a| @current_set.exclude_pattern([ :call, :any, a], message) }
391
379
  end
392
380
 
393
- def exclude_fvccall (*args)
381
+ def exclude_fvccall(*args)
394
382
  exclude_fvcall(*args)
395
383
  exclude_call_to(*args)
396
384
  end
397
385
 
398
- #
399
386
  # This rule :
400
387
  #
401
388
  # exclude_rebinding Kernel
@@ -405,7 +392,7 @@ module Rufus
405
392
  # k = Kernel
406
393
  # k = ::Kernel
407
394
  #
408
- def exclude_rebinding (*args)
395
+ def exclude_rebinding(*args)
409
396
  args, message = extract_message(args)
410
397
  args.each do |a|
411
398
  expand_class(a).each do |c|
@@ -418,21 +405,19 @@ module Rufus
418
405
  # prevents access (calling methods and rebinding) to a class (or a list
419
406
  # of classes
420
407
  #
421
- def exclude_access_to (*args)
408
+ def exclude_access_to(*args)
422
409
  exclude_call_on *args
423
410
  exclude_rebinding *args
424
411
  end
425
412
 
426
- #
427
- # bans method definitions
413
+ # Bans method definitions
428
414
  #
429
415
  def exclude_def
430
416
 
431
417
  @current_set.exclude_symbol(:defn, 'method definitions are forbidden')
432
418
  end
433
419
 
434
- #
435
- # bans the defintion and the [re]openening of classes
420
+ # Bans the defintion and the [re]openening of classes
436
421
  #
437
422
  # a list of exceptions (classes) can be passed. Subclassing those
438
423
  # exceptions is permitted.
@@ -454,8 +439,7 @@ module Rufus
454
439
  [ :class ], 'defining a class is forbidden')
455
440
  end
456
441
 
457
- #
458
- # bans the definition or the opening of modules
442
+ # Bans the definition or the opening of modules
459
443
  #
460
444
  def exclude_module_tinkering
461
445
 
@@ -463,8 +447,7 @@ module Rufus
463
447
  :module, 'defining or opening a module is forbidden')
464
448
  end
465
449
 
466
- #
467
- # bans referencing or setting the value of global variables
450
+ # Bans referencing or setting the value of global variables
468
451
  #
469
452
  def exclude_global_vars
470
453
 
@@ -472,8 +455,7 @@ module Rufus
472
455
  @current_set.exclude_symbol(:gasgn, 'global vars are forbidden')
473
456
  end
474
457
 
475
- #
476
- # bans the usage of 'alias'
458
+ # Bans the usage of 'alias'
477
459
  #
478
460
  def exclude_alias
479
461
 
@@ -481,8 +463,7 @@ module Rufus
481
463
  @current_set.exclude_symbol(:alias_method, "'alias_method' is forbidden")
482
464
  end
483
465
 
484
- #
485
- # bans the use of 'eval', 'module_eval' and 'instance_eval'
466
+ # Bans the use of 'eval', 'module_eval' and 'instance_eval'
486
467
  #
487
468
  def exclude_eval
488
469
 
@@ -491,16 +472,14 @@ module Rufus
491
472
  exclude_call_to(:instance_eval, 'instance_eval() is forbidden')
492
473
  end
493
474
 
494
- #
495
- # bans the use of backquotes
475
+ # Bans the use of backquotes
496
476
  #
497
477
  def exclude_backquotes
498
478
 
499
479
  @current_set.exclude_symbol(:xstr, 'backquotes are forbidden')
500
480
  end
501
481
 
502
- #
503
- # bans raise and throw
482
+ # Bans raise and throw
504
483
  #
505
484
  def exclude_raise
506
485
 
@@ -518,10 +497,9 @@ module Rufus
518
497
  end
519
498
  end
520
499
 
500
+ # The actual check method, check() is rather a bootstrap one...
521
501
  #
522
- # the actual check method, check() is rather a bootstrap one...
523
- #
524
- def do_check (sexp)
502
+ def do_check(sexp)
525
503
 
526
504
  @set.check(sexp)
527
505
 
@@ -532,17 +510,19 @@ module Rufus
532
510
  sexp.each { |c| do_check c }
533
511
  end
534
512
 
513
+ # A simple parse (relies on ruby_parser currently)
535
514
  #
536
- # a simple parse (relies on ruby_parser currently)
537
- #
538
- def parse (rubycode)
515
+ def parse(rubycode)
539
516
 
540
- #(@parser ||= RubyParser.new).parse(rubycode).to_a
541
- #
542
- # parser goes ballistic after a while, seems having a new parser
543
- # each is not heavy at all
517
+ self.class.parse(rubycode)
518
+ end
519
+
520
+ # A simple parse (relies on ruby_parser currently)
521
+ #
522
+ def self.parse(rubycode)
544
523
 
545
524
  RubyParser.new.parse(rubycode).to_a
546
525
  end
547
526
  end
548
527
  end
528
+
@@ -0,0 +1,3 @@
1
+
2
+ require 'rufus/treechecker'
3
+
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |s|
4
+
5
+ s.name = 'rufus-treechecker'
6
+ s.version = File.read('lib/rufus/treechecker.rb').match(/VERSION = '([^']+)'/)[1]
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = [ 'John Mettraux' ]
9
+ s.email = [ 'jmettraux@gmail.com' ]
10
+ s.homepage = 'http://rufus.rubyforge.org'
11
+ s.rubyforge_project = 'rufus'
12
+ s.summary = "tests strings of Ruby code for unauthorized patterns (exit, eval, ...)"
13
+ s.description = %{
14
+ tests strings of Ruby code for unauthorized patterns (exit, eval, ...)
15
+ }
16
+
17
+ #s.files = `git ls-files`.split("\n")
18
+ s.files = Dir[
19
+ 'Rakefile',
20
+ 'lib/**/*.rb', 'spec/**/*.rb', 'test/**/*.rb',
21
+ '*.gemspec', '*.txt', '*.rdoc', '*.md'
22
+ ]
23
+
24
+ s.add_runtime_dependency 'ruby_parser', '>= 2.0.5'
25
+
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency 'rspec', '>= 2.0'
28
+
29
+ s.require_path = 'lib'
30
+ end
31
+